前言
最近在HDLbits 网站(https://hdlbits.01xz.net/wiki/)上练习Verilog代码,将仿真通过的部分代码做一个记录,希望大家多多批评指正,共同进步。
代码部分
Module_add
//Module_add
module top_module(
input [31:0] a,
input [31:0] b,
output [31:0] sum
);
wire [15:0] sum1,sum2;
wire cin,cout1,cout2;
assign cin = 1'b0;
add16 inst1(a[15:0], b[15:0], cin, sum1, cout1);
add16 inst2(a[31:16], b[31:16], cout1, sum2, cout2);
assign sum = {sum2, sum1};
endmodule
//
注意:
1、要声明变量cin,再赋值,(考虑代码复用);
2、今后多尝试按名称实例化,按位置容易错。
Module_fadd
//Module_fadd
module top_module (
input [31:0] a,
input [31:0] b,
output [31:0] sum
);
wire cin1, cout1, cout2;
wire [15:0] sum1, sum2;
assign cin1 = 1'b0;
add16 instance1(a[15:0], b[15:0], cin1, sum1, cout1);
add16 instance2(a[31:16], b[31:16], cout1, sum2, cout2);
assign sum = {sum2, sum1};
endmodule
module add1 ( input a, input b, input cin, output sum, output cout );
always @(a or b or cin)
{cout, sum} = a + b + cin;
endmodule
Module_cseladd
//Module_cseladd
module top_module(
input [31:0] a,
input [31:0] b,
output [31:0] sum
);
wire cin1,cin2_0,cin2_1, cout1, cout2;
// sum2_0 means carry_in from the first add16 is 0;
// sum2_1 means carry_in from the first add16 is 1;
wire [15:0] sum1, sum2_0, sum2_1;
wire [31:0] sum_0, sum_1;
assign cin1 = 1'b0;
assign cin2_0 = 1'b0;
assign cin2_1 = 1'b1;
add16 instance1(.a(a[15:0]), .b(b[15:0]), .cin(cin1), .cout(cout1), .sum(sum1));
add16 instance2_0(.a(a[31:16]), .b(b[31:16]), .cin(cin2_0), .cout(cout2), .sum(sum2_0));
add16 instance2_1(.a(a[31:16]), .b(b[31:16]), .cin(cin2_1), .cout(cout2), .sum(sum2_1));
assign sum_0 = {sum2_0, sum1};
assign sum_1 = {sum2_1, sum1};
always@(*)
begin
case (cout1)
1'b0 : sum = sum_0;
1'b1 : sum = sum_1;
endcase
end
endmodule
Module_addsub
module top_module(
input [31:0] a,
input [31:0] b,
input sub,
output [31:0] sum
);
wire [15:0] sum1,sum2;
wire cout1,cout2;
wire [31:0] b_xor;
assign b_xor = b ^ {32{sub}};
add16 instance1(a[15:0], b_xor[15:0], sub, sum1, cout1);
add16 instance2(a[31:16], b_xor[31:16], cout1, sum2, cout2);
assign sum = {sum2, sum1};
endmodule
注:
1、A^B=AB’+A’B,所以A和0异或等于A,A和1异或等于~A,A和自己异或等于0。
2、若写成assign b_xor = b ^ sub,则会报错,此处的异或是按位异或,所以得把b弄成32位。而且题目也有提示;这一句很多人写复杂了,有人用If…else去判断sub。
Always case2
module top_module (
input [3:0] in,
output reg [1:0] pos );
always @(*)
begin
casez(in)
4'bzzz1: pos = 2'b00;
4'bzz1z: pos = 2'b01;
4'bz1zz: pos = 2'b10;
4'b1zzz: pos = 2'b11;
default: pos = 2'b00;
endcase
end
endmodule
注:z代表不关心,平时用的2’bz0也可写成2’b?0
Always nolatches
代码:
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;
16'he072 : down = 1;
16'he074 : right = 1;
16'he075 : up = 1;
endcase
end
endmodule
注:
1、所有的输出都必须有赋值——在一个module里,如果有多个输出,而某条件成立时只对一个输出进行赋值(比如0),那么就会产生latch;可以在写case语句前就对所有的输出进行赋值,这样就可以避免latch产生。
Conditional
module top_module (
input [7:0] a, b, c, d,
output [7:0] min);//
wire [7:0] min_1,min_2,min_3;
assign min_1 = a < b ? a : b;
assign min_2 = min_1 < c ? min_1 : c;
assign min_3 = min_2 < d ? min_2 : d;
assign min = min_3;
endmodule
注:操作符优先级中,?:排在最后,所以此处不必写成 (a<b) ? a : b
Reduction
module top_module (
input [7:0] in,
output parity);
assign parity = ^ in;
endmodule
注:同理,要想对一个向量的所有位进行与/或操作也一样:
assign parity = & in;
assign parity = | in;
Vector100r
先来一个错误的答案。。。
代码打多了还以为变量类型不是reg就是wire了,都忘记还有integer…
改了变量就对了。
module top_module(
input [99:0] in,
output [99:0] out
);
parameter number = 100;
integer i;
always @(*)
begin
for(i=0; i<number; i=i+1)
begin
out[i] = in[number-i-1];
end
end
endmodule
Popcount255
常规操作,贴上错误的代码。
这个错误倒挺有价值的,让我知道我还是用软件思维在描述硬件。
assign和always语句块是并行的,而且assign的赋值是一直执行的。也就是说,如果我在always语句块外面用assign给out赋值,那么always块里的for循环完全失效了,因为out一直等于0,把赋值移到always里就好了;
同理,今后也不能在两个always块里对同一个变量进行赋值。
module top_module(
input [254:0] in,
output [7:0] out );
parameter Bits = 255;
//assign out = 0;
integer i;
always @(*)
begin
out = 0;
for(i=0; i<Bits; i=i+1)
begin
if (in[i])
out = out + 1;
else
out = out;
end
end
endmodule
Adder100i
module top_module(
input [99:0] a, b,
input cin,
output [99:0] cout,
output [99:0] sum );
integer i;
parameter Bits = 100;
always @(*)
begin
{ cout[0], sum[0] } = a[0] + b[0] + cin;
for(i=1;i<Bits;i=i+1)
begin
{cout[i], sum[i]} = a[i] + b[i] + cout[i-1];
end
end
endmodule
注:这一题得多想下,看到实例化我还以为需要和Module_fadd一样再写一个一位加法器然后再实例化,所以觉得很复杂。
其实好像只要加法器的cout和下一个加法器的cin用同一个变量表示,不就相当于连接上了嘛。不一定需要通过实例化来连线。(不知道这样理解是否有问题)
Popcount3
A “population count” circuit counts the number of '1’s in an input vector. Build a population count circuit for a 3-bit input vector.
module top_module(
input [2:0] in,
output [1:0] out );
integer i;
always@(*)
begin
out = 0;
for(i=0;i<3;i=i+1)
out = in[i]+ out;
end
// 答案提供的其他方法
// This is a function of 3 inputs. One method is to use a 8-entry truth table:
// in[2:0] out[1:0]
// 000 00
// 001 01
// 010 01
// 011 10
// 100 01
// 101 10
// 110 10
// 111 11
// assign out[0] = (~in[2] & ~in[1] & in[0]) | (~in[2] & in[1] & ~in[0]) | (in[2] & ~in[1] & ~in[0]) | (in[2] & in[1] & in[0]);
// assign out[1] = (in[1] & in[0]) | (in[2] & in[0]) | (in[2] & in[1]);
// Using the addition operator works too:
// assign out = in[0]+in[1]+in[2];
// Yet another method uses behavioural code inside a procedure (combinational always block)
// to directly implement the truth table:
/*
always @(*) begin
case (in)
3'd0: out = 2'd0;
3'd1: out = 2'd1;
3'd2: out = 2'd1;
3'd3: out = 2'd2;
3'd4: out = 2'd1;
3'd5: out = 2'd2;
3'd6: out = 2'd2;
3'd7: out = 2'd3;
endcase
end
*/
endmodule
注:这道题隐含了in是用二进制表示的(毕竟问1的个数,显然就是01代码了),所以不用这么复杂,直接 assign out = in[0]+in[1]+in[2];
Gatesv
module top_module(
input [3:0] in,
output [2:0] out_both,
output [3:1] out_any,
output [3:0] out_different );
assign out_any = in[3:1] | in[2:0];
assign out_both = in[2:0] & in[3:1];
assign out_different = in ^ {in[0], in[3:1]};
/* 不懂可以看下面详细解释
assign out_both = { in[3] & in[2], in[2] & in[1], in[1] & in[0] };
assign out_any = { in[3] | in[2], in[2] | in[1], in[1] | in[0] };
assign out_different = { in[3] ^ in[0], in[2] ^ in[3], in[1] ^ in[2], in[0] ^ in[1]};
*/
endmodule
之后尝试以专题形式总结
Circuits_Combinational Logic_Arithmetic Circuits 总结
3-bit binary adder & 4-digit BCD adder
这两题有以下共同点:
1.a和b的位数均大于1,因此在实例化的时候要注意输入和输出的位宽,比如
bcd_fadd u1_fadd(
.a(a[3:0]),
.b(b[3:0]),
.cin(cin),
.cout(cout_temp[0]),
.sum(sum[3:0])
);
2.要进行循环例化。注意不能直接用for,而要用generate语句搭配for循环。注意写的时候注意别漏了begin-end块的名字
generate
genvar i;
for(i=4;i<16;i=i+4)
begin:fadder
bcd_fadd u1_fadd(
.a(a[i+3:i]),
.b(b[i+3:i]),
.cin(cout_temp[i-4]),
.cout(cout_temp[i+3:i]),
.sum(sum[i+3:i]));
end
endgenerate
最后附上代码
//3-bit binary adder
module top_module(
input [2:0] a, b,
input cin,
output [2:0] cout,
output [2:0] sum );
fadd u1_fadd(
.a(a[0]),
.b(b[0]),
.cin(cin),
.cout(cout[0]),
.sum(sum[0])
);
generate //多个例化不可只用for,要用generate
genvar i;
for(i=1;i<3;i=i+1)
begin:adder //注意别漏了模块名
fadd u2_fadd(
.a(a[i]),
.b(b[i]),
.cin(cout[i-1]),
.cout(cout[i]),
.sum(sum[i])
);
end
endgenerate
endmodule
module fadd(input a,b,cin,
output cout,sum);
assign {cout,sum}=a+b+cin;
endmodule
//4-digit BCD adder
module top_module(
input [15:0] a, b,
input cin,
output cout,
output [15:0] sum );
wire [15:0] cout_temp;
bcd_fadd u1_fadd(
.a(a[3:0]),
.b(b[3:0]),
.cin(cin),
.cout(cout_temp[0]),
.sum(sum[3:0])
);
generate
genvar i;
for(i=4;i<16;i=i+4)
begin:fadder
bcd_fadd u1_fadd(
.a(a[i+3:i]),
.b(b[i+3:i]),
.cin(cout_temp[i-4]),
.cout(cout_temp[i+3:i]),
.sum(sum[i+3:i]));
end
endgenerate
assign cout = cout_temp[12];
endmodule