目录
前言
本文将描述寄存器堆与算术逻辑单元的 Verilog 实现。
一、 32 × 32 b i t 32\times32\ bit 32×32 bit 寄存器堆
1、要求
使用32个32bit寄存器组成的寄存器堆,实现异步读,同步写。需要包含零号寄存器,不能被写入且读取到零号寄存器的时候读出的数是 0
2、接口定义
“2读1写”:两个读端口 + 一个写端口
信号名 | I/O | 说明 |
---|---|---|
clk | Input | 时钟 |
waddr[4:0] | Input | 写口地址 |
raddr1[4:0] | Input | 读口地址1 |
raddr2[4:0] | Input | 读口地址2 |
wen | Input | 写使能 |
wdata[31:0] | Input | 写数据 |
rdata1[31:0] | Output | 读口1数据 |
rdata2[31:0] | Output | 读口2数据 |
3、RTL代码段
`timescale 10 ns / 1 ns
`define DATA_WIDTH 32
`define ADDR_WIDTH 5
module reg_file(
input clk,
input [`ADDR_WIDTH - 1:0] waddr,
input [`ADDR_WIDTH - 1:0] raddr1,
input [`ADDR_WIDTH - 1:0] raddr2,
input wen,
input [`DATA_WIDTH - 1:0] wdata,
output [`DATA_WIDTH - 1:0] rdata1,
output [`DATA_WIDTH - 1:0] rdata2
);
// TODO: Please add your logic design here
reg [`DATA_WIDTH - 1:0] rf[`DATA_WIDTH - 1:0];
always@(posedge clk)begin
if (waddr != 5'd0 && wen)
rf[waddr] <= wdata;
end
assign rdata1 = (raddr1 != 5'd0) ? rf[raddr1] : 32'd0;
assign rdata2 = (raddr2 != 5'd0) ? rf[raddr2] : 32'd0;
endmodule
4、信号变化说明
32 × 32 32\times32 32×32 位寄存器堆具有写入和读出的功能。每当读取到 c l k clk clk 信号的上升沿时,如果要写入的地址 w a d d r waddr waddr 不是 0 0 0 (即不是向零号寄存器写入)且写使能 w e n wen wen 为 1 1 1 时,向寄存器
堆内写入数据(将 w d a t a wdata wdata 赋值给 r f [ w a d d r ] rf[waddr] rf[waddr])。读出数据时,如果读取的地址不为 0 0 0 (读取零号寄存器时读到的数是 0 0 0)则将 r f [ r a d d r ] rf[raddr] rf[raddr] 的值赋给 r d a t a 1 rdata1 rdata1。
二、ALU算术逻辑单元
1、要求
实现五种基本功能操作:逻辑按位与(AND)、逻辑按位或(OR)、算术加法(ADD)、算数减法(SUB)、有符号数整数比较(SLT)。要求ADD、SUB、SLT复用同一套加法器逻辑电路(仅用一个全加器)。
2、接口定义
信号名 | I/O | 说明 |
---|---|---|
A[31:0] | Input | 操作数A |
B[31:0] | Input | 操作数B |
ALUop[2:0] | Input | ALU部件控制端信号 |
Overflow | Output | 溢出标志信号,指示有符号数的加减法运算结果是否溢出,非此操作时信号未定义 |
CarryOut | Output | 进借位标志信号,指示无符号数的加减法运算结果是否产生进位/借位,非此操作时信号未定义 |
Zero | Output | 零标志,指示ALU运算结果(Result)的32个比特位是否为全0 |
Result[31:0] | Output | ALU输出结果 |
3、RTL代码段
加法、减法、比较三个操作复用同一套加法电路
`timescale 10 ns / 1 ns
`define DATA_WIDTH 32
`define ope_AND 3'b000
`define ope_OR 3'b001
`define ope_ADD 3'b010
`define ope_SUB 3'b110
`define ope_SLT 3'b111
module alu(
input [`DATA_WIDTH - 1:0] A,
input [`DATA_WIDTH - 1:0] B,
input [ 2:0] ALUop,
output Overflow,
output CarryOut,
output Zero,
output [`DATA_WIDTH - 1:0] Result
);
// TODO: Please add your logic design here
wire [`DATA_WIDTH - 1:0] ADDSUB_A_B;
wire [`DATA_WIDTH - 1:0] SLT_A_B;
wire CarryOut_origin;
assign Overflow = (ALUop === `ope_ADD) ? ((A[31]) && (B[31])) && (~ADDSUB_A_B[31]) || ((~A[31]) && (~B[31]) && (ADDSUB_A_B[31]))
: ((ALUop === `ope_SUB || ALUop === `ope_SLT) && (B === 32'h80000000)) ? ~A[31]
: ((ALUop === `ope_SUB || ALUop === `ope_SLT) && (B != 32'h80000000)) ?
((A[31]) && (~B[31])) && (~ADDSUB_A_B[31]) || ((~A[31]) && (B[31]) && (ADDSUB_A_B[31]))
: 1'b0;//进行与、或操作时 Overflow 无定义
assign {CarryOut_origin, ADDSUB_A_B} = {1'b0, A} + {1'b0, (ALUop === `ope_SUB || ALUop === `ope_SLT) ? ~B : B} + {31'b0, ALUop[2]};
assign SLT_A_B = (ALUop === `ope_SLT) ? ADDSUB_A_B[31] ^ Overflow : 32'b0;
assign CarryOut = (ALUop === `ope_ADD) ? CarryOut_origin //加法运算的溢出位即为进位
: (ALUop === `ope_SUB && B != 32'b0) ? ~CarryOut_origin //减法运算如果 B 不是全 0 且没有借位,都会溢出;因此溢出位为 1 代表没有借位
: 1'b0; //既不是加法又不是减法则赋一个无意义的值;或者进行减法且 B 为全 0 则赋为 0
assign Zero = (Result === 32'b0) ? 1'b1 : 1'b0;
assign Result = (ALUop === `ope_AND) ? (A & B)
: (ALUop === `ope_OR) ? (A | B)
: (ALUop === `ope_ADD || ALUop === `ope_SUB) ? ADDSUB_A_B
: (ALUop === `ope_SLT) ? SLT_A_B
: 32'b0;
endmodule
4、信号变化说明
(1)overflow
a. 如果进行加法 (ALUop === 3’b010),overflow = ((A[31]) && (B[31])) && (~ADDSUB_A_B[31]) || ((~A[31]) && (~B[31]) && (ADDSUB_A_B[31])),即:A 为负数且 B 为负数,而 A+B 是正数;或者 A 为正数且 B 为正数,而 A+B 是负数。此时表示数据已溢出。
b. 如果进行减法(ALUop === `ope_SUB || ALUop === `ope_SLT),overflow = ((A[31]) && (~B[31])) && (~ADDSUB_A_B[31]) || ((~A[31]) && (B[31]) && (ADDSUB_A_B[31])),即:A 为负数且 B 为正数,而 A-B 是正数;或者 A 为正数且 B 为负数,而 A-B 是负数。此时表示数据已溢出。
c. 需要考虑特殊情况 B = 32’h80000000,此时 B = ~B+1 。考虑 A + + +B 和 A − - −B(注意对有符号数是补码运算):如果 A[31] 是 1,A + + +B < 0,此时无溢出;而如果 A[31] 是 0,说明 A > 0 > B,A − - −B < 0,有溢出。故可以用 A 的符号位取反来表示是否溢出。
(2)carryout
注意:计算加法时使用全加器,左边的结果为 {carryout_origin, ADDSUB_A_B} 是 33 位的数,右边的加数也应该转换为 33 位
进行加法时,进位可以直接求出;减法时,进位是 carryout_origin 取反;需要排除减法之中减数 B = 1’b0 的情况,此时 carryout_origin 是 0,无需取反。
(3)SLT_A_B
比较大小时,可以判断 A − - −B 的符号来判断 A 与 B 的大小。而如果 A − - −B 的运算溢出,符号位不能代表 A − - −B 的符号,因此需要与 overflow 异或。
总结
本次实验总体难度不大,作为开发项目的入门学习,对我们之后的实验有很大帮助。