#include #include #include #include #define uint unsigned int /* ================================ PARALLEL PORT ================================= */ #define IREGDIR 0 // Change the values if your register map is different than here #define IREGPIN 1 #define IREGPORT 2 #define MODE_ALL_OUTPUT 0xFF #define MODE_ALL_INPUT 0X00 /* =================================== COUNTER ==================================== */ #define CLK_FREQ 50e6 #define IRESETVAL 0 // Change the values if your register map is different than here #define ICOUNTER 0 #define IRZ 1 #define ISTART 2 #define ISTOP 3 #define IIRQEN 4 #define ICLREOT 5 #define RESETVAL 0xFF000000 // Counter starts counting from this value #define IRQENVAL 1 #define IRQDISVAL 0 #define CLREOTVAL 1 #define ARBITVAL 0x0000FFFF // Arbitrary value used for addresses, see VHDL /* ================================================================================ */ #define N 10000 // table size of values to swap for lab 2, max 65535 (16bits) static uint gpio0 = 0x0; static uint gpio1 = 0x0; #define GPIO0(x) (x) #define GPIO1(x) (x) #define CheckBit(seq, pos) (seq & (1UL << (pos))) #define SetBit(seq, pos) (seq |= (1UL << (pos))) #define ClrBit(seq, pos) (seq &= ~(1UL << (pos))) #define ToggleBit(seq, pos) (seq ^= (1UL << (pos))) #define MEASURE_ANALOG_ /** * util_measure_analog: sets gpio0x to desired level * * @param gpio0x: gpio0 pin id on board schematic * @param level: '0' for low (0V) or '1' for high (3.3V) */ static inline void util_measure_analog(uint gpio0x, int level) { #ifdef MEASURE_ANALOG IOWR_8DIRECT(PARALLEL_PORT_0_BASE, IREGPORT, (level ? SetBit(gpio0, gpio0x) : ClrBit(gpio0, gpio0x))); #endif } /** * special_bitswap_function & special_bitswap_acceleration: * swap MSB with LSB and middle 16bits symmetrically: e.g. FB2356A0 --> A06AC4FB */ void special_bitswap_optfunction(uint* tab, size_t size) { for(int n = 0; n < size; n++) { uint n1 = tab[n] >> 24, n23 = 0, n4 = tab[n] << 24; for(int i = 0; i < 8; i++) { n23 |= (tab[n] & (1 << (23-i))) >> (15-2*i); n23 |= (tab[n] & (1 << ( 8+i))) << (15-2*i); } tab[n] = n4 | n23 | n1; } } void special_bitswap_instruction(uint* tab, size_t size) { for(int n = 0; n < size; n++) { tab[n] = ALT_CI_SPECIAL_BITSWAP_0(tab[n], NULL); } } #define TabAddress 0 #define TabLength 4 #define AccStart 8 #define AccFinished 12 void special_bitswap_accelerator(uint* tab, size_t size) { int i=0; // provide necessary data to accelerator, see VHDL for details IOWR_32DIRECT(SPECIAL_BITSWAP_TAB_ACCELERATOR_0_BASE, TabAddress, tab); IOWR_32DIRECT(SPECIAL_BITSWAP_TAB_ACCELERATOR_0_BASE, TabLength, size); // start special bitswap operations IOWR_32DIRECT(SPECIAL_BITSWAP_TAB_ACCELERATOR_0_BASE, AccStart, 1); // printf("AccStart valid %d\n", (IORD_32DIRECT(SPECIAL_BITSWAP_TAB_ACCELERATOR_0_BASE, AccStart) & 1) == 0); // printf("AccFinished valid %d\n", IORD_32DIRECT(SPECIAL_BITSWAP_TAB_ACCELERATOR_0_BASE, AccFinished) & 1 == 1); // wait for accelerator to finish all operations while(!(IORD_32DIRECT(SPECIAL_BITSWAP_TAB_ACCELERATOR_0_BASE, AccFinished) & 1)) i++; printf("iloop :) %d\n", i); printf("TabAddress valid %d\n", IORD_32DIRECT(SPECIAL_BITSWAP_TAB_ACCELERATOR_0_BASE, TabAddress) == tab); printf("TabLength valid %d\n", IORD_32DIRECT(SPECIAL_BITSWAP_TAB_ACCELERATOR_0_BASE, TabLength) == size); printf("AccStart valid %d\n", IORD_32DIRECT(SPECIAL_BITSWAP_TAB_ACCELERATOR_0_BASE, AccStart) & 1 == 0); // will always be 0, immediate reset in VHDL printf("AccFinished valid %d\n", IORD_32DIRECT(SPECIAL_BITSWAP_TAB_ACCELERATOR_0_BASE, AccFinished) & 1 == 1); } int main() { printf("Hello from Nios II!\n\n"); /* quick bitswap sanity check */ uint randValue = 0xFB2356A0, rv1 = randValue, rv2 = randValue, rv3 = randValue; printf("Performing quick sanity check on original value: %x\n\n", randValue); special_bitswap_optfunction(&rv1, 1); special_bitswap_instruction(&rv2, 1); special_bitswap_accelerator(&rv3, 1); printf("Bitswap using optimized C function: ............ %x\n", rv1); printf("Bitswap using custom instruction: .............. %x\n", rv2); printf("Bitswap using hardware acceleration: ........... %x\n\n", rv3); /* generate random array of numbers */ uint randArray[N]; for(int i = 0; i < N; i++) { randArray[i] = rand(); } /* calibrate counter measures */ IOWR(COUNTER_0_BASE, ISTART, ARBITVAL); // Start the counter int iord_time = IORD(COUNTER_0_BASE, 0); iord_time = IORD(COUNTER_0_BASE, 0) - iord_time; /* prepare logic analyzer measures */ IOWR_8DIRECT(PARALLEL_PORT_0_BASE, IREGDIR, MODE_ALL_OUTPUT); /* time operation speed */ IOWR(COUNTER_0_BASE, IRZ, ARBITVAL); // Reset the counter to 0 util_measure_analog(GPIO0(1), 1); special_bitswap_optfunction(&randArray, N); util_measure_analog(GPIO0(1), 0); int optfunction_time = IORD(COUNTER_0_BASE, 0) - iord_time; printf("Optimized C function time: ..... %lf seconds for %d operations\n", optfunction_time/CLK_FREQ, N); for(int i=0; i < 500000; i++) ; // wait for visibility using logic analyzer IOWR(COUNTER_0_BASE, IRZ, ARBITVAL); // Reset the counter to 0 util_measure_analog(GPIO0(2), 1); special_bitswap_instruction(&randArray, N); util_measure_analog(GPIO0(2), 0); int instruction_time = IORD(COUNTER_0_BASE, 0) - iord_time; printf("Custom instruction time: ....... %lf seconds for %d operations\n", instruction_time/CLK_FREQ, N); for(int i=0; i < 500000; i++) ; // wait for visibility using logic analyzer IOWR(COUNTER_0_BASE, IRZ, ARBITVAL); // Reset the counter to 0 util_measure_analog(GPIO0(3), 1); special_bitswap_accelerator(&randArray, N); util_measure_analog(GPIO0(3), 0); int accelerator_time = IORD(COUNTER_0_BASE, 0) - iord_time; printf("Hardware acceleration time: .... %lf seconds for %d operations\n", accelerator_time/CLK_FREQ, N); return 0; }