355 lines
12 KiB
C++
355 lines
12 KiB
C++
/*
|
|
* CRC_DMA.cpp
|
|
*
|
|
* Created on: Feb 8, 2025
|
|
* Author: user
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <sys/mman.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
|
|
#include "axi_crc_dma.h"
|
|
|
|
|
|
// #define DEBUG
|
|
|
|
#define TEST_RUNS 10
|
|
|
|
#define MAX_PACKET_SIZE 10000
|
|
#define MAX_NUMBER_PACKETS 100
|
|
|
|
// Berechnen einer 32 Bit CRC-Pruefsumme mit allen Parametern
|
|
uint32_t calcCRC32(
|
|
uint8_t* inBytes,
|
|
size_t size,
|
|
uint32_t polynomial,
|
|
uint32_t initialValue,
|
|
uint32_t finalXOR,
|
|
uint8_t inputReflected,
|
|
uint8_t outputReflected
|
|
);
|
|
|
|
|
|
int main(int argc, char** argv)
|
|
{
|
|
// Anzahl Testlaeufe
|
|
int testRuns = TEST_RUNS;
|
|
|
|
// Argument auswerten
|
|
if (argc > 1) {
|
|
testRuns = atoi(argv[1]);
|
|
}
|
|
|
|
// Logdatei anlegen
|
|
char logFileName[100];
|
|
time_t now = time(NULL);
|
|
struct tm *t = localtime(&now);
|
|
|
|
strftime(logFileName, sizeof(logFileName)-1, "log_%Y-%m-%d_%H-%M-%S.txt", t);
|
|
FILE *logFile = fopen(logFileName, "w");
|
|
|
|
if (logFile == NULL) {
|
|
printf("Oeffnen/Erstellen der Logdatei fehlgeschlagen!\n\n");
|
|
return 1;
|
|
}
|
|
|
|
// some established CRC32 Parameter sets. Source: https://reveng.sourceforge.io/crc-catalogue/ (13.02.2025)
|
|
const CrcParameterSet CRC32_AIXM = {
|
|
.Polynomial = 0x814141ab,
|
|
.InitalValue = 0x0,
|
|
.FinalXOR = 0x0,
|
|
.InputReflected = false,
|
|
.OutputReflected = false
|
|
};
|
|
|
|
const CrcParameterSet CRC32_ISO_HDLC = {
|
|
.Polynomial = 0x04c11db7,
|
|
.InitalValue = 0xFFFFFFFF,
|
|
.FinalXOR = 0xFFFFFFFF,
|
|
.InputReflected = true,
|
|
.OutputReflected = true
|
|
};
|
|
|
|
const CrcParameterSet CRC32_ISCSI = {
|
|
.Polynomial = 0x1edc6f41,
|
|
.InitalValue = 0xFFFFFFFF,
|
|
.FinalXOR = 0xFFFFFFFF,
|
|
.InputReflected = true,
|
|
.OutputReflected = true
|
|
};
|
|
|
|
const CrcParameterSet CRC32_CD_ROM_EDC = {
|
|
.Polynomial = 0x8001801b,
|
|
.InitalValue = 0x0,
|
|
.FinalXOR = 0x0,
|
|
.InputReflected = false,
|
|
.OutputReflected = false
|
|
};
|
|
|
|
const CrcParameterSet CRC32_BZIP2 = {
|
|
.Polynomial = 0x04c11db7,
|
|
.InitalValue = 0xFFFFFFFF,
|
|
.FinalXOR = 0xFFFFFFFF,
|
|
.InputReflected = false,
|
|
.OutputReflected = false
|
|
};
|
|
|
|
CrcParameterSet CrcSets[5] = {CRC32_AIXM, CRC32_ISO_HDLC, CRC32_ISCSI, CRC32_CD_ROM_EDC, CRC32_BZIP2};
|
|
|
|
// Fuer Erzeugung "zufaelliger" Daten
|
|
srand(time(NULL));
|
|
|
|
// UIO & pointers
|
|
int fdCRC = open("/dev/uio0", O_RDWR);
|
|
int fdMem = open("/dev/uio16", O_RDWR);
|
|
PCRC_DMA_Typedef CRC = (PCRC_DMA_Typedef) mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fdCRC, 0);
|
|
uint32_t* pMem = (uint32_t*) mmap(NULL, 0x20000000, PROT_READ | PROT_WRITE, MAP_SHARED, fdMem, 0);
|
|
|
|
// Physische Adressen anlegen
|
|
uint32_t uio16PhysBase = 0x30000000; // UIO16 physical Baseaddress
|
|
uint32_t* pDataPhy = (uint32_t*) uio16PhysBase;
|
|
|
|
// Speicher fuer die Ergebnisse der CRC Berechnungen durch Hardware und Software
|
|
uint32_t crc_sw[MAX_NUMBER_PACKETS];
|
|
uint32_t crc_hw[MAX_NUMBER_PACKETS];
|
|
|
|
bool allTestrunsOK = true;
|
|
size_t totalDataRead = 0; // Zaehler fuer insgesamt gelesene Daten
|
|
|
|
// Die Software ist in mehrere Testlaufe unterteilt
|
|
// Jeder Testdurchlauf erzeugt eine zufaellige Anzahl Pakete und eine zufaellige Paketgroesse
|
|
for (int TestRun = 1; TestRun <= testRuns; TestRun++) {
|
|
CrcParameterSet paraSet = CrcSets[TestRun % 5];
|
|
|
|
// Paketgroesse und Paketanzahl erzeugen
|
|
uint16_t packet_size = (uint16_t) (rand() % MAX_PACKET_SIZE) + 1;
|
|
uint16_t number_packets = (uint16_t) (rand() % MAX_NUMBER_PACKETS) + 1;
|
|
|
|
// Mehrdimensionale Arrays deklarieren und mit virtuellen Adressen initialisieren
|
|
uint32_t (*data)[packet_size] = (uint32_t (*)[packet_size]) pMem;
|
|
uint32_t (*DataDest)[packet_size+1] = (uint32_t (*)[packet_size+1]) (pMem + packet_size*number_packets);
|
|
|
|
// Ausgabe
|
|
printf("------------- Starten von Testdurchlauf %i -------------\n\n", TestRun);
|
|
fprintf(logFile, "------------- Starten von Testdurchlauf %i -------------\n\n", TestRun);
|
|
printf("Paketgroesse: %i\tPaketanzahl: %i\n\n", packet_size, number_packets);
|
|
fprintf(logFile, "Paketgroesse: %i\tPaketanzahl: %i\n\n", packet_size, number_packets);
|
|
|
|
// Testdaten erzeugen
|
|
printf("Testdaten erzeugen\n");
|
|
fprintf(logFile, "Testdaten erzeugen\n");
|
|
for (int packet = 0; packet < number_packets; packet++) {
|
|
for (int word = 0; word < packet_size; word++) {
|
|
data[packet][word] = (uint32_t) rand();
|
|
}
|
|
}
|
|
|
|
// axi_crc_dam Komponete parametrieren
|
|
CRC->Control |= (1<<1); // INT aktivieren
|
|
CRC->ReadAddress = (uint32_t) pDataPhy;
|
|
CRC->WriteAddress = (uint32_t) (pDataPhy + number_packets * packet_size);
|
|
CRC->PacketSize = packet_size - 1;
|
|
CRC->NumberPackets = number_packets - 1;
|
|
CRC_DMA_set_parameters(CRC, ¶Set);
|
|
|
|
// Interrupt zurücksetzen und aktivieren
|
|
CRC->InterruptStatus = 0;
|
|
int reenable = 1;
|
|
write(fdCRC, (void*) &reenable, 4);
|
|
|
|
// CRC Berechnung mit Hardware starten
|
|
printf("CRC-Berechnung in Hardware starten\n");
|
|
fprintf(logFile, "CRC-Berechnung in Hardware starten\n");
|
|
CRC->Control |= (1<<0);
|
|
|
|
// Auf INT warten
|
|
printf("Auf Interrupt warten...\n");
|
|
fprintf(logFile, "Auf Interrupt warten...\n");
|
|
int pending;
|
|
read(fdCRC, (void*) &pending, 4);
|
|
CRC->InterruptStatus = 0;
|
|
write(fdCRC, (void*) &reenable, 4);
|
|
printf("Interrupt erhalten\n");
|
|
fprintf(logFile, "Interrupt erhalten\n");
|
|
|
|
// Hardwareergebnis in Array ablegen
|
|
for (int p = 0; p < number_packets; p++) {
|
|
crc_hw[p] = DataDest[p][packet_size];
|
|
}
|
|
|
|
// CRC Berechnung in Software durchfuehren
|
|
printf("CRC-Berechnung in Software durchfuehren\n");
|
|
fprintf(logFile, "CRC-Berechnung in Software durchfuehren\n");
|
|
for (int p = 0; p < number_packets; p++) {
|
|
crc_sw[p] = calcCRC32((uint8_t*) (&data[p][0]),
|
|
packet_size*4,
|
|
paraSet.Polynomial,
|
|
paraSet.InitalValue,
|
|
paraSet.FinalXOR,
|
|
paraSet.InputReflected ? 1 : 0,
|
|
paraSet.OutputReflected ? 1 : 0
|
|
);
|
|
|
|
// printf("Packet %i:\t0x%08x\n", p, crc_sw[p]);
|
|
// fprintf(logFile, "Packet %i:\t0x%08x\n", p, crc_sw[p]);
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
// data und DataDest komplett ausgeben
|
|
printf("\ndata\tDataDest:\n");
|
|
fprintf(logFile, "\ndata\tDataDest:\n");
|
|
for (int p = 0; p < number_packets; p++) {
|
|
for (int w = 0; w < packet_size+1; w++) {
|
|
|
|
// dataDest ausgeben
|
|
if (w < packet_size) {
|
|
printf("0x%08x: 0x%08x\t0x%08x: 0x%08x\n", &DataDest[p][w], DataDest[p][w], &data[p][w], data[p][w]);
|
|
fprintf(logFile, "0x%08x: 0x%08x\t0x%08x: 0x%08x\n", &DataDest[p][w], DataDest[p][w], &data[p][w], data[p][w]);
|
|
} else {
|
|
printf("0x%08x: 0x%08x\n", &DataDest[p][w], DataDest[p][w]);
|
|
fprintf(logFile, "0x%08x: 0x%08x\n", &DataDest[p][w], DataDest[p][w]);
|
|
}
|
|
}
|
|
}
|
|
printf("\n\n");
|
|
fprintf(logFile, "\n\n");
|
|
#endif
|
|
|
|
// Daten und Ergebnisse vergleichen
|
|
unsigned int wrongWords = 0; // Zaehler fuer Anzahl der fehlerhaften Worte im (Ziel-)Speicher
|
|
printf("Daten und Ergebnisse vergleichen:\n");
|
|
fprintf(logFile, "Daten und Ergebnisse vergleichen:\n");
|
|
bool allPaketsOK = true;
|
|
for (int p = 0; p < number_packets; p++) {
|
|
bool dataOK = true;
|
|
bool crcOK = true;
|
|
|
|
printf("Paket %i:\t", p);
|
|
fprintf(logFile, "Paket %i:\t", p);
|
|
|
|
for (int w = 0; w < packet_size; w++) {
|
|
// Daten vergleichen
|
|
if (data[p][w] != DataDest[p][w]) {
|
|
dataOK = false;
|
|
wrongWords++;
|
|
printf("Fehler bei Datenwort %i\t", w);
|
|
fprintf(logFile, "Fehler bei Datenwort %i\t", w);
|
|
}
|
|
}
|
|
|
|
if (dataOK) {
|
|
printf("Daten OK\t");
|
|
fprintf(logFile, "Daten OK\t");
|
|
}
|
|
|
|
// CRC Ergebnis vergleichen
|
|
if (crc_hw[p] != crc_sw[p]) {
|
|
crcOK = false;
|
|
wrongWords++;
|
|
printf("Fehler bei CRC\t");
|
|
fprintf(logFile, "Fehler bei CRC\t");
|
|
}
|
|
|
|
if (crcOK) {
|
|
printf("CRC OK\t");
|
|
fprintf(logFile, "CRC OK\t");
|
|
}
|
|
|
|
printf("CRC: 0x%08x\n", crc_hw[p]);
|
|
fprintf(logFile, "CRC: 0x%08x\n", crc_hw[p]);
|
|
|
|
if (!(crcOK && dataOK)) {
|
|
allPaketsOK = false;
|
|
}
|
|
}
|
|
|
|
if (allPaketsOK) {
|
|
printf("Alle Pakete OK\nTestlauf erfolgreich abgeschlossen!\n");
|
|
fprintf(logFile, "Alle Pakete OK\nTestlauf erfolgreich abgeschlossen!\n");
|
|
} else {
|
|
allTestrunsOK = false;
|
|
printf("Ein oder mehrere Pakete nicht OK.\n");
|
|
fprintf(logFile, "Ein oder mehrere Pakete nicht OK.\n");
|
|
double percentageWrong = (double) wrongWords / (number_packets*packet_size + number_packets);
|
|
printf("%f Prozent der geschriebenen Worte sind fehlerhaft!\n", percentageWrong);
|
|
fprintf(logFile, "%f Prozent der geschriebenen Worte sind fehlerhaft!\n", percentageWrong);
|
|
}
|
|
|
|
// Menge der gelesene Daten ausgeben
|
|
size_t dataReadThisRun = packet_size * number_packets * sizeof(uint32_t);
|
|
totalDataRead += dataReadThisRun;
|
|
printf("Gelesene Datenmenge in diesem Testlauf: %zu Bytes\n\n", dataReadThisRun);
|
|
fprintf(logFile, "Gelesene Datenmenge in diesem Testlauf: %zu Bytes\n\n", dataReadThisRun);
|
|
}
|
|
|
|
if (allTestrunsOK) {
|
|
printf("Alle Testlaeufe erfolgreich abgeschlossen!\n");
|
|
fprintf(logFile, "Alle Testlaeufe erfolgreich abgeschlossen!\n");
|
|
} else {
|
|
printf("Ein oder mehrere Testlaeufe sind fehlerhaft!\n");
|
|
fprintf(logFile, "Ein oder mehrere Testlaeufe sind fehlerhaft!\n");
|
|
}
|
|
|
|
printf("Insgesamt gelesene Datenmenge: %zu Bytes\n", totalDataRead);
|
|
fprintf(logFile, "Insgesamt gelesene Datenmenge: %zu Bytes\n", totalDataRead);
|
|
|
|
fclose(logFile);
|
|
return 0;
|
|
}
|
|
|
|
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;
|
|
}
|