Yogi rides the new 6 wheeled robotic base platform. Designed in Solidworks and milled on my CNC machine.

Friday April 19 , 2024
Font Size
   

Front panel interface controllers using CPLDs and Verilog - Testbench

Electronics

Article Index
Front panel interface controllers using CPLDs and Verilog
Hex To 7-Segment Decoder
Testbench
All Pages

 

TestBench

The first thing I do when creating a new verilog file is to create the Testbench. This file provides test stimulus signals to our module purely for simulation (and therefor is typically not synthesizable).  I find writing the testbench first prepares myself for the behavior of the actual module.

In this testbench I wrote three functions (tasks actually) that handle the bus communication, ac97_ldaddr(addr), ac97_write(data), ac97_read(data). The ac97 first loads a desired address into the internal address latch of the CPLD. One or more read or write functions can then follow. The address latch will automatically increment after each read or write allowing for a range of memory locations to be read or written efficiently.


module tb ();

reg clk, rst;
wire [3:0] da;
reg rd,wr,lda;
wire intr;

reg disp_clk;
wire [7:0] display;
wire [7:0] disp_select;

reg [6:0] keys;

reg [3:0] tbda;
reg [7:0] w;  // a temp variable


ac97ui ac97 (
    clk, rst, da, rd, wr, lda, intr,
    disp_clk, display, disp_select,
    keys
);

task ac97_ldaddr;
input [3:0] addr;
begin
  wait(clk);
    tbda <= addr;
    lda <= 0;
    #1 lda <= 1;
    #1;
end
endtask

task ac97_write;
input [3:0] data;
begin
  wait(clk);
  tbda <= data;
  wr <= 0;
    #1 wr <= 1;
    #1;
end
endtask

task ac97_read;
output [3:0] data;
begin
  wait(clk);
    rd <= 0;
    #1 data <= da;
       rd <= 1;
    #1;
end
endtask

initial begin
  $dumpfile("ac97.vcd");
  $dumpvars; //(0,clk,rst,da,rd,wr,lda,intr);

    //$monitor("monitor:  t=", $time, "  da:", da, "  addr:", ac97.addr, "  tbda:",tbda);
    //$monitor("display:  t=%0d  display:%b  digit:%h  addr:%b  select:%b ", $time, display, ac97.digit, ac97.disp_addr, disp_select);
    clk = 1;
    disp_clk = 1;
    rst = 0;
    rd = 1;
    wr = 1;
    lda =1;
    keys = 7'b1111111;
    #1 rst = 1;

    /* Sample write cycles
     */


    // load address 0, writing to 6 digits of 7-segment LED display
    #5 $display("Testing bus interface for proper reading/writing:");
       ac97_ldaddr(ac97.D0);

  // write digits
  $display("writing digits.");
    ac97_write(4'hf);
    ac97_write(4'h2);
    ac97_write(4'h4);
    ac97_write(4'h5);
    ac97_write(4'h8);
    ac97_write(4'h1);

  // write LEDs
  $display("writing status LEDs.");
  ac97_write(4'b0110);
  ac97_write(4'b1001);

  // write dots
  $display("writing dots.");
  ac97_write(4'b0010);  // notice the 2 msb's will read as 11 (purposely not implemented!)
  ac97_write(4'b1011);

  // read digits
  $display("reading digits:");
  ac97_ldaddr(ac97.D0);
  for(w=0; w<6; w=w+1)
  begin
    ac97_read(tbda);
    $display("  digit %d: %h", w, tbda);
  end

  // read LEDs
    ac97_ldaddr(ac97.LEDS2);
  ac97_read(w[7:4]);
  ac97_read(w[3:0]);
  $display("LEDs: %b", w);

  // read dots
    ac97_ldaddr(ac97.DP2);
  ac97_read(w[7:4]);
  ac97_read(w[3:0]);
  $display("dots: %b", w);


  // read buttons
    ac97_ldaddr(ac97.BUTTONS2);
  ac97_read(w[7:4]);
  ac97_read(w[3:0]);
  $display("buttons: %b\n", w);

  // press some buttons to test the interrupts
  #10 $display("pressing a button:");
      keys[2] = 0;
  #20 $display("releasing button:");
      keys[2] = 1;
  #10 $display("pressing a button:");
      keys[5] = 0;
  #20 $display("releasing button:");
      keys[5] = 1;

   
  // change the display
  #5 ac97_ldaddr(ac97.D0);  // uh oh! taking away the 5 cycle delay messes up the interrupt!
    ac97_write(4'h1);
    ac97_write(4'h6);
    ac97_write(4'h3);
    ac97_write(4'h9);
    ac97_write(4'h7);
    ac97_write(4'h0);

    #1300 $writememh("regfile",ac97.mem);
    #1 rst = 0;
    $finish;
end

// if we are writing or doing a load address, write contents of tbda to da bus
assign da = (!wr||!lda) ? tbda : 4'bz;

// toggle the system and display clocks
always clk = #1 ~clk;
always disp_clk = #10 ~disp_clk;

// handle interupts
always @ (negedge intr)
begin
    /* Read buttons
        - verify state of interrupt flag before and after we read the button state
     */
    $display("interrupt at time=%0d",$time);
    if(intr==1'b1)
      $display(" interrupt value incorrect, should be set");
    ac97_ldaddr(ac97.BUTTONS2);
  ac97_read(w[7:4]);
  ac97_read(w[3:0]);
  $display("buttons: %b", w);
    if(intr==1'b0)
      $display(" interrupt value incorrect, should be clear");
end

endmodule



User Rating: / 96
PoorBest 

RSS Feeds

Visitor Poll

What sort of peripherals do you desire in a robotics main board? (you may vote more than once.)

Who's Online

We have 2 guests online