Verilog HDL 代码和仿真文件
偶分频器
设计文件
verilog
module divider(
input wire clk,
input wire rst_n,
output reg clk_div
);
parameter NUM_DIV = 4; //4分频
integer cnt; // 计数
always @(posedge clk or posedge rst_n) begin
if(rst_n) begin //复位信号,高电平有效
cnt = 0;
clk_div <= 1'b0;
end
else if(cnt < NUM_DIV / 2 -1) begin
cnt = cnt + 1;
clk_div <= clk_div;
end
else begin
cnt = 0;
clk_div <= ~clk_div;
end
end
endmodule仿真文件
verilog
module divider_sim(
);
reg clk;
reg rst_n;
wire clk_div;
divider divider(
.clk(clk),
.rst_n(rst_n),
.clk_div(clk_div)
);
initial begin
clk <= 1;
rst_n <= 0;
#1 rst_n <= 1; //快速进行复位操作,防止分频器clk_div 一直表现为高阻态
#1 rst_n <= 0;
end
always #10 clk <= ~clk; //设置时钟周期为20ns,即主频为50MHz
endmodule3-8译码器
设计文件
verilog
module decode38a(
input wire[2:0] a,
output reg[7:0] y
);
/*
第一种方法,按照公式,进行数据流描述,代码较多,但是可综合
assign y[0] = ~a[2] & ~a[1] & ~a[0];
assign y[1] = ~a[2] & ~a[1] & a[0];
assign y[2] = ~a[2] & a[1] & ~a[0];
assign y[3] = ~a[2] & a[1] & a[0];
assign y[4] = a[2] & ~a[1] & ~a[0];
assign y[5] = a[2] & ~a[1] & a[0];
assign y[6] = a[2] & a[1] & ~a[0];
assign y[7] = a[2] & a[1] & a[0];
*/
/*第二种,用 for循环, 方法简单,所用代码较少,但是不可综合 */
integer i;
always@(*) begin
for(i = 0; i <= 7; i = i + 1) begin
if (a == i)
y[i] = 1;
else
y[i] = 0;
end
end
endmodule仿真文件
verilog
module decode38_simulation(
);
reg[2:0] a;
wire[7:0] y;
decode38a decode38a(
.a(a),
.y(y)
);
initial
begin
#0 a <= 3'b000;
#100 a <= 3'b001;
#100 a <= 3'b010;
#100 a <= 3'b011;
#100 a <= 3'b100;
#100 a <= 3'b101;
#100 a <= 3'b110;
#100 a <= 3'b111;
end
endmodule流水灯
一共有四个LED灯:
- 首先1、3 灯亮,然后2、4 灯亮,接着1、2、3、4灯依次点亮,然后全灭,最后再点亮
- 重复上一步
因为时钟周期20ns,基本上肉眼看不到效果,所以设置了一个4分频器,用户可以修改变量NUM_DIV的值,实现自己想要的分频效果
设计文件
顶层模块 flow_led_top.v
verilog
module flow_led_top(
input clk,
input rst_n,
output [3:0] led
);
wire clk_div;
//调用分频器模块
divider divider(
.clk(clk),
.rst_n(rst_n),
.clk_div(clk_div)
);
//调用流水灯的控制模块
flow_led flow_led(
.clk(clk),
.clk_div(clk_div),
.led(led)
);
endmodule分频器模块 divider.v
verilog
module divider(
input wire clk,
input wire rst_n,
output reg clk_div
);
parameter NUM_DIV = 4; //4分频
integer cnt; // 计数
always @(posedge clk or posedge rst_n) begin
if(rst_n) begin //复位信号,高电平有效
cnt = 0;
clk_div <= 1'b0;
end
else if(cnt < NUM_DIV / 2 -1) begin
cnt = cnt + 1;
clk_div <= clk_div;
end
else begin
cnt = 0;
clk_div <= ~clk_div;
end
end
endmodule流水灯控制模块 flow_led.v
verilog
module flow_led(
input clk,
input rst_n,
output reg[3:0] led
);
//定义当前状态,下一个状态
reg[10:0] current_state, next_state;
//12种状态编码
parameter s0 = 11'b00000000000,
s1 = 11'b00000000001,
s2 = 11'b00000000010,
s3 = 11'b00000000100,
s4 = 11'b00000001000,
s5 = 11'b00000010000,
s6 = 11'b00000100000,
s7 = 11'b00001000000,
s8 = 11'b00010000000,
s9 = 11'b00100000000,
s10 = 11'b01000000000,
s11 = 11'b10000000000;
always @(posedge clk or posedge rst_n) begin
if(rst_n) begin //复位信号,高电平有效
current_state <= s0;
end else begin
current_state <= next_state;
end
end
always @(current_state) begin
case(current_state)
s0: next_state <= s1;
s1: next_state <= s2;
s2: next_state <= s3;
s3: next_state <= s4;
s4: next_state <= s5;
s5: next_state <= s6;
s6: next_state <= s7;
s7: next_state <= s8;
s8: next_state <= s9;
s9: next_state <= s10;
s10: next_state <= s11;
s11: next_state <= s0;
default: next_state <=s0;
endcase
end
always @(posedge clk) begin
case(current_state)
s0: led <= 4'b0101;
s1: led <= 4'b1010;
s2: led <= 4'b0001;
s3: led <= 4'b0011;
s4: led <= 4'b0111;
s5: led <= 4'b1111;
s6: led <= 4'b1110;
s7: led <= 4'b1100;
s8: led <= 4'b1000;
s9: led <= 4'b0000;
s10: led <= 4'b1111;
s11: led <= 4'b0000;
default: led <= 4'b0000;
endcase
end
endmodule仿真文件
flow_led_sim.v
verilog
module flow_led_sim(
);
reg clk;
wire[3:0] led;
reg rst_n;
wire clk_div;
divider divider(
.clk(clk),
.rst_n(rst_n),
.clk_div(clk_div)
);
flow_led_top flow_led_top(
.clk(clk),
.rst_n(rst_n),
.led(led)
);
initial begin
clk <= 1;
rst_n <= 0;
//开始的时候电路有的信号为高阻态, 如果不复位的话可能会导致仿真不成功
//下面的代码相当于快速按下复位按钮
#1 rst_n <= 1;
#1 rst_n <= 0;
end
//设置时钟周期 100ns
always #50 clk <= ~clk;
endmoduleALU 算术逻辑单元
设计文件
顶层模块 alu_32bits_top.v
verilog
module alu_32bits_top(
ldr0, ldr1, ldr2, ldr3,
lddr1, lddr2,
cf, of, zf, nf,
nr0_bus, nr1_bus, nr2_bus, nr3_bus, nalu_bus, nsw_bus,
i_data, alu_sel, DBUS
);
input ldr0, ldr1, ldr2, ldr3;
input nr0_bus, nr1_bus, nr2_bus, nr3_bus, nalu_bus, nsw_bus;
input lddr1, lddr2;
input [31:0] i_data; //输入数据
input [3:0] alu_sel; //alu选择控制信号
output cf, of, zf, nf;
output wire[31:0] DBUS;
wire [31:0] o_y;
wire [31:0] data;
wire [31:0] i_a;
wire [31:0] i_b;
alu_32bits alu_32bits(
.i_a(i_a), .i_b(i_b), .alu_sel(alu_sel), .o_y(o_y),
.cf(cf), .of(of), .zf(zf), .nf(nf)
);
register r0(
.ldr(ldr0),
.ctrl(nr0_bus),
.i_data(DBUS),
.o_data(data)
);
register r1(
.ldr(ldr1),
.ctrl(nr1_bus),
.i_data(DBUS),
.o_data(data)
);
register r2(
.ldr(ldr2),
.ctrl(nr2_bus),
.i_data(DBUS),
.o_data(data)
);
register r3(
.ldr(ldr3),
.ctrl(nr3_bus),
.i_data(DBUS),
.o_data(data)
);
dr dr1(
.lddr(lddr1),
.rst_n(0),
.i_data(data),
.o_data(i_a)
);
dr dr2(
.lddr(lddr2),
.rst_n(0),
.i_data(data),
.o_data(i_b)
);
buff input_buff( //输入缓冲器
.ctrl(nsw_bus),
.i_data(i_data),
.o_data(DBUS)
);
buff output_buff( //输出缓冲器
.ctrl(nalu_bus),
.i_data(o_y),
.o_data(DBUS)
);
endmoduleALU控制模块 alu_32bits.v
verilog
module alu_32bits(
input [31:0] i_a, //两个输入数据 i_a, i_b
input [31:0] i_b,
input [3:0] alu_sel, //alu 功能选择信号
output reg[31:0] o_y, //输出结果 o_y
output reg cf, //进位/借位标志, cf=1,有进位或者借位
output reg of, //溢出标志, of=1, 有溢出
output reg zf, //零标志, zf=1, 运算结果为0
output reg nf //负数标志, nf=1, 运算结果为负数
);
reg[32:0] cf_temp; //临时变量, 用于判断进位标志cf
reg[32:0] of_temp; //临时变量, 用于判断溢出标志of
always @(i_a, i_b, alu_sel) begin
cf <= 0;
of <= 0;
case (alu_sel)
4'b0001: //加法
begin
cf_temp <= {1'b0, i_a} + {1'b0, i_b}; //将i_a, i_b扩充一位后再相减,便于接下来判断进位/借位
of_temp <= {i_a[31], i_a} + {i_b[31], i_b}; //将i_a, i_b变成双符号位之后相加, 便于接下来判断溢出
o_y <= cf_temp[31:0]; //相加结果
cf <= cf_temp[32]; //进位/借位标志
of <= of_temp[32] ^ of_temp[31]; //溢出标志, 双符号位,相加后如果两个符号位不相等则溢出
end
4'b0010: //减法
begin
cf_temp <= {1'b0, i_a} - {1'b0, i_b}; //将i_a, i_b扩充一位后再相减,便于接下来判断进位/借位
of_temp <= {i_a[31], i_a} - {i_b[31], i_b}; //将i_a, i_b变成双符号位之后相减, 便于接下来判断溢出
o_y <= cf_temp[31:0]; //相减结果
cf <= cf_temp[32]; //进位/借位标志
of <= of_temp[32] ^ of_temp[31]; //溢出标志, 双符号位,相减后如果两个符号位不相等则溢出
end
4'b0011: //加1
begin
cf_temp <= {1'b0, i_a} + 1; //将i_a扩充一位后再加1,便于接下来判断进位/借位
of_temp <= {i_a[31], i_a} + 1; //将i_a变成双符号位之后再加1, 便于接下来判断溢出
o_y <= cf_temp[31:0]; //加1结果
cf <= cf_temp[32]; //进位/借位标志
of <= of_temp[32] ^ of_temp[31]; //溢出标志, 双符号位,相减后如果两个符号位不相等则溢出
end
4'b0100: //减1
begin
cf_temp <= {1'b0, i_a} - 1; //将i_a扩充一位后再减1,便于接下来判断进位/借位
of_temp <= {i_a[31], i_a} - 1; //将i_a变成双符号位之后再减1, 便于接下来判断溢出
o_y <= cf_temp[31:0]; //减1结果
cf <= cf_temp[32]; //进位/借位标志
of <= of_temp[32] ^ of_temp[31]; //溢出标志, 双符号位,相减后如果两个符号位不相等则溢出
end
4'b0101:
begin
o_y <= i_a & i_b; //与
end
4'b0110:
begin
o_y <= i_a | i_b; //或
end
4'b0111:
begin
o_y <= i_a ^ i_b; //异或
end
4'b1000:
begin
o_y <= ~i_a; //取反
end
4'b1001:
begin
o_y <= i_a << 1; //算术左移一位
end
4'b1010:
begin
o_y <= i_a >> 1; //算术右移一位
end
4'b1011:
begin
o_y <= i_a; //直通
end
default:
begin
o_y <= 32'bxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
end
endcase
if(o_y == 0) begin //零标志
zf <= 1;
end
else begin
zf <= 0;
end
nf <= o_y[31]; //负数标志
end
endmodule通用寄存器模块 register.v
verilog
module register(
input [31:0] i_data, //输入数据
input ldr, //输入锁存信号, 上升沿时刻, 输入存入
input ctrl, //输入控制, ctrl=0时,寄存器锁存输出, 否则输出端为高阻态
output reg[31:0] o_data //输出数据
);
reg[31:0] data; //寄存器当中的锁存值
always @(posedge ldr) begin //当ldr上升沿时,就将输入的数据存入寄存器
data <= i_data;
end
always @(*) begin //所有可能的敏感信号发生变化时, 如果控制信号ctrl为0, 就将寄存器锁存值输出; 否则为高阻态
if(~ctrl) begin
o_data <= data;
end
else begin
o_data <= 32'bzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz;
end
end
endmodule数据寄存器模块 dr.v
verilog
module dr(
input lddr, //输入数据锁存信号, 上升沿时刻, 输入存入
input rst_n, //复位信号, rst_n=1时, 复位信号有效
input [31:0] i_data, //输入数据
output reg[31:0] o_data //输出数据
);
always @(posedge lddr or posedge rst_n) begin
// rst_n == 1? o_data[31:0] <= 32'b0 : o_data <= i_data;
if(rst_n) begin
o_data[31:0] <= 32'b0;
end
else begin
o_data <= i_data;
end
end
endmodule输入输出缓冲器模块 buff.v
verilog
//输入/输出缓冲器
module buff(
input ctrl, //控制信号, ctrl=0时, 缓冲器打开, 否则输出为高阻态
input [31:0] i_data, //输入数据
output reg[31:0] o_data //输出数据, 三态
);
always @(*) begin
if(~ctrl) begin
o_data <= i_data;
end
else begin
o_data <= 32'bzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz;
end
end
endmodule仿真文件
alu_32bits_top_sim.v
verilog
module alu_32bits_top_sim(
);
reg [31:0] i_data;
reg [3:0] alu_sel;
reg ldr0, ldr1, ldr2, ldr3, lddr1, lddr2;
reg nr0_bus, nr1_bus, nr2_bus, nr3_bus, nalu_bus, nsw_bus;
wire [31:0]DBUS;
wire cf,zf,of,nf;
alu_32bits_top alu_32bits_top(
.ldr0(ldr0), .ldr1(ldr1), .ldr2(ldr2), .ldr3(ldr3),
.lddr1(lddr1), .lddr2(lddr2),
.cf(cf), .of(of), .zf(zf), .nf(nf),
.nr0_bus(nr0_bus), .nr1_bus(nr1_bus), .nr2_bus(nr2_bus), .nr3_bus(nr3_bus), .nalu_bus(nalu_bus), .nsw_bus(nsw_bus),
.i_data(i_data), .alu_sel(alu_sel), .DBUS(DBUS)
);
initial begin
#0 alu_sel=1;
#80;alu_sel=2;
#80;alu_sel=5;
end
always begin
#0 i_data=8'h50;
#20;i_data=8'h55;
#20;i_data=8'hAA;
#20;i_data=8'h55;
#20;i_data=8'hAA;
end
initial begin
lddr1=0;
#45;lddr1=1;#5;lddr1=0;
end
initial begin
nr0_bus=1;
#40;nr0_bus=0;
#20;nr0_bus=1;
end
initial begin
lddr2=0;
#65;lddr2=1;#5;lddr2=0;
end
initial begin
nr1_bus=1;
#60;nr1_bus=0;
#20;nr1_bus=1;
end
initial begin
nr2_bus=1;
end
initial begin
nr3_bus=1;
end
initial begin
ldr0=0;
#10;ldr0=1;#10;ldr0=0;
end
initial begin
ldr1=0;
#30;ldr1=1;#10;ldr1=0;
end
initial begin
ldr2=0;
end
initial begin
ldr3=0;
end
initial begin
nsw_bus=0;
#40;nsw_bus=1;
end
initial begin
#0 nalu_bus=1;
#50;nalu_bus=0;
#20;nalu_bus=0;
end
endmodule
秋叶依剑