【HDLBits答案及思路(仅供参考,1 Getting Started与2 Verilog Language)】
HDLBits学习笔记,答案分享
目录(点击题目直达)
- 0 引言
- 1 Getting Started
- 2 Verilog Language
-
- 2.1 Basics
- 2.2 Vectors
- 2.3 Modules: Hierarchy
- 2.4 Procedures
- 2.5 More Verilog Features
-
- ● Conditional ternary operator (Conditional)
- ● Reduction operators (Reduction)
- ● Reduction: Even wider gates (Gates100)
- ● Combinational for-loop: Vector reversal 2 (Vector100r)
- ● Combinational for-loop: 255-bit population count (Popcount255)
- ● Generate for-loop: 100-bit binary adder 2 (Adder100i)
- ● Generate for-loop: 100-digit BCD adder (Bcdadd100)
0 引言
最近通过HDLBits学习verilog,写下此文记录下学习过程和一些心得,文中不对之处请各位批评指正。此文仅为1 Getting Started与2 Verilog Language两章题目,更多题目请见:
【HDLBits答案及思路(仅供参考,3 Circuits)(暂未更新)】
【HDLBits答案及思路(仅供参考,4 Verification: Reading Simulations与5 Verification: Writing Testbenches)(暂未更新)】
所有代码都通过了HDLBits网站验证,但是可能在写文修改格式时出现一些问题,所以发现有不正确之处,请联系我修改。同时,我的方法不一定是最优解决方案,仅供参考,如果朋友有更好的解决思路,也希望能够不吝赐教。注:HDLBits中模块端口声明并没有指定数据类型,我也不打算修改。
文中括号外标题对应于HDLBits首页中的标题,括号内的标题对应于具体题目左上角的标题,如● Getting Started (Step one),Getting Started是进入主页面后看到的标题,Step one是做题时左上角显示的标题。
1 Getting Started
● Getting Started (Step one)
module top_module( output one );
// Insert your code here
assign one = 1'b1;
endmodule
注:verilog进行赋值时需要注意位宽问题,最好指定位宽,1'b1表示1位二进制数1。
● Output Zero (Zero)
module top_module(
output zero
);// Module body starts after semicolon
assign zero = 1'b0;
endmodule
2 Verilog Language
2.1 Basics
● Simple wire (Wire)
module top_module(
input in,
output out );
assign out = in;
endmodule
● Four wires (Wire4)
module top_module(
input a,b,c,
output w,x,y,z );
assign w = a;
assign x = b;
assign y = b;
assign z = c;
endmodule
● Inverter (Notgate)
module top_module( input in, output out );
assign out = !in;
endmodule
● AND gate (Andgate)
module top_module(
input a,
input b,
output out );
assign out = a & b;
endmodule
● NOR gate (Norgate)
module top_module(
input a,
input b,
output out );
assign out = ~(a | b);
endmodule
● XNOR gate (Xnorgate)
module top_module(
input a,
input b,
output out );
assign out = ~(a^b);
endmodule
● Declaring wires (Wire decl)
`default_nettype none
module top_module(
input a,
input b,
input c,
input d,
output out,
output out_n );
wire and_ab,and_cd,or1;
assign and_ab = a & b;
assign and_cd = c & d;
assign or1 = and_ab | and_cd;
assign out = or1;
assign out_n = ~or1;
endmodule
● 7458 chip (7458)
module top_module (
input p1a, p1b, p1c, p1d, p1e, p1f,
output p1y,
input p2a, p2b, p2c, p2d,
output p2y );
assign p1y = (p1a & p1b & p1c) | (p1d & p1e & p1f);
assign p2y = (p2a & p2b) | (p2c & p2d);
endmodule
2.2 Vectors
● Vectors (Vector0)
module top_module (
input wire [2:0] vec,
output wire [2:0] outv,
output wire o2,
output wire o1,
output wire o0 ); // Module body starts after module declaration
assign outv = vec;
assign o0 = vec[0];
assign o1 = vec[1];
assign o2 = vec[2];
endmodule
● Vectors in more detail (Vector1)
`default_nettype none // Disable implicit nets. Reduces some types of bugs.
module top_module(
input wire [15:0] in,
output wire [7:0] out_hi,
output wire [7:0] out_lo );
assign out_hi[7:0] = in[15:8];
assign out_lo[7:0] = in[7:0];
endmodule
● Vector part select (Vector2)
module top_module(
input [31:0] in,
output [31:0] out );
assign out[31:24] = in[7:0];
assign out[23:16] = in[15:8];
assign out[15:8] = in[23:16];
assign out[7:0] = in[31:24];
endmodule
● Bitwise operators (Vectorgates)
module top_module(
input [2:0] a,
input [2:0] b,
output [2:0] out_or_bitwise,
output out_or_logical,
output [5:0] out_not
);
assign out_or_bitwise = a|b;
assign out_or_logical = a||b;
assign out_not = {~b,~a};
endmodule
● Four-input gates (Gates4)
module top_module(
input [3:0] in,
output out_and,
output out_or,
output out_xor
);
//写法一
/*assign out_and = in[3] & in[2] & in[1] & in[0];
assign out_or = in[3] | in[2] | in[1] | in[0];
assign out_xor = in[3] ^ in[2] ^ in[1] ^ in[0];*/
//写法二
assign out_and = ∈
assign out_or = |in;
assign out_xor = ^in;
endmodule
注:将运算符&、|、^放在vari[msb,lsb]左边表示从msb位开始按位与、或、异或到lsb位,即:&vari==vari[msb]&…&vari[lsb]。
● Vector concatenation operator (Vector3)
module top_module (
input [4:0] a, b, c, d, e, f,
output [7:0] w, x, y, z );//
assign w = {a,b[4:2]};
assign x = {b[1:0],c[4:0],d[4]};
assign y = {d[3:0],e[4:1]};
assign z = {e[0],f,2'b11};
endmodule
注:verilog的拼接操作:{in1,in2}。
● Vector reversal 1 (Vectorr)
module top_module(
input [7:0] in,
output [7:0] out
);
assign out = {in[0],in[1],in[2],in[3],in[4],in[5],in[6],in[7]};
endmodule
● Replication operator (Vector4)
module top_module (
input [7:0] in,
output [31:0] out );
assign out = { {24{in[7]}},in };
endmodule
注:verilog的复制操作:{n{in}}。
● More replication (Vector5)
module top_module (
input a, b, c, d, e,
output [24:0] out );
assign out = ~{ {5{a}},{5{b}},{5{c}},{5{d}},{5{e}} } ^ {5{a,b,c,d,e}};
endmodule
2.3 Modules: Hierarchy
● Modules (Module)
module top_module ( input a, input b, output out );
mod_a inst1(.in1(a),
.in2(b),
.out(out));
endmodule
注:通过端口名称进行模块实例化(推荐此种方式)。
● Connecting ports by position (Module pos)
module top_module (
input a,
input b,
input c,
input d,
output out1,
output out2
);
mod_a inst2(out1,out2,a,b,c,d);
endmodule
注:通过端口位置进行模块实例化(不推荐此种方式,因为被实例化模块端口顺序改变后,实例化的端口也得改)。
● Connecting ports by name (Module name)
module top_module (
input a,
input b,
input c,
input d,
output out1,
output out2
);
mod_a inst1(.in1(a),
.in2(b),
.in3(c),
.in4(d),
.out1(out1),
.out2(out2)
);
endmodule
● Three modules (Module shift)
module top_module (
input clk,
input d,
output q );
wire wire1;
wire wire2;
my_dff mod_a(
.clk(clk),
.d(d),
.q(wire1));
my_dff mod_b(
.clk(clk),
.d(wire1),
.q(wire2));
my_dff mod_c(
.clk(clk),
.d(wire2),
.q(q));
endmodule
● Modules and vectors (Module shift8)
module top_module (
input clk,
input [7:0] d,
input [1:0] sel,
output [7:0] q
);
wire [7:0]wire1;
wire [7:0]wire2;
wire [7:0]wire3;
my_dff8 moda(
.clk(clk),
.d(d),
.q(wire1));
my_dff8 modb(
.clk(clk),
.d(wire1),
.q(wire2));
my_dff8 modc(
.clk(clk),
.d(wire2),
.q(wire3));
always@(*)
begin
case(sel)
2'b00:q=d;
2'b01:q=wire1;
2'b10:q=wire2;
2'b11:q=wire3;
default:q=d;
endcase
end
endmodule
● Adder 1 (Module add)
module top_module(
input [31:0] a,
input [31:0] b,
output [31:0] sum
);
wire cin_1,cin_2;
assign cin_1 = 1'b0;
add16 u1_add16(
.a(a[15:0]),
.b(b[15:0]),
.cin(cin_1),//可直接写.cin(1'b0)
.cout(cin_2),
.sum(sum[15:0]));
add16 u2_add16(
.a(a[31:16]),
.b(b[31:16]),
.cin(cin_2),
.cout(),
.sum(sum[31:16]));
endmodule
● Adder 2 (Module fadd)
module top_module (
input [31:0] a,
input [31:0] b,
output [31:0] sum
);
wire cout_l;
add16 ul_add16(
.a(a[15:0]),
.b(b[15:0]),
.sum(sum[15:0]),
.cin(1'b0),
.cout(cout_l));
add16 uh_add16(
.a(a[31:16]),
.b(b[31:16]),
.sum(sum[31:16]),
.cin(cout_l),
.cout());
endmodule
module add1 (input a,b,cin,
output sum,cout );
assign {cout,sum}=a+b+cin;
endmodule
● Carry-select adder (Module cseladd)
module top_module(
input [31:0] a,
input [31:0] b,
output [31:0] sum
);
wire carry;
wire [15:0]sum_uh1;
wire [15:0]sum_uh2;
add16 ul_add16(
.a(a[15:0]),
.b(b[15:0]),
.cin(1'b0),
.sum(sum[15:0]),
.cout(carry));
add16 uh1_add_16(
.a(a[31:16]),
.b(b[31:16]),
.cin(1'b0),
.sum(sum_uh1),
.cout());
add16 uh2_add_16(
.a(a[31:16]),
.b(b[31:16]),
.cin(1'b1),
.sum(sum_uh2),
.cout());
assign sum=carry?{sum_uh2,sum[15:0]}:{sum_uh1,sum[15:0]};
endmodule
注:进位选择加法器,用面积换速度,高位加法器有两个,一个carry_in=0,一个carry_in=1,当低位加法器计算出carry_out后,通过选择器“瞬间”可以得到整个输入的结果。三目运算符:?:。
● Adder-subtractor (Module addsub)
module top_module(
input [31:0] a,
input [31:0] b,
input sub,
output [31:0] sum
);
wire [31:0] bxor;
wire carry;
assign bxor=b^{32{sub}};
add16 add16_u1(
.a(a[15:0]),
.b(bxor[15:0]),
.cin(sub),
.sum(sum[15:0]),
.cout(carry));
add16 add16_u2(
.a(a[31:16]),
.b(bxor[31:16]),
.cin(carry),
.sum(sum[31:16]),
.cout());
endmodule
2.4 Procedures
● Always blocks (combinational) (Alwaysblock1)
// synthesis verilog_input_version verilog_2001
module top_module(
input a,
input b,
output wire out_assign,
output reg out_alwaysblock
);
assign out_assign = a & b;
always@(*)
begin
out_alwaysblock = a & b;
end
endmodule
注:assign左侧必须为线网类型,如wire;always过程块中左侧必须为变量类型,如reg。
● Always blocks (clocked) (Alwaysblock2)
// synthesis verilog_input_version verilog_2001
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
注:组合电路用always@(*),时序电路用always@(posedge clk)。
● If statement (Always if)
// synthesis verilog_input_version verilog_2001
module top_module(
input a,
input b,
input sel_b1,
input sel_b2,
output wire out_assign,
output reg out_always );
assign out_assign = (sel_b1==1 && sel_b2==1) ? b : a;
always@(*)
begin
if (sel_b1==1 && sel_b2==1)
begin
out_always = b;
end
else
begin
out_always = a;
end
end
endmodule
注:三目运算符等于最基础的if-else。
● If statement latches (Always if2)
// synthesis verilog_input_version verilog_2001
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)
keep_driving = 0;
else if(gas_tank_empty)
keep_driving = 0;
else
keep_driving = 1;
end
endmodule
注:verilog中if语句必须有else,否则容易产生锁存latch。
● 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
case(sel)
3'd0:out = data0;
3'd1:out = data1;
3'd2:out = data2;
3'd3:out = data3;
3'd4:out = data4;
3'd5:out = data5;
default:out = 3'd0;
endcase
end
endmodule
注:verilog中case语句必须有default,否则也容易产生锁存latch。
● Priority encoder (Always case2)
// synthesis verilog_input_version verilog_2001
module top_module (
input [3:0] in,
output reg [1:0] pos );
always@(*)begin
if(in[0]==1)
pos = 2'd0;
else if(in[1]==1)
pos = 2'd1;
else if(in[2]==1)
pos = 2'd2;
else if(in[3]==1)
pos = 2'd3;
else
pos = 2'd0;
end
endmodule
● 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'bzzzz_zzz1: pos= 3'd0;
8'bzzzz_zz10: pos= 3'd1;
8'bzzzz_z100: pos= 3'd2;
8'bzzzz_1000: pos= 3'd3;
8'bzzz1_0000: pos= 3'd4;
8'bzz10_0000: pos= 3'd5;
8'bz100_0000: pos= 3'd6;
8'b1000_0000: pos= 3'd7;
default: pos= 3'd0;
endcase
end
endmodule
注:case:完全匹配为1,casez:某位的值为z则忽略,casex:某位的值为x或z则忽略。一般经常用casez,慎用casex。
● Avoiding latches (Always nolatches)
// 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
left = 0; down = 0;
right = 0; up = 0;
case(scancode)
16'he06b:begin
left = 1; down = 0;
right = 0; up = 0;
end
16'he072:begin
left = 0; down = 1;
right = 0; up = 0;
end
16'he074:begin
left = 0; down = 0;
right = 1; up = 0;
end
16'he075:begin
left = 0; down = 0;
right = 0; up = 1;
end
default:begin
left = 0; down = 0;
right = 0; up = 0;
end
endcase
end
endmodule
2.5 More Verilog Features
● Conditional ternary operator (Conditional)
module top_module (
input [7:0] a, b, c, d,
output [7:0] min);
wire [7:0] compare_ab, compare_cd;
always@(*)begin
compare_ab = a<b?a:b;
compare_cd = c<d?c:d;
min = compare_ab<compare_cd?compare_ab:compare_cd;
end
endmodule
● Reduction operators (Reduction)
module top_module (
input [7:0] in,
output parity);
assign parity = ^in[7:0];
endmodule
注:奇偶校验,偶校验用异或:^,奇校验用同或:~^。
● Reduction: Even wider gates (Gates100)
module top_module(
input [99:0] in,
output out_and,
output out_or,
output out_xor
);
assign out_and = &in[99:0];
assign out_or = |in[99:0];
assign out_xor = ^in[99:0];
endmodule
● Combinational for-loop: Vector reversal 2 (Vector100r)
module top_module(
input [99:0] in,
output [99:0] out
);
integer i;
always@(*)begin
out = 0;
for(i=0;i<100;i=i+1)begin
out[i] = in[99-i];
end
end
endmodule
注:verilog中for循环的循环变量定义为integer类型。
● Combinational for-loop: 255-bit population count (Popcount255)
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]==1'b1)begin
out = out + 1'b1;
end else begin
out = out;
end
end
end
endmodule
● Generate for-loop: 100-bit binary adder 2 (Adder100i)
//方法一:generate-for
/*module top_module(
input [99:0] a, b,
input cin,
output [99:0] cout,
output [99:0] sum );
genvar i;
generate
for(i=0;i<100;i=i+1)begin:RIPPLE_CARRY_ADDER
if(i==0)begin
full_adder_1 fadder1(
.a(a[i]),
.b(b[i]),
.cin(cin),
.sum(sum[i]),
.cout(cout[i]));
end else begin
full_adder_1 fadder1(
.a(a[i]),
.b(b[i]),
.cin(cout[i-1]),
.sum(sum[i]),
.cout(cout[i]));
end
end
endgenerate
endmodule
module full_adder_1(
input a,b,cin,
output cout,sum);
assign {cout,sum}=a+b+cin;
endmodule*/
//方法二:数组实例化
module top_module(
input [99:0] a, b,
input cin,
output [99:0] cout,
output [99:0] sum );
full_adder_1 fadd1_inst[99:0](
.a(a),
.b(b),
.cin({cout[98:0],cin}),
.sum(sum),
.cout(cout));
endmodule
module full_adder_1(
input a,b,cin,
output cout,sum);
assign {cout,sum}=a+b+cin;
endmodule
注:同个模块多次实例化:使用generate-for循环结构或者使用数组实例化。generate-for循环结构中循环变量定义为genvar类型,且循环位于generate块内,for后的begin需接名字(标识)。数组实例化与常规实例化的区别在于实例名后需接循环数组长度,后续端口矢量长度需要与之匹配。
● Generate for-loop: 100-digit BCD adder (Bcdadd100)
module top_module(
input [399:0] a, b,
input cin,
output cout,
output [399:0] sum );
reg [99:0]cout_t;
/*//方法一:利用generate-for
genvar i;
generate
for(i=0;i<100;i=i+1)begin:BCDAdd100
if(i==0)begin
bcd_fadd bcdfadd_inst(
.a(a[3:0]),
.b(b[3:0]),
.cin(cin),
.sum(sum[3:0]),
.cout(cout_t[0]));
end else begin
bcd_fadd bcdfadd_inst(
.a(a[i*4+3:i*4]),
.b(b[i*4+3:i*4]),
.cin(cout_t[i-1]),
.sum(sum[i*4+3:i*4]),
.cout(cout_t[i]));
end
end
endgenerate
assign cout=cout_t[99];*/
//方法二:利用数组实例化
bcd_fadd bcdfadd_inst[99:0](
.a(a[399:0]),
.b(b[399:0]),
.cin({cout_t[98:0],cin}),
.sum(sum[399:0]),
.cout(cout_t[99:0]));
assign cout=cout_t[99];
endmodule
注:for循环中的a[i*4+3:i*4]是允许的,因为对于每次循环而言,i为一个定值。也可以用a[i*4+3-:4]代替。
更多推荐



所有评论(0)