/* ------------------------------------------------------------------------------- * intr_latency.c * * author: Mark McDermott * Created: Jan 30, 2009 * Updated: Apr 23, 2017 For Zedboard * Updated: Feb 2, 2021 For Ultra96 * * This routine measures the average latency from the time an interrupt input * to the SOC occurs to when it is handled. This is used to determine how fast * the SOC can handle interrupts from the H1KP * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #undef DEBUG #define DEBUG /* ------------------------------------------------------------------------------- * One-bit masks for bits 0-31 */ #define ONE_BIT_MASK(_bit) (0x00000001 << (_bit)) /* -------------------------------------------------------------------------------*/ #define MAP_SIZE 4096UL #define MAP_MASK (MAP_SIZE - 1) //For project #define ROWS 32 #define COLS 32 /* ------------------------------------------------------------------------------- * Device path name for the GPIO device */ #define GPIO_DEV_PATH "/dev/gpio_int" #define GPIO_DR_NUM 0x0 // Pin Number #define GPIO_DR 0xA0050004 // Interrupt register /* ------------------------------------------------------------------------------- * Number of interrupt latency measurements to take: */ #define NUM_MEASUREMENTS 100 #define MAX_STRING_LENGTH 100 /* ------------------------------------------------------------------------------- * File descriptor for GPIO device */ int gpio_dev_fd = -1; /* ------------------------------------------------------------------------------- * Counter of number of times sigio_signal_handler() has been executed */ volatile int sigio_signal_count = 0; /* ------------------------------------------------------------------------------- * Flag to indicate that a SIGIO signal has been processed */ static volatile sig_atomic_t sigio_signal_processed = 0; /* ------------------------------------------------------------------------------- * Time stamp set in the last sigio_signal_handler() invocation: */ struct timeval sigio_signal_timestamp; /* ------------------------------------------------------------------------------- * Array of interrupt latency measurements (in micro seconds): */ unsigned long intr_latency_measurements[NUM_MEASUREMENTS]; /* ------------------------------------------------------------------------------- * Function prototypes */ int gpio_set_pin(unsigned int target_addr, unsigned int pin_number, unsigned int bit_val); unsigned long int_sqrt(unsigned long n); void sigio_signal_handler(int signo); void compute_interrupt_latency_stats( unsigned long *min_latency_p, unsigned long *max_latency_p, double *average_latency_p, double *std_deviation_p); int fm(unsigned int target_addr, unsigned int value[], unsigned int lp_cnt, unsigned int increment, int fd); void extract_integers(unsigned long input_number, unsigned int *int1, unsigned int *int2) { int byte_count = 0; unsigned long temp = input_number; while(temp>0) { temp = temp>>8; byte_count = byte_count+1; } int zeros = 8 - byte_count; printf("before_shift = %lu",input_number); printf("byte_count = %i",byte_count); if(byte_count>4){ input_number = input_number << 8*zeros; //unsigned int hex_num = 0xFFFFFFFF; printf("shifted_input = %lu",input_number); *int1 = (unsigned int)(input_number & 0xFFFFFFFF); *int2 = (unsigned int)((input_number >> 32) & 0xFFFFFFFF); } else { input_number = input_number << 8*(4-byte_count); *int2 = (unsigned int)(input_number & 0xFFFFFFFF); *int1 = 0; } } void Convert_string_to_int(int len,char* input_data,unsigned int input_arr[]) { int index = 0; for(int i=0;i\n", argv[0]); return EXIT_FAILURE; } else if (strcmp(argv[1], "-f") == 0) { const char *filename = argv[2]; printf("File parsing if condition\n"); FILE *file = fopen(filename, "r"); if (file == NULL) { perror("Error opening file"); exit(EXIT_FAILURE); } // Read data from the file for (i = 0; i < ROWS; i++) { for (j = 0; j < COLS; j++) { if (fscanf(file, "%d,", &data[i][j]) != 1) { printf("Error reading from file.\n"); fclose(file); return 1; } } } // Close the file fclose(file); } /*for (i = 0; i < ROWS; i++) { for (j = 0; j < COLS; j++) { printf("%d ", data[i][j]); } }*/ /* -------------------------------------------------------------------------- * Register signal handler for SIGIO signal: */ struct sigaction sig_action; memset(&sig_action, 0, sizeof sig_action); sig_action.sa_handler = sigio_signal_handler; /* -------------------------------------------------------------------------- * Block all signals while our signal handler is executing: */ (void)sigfillset(&sig_action.sa_mask); rc = sigaction(SIGIO, &sig_action, NULL); if (rc == -1) { perror("sigaction() failed"); return -1; } /* ------------------------------------------------------------------------- * Open the device file */ gpio_dev_fd = open(GPIO_DEV_PATH, O_RDWR); if (gpio_dev_fd == -1) { perror("open() of " GPIO_DEV_PATH " failed"); return -1; } /* ------------------------------------------------------------------------- * Set our process to receive SIGIO signals from the GPIO device: */ rc = fcntl(gpio_dev_fd, F_SETOWN, getpid()); if (rc == -1) { perror("fcntl() SETOWN failed\n"); return -1; } /* ------------------------------------------------------------------------- * Enable reception of SIGIO signals for the gpio_dev_fd descriptor */ int fd_flags = fcntl(gpio_dev_fd, F_GETFL); rc = fcntl(gpio_dev_fd, F_SETFL, fd_flags | O_ASYNC); if (rc == -1) { perror("fcntl() SETFL failed\n"); return -1; } int dh = open("/dev/mem", O_RDWR | O_SYNC); if (dh == -1) { printf("Unable to open /dev/mem. Ensure it exists (major=1, minor=1)\n"); printf("Must be root to run this routine.\n"); return -1; } volatile unsigned int *APLL_CTRL, *APLL_CFG, *PLL_STATUS, *pl0_clk_CTRL, *pl1_clk_CTRL, *clk_reg,*pl0_clk,*pl1_clk; //Configured the register value for pl0 clock and pl1 clock APLL_CTRL = (unsigned int *)mmap(NULL, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, dh, 0x00FD1A0020 & ~MAP_MASK); APLL_CFG = (unsigned int *)mmap(NULL, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, dh, 0x00FD1A0024 & ~MAP_MASK); PLL_STATUS = (unsigned int *)mmap(NULL, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, dh, 0x00FD1A0044 & ~MAP_MASK); pl0_clk_CTRL = (unsigned int *)mmap(NULL, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, dh, 0x00FF5E00C0 & ~MAP_MASK); pl0_clk = pl0_clk_CTRL + ((0x00FF5E00C0 & MAP_MASK) >> 2); pl1_clk_CTRL = (unsigned int *)mmap(NULL, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, dh, 0x00FF5E00C4 & ~MAP_MASK); pl1_clk = pl1_clk_CTRL + ((0x00FF5E00C4 & MAP_MASK) >> 2); // Configured for 100 MHz *pl0_clk = (1 << 24) | (6 << 16) // 3 to 6 50 MHz | (5 << 8); //Configured for 100 MHz *pl1_clk = (1 << 24) | (6 << 16) | (5 << 8); volatile unsigned int *reg0_keccak, *reg0_keccak_value,*num_bytes_keccak, *num_bytes_keccak_value,*start_keccak_addr, *start_keccak_addr_value; volatile unsigned int *capture_timer, *capture_timer_value; volatile unsigned int *output_reg, *output_address; volatile unsigned int *output_reg_index, *output_address_index; //Configured the register value for Keccak module - bytes and start address reg0_keccak = (unsigned int *)mmap(NULL, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, dh, 0xb0000000 & ~MAP_MASK); num_bytes_keccak = (unsigned int *)mmap(NULL, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, dh, 0xb0000004 & ~MAP_MASK); start_keccak_addr = (unsigned int *)mmap(NULL, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, dh, 0xb0000008 & ~MAP_MASK); //Configured the register value for Capture timer capture_timer = (unsigned int *)mmap(NULL, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, dh, 0xb0002008 & ~MAP_MASK); reg0_keccak_value = reg0_keccak + ((0xb0000000 & MAP_MASK) >> 2); num_bytes_keccak_value = num_bytes_keccak + ((0xb0000004 & MAP_MASK) >> 2); start_keccak_addr_value = start_keccak_addr + ((0xb0000008 & MAP_MASK) >> 2); capture_timer_value = capture_timer + ((0xb0002008 & MAP_MASK) >> 2); /* ------------------------------------------------------------------------- * Take interrupt latency measurements in a loop: */ //Hardcoded for 0xffffffff for 4 bytes //Project code - to write data into ocm volatile unsigned int *regs, *address ; volatile unsigned int target_addr, offset, value, lp_cnt; lp_cnt = 1; // Write at least 1 location offset = 0; target_addr = 0xfffc0000; //write in OCM address regs = (unsigned int *)mmap(NULL, MAP_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, dh, target_addr & ~MAP_MASK); // Printing the array and sending data to ocm int flag = 0; for (i = 0; i < ROWS; i++) { for (j = 0; j < COLS; j++) { //printf("%d ", data[i][j]); value = data[i][j]; address = regs + (((target_addr + offset) & MAP_MASK)>>2); if(flag==0) { flag = 1; *address = value; // perform write command } else if(flag==1) { flag = 0; offset += 4; int temp = *address; temp = temp<<8; temp = temp <<8; *address = temp + value; //printf(" = 0x%.8x\n", *address);// display register value } //printf("0x%.8x" , (target_addr + offset)); //printf(" = 0x%.8x\n", *address);// display register value } //printf("\n"); } //Output registers output_reg = (unsigned int *)mmap(NULL, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, dh, 0xb0000044 & ~MAP_MASK); output_address = output_reg + ((0xb0000044 & MAP_MASK) >> 2); volatile unsigned int offset1; offset1 = 0; int k=0,l=0; // iteration for output output_reg_index = (unsigned int *)mmap(NULL, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, dh, 0xb0000014 & ~MAP_MASK); output_address_index = output_reg + ((0xb0000014 & MAP_MASK) >> 2); *num_bytes_keccak_value = 0x0800; //Num of bytes = fixed -> 2048 *start_keccak_addr_value = 0xfffc0000; sigset_t signal_mask, signal_mask_old, signal_mask_most; for (i = 0; i < NUM_MEASUREMENTS; i ++) { /* --------------------------------------------------------------------- * Reset sigio_signal_processed flag: */ sigio_signal_processed = 0; /* --------------------------------------------------------------------- * NOTE: This next section of code must be excuted each cycle to prevent * a race condition between the SIGIO signal handler and sigsuspend() */ (void)sigfillset(&signal_mask); (void)sigfillset(&signal_mask_most); (void)sigdelset(&signal_mask_most, SIGIO); (void)sigprocmask(SIG_SETMASK, &signal_mask, &signal_mask_old); /* --------------------------------------------------------------------- * Take a start timestamp for interrupt latency measurement */ (void)gettimeofday(&start_timestamp, NULL); /* --------------------------------------------------------------------- * Assert GPIO output pin to trigger generation of edge sensitive interrupt: */ //Reset Keccak *reg0_keccak_value = 0x1; *reg0_keccak_value = 0x0; //Start Keccak *reg0_keccak_value = 0x02; /* --------------------------------------------------------------------- * Wait for SIGIO signal handler to be executed. */ if (sigio_signal_processed == 0) { rc = sigsuspend(&signal_mask_most); /* Confirm we are coming out of suspend mode correctly */ assert(rc == -1 && errno == EINTR && sigio_signal_processed); } (void)sigprocmask(SIG_SETMASK, &signal_mask_old, NULL); assert(sigio_signal_count == i + 1); // Critical assertion unsigned int timer_value_interrupt = *capture_timer_value; //Stop Keccak *reg0_keccak_value = 0x0; //Get data from Output registers FILE *output_file = fopen("output.txt", "w"); // Check if the file was opened successfully if (output_file == NULL) { printf("Error opening the file.\n"); return 1; // Return error code } // Write the data into the file //defined k,l for output volatile int value1=0; for(k=0; k<30;k++) { offset1 = 0; *output_address_index = k; //printf("To print each block of 480 bits"); while(offset1<15){ output_address = output_reg + (((0xb0000044 + 4*offset1) & MAP_MASK)>>2); value1 = *output_address; volatile unsigned int num1 = (value1 >> 16) & 0xFFFF; volatile unsigned int num2 = value1 & 0xFFFF; fprintf(output_file, "0x%x, ",num1); fprintf(output_file, "0x%x, ",num2); offset1 = offset1 + 1; } fprintf(output_file,"\n"); } fclose(output_file); /* --------------------------------------------------------------------- * Compute interrupt latency: */ intr_latency_measurements[i] = timer_value_interrupt; } // End of for loop /* ------------------------------------------------------------------------- * Close device file */ (void)close(gpio_dev_fd); /* ------------------------------------------------------------------------- * Compute interrupt latency stats: */ unsigned long min_latency; unsigned long max_latency; double average_latency; double std_deviation; compute_interrupt_latency_stats( &min_latency, &max_latency, &average_latency, &std_deviation); /* * Print interrupt latency stats: */ printf("Minimum Latency: %lu\n" "Maximum Latency: %lu\n" "Average Latency: %f\n" "Standard Deviation: %f\n" "Number of samples: %d\n", min_latency, max_latency, average_latency, std_deviation, NUM_MEASUREMENTS); FILE* fp1; fp1 = fopen("convolution_latency.csv","a"); fprintf(fp1, "%lu, %lu, %f, %f\n", min_latency, max_latency, average_latency, std_deviation); fclose(fp1); return 0; } /* ----------------------------------------------------------------------------- * SIGIO signal handler */ void sigio_signal_handler(int signo) { volatile int rc1; assert(signo == SIGIO); // Confirm correct signal # sigio_signal_count++; // printf("sigio_signal_handler called (signo=%d)\n", signo); /* ------------------------------------------------------------------------- * Set global flag */ sigio_signal_processed = 1; /* ------------------------------------------------------------------------- * Take end timestamp for interrupt latency measurement */ (void)gettimeofday(&sigio_signal_timestamp, NULL); } /* ----------------------------------------------------------------------------- * Compute interrupt latency stats */ void compute_interrupt_latency_stats( unsigned long *min_latency_p, unsigned long *max_latency_p, double *average_latency_p, double *std_deviation_p) { int i; unsigned long val; unsigned long min = ULONG_MAX; unsigned long max = 0; unsigned long sum = 0; unsigned long sum_squares = 0; for (i = 0; i < NUM_MEASUREMENTS; i++) { val = intr_latency_measurements[i]; if (val < min) { min = val; } if (val > max) { max = val; } sum += val; sum_squares += val * val; } *min_latency_p = min; *max_latency_p = max; unsigned long average = (unsigned long)sum / NUM_MEASUREMENTS; unsigned long std_deviation = int_sqrt((sum_squares / NUM_MEASUREMENTS) - (average * average)); *average_latency_p = average; *std_deviation_p = std_deviation; } /* --------------------------------------------------------------- * sqrt routine */ unsigned long int_sqrt(unsigned long n) { unsigned long root = 0; unsigned long bit; unsigned long trial; bit = (n >= 0x10000) ? 1 << 30 : 1 << 14; do { trial = root + bit; if (n >= trial) { n -= trial; root = trial + bit; } root >>= 1; bit >>= 2; } while (bit); return root; } /* ----------------------------------------------------------------------------- * * gpio_set_pin routine: This routine sets and clears a single bit * in a GPIO register. * */ int gpio_set_pin(unsigned int target_addr, unsigned int pin_number, unsigned int bit_val) { unsigned int reg_data; int fd = open("/dev/mem", O_RDWR | O_SYNC); if (fd == -1) { printf("Unable to open /dev/mem. Ensure it exists (major=1, minor=1)\n"); return -1; } volatile unsigned int *regs, *address; regs = (unsigned int *)mmap(NULL, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, target_addr & ~MAP_MASK); address = regs + (((target_addr)&MAP_MASK) >> 2); #ifdef DEBUG1 printf("REGS = 0x%.8x\n", regs); printf("Target Address = 0x%.8x\n", target_addr); printf("Address = 0x%.8x\n", address); // display address value // printf("Mask = 0x%.8x\n", ONE_BIT_MASK(pin_number)); // Display mask value #endif /* Read register value to modify */ reg_data = *address; if (bit_val == 0) { /* Deassert output pin in the target port's DR register*/ reg_data &= ~ONE_BIT_MASK(pin_number); *address = reg_data; } else { /* Assert output pin in the target port's DR register*/ reg_data |= ONE_BIT_MASK(pin_number); *address = reg_data; } int temp = close(fd); if (temp == -1) { printf("Unable to close /dev/mem. Ensure it exists (major=1, minor=1)\n"); return -1; } munmap(NULL, MAP_SIZE); return 0; } int fm(unsigned int target_addr, unsigned int value[], unsigned int lp_cnt, unsigned int increment, int fd) { // int fd = open("/dev/mem", O_RDWR | O_SYNC); volatile unsigned int *regs, *address; volatile unsigned int offset; offset = 0; if (fd == -1) { perror("Unable to open /dev/mem. Ensure it exists (major=1, minor=1)\n"); return -1; } if (lp_cnt > 0x3ff) { // Max is 4096 bytes lp_cnt = 0x3ff; printf("Setting max repeat value to 0x3ff\n"); } regs = (unsigned int *)mmap(NULL, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, target_addr & ~MAP_MASK); /* --------------------------------------------------------------- * Main loop */ int j = 0; while (j> 2); *address = value[j]; // perform write command printf("0x%.8x", (target_addr + offset)); printf(" = 0x%.8x\n", *address); // display register value //value = value + increment; // increment value by incr //lp_cnt -= 1; // decrement loop j = j+1; offset += 4; // WORD alligned } // End of while loop int temp = close(fd); // Close memory if (temp == -1) { perror("Unable to close /dev/mem. Ensure it exists (major=1, minor=1)\n"); return -1; } munmap(NULL, MAP_SIZE); // Unmap memory return 0; // Return status } // End of pm routine