Bericht: Testkonzept fast fertig
This commit is contained in:
Binary file not shown.
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 59 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 69 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 78 KiB |
Binary file not shown.
+150
-8
@@ -255,21 +255,22 @@ Sobald alle Datenpakete verarbeitet und wieder in den Speicher geschrieben wurde
|
||||
|
||||
Um das CRC-DMA-IP in ein Gesamtsystem einzubinden, müssen die AXI-Lite und Full-AXI Schnittstellen mit dem Processing System (PS) des Zynq-SoC verbunden werden.
|
||||
Im hier erstellten Gesamtsystem wurde die Full-AXI-Master Schnittstelle mit der ACP-Schnittstelle verbunden.
|
||||
Da Speicherzugriffe auf das SDRAM mit der ACP-Schnittstelle über den Cache erfolgen, sind die Daten so stets mit der CPU snychronisiert.
|
||||
Da Speicherzugriffe auf das SDRAM mit der ACP-Schnittstelle über den Cache erfolgen, sind die Daten so stets mit der CPU synchronisiert.
|
||||
|
||||
Die GP-Master-AXI Schnittstelle ist mit der AXIL-Slave Schnittstelle des IPs verbunden.
|
||||
Damit ist die CPU in der Lage, die Konfigurationsregister des IPs zu schreiben und das IP zu starten.
|
||||
|
||||
Die Interuptleitung des IPs ist mit dem Interrupt-Controller des Zynq-SoC verbunden.
|
||||
Die Interruptleitung des IPs ist mit dem Interrupt-Controller des Zynq-SoC verbunden.
|
||||
|
||||
Der System ILA dient zur genaueren Betrachung der Full-AXI-Bursts IPs auf der Hardware.
|
||||
Dies wird in Abschnitt~\ref{sec:VerifikationGesamtsystem} genauer beschrieben.
|
||||
|
||||
Dieses Gesamtsystem kann nun synthetisiert und implementiert werden.
|
||||
|
||||
\newpage
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
\section{Konzept und Umsetzung der Software}
|
||||
|
||||
|
||||
\section{Software - Treiberfunktion}
|
||||
|
||||
\newpage
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
@@ -285,13 +286,154 @@ Daher liegt ein besonderes Augenmerk auf der Verifikation dieser Komponente.
|
||||
|
||||
\subsubsection{Referenzprogramm}
|
||||
|
||||
Zur Erstellung der
|
||||
Zunächst wurde das C-Programm \emph{crc.c} geschrieben, welches CRC-Prüfsummen in Software berechnet.
|
||||
Der CRC-Algorithmus wurde hauptsächlich mithilfe von Sunshine2k.de \cite{SunshineCrcErklärung} erstellt.
|
||||
Parallel wurden die Ergebnisse mit anderen CRC-Online Rechnern verglichen, um die Korrektheit der Berechnung zu überprüfen \cite{crcCalc}.
|
||||
|
||||
Kern dieses Programms ist die Funktion \texttt{uint32\_t calcCRC32(...)}, welche die CRC-Prüfsumme über ein Datenpaket berechnet.
|
||||
Mithilfe dieser Funktion können CRC-Prüfsummen für beliebige Datenpakete und für eine beliebige Kombination an CRC-Parametern berechnet werden.
|
||||
|
||||
Neben dem testweise Berechnen von Prüfsummen werden in der \texttt{main}-Funktion auch die CRC-Prüfsummen für die Testbench der CRC-Berechnungskomponente berechnet.
|
||||
Dies geschieht in der Funktion \texttt{void calc\_axis\_crc\_tb()}.
|
||||
|
||||
% \begin{lstlisting}[caption={Starten und Stoppen der Übertragung}, label={code:OW_start_transmission}]
|
||||
% uint32_t calcCRC32(
|
||||
% uint8_t* inBytes,
|
||||
% size_t size,
|
||||
% uint32_t polynomial,
|
||||
% uint32_t initialValue,
|
||||
% uint32_t finalXOR,
|
||||
% uint8_t inputReflected,
|
||||
% uint8_t outputReflected
|
||||
% ) {
|
||||
% uint32_t crc = initialValue;
|
||||
% uint8_t byte;
|
||||
|
||||
% for (size_t i = 0; i < size; i++) {
|
||||
% byte = inBytes[i];
|
||||
|
||||
% if (inputReflected != 0) {
|
||||
% uint8_t reflected = 0;
|
||||
|
||||
% for (int b = 0; b < 8; b++) {
|
||||
% if ((byte & (1<<b)) != 0) {
|
||||
% reflected |= (uint8_t) (1<<(7-b));
|
||||
% }
|
||||
% }
|
||||
% byte = reflected;
|
||||
% }
|
||||
|
||||
% crc ^= (uint32_t) (byte << 24);
|
||||
|
||||
% for (int bit = 0; bit < 8; bit++) {
|
||||
% if ((crc & (uint32_t)(1<<31)) != 0) {
|
||||
% crc = (uint32_t) (crc << 1) ^ polynomial;
|
||||
% } else {
|
||||
% crc <<= 1;
|
||||
% }
|
||||
% }
|
||||
% }
|
||||
|
||||
% if (outputReflected != 0) {
|
||||
% uint32_t reflected = 0;
|
||||
|
||||
% for (int i = 0; i < 32; i++) {
|
||||
% if ((crc & (uint32_t) (1<<i)) != 0) {
|
||||
% reflected |= (uint32_t) (1<<(31-i));
|
||||
% }
|
||||
% }
|
||||
% crc = reflected;
|
||||
% }
|
||||
|
||||
% return crc ^ finalXOR;
|
||||
% }
|
||||
% \end{lstlisting}
|
||||
|
||||
\subsubsection{Simulation / Testbench}
|
||||
|
||||
\subsection{Verifikation des CRC-DMA-IPs}
|
||||
Um die Korrektheit der CRC-Berechnungskomponente \emph{axis\_crc} zu gewährleisten, wurde eine Testbench erstellt.
|
||||
In dieser Testbench werden von der CRC-Berechnungskomponente insgesamt 24 Prüfsummen über dasselbe Datenpaket von drei 32-Bit-Worten mit verschiedenen Parametern berechnet.
|
||||
Da auch nur ein kleinster Fehler in der Implementierung des CRC-Algorithmus völlig andere Ergebnisse zur Folge hätte, genug es zunächst nur ein Datenpaket für die Verifikation zu nutzen.
|
||||
|
||||
\subsection{Verifikation des Gesamtsystems}
|
||||
Die Testbench wurde in VHDL geschrieben und überprüft automatisch die Korrektheit der berechneten CRC-Prüfsummen sowie das korrekte Ausgeben der Daten.
|
||||
|
||||
\begin{figure}[H]
|
||||
\centering
|
||||
\includegraphics[width=1.0\textwidth]{wave_axis_crc.png}
|
||||
\caption{Wave-Diagramm der \emph{axis\_crc} Testbench}
|
||||
\label{fig:AxisCrcTestbenchWave}
|
||||
\end{figure}
|
||||
|
||||
In Abbildung~\ref{fig:AxisCrcTestbenchWave} ist ein Ausschnitt des Wave-Diagramms der Testbench dargestellt.
|
||||
Falls einer der 24 Testfälle fehlschlägt, das heißt, wenn entweder die zugeführten Daten nicht wieder korrekt ausgegeben werden oder wenn die CRC-Prüfsumme falsch ist, wird eine Fehlermeldung ausgegeben.
|
||||
Somit kann die korrekte Funktionalität der CRC-Berechnungskomponente gewährleistet werden.
|
||||
|
||||
Die in dieser Arbeit erstellte CRC-Berechnungskomponente wurde mithilfe dieser Testbench erfolgriech verfiziert.
|
||||
|
||||
\subsection{Simulation des CRC-DMA-IPs}
|
||||
|
||||
\begin{figure}[H]
|
||||
\centering
|
||||
\includegraphics[width=1.0\textwidth]{Blockschaltbilder/axi_crc_dma_sim_default_view.png}
|
||||
\caption{Simulation des CRC-DMA-IPs}
|
||||
\label{fig:BlockschaltbildCRC_DMA_IP_Simulation}
|
||||
\end{figure}
|
||||
|
||||
Zur Simulation des gesamten CRC-DMA-IPs wird das Block-Design \emph{axi\_crc\_dma\_sim\_01} verwendet, welches in Abbildung~\ref{fig:BlockschaltbildCRC_DMA_IP_Simulation} dargestellt ist.
|
||||
Das IP \emph{axil\_master\_with\_rom} ist ein AXIL-Master, der die nötige Konfiguration des CRC-DMA-IPs durchführt und den Vorgang anschließend startet.
|
||||
Er stammt aus dem IP-Verzeichnis dieser Vorlesung.
|
||||
Die AXIL-Schreibbefehle für den AXIL-Master sind im Stimuli-Script \emph{axi\_crc\_dma\_sim.stm} definiert.
|
||||
|
||||
Das IP \emph{axi3\_slave\_verif} ist ein Baustein, der als Full-AXI-Slave fungiert.
|
||||
Er akzeptiert Schreibbursts und gibt bei Lesebursts selbst erzeugte Daten wieder.
|
||||
Dabei hat diese Komponente jedoch keinen internen Speicher, sondern dient nur dazu, korrekte Reaktionen auf Lese- und Schreibbursts zu erzeugen.
|
||||
Die Adressen und die eigentlichen Daten werden von dieser Komponente nicht verarbeitet.
|
||||
Das Grundgerüst dieser Komponente wurde mithilfe von ChatGPT erstellt und anschließend in der Simulation etwas angepasst, sodass das Verhalten möglichst dem korrekten Verhalten einer Full-AXI-Slave Schnittstelle entspricht.
|
||||
|
||||
In diesem Simulations-Block-Design wird zum einen die Funktionsweise der AXIL-Schnittstelle überprüft.
|
||||
Das heißt, dass die AXIL-Register richtig geschrieben und gelesen werden können und dass der CRC-DMA-Vorgang über das Kontrollregister gestartet werden kann.
|
||||
Zum anderen wird vornehmlich das richtige DMA-Verhalten des IPs überprüft.
|
||||
Dabei sind untern anderem folgende Punkte von Bedeutung:
|
||||
\begin{itemize}
|
||||
\item Werden die Valid/Ready-Handshakes korrekt durchgeführt?
|
||||
\item Werden die korrekten Adressen übergeben?
|
||||
\item Werden die korrekten Daten übergeben?
|
||||
\item Wird die korrekte Menge an Daten entsprechend der Konfiguration gelesen?
|
||||
\item Wird die korrekte Menge an Daten entsprechend der Konfiguration geschrieben?
|
||||
\item Werden stets maximal mögliche Burstlängen verwendet?
|
||||
\item Werden 4kB-Adressgrenzen korrekt behandelt?
|
||||
\item Wird Interruptleitung nach dem Vorgang korrekt gesetzt?
|
||||
\end{itemize}
|
||||
|
||||
Da es sich um eine manuelle Testbench handelt, werden all diese Punkte durch das Betrachten des Wave-Diagramms überprüft.
|
||||
Zusätzlich wurden dabei verschiedene Konfigurationen des IPs getstest, um auch die Funktionalität bei unterschiedlichen Parametern zu überprüfen und Edge-Cases mit abzudecken.
|
||||
|
||||
\begin{figure}[H]
|
||||
\centering
|
||||
\includegraphics[width=1.0\textwidth]{wave_axi_dma_sim_1_ausschnitt.png}
|
||||
\caption{Exemplarisches Wave-Diagramm der Simulation des CRC-DMA-IPs}
|
||||
\label{fig:CRC_DMA_IP_SimulationWave}
|
||||
\end{figure}
|
||||
|
||||
\subsection{Verifikation des Gesamtsystems} \label{sec:VerifikationGesamtsystem}
|
||||
|
||||
Die Verifikation des Gesamtsystems erfolgt auf der Hardware.
|
||||
|
||||
Für die finale Verifikation des CRC-DMA-IPs bzw. des Gesamtsystems wurde das Testprogramm \texttt{CRC\_DMA.cpp} erstellt, welches im Kontext eines Linux Betriebssystems ausgeführt wird.
|
||||
Das Testprogramm ist in mehrere Testläufe unterteilt.
|
||||
Der Ablauf eines Testlaufs ist wie folgt:
|
||||
\begin{enumerate}
|
||||
\item Auswählen eines neuen CRC-Parameter-Satzes
|
||||
\item Zufällige Datenpakete erzeugen mit einer zufälligen Paketanzahl und -größe
|
||||
\item Konfiguration der CRC-DMA-IPs
|
||||
\item Starten des CRC-DMA-IPs
|
||||
\item Berechnen der CRC-Prüfsummen in Software zur Verifikation
|
||||
\item Warten auf den Interrupt des IPs
|
||||
\item Überprüfen der vom IP geschriebenen Daten und CRC-Prüfsummen
|
||||
\end{enumerate}
|
||||
|
||||
Die Anzahl der Testläufe wird dem Programm als Argument beim Ausführen übergeben.
|
||||
Die Testergebnisse werden in einer Log-Datei gespeichert.
|
||||
|
||||
\newpage
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
breaklines=true, % Automatischer Zeilenumbruch
|
||||
frame=single, % Rahmen um den Codeblock
|
||||
captionpos=b, % Position der Beschriftung
|
||||
morekeywords={uint32_t, uint16_t, uint8_t, TIM_HandleTypeDef},
|
||||
morekeywords={uint32_t, uint16_t, uint8_t, size_t},
|
||||
}
|
||||
|
||||
%Zum Zusammenfügen von Spalten in tabular
|
||||
|
||||
@@ -3,14 +3,6 @@
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// PC speichert mit LITTLE ENDIAN
|
||||
|
||||
// Berechnen einer 8 Bit CRC-Pruefsumme
|
||||
uint8_t calcCRC8(uint8_t* data, size_t size);
|
||||
|
||||
// Berechnen einer 16 Bit CRC-Pruefsumme
|
||||
uint16_t calcCRC16(uint8_t* inBytes, size_t size);
|
||||
|
||||
// Berechnen einer 32 Bit CRC-Pruefsumme mit allen Parametern
|
||||
uint32_t calcCRC32(
|
||||
uint8_t* inBytes,
|
||||
@@ -51,51 +43,6 @@ int main()
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
uint8_t calcCRC8(uint8_t* inBytes, size_t size)
|
||||
{
|
||||
const uint8_t polynomial = 0xD5;
|
||||
uint8_t crc = 0x0; // initial value
|
||||
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
crc ^= inBytes[i];
|
||||
|
||||
for (int bit = 0; bit < 8; bit++) {
|
||||
if ((crc & 0x80) != 0) {
|
||||
crc = (uint8_t) ((crc << 1) ^ polynomial);
|
||||
}
|
||||
else {
|
||||
crc = (uint8_t)(crc << 1);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
|
||||
uint16_t calcCRC16(uint8_t* inBytes, size_t size)
|
||||
{
|
||||
const uint16_t polynomial = 0x1021;
|
||||
uint16_t crc = 0;
|
||||
|
||||
for (size_t b = 0; b < size; b++) {
|
||||
crc ^= (uint16_t) (inBytes[b] << 8);
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if ((crc & 0x8000) != 0) {
|
||||
crc = (uint16_t) (crc << 1) ^ polynomial;
|
||||
} else {
|
||||
crc = (uint16_t)(crc << 1);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
|
||||
uint32_t calcCRC32(
|
||||
uint8_t* inBytes,
|
||||
size_t size,
|
||||
|
||||
Reference in New Issue
Block a user