HDLBits-Verilog Practice-3-Verification: Reading Simulations -> Verification: Writing Testbenches
注:建议使用 Ctrl+F
利用关键词、题号、题目名称 查阅本文内容
笔记内容
-
本文范围 Verification: Reading Simulations -> Verification: Writing Testbenches
-
网页本身给出的语法点,和一些语法的使用思路
-
做题过程中的反思
-
参考答案xiaop1/Verilog-Practice: HDLBits website practices & solutions
Verification: Reading Simulations
Finding bugs in code
Bugs mux2
-
A mux coded as
(~sel & a) | (sel & b)
does not work for vectors.
This is because these are bitwise operators, and sel is only a 1 bit wide quantity, which leaves the upper bits of a and b zeroed. It is possible to code it using the replication operator, but this is somewhat difficult to read:( {8{~sel}} & a ) | ( {8{sel}} & b )
-
The simulation waveform shows that when sel = 1, a should be selected. This is flipped in the suggested code.
因此,我们有,
assign out = sel ? a : b;
Bugs nand3
You must use the provided 5-input AND gate:module andgate ( output out, input a, input b, input c, input d, input e );
管脚若悬空(dangling)则默认置零,因此末两个空闲输入需显式指明为 1'b1
module top_module (input a, input b, input c, output out);
wire temp;
andgate inst1 ( temp, a, b, c, 1'b1, 1'b1 );
assign out=~temp;
endmodule
Bugs mux4
- 声明临时向量时记得要写向量域
- 这里使用 分治算法 解决 选择 问题,需要分析 选择的依据(喂给子模块的sel)的选取 。
module top_module (
input [1:0] sel,
input [7:0] a,
input [7:0] b,
input [7:0] c,
input [7:0] d,
output [7:0] out ); //
wire [7:0]mux0, mux1;
mux2 mux00 ( sel[0], a, b, mux0 );
mux2 mux01 ( sel[0], c, d, mux1 );
mux2 mux02 ( sel[1], mux0, mux1, out );
endmodule
Bugs addsubz
- 对于向量是否为全0 应先使用 归约运算符 得到 1-bit 的结果;再写判断
- 组合逻辑 if-else 要写全避免锁存器;
always @(*) begin
case (do_sub)
0: out = a+b;
1: out = a-b;
endcase
if (~(|out))
result_is_zero = 1;
else
result_is_zero = 0;
end
Bugs case
错误的代码:
module top_module (
input [7:0] code,
output reg [3:0] out,
output reg valid=1 );
always @(*)begin
case (code)
8'h45: out = 0;
8'h16: out = 1;
8'h1e: out = 2;
8'h26: out = 3;
8'h25: out = 4;
8'h2e: out = 5;
8'h36: out = 6;
8'h3d: out = 7;
8'h3e: out = 8;
8'h46: out = 9;
default: begin
valid=0;
out=0;
end
endcase
end
endmodule
always块 里的 case语句中的 default 对valid 的赋值(L19) 将会永久覆盖 上面module参数声明列表中的默认赋值(L4)。即,上述代码将 valid 恒置为0。
因此,如下面代码所示,在**always块内case块外 (L10) **增加关于valid的默认赋值。
(由此看来,在参数列表的默认赋值没什么用,太容易被覆盖了。)
module top_module (
input [7:0] code,
output reg [3:0] out,
output reg valid
);
// A combinational always block.
always @(*) begin
out = 0; // To avoid latches, give the outputs a default assignment
valid = 1; // then override them in the case statement. This is less
// code than assigning a value to every variable for every case.
case (code)
8'h45: out = 0;
8'h16: out = 1;
8'h1e: out = 2;
8'h26: out = 3; // 8'd26 is 8'h1a
8'h25: out = 4;
8'h2e: out = 5;
8'h36: out = 6;
8'h3d: out = 7;
8'h3e: out = 8;
8'h46: out = 9; // 6'h46 is 8'h46
default: valid = 0;
endcase
end
endmodule
Build a circuit from a simulation waveform.
笔记
Sim/circuit9
在模块的输入输出声明处,可以初始化输出值(代码 L25)。
同步复位值在代码L29处控制。
以上是两件事,不可随意互相取代。
相应代码
module top_module ();
reg clk=0;
always #5 clk = ~clk; // Create clock with period=10
initial `probe_start; // Start the timing diagram
`probe(clk); // Probe signal "clk"
`probe(a);
`probe(q);
// A testbench
reg in=0;
reg a=1;
initial begin
#40 a<=0;
#50 $finish; // Quit the simulation
end
reg [3:0]q;
test inst1 ( clk,a,q ); // Sub-modules work too.
endmodule
module test (
input clk,
input a,
output reg [3:0] q=4'h3 ); //initialization
always@(posedge clk)
if(a)
q<=4'h4;
else
q<= (q+1'b1==4'h7)? 4'h0:q+1'b1;
endmodule
Sim/circuit8
本题的p
本质是一个锁存器,其波形图一定程度上展示了锁存器的毛刺敏感。
波形图
代码
assign p=clock?a&clock:p;
always@(negedge clock)
q<=p|clock;
Verification: Writing Testbenches
Tb/and
这题第五个测试样例要求保持第四个样例的输出不变= =。就是在这里记录一下这个坑。(因为它的输出不显示第五个测试样例,无法做针对性修改。)
initial begin
in = 2'b00;
#10
in = 2'b01;
#10
in = 2'b10;
#10
in = 2'b11;
end
andgate inst(.in(in), .out(out));