/** * A test for an independent-clock FIFO */ #ifndef LFSR_SEED #define LFSR_SEED 0xcdef #endif #ifndef RAND_SEED #define RAND_SEED 2 #endif #ifndef TEST_COUNT #define TEST_COUNT 5000 #endif // rand() seed; used in multiple threads, so global int randSeed = RAND_SEED; // reporting stats int cyclesEF, cyclesFF; DUT { module TFIFO_WRAPPER (input CLK156, input RST156, output CLK250, // write port output FF, input WREN, input[15:0] DIN, // read port output EF, input RDEN, output[15:0] DOUT); create_clock CLK156 -period 6.4; // we drive this clock create_clock CLK250 -period 4.0; // this is a DUT output // reset [CLK156, RST156]; // write to the DUT [CLK156, WREN, DIN]; // read from the DUT [CLK250, RDEN] -> [DOUT]; } main() { int tid; exec thread_write(tid); exec thread_read (tid); } /** * The writer thread: writes TEST_COUNT LFSR words to the FIFO * * @param tid The thread ID for this thread */ void thread_write(int &tid) { int i; int words_written = 0; bit16 lfsr = LFSR_SEED; // fifo reset: careful, see PG057 for(i=0; i<4; i++) [.C, 1]; for(i=0; i<26; i++) [.C, 0]; while(true) { if(FF) { // wait 1 cycle if the fifo is full [.C, 0, .X]; // drive data as X ++cyclesFF; // record full cycle count continue; } for(i=0; i < wait1_count(); i++) [.C, 0, .X]; // PR wait before writing this word [.C, 1, lfsr]; // write the test data lfsr_next(lfsr); // advance the test data if(++words_written >= TEST_COUNT) break; } [.C, 0, .X]; // clean up: leave WREN low } // thread_write() /** * The reader thread: reads TEST_COUNT LFSR words from the FIFO * * @param tid The thread ID for this thread */ void thread_read(int &tid) { int i; int words_read = 0; bit16 lfsr = LFSR_SEED; while(true) { if(EF) { // wait 1 cycle if the fifo is empty [.C, 0] -> []; // ignore DOUT; don't test ++cyclesEF; // record empty cycle count continue; } for(i=0; i < wait2_count(); i++) [.C, 0] -> []; // PR wait before reading this word [.C, 1] -> [lfsr]; // read the fifo if(++words_read >= TEST_COUNT) { report( "finished: %d words read. The FIFO was empty for %d cycles, " "and full for %d cycles\n", words_read, cyclesEF, cyclesFF); exit(0); // test finished } lfsr_next(lfsr); } } // thread_read() /** * Calculate and return the next value in an LFSR16 sequence. This is a * maximal-length 16-bit Galois LFSR. 0 is not a valid value for the LFSR, so * is checked for and modified. * * @param lfsr The current LFSR value on entry, and the new one on return */ void lfsr_next(bit16 &lfsr) { if(lfsr == 0) lfsr = 1; bool lsb = lfsr & 1; lfsr >>= 1; if(lsb) lfsr ^= 0xB400; } /** * Return a cycle count which is used to insert a PR delay when writing to * the FIFO * * @return The cycle count */ int wait1_count() { result = rand(randSeed, 0, 99); if (result < 80) result = 0; // 80% 0 cycle else if(result < 85) result = 1; // 5% 1 cycle else if(result < 90) result = 2; // 5% 2 cycle else if(result < 94) result = 3; // 4% 3 cycle else if(result < 98) result = 4; // 4% 4 cycle else result = 5; // 2% 5 cycle } // wait1_count() /** * Return a cycle count which is used to insert a PR delay when reading from * the FIFO * * @return The cycle count */ int wait2_count() { result = rand(randSeed, 0, 99); if (result < 38) result = 0; // 38% 0 cycle else if(result < 55) result = 1; // 17% 1 cycle else if(result < 75) result = 2; // 20% 2 cycle else if(result < 90) result = 4; // 15% 4 cycle else result = 20; // 10% 20 cycle } // wait2_count() // ----------------------------------- EOF ------------------------------------