HDLBits练习答案
- 1.Getting Started
- 2. Verilog Language
- 2.3 Modules:Hierarchy
- 2.4 Procedures
- 2.5 More Verilog Features
- 2.5.1 Conditional ternary operator
- 2.5.2 Reduction operators---Reduction
- 2.5.3 Reduction:Event wider gates---Gates100
- 2.5.4 Combinational for-loop:Vector reversal 2---Vector100r
- 2.5.5 Combinational for-loop:255-bit population count---Popcount255
- 2.5.6 Generate for-loop:100-bit binary adder 2---Adder100i
- 2.5.7 Generate for-loop:100-bit digit BCD adder---Bcdadd100
- 3 Circuits
1.Getting Started
2. Verilog Language
2.3 Modules:Hierarchy
2.3.5 Modules and vertors
module top_module (
input clk,
input [7:0] d,
input [1:0] sel,
output [7:0] q
);
wire [7:0] q1,q2,q3,qout;
my_dff8 U1(clk, d, q1);
my_dff8 U2(clk, q1, q2);
my_dff8 U3(clk, q2, q3);
always @(*)
begin
case(sel)
2'b00: qout<=d;
2'b01: qout<=q1;
2'b10: qout<=q2;
2'b11: qout<=q3;
endcase
end
assign q=qout;
endmodule
2.3.6 Adder 1
方法1:直接使用变量进行访问,处理方法是将相应的数据按照Module定义的顺序进行调用,参数位置不可以错
module top_module(
input [31:0] a,
input [31:0] b,
output [31:0] sum
);
wire [15:0] suml,sumh;
wire cinl,coutl,couth;
assign cinl=0;
add16 U1(a[15:0], b[15:0], cinl, suml, coutl);
add16 U2(a[31:16], b[31:16], coutl, sumh, couth);
assign sum={sumh, suml};
endmodule
方法2:使用点变量的方式,好处就是参数位置可以随意调整。
module top_module(
input [31:0] a,
input [31:0] b,
output [31:0] sum
);
wire [15:0] suml,sumh;
wire cinl,coutl,couth;
assign cinl=0;
add16 U1(.b(b[15:0]), .cin(cinl), .sum(suml), .cout(coutl),.a(a[15:0]) );
add16 U2(.a(a[31:16]),.cin(coutl), .sum(sumh), .cout(couth), .b(b[31:16]) );
assign sum={sumh, suml};
endmodule
2.3.7 Adder 2
此任务是先完成一个小模块add1的设计,两个1bit的数据相加运算,然后再调试add16实现顶层模块的功能
module top_module (
input [31:0] a,
input [31:0] b,
output [31:0] sum
);//
wire [15:0] suml,sumh;
wire cinl,cinh,coutl,couth;
assign cinl=0;
add16 U1(a[15:0],b[15:0],cinl,suml,coutl);
add16 U2(a[31:16],b[31:16],coutl,sumh,couth);
assign sum={sumh,suml};
endmodule
module add1 ( input a, input b, input cin, output sum, output cout );
// Full adder module here
assign sum=a^b^cin;
assign cout= (a&b)|(b&cin)|(a&cin);
endmodule
2.3.8 Carry-select adder
通过低16位的计算得到的进位结果进行选择,这里代码编写的时候要注意改掉以前使用C语言的习惯,比如:
if()
{}
else
{}
在不知不觉中就喜欢添加“{}”,经常导致出错。
module top_module(
input [31:0] a,
input [31:0] b,
output [31:0] sum
);
wire [15:0] suml,sumh0,sumh1;
wire [31:0] sumh;
wire cinl,cinh0,cinh1,coutl;
assign cinl=0;
assign cinh0=0;
assign cinh1=1;
add16 U1(a[15:0], b[15:0], cinl, suml,coutl);
add16 U2(a[31:16], b[31:16], cinh0, sumh0);
add16 U3(a[31:16], b[31:16], cinh1, sumh1);
always @(*) begin
if(coutl==0)
sumh <= {sumh0, suml};
else
sumh <= {sumh1, suml};
end
assign sum = sumh;
endmodule
2.3.9 Adder-subrtactor
module top_module(
input [31:0] a,
input [31:0] b,
input sub,
output [31:0] sum
);
wire [31:0] bxor;
wire [15:0] suml,sumh;
wire cinh;
always @(*)begin
if(sub)
bxor <= b^32'hffff_ffff;
else
bxor <= b^32'h0000_0000;
end
add16 U1(a[15:0], bxor[15:0], sub, suml, cinh);
add16 U2(a[31:16], bxor[31:16], cinh, sumh);
assign sum = {sumh, suml};
endmodule
2.4 Procedures
2.4.1 Always block1
使用一个与门设计,输出wire和reg
module top_module(
input a,
input b,
output wire out_assign,
output reg out_alwaysblock
);
reg out2;
assign out_assign = a & b;
always @(*) begin
out_alwaysblock <= a & b;
end
endmodule
2.4.2 Always block2
用异或门实现三种输出,第一种assign实现组合逻辑,第二种用always@(*)实现组合逻辑,第三种用always @(posedge clk)实现时序逻辑
module top_module(
input clk,
input a,
input b,
output wire out_assign,
output reg out_always_comb,
output reg out_always_ff );
assign out_assign = a^b;
always @(*)begin
out_always_comb <= a^b;
end
always @(posedge clk)begin
out_always_ff <= a^b;
end
endmodule
2.4.4 If statement
用两种方式实现2选1选择器
module top_module(
input a,
input b,
input sel_b1,
input sel_b2,
output wire out_assign,
output reg out_always );
// reg out0;
assign out_assign = ((sel_b1==1)&&(sel_b2==1))? b:a;
always @(*)begin
if((sel_b1==1)&&(sel_b2==1))
out_always <= b;
else
out_always <= a;
end
endmodule
2.4.5 If statement latches
在verilog中如果if-else只写一半,则会出现闩锁,输出状态可能与实际设想的不一致
module top_module (
input cpu_overheated,
output reg shut_off_computer,
input arrived,
input gas_tank_empty,
output reg keep_driving ); //
always @(*) begin
if (cpu_overheated)
shut_off_computer = 1;
else
shut_off_computer = 0;
end
always @(*) begin
if (arrived | gas_tank_empty)
keep_driving = 0;
else
keep_driving = 1;
end
endmodule
上半部分很好理解,下面的语句就不太容易理解了,我们从原来的语句来看,代码的本意应该是如下的真值表,但是原来的代码在arrived=1时就会出现异常,所以我们订正后的代码只要符合该真值表即可。
| arrived | gas_tank_empty | keep_driving |
|---|---|---|
| 0 | 0 | 1 |
| 0 | 1 | 0 |
| 1 | 0 | 0 |
| 1 | 1 | 0 |
2.4.6 Case statement— Always case
// synthesis verilog_input_version verilog_2001
module top_module (
input [2:0] sel,
input [3:0] data0,
input [3:0] data1,
input [3:0] data2,
input [3:0] data3,
input [3:0] data4,
input [3:0] data5,
output reg [3:0] out );//
always@(*) begin // This is a combinational circuit
case(sel)
3'b000: out = data0;
3'b001: out = data1;
3'b010: out = data2;
3'b011: out = data3;
3'b100: out = data4;
3'b101: out = data5;
default out = 3'b000;
endcase
end
endmodule
2.4.6 Priority encoder—Always case2
// synthesis verilog_input_version verilog_2001
module top_module (
input [3:0] in,
output reg [1:0] pos );
always @(*)begin
case(in)
4'b0000: pos = 0;
4'b0001: pos = 0;
4'b0010: pos = 1;
4'b0011: pos = 0;
4'b0100: pos = 2;
4'b0101: pos = 0;
4'b0110: pos = 1;
4'b0111: pos = 0;
4'b1000: pos = 3;
4'b1001: pos = 0;
4'b1010: pos = 1;
4'b1011: pos = 0;
4'b1100: pos = 2;
4'b1101: pos = 0;
4'b1110: pos = 1;
4'b1111: pos = 0;
default: pos = 0;
endcase
end
endmodule
2.4.7 Priority encoder with casez—Always casez
// synthesis verilog_input_version verilog_2001
module top_module (
input [7:0] in,
output reg [2:0] pos );
always @(*) begin
casez (in)
8'bzzzzzzz1: pos = 0;
8'bzzzzzz1z: pos = 1;
8'bzzzzz1zz: pos = 2;
8'bzzzz1zzz: pos = 3;
8'bzzz1zzzz: pos = 4;
8'bzz1zzzzz: pos = 5;
8'bz1zzzzzz: pos = 6;
8'b1zzzzzzz: pos = 7;
default: pos = 0;
endcase
end
endmodule
2.4.7 Avoid latches—Always nolatches
此处介绍了一种不使用default的方法避免出现latch的方法,类似于C中的变量初始化
// synthesis verilog_input_version verilog_2001
module top_module (
input [15:0] scancode,
output reg left,
output reg down,
output reg right,
output reg up );
always @(*) begin
up = 1'b0; down = 1'b0; left = 1'b0; right = 1'b0;
case (scancode)
16'he06b: left = 1'b1;
16'he072: down = 1'b1;
16'he074: right = 1'b1;
16'he075: up = 1'b1;
endcase
end
endmodule
2.5 More Verilog Features
2.5.1 Conditional ternary operator
三目操作符(x)? (y):(z)
module top_module (
input [7:0] a, b, c, d,
output [7:0] min);//
// assign intermediate_result1 = compare? true: false;
wire [7:0] min0,min1;
always @(*)begin
min0 = (a<b)?a:b;
min1 = (c<d)?c:d;
min <= (min0<min1)?min0:min1;
end
endmodule
2.5.2 Reduction operators—Reduction
归约运算符(缩位运算符)对一个数据的内部所有位进行&、|、^等等操作
module top_module (
input [7:0] in,
output parity);
assign parity = ^in;
endmodule
2.5.3 Reduction:Event wider gates—Gates100
module top_module(
input [99:0] in,
output out_and,
output out_or,
output out_xor
);
assign out_and = ∈
assign out_or = |in;
assign out_xor = ^in;
endmodule
2.5.4 Combinational for-loop:Vector reversal 2—Vector100r
100bit的数据倒序输出
module top_module(
input [99:0] in,
output [99:0] out
);
integer i;
always @(*)begin
for(i=0; i<100; i++)
out[99-i] <= in[i];
end
endmodule
2.5.5 Combinational for-loop:255-bit population count—Popcount255
计算一串序列中1的个数
module top_module(
input [254:0] in,
output [7:0] out );
integer i;
always @(*)begin
out = 0;
for(i=0; i<255; i=i+1)
begin
if(in[i])
out= out+1'b1;
end
end
endmodule
2.5.6 Generate for-loop:100-bit binary adder 2—Adder100i
相当于例化100个1bit的全加器来实现100bit的带进位的加法器
module top_module(
input [99:0] a, b,
input cin,
output [99:0] cout,
output [99:0] sum );
integer i;
always @(*)begin
sum[0] = (a[0]^b[0])^cin;
cout[0] = (a[0]&b[0]) | ((a[0]^b[0])&cin);
for(i=1; i<100; i=i+1)begin
sum[i] = (a[i]^b[i])^cout[i-1];
cout[i] = (a[i]&b[i]) | ((a[i]^b[i])&cout[i-1]);
end
end
endmodule
2.5.7 Generate for-loop:100-bit digit BCD adder—Bcdadd100
待更新
3 Circuits
3.1 Combinational Logic
3.1.1 Basic Gates
1.wire
module top_module (
input in,
output out);
assign out = in;
endmodule
- GND
module top_module (
output out);
assign out = 0;
endmodule
- NOR
module top_module (
input in1,
input in2,
output out);
assign out = !(in1 | in2);
endmodule
- Another gate
module top_module (
input in1,
input in2,
output out);
assign out = in1 & (!in2);
endmodule
版权声明:本文为weixin_43306071原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。