testing.v.txt
上传用户:saul_905
上传日期:2013-11-27
资源大小:184k
文件大小:16k
源码类别:

VHDL/FPGA/Verilog

开发平台:

Visual C++

  1. Some Examples of Verilog testbench techniques.
  2.       1.0   Introduction
  3.       2.0   Generating Periodic Signals
  4.       3.0   Generating and Receiving Serial Characters
  5.       4.0   Memories
  6.       5.0   Bus Models
  7. 1.0   Introduction
  8. A testbench is a verilog program that wraps around an actual design.  
  9. The testbench is typically not part of the design and does not result 
  10. in actual circuitry or gates.  Verilog code for testbenches may be 
  11. much more "free style" than Verilog code that must be 
  12. synthesized - anything goes.  Here are some tidbits from various
  13.  projects I've worked on.  The code is not completely general nor 
  14. perfect, but hopefully may provide ideas for designers just starting
  15.  out with testbench design.  Oh, and the names have been changed
  16.  to protect the innocent.  I hope I haven't introduced error in 
  17. doctoring up these examples.  Again, none of the following  code 
  18. is intended to be synthesizable!
  19. 2.0   Generating Periodic Signals.
  20. Say you have a period signal.  Try tossing in a little random fluctuation
  21.  on where the edges occur - you may catch a an unexpected bug! 
  22.  But, be careful about using random because if you move on to 
  23. manufacturing test, then your testbench may not be deterministic. 
  24.  Often, for the sake of the tester, you must enforce transitions to 
  25. occur in specific periods.  In this case, you may need to add 
  26. statements that delay changes to fall in these periods.  Anyway,
  27.  let's drive the foo1in signal.  We'll add in some random, count 
  28. the transitions and print out a message.
  29. initial begin
  30.    #1 foo1in = 0;
  31.       forever begin
  32.          #(`PERIOD/2 + ($random % 10)*(` PERIOD/20)) foo1in = 1;
  33.          foo1_input_count = foo1_input_count + 1;
  34.          $display ("#Foo1 rising edges = %d", foo1_input_count);
  35.          #(` PERIOD/2 + ($random % 10)*(` PERIOD/20)) foo1in = 0;
  36.       end
  37. end
  38. Here's another code snippet - a task that generates a period message..
  39. task generate_syncs;
  40.    event send_sync;
  41.    begin
  42.       syncdata = SYNC_START;
  43.       syncstb  = 0;
  44.    
  45.       fork
  46.          // Generate periodic event for sending the sync
  47.          forever #(1000000000.0 * RATE) ->send_sync; // convert RATE to nanoseconds
  48.          
  49.          // Wait on send_sync event, and then send SYNC synchronized with clk
  50.          forever begin
  51.             @(send_sync);
  52.             syncdata = syncdata + CMTS_FREQ * CMTS_RATE;
  53.             $display ("... SYNC = %h at time %0t, Local Time = %h", syncdata, $time, local_time);
  54.             @(posedge clk) #1;
  55.             syncstb = 1;
  56.             @(posedge clk) #1;
  57.             syncstb = 0;
  58.          end
  59.       join
  60.    end
  61. endtask
  62. 3.0   Generating and Receiving Serial Characters
  63. Say your design inputs or outputs serial characters.  Here is some 
  64. code for both.  First, some defines:
  65. /*  Serial Parameters used for send_serial task and its callers. */
  66. `define PARITY_OFF   1'b0
  67. `define PARITY_ON    1'b1
  68. `define PARITY_ODD   1'b0
  69. `define PARITY_EVEN  1'b1
  70. `define NSTOPS_1     1'b0
  71. `define NSTOPS_2     1'b1
  72. `define BAUD_9600    2'b00
  73. `define BAUD_4800    2'b01
  74. `define BAUD_2400    2'b10
  75. `define BAUD_1200    2'b11
  76. `define NBITS_7      1'b0
  77. `define NBITS_8      1'b1
  78. Here's how you call it:
  79. send_serial (8'hAA, `BAUD_9600, `PARITY_EVEN, `PARITY_ON, `NSTOPS_1, `NBITS_7, 0);
  80. Here's a task that sends a character.
  81. task send_serial;
  82. input [7:0] inputchar;
  83. input baud;
  84. input paritytype;
  85. input parityenable;
  86. input nstops;
  87. input nbits;
  88. input baud_error_factor;
  89. reg       nbits;
  90. reg       parityenable;
  91. reg       paritytype;
  92. reg [1:0] baud;
  93. reg       nstops;
  94. integer   baud_error_factor;  // e.g. +5 means 5% too fast and -5 means 5% too slow
  95. reg   [7:0] char;
  96. reg         parity_bit;
  97. integer     bit_time;
  98. begin
  99.    char = inputchar;
  100.    parity_bit = 1'b0;
  101.    case (baud)
  102.       `BAUD_9600: bit_time = 1000000000/(9600 + 96*baud_error_factor);
  103.       `BAUD_4800: bit_time = 1000000000/(4800 + 48*baud_error_factor);
  104.       `BAUD_2400: bit_time = 1000000000/(2400 + 24*baud_error_factor);
  105.       `BAUD_1200: bit_time = 1000000000/(1200 + 12*baud_error_factor);
  106.    endcase   
  107.    $display ("Sending character %h, at %0d baud (err=%0d), %0d bits, %0s parity, %0d stops",
  108.        (nbits == `NBITS_7) ? (char & 8'h7f) : char,
  109.       1000000000/bit_time,
  110.       baud_error_factor,
  111.       (nbits == `NBITS_7) ? 7 : 8,
  112.       (parityenable == `PARITY_OFF) ? "NONE" : (paritytype == `PARITY_EVEN) ? "EVEN" : "ODD",
  113.       (nstops == `NSTOPS_1) ? 1 : 2
  114.    );
  115.       
  116.    // Start bit
  117.    serial_character = 1'b0;   // Start bit.
  118.    #(bit_time);
  119.    // Output data bits
  120.    repeat ( (nbits == `NBITS_7) ? 7 : 8) begin
  121.       serial_character = char[0];
  122.       #(bit_time);
  123.       char = {1'b0, char[7:1]};
  124.    end
  125.    
  126.    if (parityenable == `PARITY_ON) begin
  127.       parity_bit = (nbits == `NBITS_7) ? ^inputchar[6:0] : ^inputchar[7:0];
  128.       if (paritytype == `PARITY_ODD)
  129.          parity_bit = ~parity_bit; // even parity
  130.          serial_character = parity_bit;
  131.          #(bit_time);
  132.       end
  133.       serial_character = 1'b1;   // Stop bit.
  134.       #(bit_time);
  135.       if (nstops) // Second stop bit
  136.          #(bit_time);
  137.    end
  138. endtask
  139. Here's a task that receives serial characters.  This particular task was 
  140. a bit messy in that it set some global variables in order to return a 
  141. status, etc.  By all means - fix this up the way you like it!
  142. reg [7:0] receive_serial_character_uart1; // Global that receives tasks result
  143. // ****  SERIAL CHARACTER LISTENER Task for UART1
  144. //
  145. //
  146. task receive_serial_uart1;
  147. input baud;
  148. input paritytype;
  149. input parityenable;
  150. input nstops;
  151. input nbits;
  152. reg       nbits;
  153. reg       parityenable;
  154. reg       paritytype;
  155. reg [1:0] baud;
  156. reg       nstops;
  157. integer     bit_time;
  158. reg         expected_parity;
  159. begin
  160. receive_serial_result_uart1 = 0;
  161. receive_serial_character_uart1 = 0;
  162. case (baud)
  163.    `BAUD_9600: bit_time = 1000000000/(9600);
  164.    `BAUD_4800: bit_time = 1000000000/(4800);
  165.    `BAUD_2400: bit_time = 1000000000/(2400);
  166.    `BAUD_1200: bit_time = 1000000000/(1200);
  167. endcase 
  168.      
  169. receive_serial_result_uart1 = `RECEIVE_RESULT_OK;  // Assume OK until bad things happen.
  170. @(negedge uart1out);  // wait for start bit edge
  171. #(bit_time/2);  // wait till center of start bit
  172. if (uart1out != 0) // make sure its really a start bit
  173.    receive_serial_result_uart1 = receive_serial_result_uart1 | `RECEIVE_RESULT_FALSESTART;
  174. else begin
  175.    repeat ( (nbits == `NBITS_7) ? 7 : 8) begin // get all the data bits (7 or 8)
  176.       #(bit_time);  // wait till center
  177.       // sample a data bit
  178.       receive_serial_character_uart1 = {uart1out, receive_serial_character_uart1[7:1]};
  179.    end
  180.    // If we are only expecting 7 bits, go ahead and right-justify what we have
  181.    if (nbits == `NBITS_7)
  182.       receive_serial_character_uart1 = {1'b0, receive_serial_character_uart1[7:1]};
  183.       
  184.       #(bit_time);
  185.       // now, we have either a parity bit, or a stop bit
  186.       if (parityenable == `PARITY_ON) begin
  187.          if (paritytype == `PARITY_EVEN)
  188.             expected_parity = (nbits == `NBITS_7) ? (^receive_serial_character_uart1[6:0]) :            
  189.                                                                                (^receive_serial_character_uart1[7:0]);
  190.          else
  191.             expected_parity = (nbits == `NBITS_7) ? (~(^receive_serial_character_uart1[6:0])) :  
  192.                                                                                (~(^receive_serial_character_uart1[7:0]));
  193.             if (expected_parity != uart1out)
  194.                receive_serial_result_uart1 = receive_serial_result_uart1 | `RECEIVE_RESULT_BADPARITY;
  195.          // wait for either 1 or 2 stop bits
  196.       end
  197.       else begin
  198. // this is a stop bit.
  199.          if (uart1out != 1)
  200.             receive_serial_result_uart1 = receive_serial_result_uart1 | `RECEIVE_RESULT_BADSTOP;
  201.          else
  202.             // that was cool.  if 2 stops, then do this again
  203.             if (nstops) begin
  204.                #(bit_time);
  205.                if (uart1out != 1)
  206.                   receive_serial_result_uart1 = receive_serial_result_uart1 | `RECEIVE_RESULT_BADSTOP;
  207.             end
  208.          #(bit_time/2);
  209.       end
  210.    end
  211. end
  212. endtask
  213. 4.0  Memories
  214. Memories, whether they are RAMs, ROMs or special memories like FIFOs 
  215. are easily modeled in Verilog.  Note that you can define your own special
  216.  testbench locations for debugging!  Say, you have a processor core hooked
  217. up to these memories.  Define some special locations that when read or 
  218. written to, display diagnostic messages.  Or, you can specify that a write to
  219.  a particular location will halt the simulation or signify PASS or FAIL.  
  220. Memories are an easy way for the embedded Verilog core processor to 
  221. communicate to the testbench.  There are many possibilities.  
  222. reg [15:0] FLASH_memory [0:(1024*32 - 1)];   // 32K of FLASH
  223. reg [15:0] SRAM_memory  [0:(1024*32 - 1)];   // 32K of SRAM
  224. //*****
  225. //
  226. //  The ASIC's ca[20] is the active LO chip select for the FLASH.
  227. //  The ASIC's ca[18] is the active LO chip select for the SRAM.
  228. // Write process for FLASH and SRAM
  229. //
  230. always @(posedge cwn) begin
  231.    if (ca[20] == 1'b0) begin
  232.       // Write to FLASH
  233.       if (ca[16:15] != 2'b00) begin
  234.          $display ("Illegal write to FLASH!");
  235.       end
  236.       else begin
  237.          $display ("Write to FLASH Address = %h, Data = %h", ca, cb);
  238.          // Our FLASH is only declared up to 32KW, so use ca[14:0]
  239.          FLASH_memory[ca[14:0]] = cb;
  240.          
  241.          // Check for magic write from the embedded processor core!  This is done in the
  242.          // C firmware simply by writing to the location.
  243.          //
  244.          if (ca == `MAGIC_ADDRESS) begin
  245.             $display ("Embedded code has signalled DONE!");
  246.             sa_test_status = `SA_TEST_DONE;
  247.             sa_test_result = cb;
  248.          end
  249.       end
  250.    end
  251.    else if (ca[18] == 1'b0) begin
  252.       // Write to SRAM
  253.       if (ca[16:15] != 2'b00) begin
  254.          $display ("Illegal write to SRAM!");
  255.       end
  256.       else begin
  257.          $display ("Write to SRAM Address = %h, Data = %h", ca, cb);
  258.          // Our SRAM is only declared up to 32KW, so use ca[14:0]
  259.          SRAM_memory[ca[14:0]] = cb;
  260.       end
  261.    end
  262. end
  263. // Read process for FLASH and SRAM
  264. //
  265. always @(crn) begin
  266.    if (crn == 1'b0) begin
  267.       case ({ca[20], ca[18]})
  268.          2'b11: cb_i <= 16'hzzzz;
  269.          2'b10: begin
  270.             $display ("Read from SRAM Address = %h, Data = %h", ca, SRAM_memory[ca[14:0]]);
  271.             cb_i <= SRAM_memory[ca[14:0]];
  272.             end
  273.          2'b01: begin
  274.             $display ("Read from FLASH Address = %h, Data = %h", ca, FLASH_memory[ca[14:0]]);
  275.             cb_i <= FLASH_memory[ca[14:0]];
  276.             end
  277.          2'b00: begin
  278.             $display ("Simultaneosly selecting FLASH and SRAM!!");
  279.             end
  280.       endcase
  281.    end
  282.    else begin
  283.       cb_i <= 16'hzzzz;
  284.    end
  285. end
  286. Clearing the memories is easy:
  287. task clear_SRAM;
  288. reg [15:0] SRAM_address;
  289. begin
  290.    $display ("Clearing SRAM..");
  291.    for (SRAM_address = 16'h0000; SRAM_address < 16'h8000; SRAM_address = SRAM_address + 1) begin
  292.       SRAM_memory[SRAM_address] = 0;
  293.    end
  294. end
  295. endtask
  296. Performing other operations is straight-forward.  How about a task 
  297. that copies a firmware hex image to a FLASH memories boot area, 
  298. relocating along the way and maybe setting a hew header bytes too. 
  299.  Now, this task is specific to a particular processor, etc. but this 
  300. shows what is fairly easily done in Verilog:
  301. task copy_to_FLASH_boot;
  302. reg [15:0] temp_memory[0:1023];
  303. reg [15:0] original_address;
  304. reg [15:0] FLASH_address;
  305. integer n;
  306. begin
  307.    $display ("Copying ROM image to FLASH boot block..");
  308.    // Read in the normal ROM file into our temporary memory.
  309.    for (original_address = 0; original_address < 1024; original_address = original_address + 1) begin
  310.       temp_memory[original_address] = 0;
  311.    end
  312.    $readmemh (`ROM_FILE, temp_memory);
  313.    
  314.    // Fill in Boot header
  315.    FLASH_memory[15'h0800] = `BOOT_COPY_LENGTH; // Let's copy 1KW maximum
  316.    FLASH_memory[15'h0801] = 0;              // Copy program to code space starting at zero
  317.    FLASH_memory[15'h0802] = temp_memory[3]; // Entry point is same as the address in the reset vector
  318.    
  319.    // Now, copy from original image into the boot area.
  320.    n = 0;
  321.    FLASH_address = 15'h0803;
  322.    original_address = 0;
  323.    while (n < 1024) begin
  324.       FLASH_memory[FLASH_address] = temp_memory[original_address];
  325.       FLASH_address = FLASH_address + 1;
  326.       original_address = original_address + 1;
  327.       n = n + 1;
  328.    end
  329. end
  330. endtask
  331. Also, test vectors are easily loaded into Verilog memories using the 
  332. $readmem statements.  You may easily read your stimulus vectors 
  333. from a file into a memory, clock out the vectors to your circuit, and 
  334. optionally capture your circuits response to another memory (or simply 
  335. write the vector out using $fdisplay).  Once you have captured one
  336.  output vector set that you know is good (e.g. your "Golden" vectors), 
  337. your testbench can compare subsequent simulation vectors against 
  338. these "Golden" vectors and detect any problems in your changing 
  339. circuit (e.g. after back-annotation, scan insertion, or alpha space
  340.  particle circuit corruption).
  341. 5.0  Bus Models
  342. Many times a processor is interfaced to the logic being tested.  If the 
  343. complete processor model/core is not present, then a "bus model" is 
  344. a simple function that emulates the bus transaction.  More simply; the
  345.  bus model allows the testbench to read and write values.  The following 
  346. task utilizes very specific timing delays.  You should probably include
  347.  'defines' for these and update them as you get better timing information.  
  348. Typically, you will test your UART or whatever peripheral in isolation 
  349. with the bus model, and later test your peripheral with the real processor core.
  350. write_to_foobar (COMPAREH_REGISTER, next_word[31:16]);
  351. #10;
  352. write_to_ foobar(COMPAREL _REGISTER, next_word[15:0]);
  353. #10;
  354. task write_to_foobar;
  355. input [15:0] address_arg;
  356. input [15:0] data_arg;
  357. // Several global bus signals are assumed: address, we, clk.
  358. begin
  359.    /* Wait until next rising clock edge */ 
  360.    @(posedge clk);
  361.    /* t_valid for address is 5ns, wait and then drive address */
  362.    #5;  // <----  Manually back-annotate this, or use a define, whatever...
  363.    address = address_arg;
  364.    /* t_valid for wrxxx is 8ns, we are already 5ns into cycle, so wait 3ns */
  365.    #3;
  366.    we <= 1'b1;
  367.    /* t_valid for wrdata is 20ns, We are 8ns into cycle, wait 12ns */
  368.    #12
  369.    data <= data_arg;
  370.    /* Wait till the next rising edge, wait for a little bit of hold time. */
  371.    @(posedge clk40);
  372.    #1;
  373.    address <= 4'hz;
  374.    #1;
  375.    we  <= 1'b0;
  376.    #4;
  377.    data <= 16'hzzzz;
  378.    //$display ("Writing data %h to address: %h", data, address);
  379. end
  380. endtask
  381. Here's a task that reads from the memory-mapped peripheral.
  382. task read_from_foobar;
  383. input [3:0] address_arg;
  384. // Let's just write to a global with the resulting data retrieved (! bad practice, I know....)
  385. // Gobal variable is 'last_data_read'.
  386. begin
  387.    /* Wait until next rising edge to do anything.. */
  388.    @(posedge clk)
  389.    /* t_valid for rwadrs is 5ns, wait and then drive address */
  390.    #5;
  391.    address = address_arg;
  392.    /* t_valid for rbxxx is 8ns, we are already 5ns into cycle, so wait 3ns */
  393.    #3;
  394.    rw <= 1'b1;
  395.    /* Wait till the next rising edge, wait for a little bit of hold time. */
  396.    @(posedge clk);
  397.    last_data_read = data;  // <-- keep in the global, caller can use if they wish.
  398.    $display ("Reading data %h from address: %h", data, address);
  399.    /* Wrap it up.  Deassert rw.  Let's float the address bus. */
  400.    rw <= 1'b0;
  401.    #1;
  402.    address <= 16'hzzzz;
  403. end
  404. endtask