一、 实验目的
理解和掌握CPU中的算术逻辑运算部件(ALU)和寄存器堆(Register File)的工作原理,并使用Verilog和ModelSim进行设计和仿真。
二、 实验内容
- 使用Verilog完成ALU的设计,并编写测试仿真文件验证其正确性。要求:
ALU支持16位的加、减、与、或以及移位运算。 - 使用Verilog完成通用寄存器堆的设计,并编写测试仿真文件验证其正确性。要求
寄存器堆包含8个16位的寄存器;
寄存器堆有两个读端口和一个写端口。
三、 实验原理
ALU和寄存器堆的原理图:
ALU :通常支持许多基本算术和按位逻辑函数,实现指令所指定的各种算术和逻辑运算操作
寄存器堆:是CPU中多个寄存器组成的阵列,通常由快速的静态随机读写存储器(SRAM)实现。这种RAM具有专门的读端口与写端口,可以多路并发访问不同的寄存器。
四、实验步骤
- Verilog关键代码描述
ALU
代码如下:
module alu(
input wire [15:0] in1, in2,
input wire [2:0] alu_op,
output reg [15:0] Z
);
always@* begin
case(alu_op)
3'b000: Z = in1+in2;
3'b001: Z = in1-in2;
3'b010: Z = in1&&in2;
3'b011: Z = in1||in2;
3'b100: Z = in1<<in2;
3'b101: Z = in1>>in2;
endcase
end
endmodule
代码截图如下:
Verilog关键代码解释:
Alu等于设置一个一个多路选择器,根据alu_op的值不同,对输入的两个数a,b进行不同方式的计算
寄存器堆
代码如下:
module reg_stack(
input wire Wen, clk,
input wire [2:0] Ra, Rb, Rw,
input wire [15:0] Busw,
output wire [15:0] Busa, Busb
);
reg [15:0] regfile[7:0];
assign Busa = regfile[Ra];
assign Busb = regfile[Rb];
always@(posedge clk) begin
if(Wen == 1)
regfile[Rw] <= Busw;
end
endmodule
代码截图如下:
Verilog关键代码解释:
设置一个 reg [15:0] regfile[7:0]; 即8个16位的寄存器
在每一个上升沿的时候判断Wen是否为1
为1则代表寄存器要写入
- 测试文件描述
ALU
测试文件代码:
`timescale 1ns / 1ps
module reg_simulation(
output [15:0] Busa,
output [15:0] Busb
);
reg [15:0] Busw;
reg [2:0] Ra,Rb,Rw;
reg clk;
reg Wen;
always #5 clk=~clk;
integer i,reg_n = 0;
initial
begin
Wen=1;
clk=0;
for(i = 0;i<8;i = i+ 1) begin
Busw = i;
Rw = i;
reg_n = reg_n + 1;
#10;
end
Wen = 0;
#10
for (i = 0;i<8/2;i=i+1) begin
Rb=reg_n-1;
Ra=reg_n-2;
reg_n = reg_n - 2;
#10;
end
Ra = 0;
Rb = 1;
#10 $stop;
end
reg_stack try(
.Wen(Wen),
.Busw(Busw),
.Rw(Rw),
.Ra(Ra),
.Rb(Rb),
.clk(clk),
.Busa(Busa),
.Busb(Busb)
);
endmodule
测试文件关键代码截图:
测试文件代码解释:
每隔10ns,输入一个a,b和operator,即使用alu计算一次a和b,最后运行10ns后停止程序。
寄存器堆
测试文件代:
`timescale 1ns / 1ps
module reg_simulation(
output [15:0] Busa,
output [15:0] Busb
);
reg [15:0] Busw;
reg [2:0] Ra,Rb,Rw;
reg clk;
reg Wen;
always #5 clk=~clk;
integer i,reg_n = 0;
initial
begin
Wen=1;
clk=0;
for(i = 0;i<8;i = i+ 1) begin
Busw = i;
Rw = i;
reg_n = reg_n + 1;
#10;
end
Wen = 0;
#10
for (i = 0;i<8/2;i=i+1) begin
Rb=reg_n-1;
Ra=reg_n-2;
reg_n = reg_n - 2;
#10;
end
Ra = 0;
Rb = 1;
#10 $stop;
end
reg_stack try(
.Wen(Wen),
.Busw(Busw),
.Rw(Rw),
.Ra(Ra),
.Rb(Rb),
.clk(clk),
.Busa(Busa),
.Busb(Busb)
);
Endmodule
测试文件关键代码截图:
测试文件代码解释:
我们在开始时,通过时钟控制,写入0-7共八个数字
再通过每次取出两个数,完成对寄存器堆的验证。
- ModelSim仿真及分析
ALU
通过我们的测试文件和verilog代码可知:
第一次输入a=1,b=2,应该进行加操作 得3
第一次输入a=4,b=2,应该进行减操作 得2
第一次输入a=2,b=4,应该进行并操作 得1
第一次输入a=2,b=4,应该进行或操作 得1
第一次输入a=32,b=2,应该进行左移操作 得128
第一次输入a=8,b=1,应该进行右移操作 得4
结合仿真文件可知,实验结果正确
寄存器堆
通过我们的测试文件和verilog代码可知:
在前90ns,我们往寄存器堆中填充了8个数
分别是0,1,2,3,4,5,6,7,
在后面的50ns中,我们从寄存器堆中取出数字
从取出的数字顺序可知:
填充顺序:0 1 2 3 4 5 6 7
取出顺序:7 6 5 4 3 2 1 0
可知寄存器堆的运用成功
五、总结
ALU
利用verilog语言设计了一个ALU支持16位的加、减、与、或以及移位运算,并在相应的测试文件中在不同的时钟设置不同的数和操作数,
结合ModelSim仿真,成功验证了ALU。
寄存器堆
利用Verilog完成通用寄存器堆的设计。
寄存器堆包含8个16位的寄存器,寄存器堆有两个读端口和一个写端口,寄存器在每一个上升沿进行判断,如果Wen为1,则往寄存器堆写入数。
结合ModelSim仿真,数字顺序可知:
填充顺序:0 1 2 3 4 5 6 7
取出顺序:7 6 5 4 3 2 1 0
可知寄存器堆的运用成功