Files
2025-02-19 14:42:38 +01:00

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, &paraSet);
// 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;
}