Add examples. Add more info to README
This commit is contained in:
37
examples/simple-counter/simple_counter.sv
Normal file
37
examples/simple-counter/simple_counter.sv
Normal file
@@ -0,0 +1,37 @@
|
||||
`timescale 1ps/1ps
|
||||
`default_nettype none
|
||||
|
||||
module simple_counter #(parameter COUNT = 16,
|
||||
localparam WIDTH = $clog2(COUNT-1)) // <-- ERROR
|
||||
(input wire clock,
|
||||
input wire reset,
|
||||
|
||||
input wire i_inc,
|
||||
input wire i_dec,
|
||||
|
||||
output reg [WIDTH-1:0] o_count);
|
||||
|
||||
logic [WIDTH-1:0] count_next;
|
||||
|
||||
always_comb
|
||||
case ({i_inc, i_dec})
|
||||
2'b01:
|
||||
if (o_count == '0)
|
||||
count_next = WIDTH'(COUNT-1);
|
||||
else
|
||||
count_next = o_count - 1'b1;
|
||||
|
||||
2'b10:
|
||||
if (o_count == WIDTH'(COUNT-1))
|
||||
count_next = '0;
|
||||
else
|
||||
count_next = o_count + 1'b1;
|
||||
|
||||
default: count_next = o_count;
|
||||
endcase
|
||||
|
||||
always_ff @(posedge clock)
|
||||
if (reset) o_count <= '0;
|
||||
else o_count <= count_next;
|
||||
|
||||
endmodule // simple_counter
|
||||
67
examples/simple-counter/simple_counter_tb.sv
Normal file
67
examples/simple-counter/simple_counter_tb.sv
Normal file
@@ -0,0 +1,67 @@
|
||||
`timescale 1ps/1ps
|
||||
|
||||
`include "utest.vh"
|
||||
|
||||
module simple_counter_tb;
|
||||
logic clock = 1'b0;
|
||||
logic reset = 1'b1;
|
||||
|
||||
always #(10ns/2) clock = ~clock;
|
||||
|
||||
parameter COUNT = 16;
|
||||
parameter ITERATIONS = 100;
|
||||
parameter DIRECTION = 1; // 1 - increment, -1 - decrement, 0 - random
|
||||
|
||||
localparam WIDTH = $clog2(COUNT-1); // <-- ERROR
|
||||
|
||||
logic i_inc;
|
||||
logic i_dec;
|
||||
logic [WIDTH-1:0] o_count;
|
||||
|
||||
simple_counter #(.COUNT(COUNT))
|
||||
DUT (.*);
|
||||
|
||||
int gold_count;
|
||||
|
||||
//// Shows that a `UTEST_BASE_DIR define exists
|
||||
// initial begin
|
||||
// `log_info(("From verilog code. Base dir: %s", `UTEST_BASE_DIR));
|
||||
// end
|
||||
|
||||
initial begin
|
||||
i_inc = 1'b0;
|
||||
i_dec = 1'b0;
|
||||
reset = 1'b1;
|
||||
repeat(2) @(posedge clock) #1;
|
||||
|
||||
reset = 1'b0;
|
||||
@(posedge clock) #1;
|
||||
|
||||
gold_count = '0;
|
||||
|
||||
for (int i = 0; i < ITERATIONS; i += 1) begin
|
||||
case (DIRECTION)
|
||||
-1: {i_inc, i_dec} = 2'b01;
|
||||
1: {i_inc, i_dec} = 2'b10;
|
||||
default: {i_inc, i_dec} = 2'($urandom);
|
||||
endcase
|
||||
|
||||
@(posedge clock) #1;
|
||||
|
||||
if (i_inc && !i_dec)
|
||||
gold_count ++;
|
||||
else if (!i_inc && i_dec)
|
||||
gold_count --;
|
||||
|
||||
if (gold_count >= COUNT) gold_count = 0;
|
||||
if (gold_count < 0) gold_count = COUNT-1;
|
||||
|
||||
if (gold_count != int'(o_count))
|
||||
`log_error(("#%0t: Gold count = %0d, DUT count = %0d", $time, gold_count, o_count));
|
||||
end
|
||||
|
||||
repeat(2) @(posedge clock) #1;
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule // simple_counter_tb
|
||||
44
examples/simple-counter/simple_counter_tb.utest
Normal file
44
examples/simple-counter/simple_counter_tb.utest
Normal file
@@ -0,0 +1,44 @@
|
||||
;; -*- scheme -*-
|
||||
|
||||
;;; Make lists combinations
|
||||
;;; Example: (combinations '(1 2 3) '(a b)) -> '((1 a) (1 b) (2 a) (2 b) (3 a) (3 b))
|
||||
(define (combinations . lists)
|
||||
(cond
|
||||
((null? lists) '())
|
||||
((null? (cdr lists)) (car lists))
|
||||
(else
|
||||
(fold (lambda (comb out)
|
||||
(append out
|
||||
(map (lambda (x)
|
||||
(if (list? comb)
|
||||
(cons x comb)
|
||||
(list x comb)))
|
||||
(car lists))))
|
||||
'() (apply combinations (cdr lists))))))
|
||||
|
||||
;;; Testbenches
|
||||
(map
|
||||
(lambda (l)
|
||||
(let ((count (car l))
|
||||
(direction (cadr l)))
|
||||
(utest/tb
|
||||
((format "c~a_d~a" count direction)
|
||||
"More complex testbench for Simple Counter"
|
||||
(format "COUNT=~a\tDIRECTION=~a" count direction))
|
||||
|
||||
;; Instead of a description, you can display the message in log
|
||||
;; (utest/log 'info "COUNT = ~a" count)
|
||||
|
||||
;; testbench body
|
||||
(utest/run-simulation-iverilog
|
||||
(utest/find-files ".*\\.sv$")
|
||||
"simple_counter_tb"
|
||||
#:parameters `((COUNT ,count)
|
||||
(ITERATIONS ,(* count 3))
|
||||
(DIRECTION ,direction))))))
|
||||
|
||||
(combinations
|
||||
(append '(10 100 1000 16 64 256)
|
||||
(let ((state (seed->random-state 0)))
|
||||
(map (lambda (x) (+ 2 (random 200 state))) (iota 100))))
|
||||
'(1 -1 0)))
|
||||
12
examples/simple-counter/simple_counter_tb_single.utest
Normal file
12
examples/simple-counter/simple_counter_tb_single.utest
Normal file
@@ -0,0 +1,12 @@
|
||||
;; -*- scheme -*-
|
||||
;; ^^^ this comment tells Emacs to use Scheme mode
|
||||
|
||||
(utest/tb
|
||||
("simple_counter_tb"
|
||||
"Simplest testbench Simple Counter")
|
||||
|
||||
(utest/run-simulation-iverilog
|
||||
;; sources
|
||||
'("simple_counter.sv" "simple_counter_tb.sv")
|
||||
;; top module name
|
||||
"simple_counter_tb"))
|
||||
@@ -0,0 +1,25 @@
|
||||
;; -*- scheme -*-
|
||||
;; ^^^ this comment tells Emacs to use Scheme mode
|
||||
|
||||
(utest/tb
|
||||
("simple_counter_permanent"
|
||||
"Testbench for Simple Counter with permanent work dir")
|
||||
|
||||
;; get base dir and make work dir
|
||||
(let* ((base (utest/base-path))
|
||||
(work (format "~a/work" base)))
|
||||
|
||||
(when (not (file-exists? work))
|
||||
(mkdir work))
|
||||
|
||||
;; parameterize work dir
|
||||
(parameterize
|
||||
((utest/work-path work)
|
||||
(utest/force-dump #t))
|
||||
|
||||
;; testbench body
|
||||
(utest/run-simulation-iverilog
|
||||
;; sources
|
||||
'("simple_counter.sv" "simple_counter_tb.sv")
|
||||
;; top module name
|
||||
"simple_counter_tb"))))
|
||||
15
examples/simple-counter/utest.vh
Normal file
15
examples/simple-counter/utest.vh
Normal file
@@ -0,0 +1,15 @@
|
||||
`ifndef UTEST_VERILOG_DEFINES
|
||||
`define UTEST_VERILOG_DEFINES
|
||||
|
||||
// Log level string prefixes for use with $display function.
|
||||
// Example usage: $display("%sError message", `LOG_ERR);
|
||||
`define LOG_INFO "INFO#"
|
||||
`define LOG_WARN "WARN#"
|
||||
`define LOG_ERR "FAIL#"
|
||||
|
||||
// Dirty hacked redefine of $display function. Must be used with two parentheses.
|
||||
// Example usage: `log_info(("Information message"));
|
||||
`define log_info(msg) begin $display({`LOG_INFO, $sformatf msg}); end
|
||||
`define log_warn(msg) begin $display({`LOG_WARN, $sformatf msg}); end
|
||||
`define log_error(msg) begin $display({`LOG_ERR, $sformatf msg}); end
|
||||
`endif
|
||||
Reference in New Issue
Block a user