mirror of
https://github.com/pConst/basic_verilog.git
synced 2025-01-28 07:02:55 +08:00
763 lines
24 KiB
C++
763 lines
24 KiB
C++
// Copyright 2008 Altera Corporation. All rights reserved.
|
|
// Altera products are protected under numerous U.S. and foreign patents,
|
|
// maskwork rights, copyrights and other intellectual property laws.
|
|
//
|
|
// This reference design file, and your use thereof, is subject to and governed
|
|
// by the terms and conditions of the applicable Altera Reference Design
|
|
// License Agreement (either as signed by you or found at www.altera.com). By
|
|
// using this reference design file, you indicate your acceptance of such terms
|
|
// and conditions between you and Altera Corporation. In the event that you do
|
|
// not agree with such terms and conditions, you may not use the reference
|
|
// design file and please promptly destroy any copies you have made.
|
|
//
|
|
// This reference design file is being provided on an "as-is" basis and as an
|
|
// accommodation and therefore all warranties, representations or guarantees of
|
|
// any kind (whether express, implied or statutory) including, without
|
|
// limitation, warranties of merchantability, non-infringement, or fitness for
|
|
// a particular purpose, are specifically disclaimed. By making this reference
|
|
// design file available, Altera expressly does not recommend, suggest or
|
|
// require that this reference design file be used in combination with any
|
|
// other product not provided by Altera.
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
int const num_lanes = 20;
|
|
int const meta_frame_len = 100;
|
|
int const lane_bits = 20;
|
|
char * lane_format = "%05I64X\n";
|
|
|
|
int const MAX_LINE = 1024;
|
|
typedef unsigned __int64 u64;
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
void panic (const char * msg)
|
|
{
|
|
fprintf (stdout,"PANIC: %s\n",msg);
|
|
exit(1);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// CRC32 - most significant bit first
|
|
u64 evolve_crc32_byte
|
|
(
|
|
u64 crc_in,
|
|
unsigned char data
|
|
)
|
|
{
|
|
int k = 0;
|
|
unsigned int fbk = 0;
|
|
u64 const poly = 0x1edc6f41; // Castagnoli 32
|
|
|
|
for (k=0; k<8; k++)
|
|
{
|
|
crc_in = crc_in << 1;
|
|
if ((crc_in & 0x100000000) != 0)
|
|
{
|
|
crc_in ^= poly;
|
|
}
|
|
|
|
if (data & 0x80)
|
|
{
|
|
crc_in ^= poly;
|
|
}
|
|
|
|
data <<= 1;
|
|
}
|
|
return (crc_in & 0xffffffff);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// CRC 32 - evolve for 64 bits, ms byte first
|
|
u64 evolve_crc32_word
|
|
(
|
|
u64 crc_in,
|
|
u64 data
|
|
)
|
|
{
|
|
int k = 0;
|
|
unsigned char dbyte[8];
|
|
|
|
for (k=0; k<8; k++)
|
|
{
|
|
dbyte [k] = unsigned char (data & 0xff);
|
|
data >>= 8;
|
|
}
|
|
|
|
for (k=7; k>=0; k--)
|
|
{
|
|
crc_in = evolve_crc32_byte (crc_in,dbyte[k]);
|
|
}
|
|
return (crc_in);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// convert text into 8 byte hex words
|
|
void sample_text_to_words
|
|
(
|
|
char * data_out_fname,
|
|
int words_wanted
|
|
)
|
|
{
|
|
FILE * g = NULL;
|
|
const char * sample_data = "Mary had a little lamb its fleece was white"
|
|
"as snow and everywhere that Mary went the lamb was sure to go."
|
|
" It followed her to school one day which was against the rule."
|
|
" All the children laughed and cheered to see a lamb at school."
|
|
" Humpty Dumpty sat on a wall. Humpty Dumpty had a great fall."
|
|
" All the king's horses and all the king's men couldn't put "
|
|
"Humpty together again. ";
|
|
int const sample_data_len = strlen (sample_data);
|
|
int n=0,k=0,z=0;
|
|
|
|
g = fopen (data_out_fname,"wt");
|
|
if (!g) panic ("Unable to write lane TX data");
|
|
|
|
for (n=0; n<words_wanted; n++)
|
|
{
|
|
for (z=0; z<8; z++)
|
|
{
|
|
fprintf (g,"%02x",sample_data[k]);
|
|
k = (k + 1) % sample_data_len;
|
|
}
|
|
fprintf (g,"\n");
|
|
}
|
|
|
|
fclose (g);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// sscanf doesn't seem to work on 64's
|
|
u64 scan64 (char * buffer)
|
|
{
|
|
unsigned int dat_ls,dat_ms;
|
|
int len = 0;
|
|
u64 dat = 0;
|
|
|
|
len = strlen(buffer);
|
|
while (len > 0 &&
|
|
(buffer[len-1] == 0xa ||
|
|
buffer[len-1] == 0xd))
|
|
{
|
|
len--;
|
|
buffer[len] = 0;
|
|
}
|
|
if (strlen (buffer) != 16) panic ("Expected 64 bit hex number");
|
|
sscanf (&(buffer[8]),"%x",&dat_ls);
|
|
buffer[8] = 0;
|
|
sscanf (buffer,"%x",&dat_ms);
|
|
dat = dat_ms;
|
|
dat <<= 16;
|
|
dat <<= 16;
|
|
dat |= dat_ls;
|
|
|
|
return (dat);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// Insert Metaframe words, CRC32, scrambling on TX data stream
|
|
// From Interlaken 1.1 protocol doc
|
|
void lane_tx_frame
|
|
(
|
|
char * data_in_fname,
|
|
char * data_out_fname,
|
|
bool error_injection
|
|
)
|
|
//
|
|
// Error schedule : 1 - wait for lock, damage a sync word
|
|
// 2 - damage a sync word
|
|
// 3 - damage a sync word
|
|
// 4 - damage an expected CRC
|
|
// 5 - damage a skip word to cause CRC error
|
|
// 6 - damage expected scrambler state word, proper CRC
|
|
// 7 - damage a sync word
|
|
// 8 - damage a sync word
|
|
// 9 - mis-synchronize the scrambler
|
|
|
|
{
|
|
FILE * f = NULL;
|
|
FILE * g = NULL;
|
|
char buffer[MAX_LINE];
|
|
int meta_cntr = 0;
|
|
u64 dat = 0;
|
|
u64 scrambler = 0x1234;
|
|
u64 next_scrambler = 0;
|
|
u64 crc32 = 0xffffffff;
|
|
|
|
// error injection controls
|
|
int words_written = 0;
|
|
int error_schedule = 0;
|
|
|
|
f = fopen (data_in_fname,"rt");
|
|
if (!f) panic ("Unable to read lane TX data");
|
|
g = fopen (data_out_fname,"wt");
|
|
if (!g) panic ("Unable to write lane TX data");
|
|
|
|
while (!feof(f))
|
|
{
|
|
// allow lock time before error injection
|
|
if (error_injection && error_schedule == 0 && words_written > 2000)
|
|
{
|
|
error_schedule = 1;
|
|
}
|
|
|
|
// unscrambled framing words
|
|
if (meta_cntr == 0)
|
|
{
|
|
// synchronization
|
|
dat = 0x78f678f678f678f6;
|
|
if (error_schedule == 1 || error_schedule == 2 || error_schedule == 3 ||
|
|
error_schedule == 7 || error_schedule == 8)
|
|
{
|
|
dat ^= 0x666; // inject error
|
|
error_schedule++;
|
|
}
|
|
crc32 = evolve_crc32_word (crc32,dat);
|
|
fprintf (g,"1 %016I64X\n",dat);
|
|
words_written++;
|
|
meta_cntr++;
|
|
}
|
|
if (meta_cntr == 1)
|
|
{
|
|
if (error_schedule == 9)
|
|
{
|
|
scrambler = 0x666; // Change scrambler evolution
|
|
error_schedule++;
|
|
}
|
|
|
|
// scrambler state
|
|
dat = 0x2800000000000000;
|
|
crc32 = evolve_crc32_word (crc32,dat);
|
|
dat |= scrambler;
|
|
|
|
if (error_schedule == 6)
|
|
{
|
|
dat ^= 0x666; // inject error
|
|
error_schedule++;
|
|
}
|
|
|
|
fprintf (g,"1 ");
|
|
fprintf (g,"%016I64X\n",dat);
|
|
words_written++;
|
|
meta_cntr++;
|
|
}
|
|
// continue on to next scrambled data
|
|
|
|
// eval next scrambler state
|
|
next_scrambler =
|
|
(scrambler << 6) ^
|
|
(((scrambler >> 16) >> 16) >> 20) ^
|
|
((scrambler & 0x7fffffffff) << 25) ^
|
|
((scrambler & 0x7fffffffff) >> 14) ^
|
|
(((scrambler & 0xffffff8000000000) >> 16) >> 17);
|
|
|
|
if (meta_cntr == 2)
|
|
{
|
|
// skip word
|
|
dat = 0x1e1e1e1e1e1e1e1e;
|
|
crc32 = evolve_crc32_word (crc32,dat);
|
|
|
|
if (error_schedule == 5)
|
|
{
|
|
dat ^= 0x666; // inject error, incorrect CRC
|
|
error_schedule++;
|
|
}
|
|
|
|
// scramble
|
|
dat ^= (scrambler << 6);
|
|
dat ^= (((next_scrambler >> 16) >> 16) >> 26);
|
|
fprintf (g,"1 %016I64X\n",dat);
|
|
words_written++;
|
|
meta_cntr++;
|
|
}
|
|
else if (meta_cntr == (meta_frame_len-1))
|
|
{
|
|
// diagnostic word
|
|
dat = 0x6400000000000000;
|
|
crc32 = evolve_crc32_word (crc32,dat);
|
|
|
|
// stick in CRC bits
|
|
crc32 ^= 0xffffffff;
|
|
dat |= crc32;
|
|
|
|
if (error_schedule == 4)
|
|
{
|
|
dat ^= 0x666; // inject error
|
|
error_schedule++;
|
|
}
|
|
|
|
// scramble
|
|
dat ^= (scrambler << 6);
|
|
dat ^= (((next_scrambler >> 16) >> 16) >> 26);
|
|
fprintf (g,"1 %016I64X\n",dat);
|
|
words_written++;
|
|
meta_cntr = 0;
|
|
|
|
// crc start over
|
|
crc32 = 0xffffffff;
|
|
}
|
|
else
|
|
{
|
|
// payload word
|
|
if (fgets (buffer,sizeof(buffer),f))
|
|
{
|
|
dat = scan64(buffer);
|
|
crc32 = evolve_crc32_word (crc32,dat);
|
|
|
|
// scramble the data
|
|
dat ^= (scrambler << 6);
|
|
dat ^= (((next_scrambler >> 16) >> 16) >> 26);
|
|
fprintf (g,"0 %016I64X\n",dat);
|
|
words_written++;
|
|
meta_cntr++;
|
|
}
|
|
}
|
|
// evolve the scrambler
|
|
scrambler = next_scrambler & 0x03ffffffffffffff;
|
|
}
|
|
|
|
fclose (f);
|
|
fclose (g);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
int count_ones (u64 dat)
|
|
{
|
|
int ones = 0;
|
|
while (dat)
|
|
{
|
|
if ((dat & 1) != 0)
|
|
{
|
|
ones++;
|
|
}
|
|
dat >>= 1;
|
|
}
|
|
return (ones);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// apply 64-67 disparity encoding
|
|
void lane_tx_disparity
|
|
(
|
|
char * data_in_fname,
|
|
char * data_out_fname
|
|
)
|
|
{
|
|
FILE * f = NULL;
|
|
FILE * g = NULL;
|
|
u64 dat = 0;
|
|
char buffer [MAX_LINE];
|
|
int running_disparity = 0;
|
|
int word_disparity = 0;
|
|
int control_bits = 0;
|
|
|
|
f = fopen (data_in_fname,"rt");
|
|
if (!f) panic ("Unable to read lane TX data");
|
|
g = fopen (data_out_fname,"wt");
|
|
if (!g) panic ("Unable to write lane TX data");
|
|
|
|
while (!feof(f))
|
|
{
|
|
if (fgets (buffer,sizeof(buffer),f))
|
|
{
|
|
if (buffer[0] != '1' &&
|
|
buffer[0] != '0') panic ("Expected leading 1/0 control word marker");
|
|
control_bits = (buffer[0] == '1') ? 2 : 1;
|
|
|
|
dat = scan64(&(buffer[2]));
|
|
word_disparity = count_ones (dat);
|
|
word_disparity = word_disparity - (64-word_disparity);
|
|
|
|
// framing bits have two 0's, one 1.
|
|
word_disparity --;
|
|
|
|
if ((word_disparity >= 0 && running_disparity >= 0) ||
|
|
(word_disparity < 0 && running_disparity < 0))
|
|
{
|
|
fprintf (g,"%x ",control_bits ^ 4);
|
|
fprintf (g,"%016I64X\n",~dat);
|
|
}
|
|
else
|
|
{
|
|
fprintf (g,"%x ",control_bits);
|
|
fprintf (g,"%016I64X\n",dat);
|
|
}
|
|
}
|
|
}
|
|
|
|
fclose (f);
|
|
fclose (g);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
int hex_nybble_val (int ch)
|
|
{
|
|
if (ch >= '0' && ch <= '9') ch -= '0';
|
|
else if (ch >= 'a' && ch <= 'f') ch = ch -'a' + 10;
|
|
else if (ch >= 'A' && ch <= 'F') ch = ch -'A' + 10;
|
|
else panic ("This is not a hex nybble char");
|
|
return (ch);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// Break up 67 bit words into (20) bit transmit blocks
|
|
void lane_tx_gearbox
|
|
(
|
|
char * data_in_fname,
|
|
char * data_out_fname
|
|
)
|
|
{
|
|
FILE * f = NULL;
|
|
FILE * g = NULL;
|
|
u64 residue = 0, dat = 0;
|
|
u64 lane_mask = 0;
|
|
int bits_residue = 0;
|
|
int ch = 0;
|
|
int n = 0, k = 0;
|
|
char buffer [MAX_LINE];
|
|
|
|
for (k=0; k<lane_bits; k++)
|
|
{
|
|
lane_mask <<= 1;
|
|
lane_mask |= 1;
|
|
}
|
|
|
|
f = fopen (data_in_fname,"rt");
|
|
if (!f) panic ("Unable to read lane TX data");
|
|
g = fopen (data_out_fname,"wt");
|
|
if (!g) panic ("Unable to write lane TX data");
|
|
|
|
while (!feof(f))
|
|
{
|
|
if (fgets (buffer,sizeof(buffer),f))
|
|
{
|
|
ch = buffer[0];
|
|
ch = hex_nybble_val(ch);
|
|
|
|
// 1st nybble is 3 bit
|
|
if (ch >= 8) panic ("Illegal framing bits");
|
|
residue = (residue << 3) | ch;
|
|
bits_residue += 3;
|
|
|
|
// 16 remaining are full 4bit
|
|
for (n=0; n<16; n++)
|
|
{
|
|
ch = buffer[2+n];
|
|
ch = hex_nybble_val(ch);
|
|
residue = (residue << 4) | ch;
|
|
bits_residue += 4;
|
|
|
|
// are there enough bits for an output word?
|
|
if (bits_residue >= lane_bits)
|
|
{
|
|
dat = residue;
|
|
k = bits_residue;
|
|
while (k > lane_bits)
|
|
{
|
|
dat >>= 1;
|
|
k--;
|
|
}
|
|
dat &= lane_mask;
|
|
bits_residue -= lane_bits;
|
|
|
|
fprintf (g,lane_format,dat);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
fclose (f);
|
|
fclose (g);
|
|
}
|
|
|
|
/////////////////////////////////////////////
|
|
|
|
void make_lane_rx_tb
|
|
(
|
|
int stimulus_words
|
|
)
|
|
{
|
|
FILE * f = fopen ("lane_rx_tb.sv","wt");
|
|
if (!f) panic ("Unable to write lane RX tb");
|
|
|
|
fprintf (f,"module lane_rx_tb ();\n");
|
|
fprintf (f,"\n");
|
|
|
|
fprintf (f,"localparam WIDTH = %d;\n",lane_bits);
|
|
fprintf (f,"localparam SAMPLE_BYTES = (WIDTH / 4) + 2;\n");
|
|
fprintf (f,"localparam META_FRAME_LEN = %d;\n",meta_frame_len);
|
|
fprintf (f,"\n");
|
|
fprintf (f,"/////////////////////////////////////\n");
|
|
fprintf (f,"// load sample data out of file\n");
|
|
fprintf (f,"/////////////////////////////////////\n");
|
|
fprintf (f,"reg [WIDTH-1:0] lane_bits,lane_bits_err;\n");
|
|
fprintf (f,"reg clk = 0, arst = 0;\n");
|
|
fprintf (f,"\n");
|
|
fprintf (f,"integer pfile = 0, pfile_err;\n");
|
|
fprintf (f,"\n");
|
|
fprintf (f,"initial begin\n");
|
|
fprintf (f," pfile = $fopen (\"lane_bits.txt\",\"r\");\n");
|
|
fprintf (f," if (pfile == 0) begin\n");
|
|
fprintf (f," $display (\"Unable to read lane_bits data file\");\n");
|
|
fprintf (f," $stop();\n");
|
|
fprintf (f," end\n");
|
|
fprintf (f," pfile_err = $fopen (\"lane_bits_err.txt\",\"r\");\n");
|
|
fprintf (f," if (pfile_err == 0) begin\n");
|
|
fprintf (f," $display (\"Unable to read lane_bits_err data file\");\n");
|
|
fprintf (f," $stop();\n");
|
|
fprintf (f," end\n");
|
|
fprintf (f,"end\n");
|
|
fprintf (f,"\n");
|
|
fprintf (f,"reg [SAMPLE_BYTES*8-1:0] buffer;\n");
|
|
fprintf (f,"integer r,s = 0;\n");
|
|
fprintf (f,"always @(negedge clk) begin\n");
|
|
fprintf (f," r = $fgets (buffer,pfile); \n");
|
|
fprintf (f," r = $sscanf (buffer,\"%%x\",lane_bits);\n");
|
|
fprintf (f," s = s + 1;\n");
|
|
fprintf (f," r = $fgets (buffer,pfile_err); \n");
|
|
fprintf (f," r = $sscanf (buffer,\"%%x\",lane_bits_err);\n");
|
|
fprintf (f,"end\n");
|
|
fprintf (f,"\n");
|
|
fprintf (f,"/////////////////////////////////////\n");
|
|
fprintf (f,"// shift sample data \n");
|
|
fprintf (f,"/////////////////////////////////////\n");
|
|
fprintf (f,"reg [2*WIDTH-1:0] sample_dat;\n");
|
|
fprintf (f,"always @(posedge clk or posedge arst) begin\n");
|
|
fprintf (f," if (arst) sample_dat <= 0;\n");
|
|
fprintf (f," else sample_dat <= (sample_dat << WIDTH) | lane_bits;\n");
|
|
fprintf (f,"end\n");
|
|
fprintf (f,"\n");
|
|
fprintf (f,"/////////////////////////////////////\n");
|
|
fprintf (f,"// test units\n");
|
|
fprintf (f,"// look at all (width) shifts of the\n");
|
|
fprintf (f,"// input stream\n");
|
|
fprintf (f,"/////////////////////////////////////\n");
|
|
fprintf (f,"wire [65:0] dout [0:WIDTH-1];\n");
|
|
fprintf (f,"wire [WIDTH-1:0] dout_valid,word_locked,sync_locked;\n");
|
|
fprintf (f,"wire [WIDTH-1:0] framing_error,crc32_error,scrambler_mismatch,missing_sync;\n");
|
|
fprintf (f,"reg [15:0] words_to_sync_lock [0:WIDTH-1];\n");
|
|
fprintf (f,"\n");
|
|
fprintf (f,"genvar i;\n");
|
|
fprintf (f,"generate\n");
|
|
fprintf (f," for (i=0; i<WIDTH; i=i+1)\n");
|
|
fprintf (f," begin : du\n");
|
|
fprintf (f," lane_rx lr (\n");
|
|
fprintf (f," .clk,.arst,\n");
|
|
fprintf (f," .din(sample_dat[2*WIDTH-1-i:WIDTH-i]),\n");
|
|
fprintf (f," .dout(dout[i]),\n");
|
|
fprintf (f," .dout_valid(dout_valid[i]),\n");
|
|
fprintf (f," .word_locked(word_locked[i]),\n");
|
|
fprintf (f," .sync_locked(sync_locked[i]),\n");
|
|
fprintf (f," .framing_error(framing_error[i]),\n");
|
|
fprintf (f," .crc32_error(crc32_error[i]),\n");
|
|
fprintf (f," .scrambler_mismatch(scrambler_mismatch[i]),\n");
|
|
fprintf (f," .missing_sync(missing_sync[i])\n");
|
|
fprintf (f," );\n");
|
|
fprintf (f," defparam lr .META_FRAME_LEN = META_FRAME_LEN;\n");
|
|
fprintf (f,"\n");
|
|
fprintf (f," // monitor time from word lock to meta frame sync\n");
|
|
fprintf (f," always @(posedge clk or posedge arst) begin\n");
|
|
fprintf (f," if (arst) words_to_sync_lock[i] <= 0;\n");
|
|
fprintf (f," else begin\n");
|
|
fprintf (f," if (!word_locked[i]) words_to_sync_lock[i] <= 0;\n");
|
|
fprintf (f," else if (!sync_locked[i] & dout_valid[i]) words_to_sync_lock[i] <= words_to_sync_lock[i] + 1'b1;\n");
|
|
fprintf (f," end\n");
|
|
fprintf (f," end\n");
|
|
fprintf (f," end\n");
|
|
fprintf (f,"endgenerate\n");
|
|
fprintf (f,"\n");
|
|
fprintf (f,"/////////////////////////////////////\n");
|
|
fprintf (f,"// spec rules\n");
|
|
fprintf (f,"/////////////////////////////////////\n");
|
|
fprintf (f,"reg fail = 1'b0;\n");
|
|
fprintf (f,"\n");
|
|
fprintf (f,"// Observe lane locking\n");
|
|
fprintf (f,"wire all_aligned = &word_locked;\n");
|
|
fprintf (f,"wire all_locked = &sync_locked;\n");
|
|
fprintf (f,"initial begin\n");
|
|
fprintf (f," // allow 1200 words to acquire word alignment.\n");
|
|
fprintf (f," // This is data dependent, could in theory take forever\n");
|
|
fprintf (f," #%d\n",1200 * 67 * 10 / lane_bits);
|
|
fprintf (f," if (!all_aligned) begin\n");
|
|
fprintf (f," $display (\"Failed to acquire word alignment within expected window\");\n");
|
|
fprintf (f," fail = 1;\n");
|
|
fprintf (f," end\n\n");
|
|
fprintf (f," // allow 4 more frames to acquire frame lock\n");
|
|
fprintf (f," #%d\n",(4 * meta_frame_len) * 67 * 10 / lane_bits);
|
|
fprintf (f," if (!all_locked) begin\n");
|
|
fprintf (f," $display (\"Failed to acquire frame lock within expected window\");\n");
|
|
fprintf (f," fail = 1;\n");
|
|
fprintf (f," end\n");
|
|
fprintf (f,"end\n");
|
|
fprintf (f,"\n");
|
|
fprintf (f,"// Lanes should sync lock after word lock +4 good sync words, not earlier or later\n");
|
|
fprintf (f,"integer n;\n");
|
|
fprintf (f,"initial begin\n");
|
|
fprintf (f," @(posedge all_locked) begin\n");
|
|
fprintf (f," for (n=0; n<WIDTH;n=n+1) begin\n");
|
|
fprintf (f," if (words_to_sync_lock[n] < %d) begin\n",3*meta_frame_len);
|
|
fprintf (f," $display (\"Chan %%d acquired sync in less than 3 frames\",n);\n");
|
|
fprintf (f," fail = 1;\n");
|
|
fprintf (f," end\n");
|
|
fprintf (f," if (words_to_sync_lock[n] > %d) begin\n",4*meta_frame_len);
|
|
fprintf (f," $display (\"Chan %%d failed to acquired sync lock in 4 frames\",n);\n");
|
|
fprintf (f," fail = 1;\n");
|
|
fprintf (f," end\n");
|
|
fprintf (f," end\n");
|
|
fprintf (f," end\n");
|
|
fprintf (f," @(negedge clk);\n");
|
|
fprintf (f," if (!fail) $display (\"All %d shifted data test lanes have locked properly\");\n",lane_bits);
|
|
fprintf (f,"end\n");
|
|
fprintf (f,"\n");
|
|
fprintf (f,"// Locked lanes should not have any error flags\n");
|
|
fprintf (f,"integer k;\n");
|
|
fprintf (f,"always @(posedge clk) begin\n");
|
|
fprintf (f," #1 \n");
|
|
fprintf (f," for (k=0; k<WIDTH;k=k+1) begin\n");
|
|
fprintf (f," if (sync_locked[k]) begin\n");
|
|
fprintf (f," if (crc32_error[k] | framing_error[k] | scrambler_mismatch[k] | missing_sync[k]) begin\n");
|
|
fprintf (f," $display (\"Chan %%d is reporting an unexpected error\",k);\n");
|
|
fprintf (f," fail = 1;\n");
|
|
fprintf (f," end\n");
|
|
fprintf (f," end\n");
|
|
fprintf (f," end\n");
|
|
fprintf (f,"end\n");
|
|
fprintf (f,"\n");
|
|
fprintf (f,"// Due dilligence that the data stream passing CRC is the original test string\n");
|
|
fprintf (f,"reg [WIDTH-1:0] text_ok = 0;\n");
|
|
fprintf (f,"integer y;\n");
|
|
fprintf (f,"always @(posedge clk) begin\n");
|
|
fprintf (f," for (y=0; y<WIDTH;y=y+1) begin\n");
|
|
fprintf (f," if (sync_locked[y] & dout_valid[y] && dout[y] == \" Humpty \") begin\n");
|
|
fprintf (f," text_ok[y] = 1'b1;\n");
|
|
fprintf (f," end\n");
|
|
fprintf (f," end\n");
|
|
fprintf (f,"end\n");
|
|
fprintf (f,"\n");
|
|
fprintf (f,"////////////////////////////////////////////////\n");
|
|
fprintf (f,"// look at response to corrupted data stream\n");
|
|
fprintf (f,"////////////////////////////////////////////////\n");
|
|
fprintf (f,"wire [65:0] dout_err;\n");
|
|
fprintf (f,"wire dout_valid_err,word_locked_err,sync_locked_err;\n");
|
|
fprintf (f,"wire framing_error_err,crc32_error_err,scrambler_mismatch_err,missing_sync_err;\n");
|
|
fprintf (f,"reg [%d-1:0] lane_bits_noise = 0;\n",lane_bits);
|
|
fprintf (f,"reg lane_bits_noise_ena = 1'b0;\n");
|
|
fprintf (f,"lane_rx dut_err (\n");
|
|
fprintf (f," .clk,.arst,\n");
|
|
fprintf (f," .din(lane_bits_err ^ (lane_bits_noise_ena ? lane_bits_noise : %d'b0)),\n",
|
|
lane_bits-1);
|
|
fprintf (f," .dout(dout_err),\n");
|
|
fprintf (f," .dout_valid(dout_valid_err),\n");
|
|
fprintf (f," .word_locked(word_locked_err),\n");
|
|
fprintf (f," .sync_locked(sync_locked_err),\n");
|
|
fprintf (f," .framing_error(framing_error_err),\n");
|
|
fprintf (f," .crc32_error(crc32_error_err),\n");
|
|
fprintf (f," .scrambler_mismatch(scrambler_mismatch_err),\n");
|
|
fprintf (f," .missing_sync(missing_sync_err)\n");
|
|
fprintf (f,");\n");
|
|
fprintf (f,"defparam dut_err .META_FRAME_LEN = META_FRAME_LEN;\n");
|
|
fprintf (f,"\n");
|
|
fprintf (f,"always @(posedge clk) begin\n");
|
|
fprintf (f," lane_bits_noise <= $random();");
|
|
fprintf (f,"end\n");
|
|
fprintf (f,"\n");
|
|
fprintf (f,"reg good_error_response = 1'b0;\n");
|
|
fprintf (f,"reg good_noise_recovery = 1'b0;\n");
|
|
fprintf (f,"initial begin\n");
|
|
fprintf (f," // look at response to framing layer errors in the data stream\n");
|
|
fprintf (f," @(posedge sync_locked_err);\n");
|
|
fprintf (f," @(posedge missing_sync_err);\n");
|
|
fprintf (f," @(posedge missing_sync_err);\n");
|
|
fprintf (f," @(posedge missing_sync_err);\n");
|
|
fprintf (f," @(posedge crc32_error_err);\n");
|
|
fprintf (f," @(posedge crc32_error_err);\n");
|
|
fprintf (f," @(posedge scrambler_mismatch_err);\n");
|
|
fprintf (f," @(posedge missing_sync_err);\n");
|
|
fprintf (f," @(posedge missing_sync_err);\n");
|
|
fprintf (f," $display (\"Correct response to data stream with sync / scrambler / CRC32 errors\");\n");
|
|
fprintf (f," @(posedge scrambler_mismatch_err);\n");
|
|
fprintf (f," @(posedge scrambler_mismatch_err);\n");
|
|
fprintf (f," @(posedge scrambler_mismatch_err);\n");
|
|
fprintf (f," @(negedge sync_locked_err);\n");
|
|
fprintf (f," @(posedge sync_locked_err);\n");
|
|
fprintf (f," good_error_response = 1'b1;\n");
|
|
fprintf (f," $display (\"Correct recovery from incorrect scrambler state\");\n");
|
|
fprintf (f,"\n");
|
|
fprintf (f," // look at response to catastrophic line noise\n");
|
|
fprintf (f," @(negedge clk) lane_bits_noise_ena = 1'b1;\n");
|
|
fprintf (f," @(negedge word_locked_err);\n");
|
|
fprintf (f," #100 @(negedge clk) lane_bits_noise_ena = 1'b0;\n");
|
|
fprintf (f," @(posedge framing_error_err);\n");
|
|
fprintf (f," @(posedge word_locked_err);\n");
|
|
fprintf (f," @(posedge sync_locked_err);\n");
|
|
fprintf (f," good_noise_recovery = 1'b1;\n");
|
|
fprintf (f," $display (\"Correct recovery from catastrophic noise burst\");\n");
|
|
fprintf (f,"end\n\n");
|
|
|
|
fprintf (f,"// stop shortly before data file is exhausted\n");
|
|
fprintf (f,"always @(posedge clk) begin\n");
|
|
fprintf (f," if (s == (%d-2)) begin\n",(stimulus_words*67/20));
|
|
fprintf (f," if (~&text_ok) begin\n");
|
|
fprintf (f," $display (\"Sample text was not properly recovered on the dout\");\n");
|
|
fprintf (f," fail = 1'b1;\n");
|
|
fprintf (f," end\n");
|
|
fprintf (f," if (!good_error_response) begin\n");
|
|
fprintf (f," $display (\"dut_err did not respond properly to error injected data stream\");\n");
|
|
fprintf (f," fail = 1'b1;\n");
|
|
fprintf (f," end\n");
|
|
fprintf (f," if (!good_noise_recovery) begin\n");
|
|
fprintf (f," $display (\"dut_err did not recover from catastrophic noise burst\");\n");
|
|
fprintf (f," fail = 1'b1;\n");
|
|
fprintf (f," end\n");
|
|
fprintf (f," end\n");
|
|
fprintf (f," else if (s == %d) begin\n",(stimulus_words*67/20));
|
|
fprintf (f," if (!fail) $display (\"PASS\");\n");
|
|
fprintf (f," else $display (\"FAIL\");\n");
|
|
fprintf (f," $stop();\n");
|
|
fprintf (f," end\n");
|
|
fprintf (f,"end\n");
|
|
fprintf (f,"\n");
|
|
|
|
fprintf (f,"/////////////////////////////////////\n");
|
|
fprintf (f,"// clock driver\n");
|
|
fprintf (f,"/////////////////////////////////////\n");
|
|
fprintf (f,"always begin\n");
|
|
fprintf (f," #5 clk = ~clk;\n");
|
|
fprintf (f,"end\n");
|
|
fprintf (f,"\n");
|
|
fprintf (f,"initial begin\n");
|
|
fprintf (f," arst = 0;\n");
|
|
fprintf (f," #1 arst = 1;\n");
|
|
fprintf (f," @(negedge clk) arst = 0;\n");
|
|
fprintf (f,"end\n");
|
|
fprintf (f,"\n");
|
|
fprintf (f,"endmodule\n");
|
|
fclose (f);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
int main (void)
|
|
{
|
|
// number of 8byte payload words desired
|
|
int words_wanted = 5000;
|
|
|
|
// write some sample data for a lane RX unit
|
|
sample_text_to_words ("sample.txt",words_wanted);
|
|
lane_tx_frame ("sample.txt","framed.txt",false);
|
|
lane_tx_frame ("sample.txt","framed_err.txt",true);
|
|
lane_tx_disparity ("framed.txt","lane_words.txt");
|
|
lane_tx_disparity ("framed_err.txt","lane_words_err.txt");
|
|
lane_tx_gearbox ("lane_words.txt","lane_bits.txt");
|
|
lane_tx_gearbox ("lane_words_err.txt","lane_bits_err.txt");
|
|
|
|
make_lane_rx_tb (words_wanted);
|
|
|
|
return (0);
|
|
}
|