// WARNING: // this hasn't been compiled and may need some refactoring // and/or bug squashing // Syntax for delay: #delayamount #2; // defaults to modelsim time units (ps) #2ns; // this works in SystemVerilog, not 1364 // these count as statements, need ; // That was easy, using it is hard // delays are kind of blocking, which can get weird always_ff @(posedge clk) #3 y <= a; // what if clk toggles faster than #3? // what if y <= #3 a; assign #3 y = a; // y toggles 3 units after a does assign y = #3 a; // y follow a from 3 units later // not always synthesizable. But esp. useful for test // Great! We've got a block and want to test it module block(input a,b,c, output y); assign y = ~a&b | c; endmodule // How would we test this? (conceptually) // Which is harder to test, combinational or sequential? // Here's an example of testing a combinational block module testbench(); logic clk, a, b, c, y; logic [2:0] count; block dut(a,b,c,y) // DUT = device under test initial clk = 0; // not synthesizable, sets first cycle // can also do this in the declaration always #5 clk <= ~clk; // no sens. list, always executes always @(posedge clk) count <= count + 1'b1; // Could write each state followed by delay assign {a,b,c} = count; endmodule // Verify we got the correct test results with eyeballs // Automatically report stuff to catch everything module testbench(); logic clk, a, b, c, y; logic [2:0] count; block dut(a,b,c,y) always #5 clk <= ~clk; always @(posedge clk) count <= count + 1'b1; assign {a,b,c} = count; initial begin clk = 0; #10; if (y!==0) $display("Error at 000"); #10; if (y!==1) $display("Error at 001"); #10; if (y!==0) $display("Error at 010"); #10; if (y!==0) $display("Error at 011"); #10; if (y!==1) $display("Error at 100"); #10; if (y!==1) $display("Error at 101"); #10; if (y!==0) $display("Error at 110"); #10; if (y!==0) $display("Error at 111"); // Implicitly comparing to changing logic values // Can probably do explicitly with a case endmodule // also be aware of $monitor (edge sense), and $time (global var) // Let's say we want to test specific vectors // Reasons: simulation time in big blocks, sequential state coverage // Let's also say we want a shorthand for the ifs above // --> can get all of this with vector files // vector file example, format: abc_yexpected 000_1 001_0 010_0 011_1 //... // underscores are decoration here per usual // read this in and do some stuff with it for compact checks // Here's an example of testing w/ testvector module testbench(); logic clk, reset, a, b, c, y, yexpected; logic [31:0] vectornum, errors; // bookkeeping logic [3:0] testvectors[10000:0]; // vector storage block dut(a,b,c,y) always begin clk = 1'b1; #5; clk = 1'b0; #5; end // another way to write the clock, not initialized initial begin $readmemb("example.tv", testvectors) // read the vectors in example.tv into testvectors // do at start. Use $readmemh for hex vector files vectornum = 0; errors = 0; reset = 1; #27; reset=0; end // apply signals on rising edge // #1 separates clk sensitive stuff from data sens. always @(posedge clk) begin #1;8 {a,b,c,yexpected} = testvectors[vectornum]; end // check results on falling edge (rising stuff resolved) always @(negedge clk) if (~reset) if (y !== yexpected) // use !== to catch x, z begin $display("Error: inputs = %b", {a,b,c}); $display(" outputs = %b (%b expected)",y,yexpected); // sprintf sort of behavior here, can use %h errors = errors+1; end vectornum = vectornum+1; if (testvectors[vectornum] === 4'bx) begin $display("Finished: %d vectors with %d errors", vectornum, errors); $finish; // prevent counter from running forever endmodule // In Modelsim we'd do this with a do file, // (so named because of the suffix .do) // can automate commands to simulator using same vocab example.do: force clk 0 0, 1 25 -repeat 50 force b 1 run 100 // eyeball results force b 0 run 100 // possible to do checking here as well, show on GUI // good online tutorials