FPGA 系列文章
- 如果你想学习有关FPGA的专业术语,可以参考这一篇:FPGA专业术语介绍
- 鼎力推荐Verilog初学者的一个刷题网站,硬件领域的leetcode,能够对编写完的代码进行在线仿真:HDLBits
- 这是第一遍刷题的记录,之后争取跟着b站课程复盘一遍 \(▔^▔)/
Basics
1.Wire
module top_module( input in, output out );
assign out = in;
endmodule
2.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
3.Notgate
module top_module( input in, output out );
assign out = ~in;
endmodule
4.Andgate
module top_module(
input a,
input b,
output out );
assign out = a & b;
endmodule
5.Norgate
module top_module(
input a,
input b,
output out );
assign out = ~(a | b);
endmodule
6.Xnorgate
module top_module(
input a,
input b,
output out );
assign out = ~(a ^ b);
endmodule
7.Wire decl
module top_module(
input a,
input b,
input c,
input d,
output out,
output out_n );
wire or_in1;
wire or_in2;
wire not_in;
assign or_in1 = a & b;
assign or_in2 = c & d;
assign not_in = or_in1 | or_in2;
assign out = not_in;
assign out_n = ~not_in;
endmodule
8.7458
module top_module (
input p1a, p1b, p1c, p1d, p1e, p1f,
output p1y,
input p2a, p2b, p2c, p2d,
output p2y );
wire orA_in1;
wire orA_in2;
wire orB_in1;
wire orB_in2;
assign orA_in1 = p2c & p2d;
assign orA_in2 = p2a & p2b;
assign orB_in1 = p1a & p1b & p1c;
assign orB_in2 = p1d & p1e & p1f;
assign p2y = orA_in1 | orA_in2;
assign p1y = orB_in1 | orB_in2;
endmodule
Vectors
1.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 o2 = vec[2];
assign o1 = vec[1];
assign o0 = vec[0];
endmodule
- Vector1
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
3.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
4.Vectorgates
- assign中若没有标记多少位,默认全部位参与计算。
- bitwise对每一位进行逻辑或运算;logical将整个矢量视为布尔值,为空视为0,不为空设为1。
- 如果 a 的值为 100(二进制,不为空logical视为1),b 的值为000(二进制,为空logical设为0),那么 bitwise = 100(二进制),logical = 1 | 0 = 1。
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[2:0] = ~a;
assign out_not[5:3] = ~b;
endmodule
5.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];
endmodule
6.Vector3
module top_module (
input [4:0] a, b, c, d, e, f,
output [7:0] w, x, y, z );//
assign w = {a[4:0],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[4:0],2'b11};
endmodule
7.Vectorr
module top_module(
input [7:0] in,
output [7:0] out
);
always @(*) begin
for(integer i = 0; i < 8; i++)begin
out[i]=in[7-i];
end
end
endmodule
8.Vector4
module top_module (
input [7:0] in,
output [31:0] out );//
assign out = {{24{in[7]}},in[7:0]};
endmodule
9.Vector5
module top_module (
input a, b, c, d, e,
output [24:0] out );//
assign out = ~{5{a,b,c,d,e}}^{{5{a}},{5{b}},{5{c}},{5{d}},{5{e}}};
endmodule
Modules:Hierarchy
1.Module
module top_module ( input a, input b, output out );
mod_a k(.in1(a),.in2(b),.out(out) );
endmodule
2.Module pos
module top_module (
input a,
input b,
input c,
input d,
output out1,
output out2
);
mod_a k(out1,out2,a,b,c,d);
endmodule
3.Module name
module top_module (
input a,
input b,
input c,
input d,
output out1,
output out2
);
mod_a k(.out1(out1),.out2(out2),.in1(a),.in2(b),.in3(c),.in4(d));
endmodule
4.Module shift
module top_module ( input clk, input d, output q );
wire mydff_out1;
wire mydff_out2;
my_dff k1(clk, d, mydff_out1);
my_dff k2(clk, mydff_out1, mydff_out2);
my_dff k3(clk, mydff_out2, q);
endmodule
5.Module shift8
module top_module (
input clk,
input [7:0] d,
input [1:0] sel,
output [7:0] q
);
wire [7:0] mydff8_out1;
wire [7:0] mydff8_out2;
wire [7:0] mydff8_out3;
my_dff8 k1(clk,d,mydff8_out1);
my_dff8 k2(clk,mydff8_out1,mydff8_out2);
my_dff8 k3(clk,mydff8_out2,mydff8_out3);
always @(*) begin
case(sel)
2'b00:
q=d;
2'b01:
q=mydff8_out1;
2'b10:
q=mydff8_out2;
2'b11:
q=mydff8_out3;
endcase
end
endmodule
6.Module add
module top_module(
input [31:0] a,
input [31:0] b,
output [31:0] sum
);
wire add16_out;
add16 k1(a[15:0],b[15:0],0,sum[15:0],add16_out);
add16 k2(a[31:16],b[31:16],add16_out,sum[31:16]);
endmodule
7.Module fadd
- {cout, sum}:这是一个赋值的目标,在代码中表示将右侧表达式的进位输出与和的结果赋值给cout和sum。
module top_module (
input [31:0] a,
input [31:0] b,
output [31:0] sum
);
wire add16_out;
add16 k1(a[15:0],b[15:0],0,sum[15:0],add16_out);
add16 k2(a[31:16],b[31:16],add16_out,sum[31:16]);
endmodule
module add1 ( input a, input b, input cin, output sum, output cout );
assign {cout, sum} = a + b + cin;
endmodule
8.Module cseladd
module top_module(
input [31:0] a,
input [31:0] b,
output [31:0] sum
);
wire add16_out1;
wire [15:0] add16_out2;
wire [15:0] add16_out3;
add16 k1(a[15:0],b[15:0],0,sum[15:0],add16_out1);
add16 k2(a[31:16],b[31:16],0,add16_out2[15:0]);
add16 k3(a[31:16],b[31:16],1,add16_out3[15:0]);
always @(*) begin
case(add16_out1)
1'b0:
sum[31:16]=add16_out2[15:0];
1'b1:
sum[31:16]=add16_out3[15:0];
endcase
end
endmodule
9.Module addsub
module top_module(
input [31:0] a,
input [31:0] b,
input sub,
output [31:0] sum
);
wire [31:0] xor_output;
wire add16_out;
always @(*) begin
for(integer i = 0; i < 32; i++)begin
xor_output[i] = b[i] ^ sub;
end
end
add16 k1(a[15:0],xor_output[15:0],sub,sum[15:0],add16_out);
add16 k2(a[31:16],xor_output[31:16],add16_out,sum[31:16]);
endmodule
Procedures
1.Alwaysblock1
module top_module(
input a,
input b,
output wire out_assign,
output reg out_alwaysblock
);
assign out_assign = a & b;
always @(*) out_alwaysblock = a & b;
endmodule
2.Alwaysblock2
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 @(*) out_always_comb = a ^ b;
always @(posedge clk) out_always_ff = a ^ b;
endmodule
3.Always if
module top_module(
input a,
input b,
input sel_b1,
input sel_b2,
output wire out_assign,
output reg out_always );
reg temp_assign; // 中间变量
always @(*) begin
case(sel_b1&sel_b2)
1'b1:
begin
temp_assign = b;
out_always = b;
end
default:
begin
temp_assign = a;
out_always = a;
end
endcase
end
assign out_assign = temp_assign;
endmodule
4.Always if2
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 = ~gas_tank_empty;
else
keep_driving = 0;
end
endmodule
5.Always case
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[2:0])
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'b0;
endcase
end
endmodule
6.Always case2
- case的特性:只有首次匹配才会被执行
- 参考:HDLBits答案汇总:优先编码器
module top_module (
input [3:0] in,
output reg [1:0] pos );
always @(*) begin
case(1)
in[0]:pos = 0;
in[1]:pos = 1;
in[2]:pos = 2;
in[3]:pos = 3;
default:pos = 0;
endcase
end
endmodule
7.Always casez
module top_module (
input [7:0] in,
output reg [2:0] pos );
always @(*) begin
casez(in[7:0])
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
8.Always nolatches
- 防止默认up,down,left,right不变生成latch,需要给up,down,left,right赋初始值 , 或者在每一个case中都为up,down,left,right赋值,后者由于代码冗长一般不推荐使用。
- case附带的多条语句需要用begin-end包围。
// 给up,down,left,right赋初始值
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:
left=1;
16'he072:
down=1;
16'he074:
right=1;
16'he075:
up=1;
endcase
end
endmodule
// 在每一个case中都为up,down,left,right赋值
module top_module (
input [15:0] scancode,
output reg left,
output reg down,
output reg right,
output reg up );
always @(*) begin
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
More Verilog Features
1.Conditional
module top_module (
input [7:0] a, b, c, d,
output [7:0] min);//
wire [7:0] min_ab;
wire [7:0] min_cd;
assign min_ab = (a < b ? a : b);
assign min_cd = (c < d ? c : d);
assign min = (min_ab <min_cd ? min_ab : min_cd);
// assign intermediate_result1 = compare? true: false;
endmodule
2.Reduction
module top_module (
input [7:0] in,
output parity);
assign parity = ^ in[7:0];
endmodule
3.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
4.Vector100r
module top_module(
input [99:0] in,
output [99:0] out
);
always @(*) begin
for(integer i = 0; i <100; i++)begin
out[i] = in[99-i];
end
end
endmodule
5.Popcount255
- 注意将out初始化为0,否则会产生锁存器使得结果不正确。
module top_module(
input [254:0] in,
output [7:0] out );
always @(*) begin
out = 0;
for(integer i = 0; i < 255; i++) begin
if(in[i] == 1'b1)
out++;
end
end
endmodule
7.Adder100i
- generate用于实例化,和for循环的用法基本一致。不同之处有两点,其一为循环变量需要在循环外用genvar关键字声明,其二为需要一个实例化名称。
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++) begin:adder
if(i==0)
assign{cout[0],sum[0]}=a[0]+b[0]+cin;
else
assign{cout[i],sum[i]}=a[i]+b[i]+cout[i-1];
end
endgenerate
endmodule
8.Bcdadd100
- 使用1位加法器合成100位加法器的典型案例,如果能独立写出来,说明你已经对上述内容基本掌握了。
module top_module(
input [399:0] a, b,
input cin,
output cout,
output [399:0] sum );
wire [99:0] temp;
genvar i;
generate
for(i=0;i<100;i++) begin:bcd_fadd
if(i == 0)
bcd_fadd k(a[3:0],b[3:0],cin,temp[0],sum[3:0]);
else
bcd_fadd k(a[4*i+3:4*i],b[4*i+3:4*i],temp[i-1],temp[i],sum[4*i+3:4*i]);
end
assign cout=temp[99];
endgenerate
endmodule