Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /**
- * @file axidma_transfer.c
- * @date Sunday, November 29, 2015 at 12:23:43 PM EST
- * @author Brandon Perez (bmperez)
- * @author Jared Choi (jaewonch)
- *
- * This program performs a simple AXI DMA transfer. It takes the input file,
- * loads it into memory, and then sends it out over the PL fabric. It then
- * receives the data back, and places it into the given output file.
- *
- * By default it uses the lowest numbered channels for the transmit and receive,
- * unless overriden by the user. The amount of data transfered is automatically
- * determined from the file size. Unless specified, the output file size is
- * made to be 2 times the input size (to account for creating more data).
- *
- * This program also handles any additional channels that the pipeline
- * on the PL fabric might depend on. It starts up DMA transfers for these
- * pipeline stages, and discards their results.
- *
- * @bug No known bugs.
- **/
- #include <stdlib.h>
- #include <stdio.h>
- #include <stdbool.h>
- #include <assert.h>
- #include <fcntl.h> // Flags for open()
- #include <sys/stat.h> // Open() system call
- #include <sys/types.h> // Types for open()
- #include <sys/mman.h>
- #include <unistd.h> // Close() system call
- #include <string.h> // Memory setting and copying
- #include <getopt.h> // Option parsing
- #include <errno.h> // Error codes
- #include <sqlite3.h>
- #include "util.h" // Miscellaneous utilities
- #include "conversion.h" // Convert bytes to MBs
- #include "libaxidma.h" // Interface ot the AXI DMA library
- /*----------------------------------------------------------------------------
- * Internal Definitions
- *----------------------------------------------------------------------------*/
- #define READ_LENGTH 1440
- #define READ_WIDTH 4
- #define FIFO_LENGTH 32768
- #define MAX_NUM_CYCLES_AVG 24
- // A convenient structure to carry information around about the transfer
- struct dma_transfer {
- void *input_buf; // The buffer to hold the input data
- int output_fd; // The file descriptor for the output file
- int output_channel; // The channel used to receive the data
- int output_size; // The amount of data to receive
- uint *output_buf; // The buffer to hold the output
- };
- static int transfer_file(axidma_dev_t dev, struct dma_transfer *trans) {
- int rc;
- float resultBuf[4000];
- // Allocate a buffer for the output file
- if (trans->output_buf == NULL) {
- rc = -ENOMEM;
- }
- // Perform the transfer
- // Perform the main transaction
- rc = axidma_oneway_transfer(dev, trans->output_channel, trans->output_buf,
- trans->output_size, true);
- if (rc < 0) {
- fprintf(stderr, "DMA read transaction failed.\n");
- }
- // Write the data to the output file
- //printf("Writing output data to `%s`.\n", output_path);
- for(int i=0; i<READ_LENGTH; i++){
- resultBuf[i] = ((float)trans->output_buf[i])/71643.667;
- }
- rc = robust_write(trans->output_fd, (char*) resultBuf, sizeof(float)*READ_LENGTH);
- return rc;
- }
- int program_init(int* memfd, volatile int** bufferLenW, axidma_dev_t* axidma_dev, struct dma_transfer* trans){
- const array_t *rx_chans;
- //Attempt to open /dev/mem
- *memfd = open("/dev/mem",O_RDWR|O_SYNC);
- if(*memfd < 0) {
- return -1;
- }
- //Map FIFO Length Register into memory
- *bufferLenW = (int*) mmap(0, 4096UL, PROT_READ | PROT_WRITE, MAP_SHARED, *memfd, 0x81200000);
- printf("FIFO Length Register Mapped @ %X \n", bufferLenW);
- // Initialize the AXIDMA device
- *axidma_dev = axidma_init();
- if (axidma_dev == NULL) {
- return -2;
- }
- //Get List of Rx Channels
- rx_chans = axidma_get_dma_rx(*axidma_dev);
- if (rx_chans->len < 1) {
- axidma_destroy(*axidma_dev);
- return -ENODEV;
- }
- //Select the first read channel and set the read size
- trans->output_channel = rx_chans->data[0];
- trans->output_size = READ_LENGTH * READ_WIDTH;
- return 0;
- }
- void program_exit(int exitCode){
- switch(exitCode){
- case -1:
- fprintf(stderr, "Unable to open /dev/mem. You must be the root user.\n");
- exit(-1);
- case -2:
- fprintf(stderr, "Unable to initialise the AXI DMA device.\n");
- exit(-2);
- case -ENODEV:
- fprintf(stderr, "AXI DMA device has no read channels.\n");
- exit(-ENODEV);
- default:
- fprintf(stderr, "Unknown error.\n");
- exit(exitCode);
- }
- }
- int generate_cycle_avg(uint* cycleAvg[], long long cycleAcmResult[], float cycleAvgResult[], uint* dmaBuf, int* numCyclesAvg, uint* targetCyclesAvg){
- //printf("Check if we're removing the final buffers\n NUM: %d\n TGT: %u\n", *numCyclesAvg, *targetCyclesAvg);
- //printf("Pointer array:\n");
- //for(int i = 0; i < MAX_NUM_CYCLES_AVG; i++) {
- // printf("[%X]", cycleAvg[i]);
- //}
- //printf("\n");
- if (*targetCyclesAvg < *numCyclesAvg) {
- //printf("Remove 2 buffers\n");
- //Remove the final two buffers from the accumulated result
- for(int i = (*numCyclesAvg - 2); i < *numCyclesAvg; i++){
- for(int j = 0; j < READ_LENGTH; j++) {
- cycleAcmResult[j] -= cycleAvg[i][j];
- }
- }
- //Free the final two buffers that were just cleared from the accumulated result
- //printf("Final addresses:\n%X\n%X\n", cycleAvg[*numCyclesAvg -1], cycleAvg[*numCyclesAvg - 2]);
- free(cycleAvg[*numCyclesAvg-1]);
- free(cycleAvg[*numCyclesAvg-2]);
- //Update the buffer count
- *numCyclesAvg = *numCyclesAvg - 2;
- } else if (*targetCyclesAvg == *numCyclesAvg) {
- //printf("Remove 1 buffer\n");
- //Subtract the final buffer from the accumulated result
- for(int j = 0; j < READ_LENGTH; j++) {
- cycleAcmResult[j] -= cycleAvg[*numCyclesAvg-1][j];
- }
- //printf("Attempt to free the final pointer\n");
- //Free the final pointer
- free(cycleAvg[(*numCyclesAvg-1)]);
- //Update the buffer count
- *numCyclesAvg = *numCyclesAvg - 1;
- }
- //printf("Shift all buffers up\n");
- //Shift all buffers up a place
- for(int i = *numCyclesAvg-1; i >= 0; i--){
- //printf("i = %d, Shift\n", i);
- cycleAvg[i+1] = cycleAvg[i];
- }
- //printf("Add a new buffer\n");
- //Add a new buffer
- cycleAvg[0] = (uint*) malloc(READ_LENGTH*sizeof(uint));
- //printf("Populate the new buffer\n", *numCyclesAvg);
- //Populate the new buffer and add to the accumulated result
- for(int i=0; i < READ_LENGTH; i++){
- cycleAvg[0][i] = dmaBuf[i];
- cycleAcmResult[i] += (uint) dmaBuf[i];
- }
- //Update the buffer count
- *numCyclesAvg = *numCyclesAvg + 1;
- //printf("Generate the average result\n\n\n");
- //Generate the cycle average result
- for(int i = 0; i < READ_LENGTH; i++) {
- cycleAvgResult[i] = ((float)cycleAcmResult[i])/(*numCyclesAvg)/71643.667;
- }
- }
- static int select_callback(int *data, int argc, char** argv, char** err) {
- *data = atoi(argv[0]);
- }
- int main(int argc, char **argv)
- {
- //Variable Declarations
- int memfd = 0;
- int returnVal = 0;
- char outFileName[50];
- char avgFileName[50];
- char rmFileName[50];
- char rmAvgFileName[50];
- sqlite3 *db;
- uint *cycleAvg[MAX_NUM_CYCLES_AVG];
- float* cycleAvgResult;
- long long* cycleAcmResult;
- int cycleAvgFd = 0;
- uint initCycleCount = 0; //Used to initially fill the accumulation array
- int numCyclesAvg = 0;
- uint targetCyclesAvg = 12;
- char* sqlErr;
- //Zero all the pointers in the cycleAvg array
- for (int i = 0; i < MAX_NUM_CYCLES_AVG; i++){
- cycleAvg[i] = 0;
- }
- cycleAvgResult = (float*) malloc(READ_LENGTH*sizeof(float));
- cycleAcmResult = (long long*) malloc(READ_LENGTH*sizeof(long long));
- for(int i = 0; i < READ_LENGTH; i++){
- cycleAvgResult[i] = 0;
- cycleAcmResult[i] = 0;
- }
- volatile int *bufferLenW;
- axidma_dev_t axidma_dev;
- struct dma_transfer trans;
- //Begin Main
- returnVal = program_init(&memfd, &bufferLenW, &axidma_dev, &trans);
- printf("Returned %d from program init()\n", returnVal);
- if(returnVal < 0){
- program_exit(returnVal);
- }
- //Open the SQL database (this should be moved to the init function later)
- returnVal = sqlite3_open("/mnt/ramdisk/settings.db", &db);
- if(returnVal){
- fprintf(stderr, "Failed to open the database\n");
- exit(returnVal);
- }
- //Inital output
- printf("AXI DMA File Transfer Info:\n");
- printf("\tReceive Channel: %d\n", trans.output_channel);
- printf("\tFIFO buffer length: %u\n", bufferLenW);
- //allocate a transfer buffer
- trans.output_buf = axidma_malloc(axidma_dev, trans.output_size);
- /*** MAIN TRANSFER LOOP ***/
- int i = 0;
- while(1){
- if(i == 999){
- i = 0;
- //remove old files
- for(int j = 987; j < 999; j++){
- sprintf(rmFileName, "/mnt/ramdisk/cycle%03d", j);
- sprintf(rmAvgFileName, "/mnt/ramdisk/avg%03d", j);
- remove(rmFileName);
- remove(rmAvgFileName);
- }
- }
- //Set the file names
- sprintf(outFileName, "/mnt/ramdisk/cycle%03d", i);
- sprintf(avgFileName, "/mnt/ramdisk/avg%03d", i);
- sprintf(rmFileName, "/mnt/ramdisk/cycle%03d", i-12);
- sprintf(rmAvgFileName, "/mnt/ramdisk/avg%03d", i-12);
- i++;
- //Attempt to open a new file
- trans.output_fd = open(outFileName, O_WRONLY|O_CREAT|O_TRUNC, S_IWUSR|S_IRUSR|S_IRGRP|S_IWGRP|S_IROTH);
- cycleAvgFd = open(avgFileName, O_WRONLY|O_CREAT|O_TRUNC, S_IWUSR|S_IRUSR|S_IRGRP|S_IWGRP|S_IROTH);
- if (trans.output_fd < 0) {
- fprintf(stderr, "Unable to create output file: %s\n", outFileName);
- axidma_free(axidma_dev, trans.output_buf, trans.output_size);
- continue;
- }
- //Attempt to remove an old file
- if(i > 11){
- remove(rmFileName);
- remove(rmAvgFileName);
- }
- int writeBuffer0 = 0;
- int writeBuffer1 = 0;
- //check for buffer overrun
- if((*bufferLenW > FIFO_LENGTH) && i > 0){
- printf("FIFO buffer overrun\n");
- }
- //wait until there are enough bytes to perform a read
- int sleepTime = 0;
- while(*bufferLenW < READ_LENGTH){
- usleep(100);
- sleepTime += 100;
- if(sleepTime > 1000000){
- printf("Sleep: %d\n", *bufferLenW);
- sleepTime = 0;
- }
- }
- //Perform the DMA transfer
- writeBuffer0 = *bufferLenW;
- transfer_file(axidma_dev, &trans);
- writeBuffer1 = *bufferLenW;
- close(trans.output_fd);
- printf("%u before transaction, %u after transaction - Slider:%u\n", writeBuffer0, writeBuffer1, targetCyclesAvg);
- //Generate the new cycle average
- generate_cycle_avg(cycleAvg, cycleAcmResult, cycleAvgResult, trans.output_buf, &numCyclesAvg, &targetCyclesAvg);
- robust_write(cycleAvgFd, (char*) cycleAvgResult, sizeof(float)*READ_LENGTH);
- close(cycleAvgFd);
- //Update the cycleAverageTarget from the database
- returnVal = sqlite3_exec(db, "SELECT val FROM settings WHERE id='numSampleAvg'", select_callback, &targetCyclesAvg, &sqlErr);
- }
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement