这部分主要是找代码中的bug。
一、 Finding bugs in code
MUX 二选一多路复用器
本题为MUX多路复用器,根据选择信号sel,来判断输出是a还是b,因此输出的位宽要和输入位宽是一致的。
同时sel是位宽是1位,而ab的位宽是8位,所以不能sel和输入一起做位运算。
module top_module (
input sel,
input [7:0] a,
input [7:0] b,
output[7:0]out
);
always @ (*)
if(sel == 1'b1)
out = a ;
else
out = b;
endmodule
nand3 与非门
此三输入 NAND 门不起作用。修复错误。
您必须使用提供的 5 输入 AND 门:
module andgate ( output out, input a, input b, input c, input d, input e );
题目分析:首先该题目进行了例化,那么既然例化,所给模块的所有信号都要写入,不能因为没有用到就擅自删除,没有用到的信号可以选择不连接,或者在本题目中,由于是与AND操作,那么没有用到的信号可以赋值1,一个数和1做与运算,还是它本身。
另外因为提供的是AND门,而我们最终要的是与非门,所以还要进行非运算,那么即可引出一根导线,对非运算后的输出进行连接即可。
wire型和reg型
在Verilog中,wire就是相当于一条导线,用来连接电路,不能存储数据,无驱动能力,是组合逻辑,只能在assign左侧赋值,不能用于always
块中赋值;
reg为寄存器型,可以综合成寄存器,latch,甚至wire(当其只是中间变量的时候),可以用于组合逻辑或者时序逻辑(只要是在always块中的信号都定义成reg型),能存储数据,有驱动能力,在always块表达式左侧被赋值。
关于例化列表信号的顺序问题
如果采用下面的例化方式,那么例化列表的顺序是可以改变的,只要信号与括号内的信号相互对应就可以成功连接。——名称相关
andgate inst1 (
.a(a),
.b(b),
.c(c),
.e(1'b1),
.d(1'b1),
.out(out1)
);
如果采用下面的例化方式,那么顺序就不能改变,必须一 一对应——位置相关
andgate inst1 (out1,a,b,c,1'b1,1'b1);
最终代码:
module top_module (input a, input b, input c, output out);
wire out1;
andgate inst1 (out1,a,b,c,1'b1,1'b1);
assign out = ~ out1;
endmodule
mux4 四选一多路复用器
题目给了我们一个二选一多路器,并且需要在此基础上来实现四选一多路器
module mux2 (
input sel,
input [7:0] a,
input [7:0] b,
output [7:0] out
);
例化名称
若某一给定模块需要进行多次例化,那么在同一模块中,实例化名称(本例中为mux2_1、mux2_2)可任意指定,但不能相同,同时也不能使用verilog中的关键字,也不能和我们已经定义过的信号相同。
题目中给出sel为两位,因此是00,01,10,11。因此我们可以采用低位的两次01、01变化来分别在信号ab和信号cd中选择,从而得到最终的两个信号,再用高位的01选择出最终的out。
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 mux2_1 ( sel[0], a, b, mux0 );
mux2 mux2_2 ( sel[0], c, d, mux1 );
mux2 mux2_3 ( sel[1], mux0, mux1, out );
endmodule
add/sub 加法减法器
逻辑取反和按位取反
“!”表示逻辑求反,“~”表示按位求反。
本题是将两个八位的数,进行加减法运算,可以看到result_is_zero信号是一位的,因此肯定是要进行逻辑操作,得到一个一位数0或者1.
由于判断结果是不是0,因此对out进行判断即可。
module top_module (
input do_sub,
input [7:0] a,
input [7:0] b,
output reg [7:0] out,
output reg result_is_zero
);
always @(*) begin
case (do_sub)
0: out = a+b;
1: out = a-b;
endcase
if (!out) //指out等于0的情况
result_is_zero = 1; //因此将该信号置高
else
result_is_zero = 0;
end
endmodule
Case statement(case语句)
这个组合电路应该可以识别8位键盘扫描码的0到9按键。它应该指示10个分支中是否有一个被识别(有效),如果是,那么被识别到的那个按键被检测到。
若题目中没有明显的错误,因此我们先进行仿真,从波形中找bug。
可看出:
参考波形中有vaild的高低变化,而我们的代码波形却一直没有变化,说明我们没有将vaild写到case语句的分支中去。
根据上面标出的我处错误,其中code26以及46是我们代码中有的,因此进行检查,发现8’h26写成了8’d26,另外46处是位数出错,不是6位,是8位。——绿色部分已经修改
至此再次仿真还存在如下的错误:
对于红色错误的部分它们都有一个特性:
out该输出下一个结果的时候,我们写的代码的输出却还是上一个的输出,因此说明生成了锁存器,说明case语句没有写全。的确,在default处没有给出输出out的值。
至此不在继续仿真,而是把valid值的情况在case语句中补上,然后进行最终的仿真。
module top_module (
input [7:0] code,
output reg [3:0] out,
output reg valid=1
);//
always @(*)
case (code)
8'h45: begin
out = 0;
valid = 1;
end
8'h16: begin
out = 1;
valid = 1;
end
8'h1e: begin
out = 2;
valid = 1;
end
8'h26: begin
out = 3;
valid = 1;
end
8'h25: begin
out = 4;
valid = 1;
end
8'h2e: begin
out = 5;
valid = 1;
end
8'h36: begin
out = 6;
valid = 1;
end
8'h3d: begin
out = 7;
valid = 1;
end
8'h3e:begin
out = 8;
valid = 1;
end
8'h46: begin
out = 9;
valid = 1;
end
default: begin
out = 0;
valid = 0;
end
endcase
endmodule
二、Build a circuit from a simulation waveform
circuit1组合电路1
根据如下波形确定其功能,并进行代码的编写。
可看出该当ab都是高电平的时候,输出q为高电平,因此是一个与门电路。
module top_module (
input a,
input b,
output q
);
assign q = a & b;
endmodule
circuit2组合电路2
这个题目时序比较多,不如上一题我们直接就可以看出描述的电路,这个题目我们找出来输出q为高电平的地方,同时写出卡诺图。可以参考卡诺图的画法。
通过卡通诺我们可以分成两种情况,q = 红色圈q1 + 黑色圈q2。
同或和异或
同或和异或互为非运算。同或也称为异或非。
红色圈如下,我们可以看出 q1 = (a同或b) 与 (c同或d )
a | b | c | d |
---|---|---|---|
0 | 0 | 0 | 0 |
0 | 0 | 1 | 1 |
1 | 1 | 0 | 0 |
1 | 1 | 1 | 1 |
黑色圈:q2 = ( a异或b ) 与上 ( c异或d )
a | b | c | d |
---|---|---|---|
0 | 1 | 0 | 1 |
0 | 1 | 1 | 0 |
1 | 0 | 0 | 1 |
1 | 0 | 1 | 0 |
因此 q = q1 + q2 = ( a异或b ) 同或( c异或d ) =~ a^ b^ c^d
module top_module (
input a,
input b,
input c,
input d,
output q
);
assign q = ~a^b^c^d;
endmodule
circuit3组合电路3
仍然找q高电平,然后画出卡诺图。
module top_module (
input a,
input b,
input c,
input d,
output q );//
assign q = b&d | b&c | a&d | a&c;
endmodule
circuit4 组合逻辑4
同上
看到一种更简便的方式
可以化简成q = b | c;
module top_module (
input a,
input b,
input c,
input d,
output q );//
assign q = (~a&b) |(a&b)|(c&d)|(c&~d);
endmodule
circuit5组合逻辑5
首先我们可看出,这是一个四选一多路器,同时根据c的值进行选择。
因此我们就可以看当c的取值为0,1,2,3……的时候,对应的q等于多少,同时q对应的输出值对应输入中abcd的哪个值。
最终可看出:
c = 0 ,q 输出 b的值。
c = 1 ,q 输出 e的值。
c = 2 ,q 输出 a的值。
c = 3 ,q 输出 d的值。
其他情况,q输出f。
module top_module (
input [3:0] a,
input [3:0] b,
input [3:0] c,
input [3:0] d,
input [3:0] e,
output [3:0] q
);
always @(*)
case(c)
4'd0: q = b;
4'd1: q = e;
4'd2: q = a;
4'd3: q = d;
default: q = 4'hf;
endcase
endmodule
circuit6组合逻辑电路6
通过波形可看出该题是根据a的取值来确定q的取值,采用case语句实现即可。
关于case中的default
在使用case语句的时候,不管有没有将所有的情况写全,都要写default,不然容易生成锁存器。
但是该波形中,无法没有给出default的情况,因此我们可以采用如下的写法:
default: q = 16’h1232;或者
default: ;
module top_module (
input [2:0] a,
output [15:0] q
);
always @(*)
case(a)
3'd0: q = 16'h1232;
3'd1: q = 16'haee0;
3'd2: q = 16'h27d4;
3'd3: q = 16'h5a0e;
3'd4: q = 16'h2066;
3'd5: q = 16'h64ce;
3'd6: q = 16'hc526;
3'd7: q = 16'h2f19;
default:q = 16'h1232 ;
endcase
endmodule
circuit7时序逻辑电路7
可看出a的上升沿与clk对齐的。同时在q 在 a变成高电平的下一时钟上升沿变成低电平。
题目两个点:
时序逻辑
取反操作
逻辑非和按位非
取反也就是进行非操作,这里同样涉及到按位非和逻辑非,但是由于输入输出是一位的,所以采用按位非和逻辑非都可。
二者的符号:
按位非:~,对操作数的每一位取反。
逻辑非:!,输出结果要么为真要么为假。(1或0)
module top_module (
input clk,
input a,
output q
);
always @ (posedge clk)
q <= ~a;
endmodule
circuit8时序逻辑电路8
根据波形,我们先看pq输出为高电平的地方。
电平触发和边沿触发
简言之: 电平触发是在高或低电平保持的时间内触发,而边沿触发是信号由高到低或由低到高这一瞬间触发。
电平触发和边沿触发的区别:边沿触发是触发器,触发器会读取并锁存输入信号。输出信号也仅在时钟信号上升(或下降)的一瞬间发生变化。锁存器是电平触发,也相当于使能信号,只要该信号处于高电平(或低电平),输出就会随着输入信号变化,直到使能信号变为低电平(或高电平)时,输出才会锁存,不再随输入变化。(比如使能信号高电平有效,因此高电平输出随着输入变化,低电平的时候保持。)
关于p:
可看出p输出信号是电平触发。当clk处于高电平的时候,p随着a变化,而低电平的时候输出保持。
关于q:
和p不同,q输出信号是边沿触发,只有时钟下降沿的一瞬间输出随a变化,否则保持。
module top_module (
input clock,
input a,
output p,
output q
);
always @ (*)begin
if(clock == 1'b1)//高电平
p = a;//p随a变化
else
p = p;//保持
end
always@(negedge clock)begin
q <= a; //边沿触发,触发器存放a的值。
end
endmodule
或者在边沿触发的时候,q也可以用来存放p的值。
module top_module (
input clock,
input a,
output p,
output q
);
always @ (*)begin
if(clock == 1'b1)//高电平
p = a;//p随a变化
else
p = p;//保持
end
always@(negedge clock)begin
q <= a;
end
endmodule
circuit9 时序逻辑电路(关于使能信号)
根据波形可看出q是边沿触发,当clk上升沿来到,q的值变化,同时当a为使能信号。高电平无效置为4。低电平使能有效进行计数。
同时q是从0-6进行计数,计数满清零。
module top_module (
input clk,
input a,
output [3:0] q
);
always@(posedge clk)
if(a)
q <= 4'd4;
else if(q == 4'd6)
q <= 1'd0;
else
q <= q + 1'd1;
endmodule
circuit10 时序逻辑电路10
题目中说 q输出可根据输出state观察。
首先对所有q高电平的情况进行分析,可看到当a,b,state三个信号,有奇数个1的时候,q才是高电平,因此相当于奇偶校验。只要是奇数个1,那么结果为1,所以可以采用异或 q = a^b ^ state。
观察state所有高电平的位置。可看出当a == b的时候,state发生变化,且状态与ab的相同,但是 ab不相等的时候,state保持之前的值不变。
module top_module (
input clk,
input a,
input b,
output q,
output state );
assign q = a ^ b ^ state;
always @(posedge clk)begin
if(a == b)
state <= b;
else
state <= state;
end
endmodule