计算机组成原理(实验一):32*32位寄存器堆 & 算术逻辑单元ALU


前言

本文将描述寄存器堆与算术逻辑单元的 Verilog 实现。


一、 32 × 32   b i t 32\times32\ bit 32×32 bit 寄存器堆

1、要求

使用32个32bit寄存器组成的寄存器堆,实现异步读,同步写。需要包含零号寄存器,不能被写入且读取到零号寄存器的时候读出的数是 0

2、接口定义

“2读1写”:两个读端口 + 一个写端口

信号名I/O说明
clkInput时钟
waddr[4:0]Input写口地址
raddr1[4:0]Input读口地址1
raddr2[4:0]Input读口地址2
wenInput写使能
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]InputALU部件控制端信号
OverflowOutput溢出标志信号,指示有符号数的加减法运算结果是否溢出,非此操作时信号未定义
CarryOutOutput进借位标志信号,指示无符号数的加减法运算结果是否产生进位/借位,非此操作时信号未定义
ZeroOutput零标志,指示ALU运算结果(Result)的32个比特位是否为全0
Result[31:0]OutputALU输出结果

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 异或。


总结

本次实验总体难度不大,作为开发项目的入门学习,对我们之后的实验有很大帮助。

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
运算器是计算机的核心部件之一,其主要功能是完成各种算术逻辑运算。在计算机组成原理实验一中,我们需要设计和实现一个简单的运算器。具体步骤如下: 1. 确定运算器的操作数格式和运算方式,如二进制补码加法、逻辑与、逻辑或等。 2. 根据运算器的操作数格式和运算方式,设计运算器的电路结构。通常包括寄存器算术逻辑单元(ALU)、控制器等。 3. 实现运算器的电路,可以使用门电路、触发器等基本电路元件,也可以使用计算机辅助设计软件进行设计和仿真。 4. 测试运算器的功能和性能,通过输入不同的操作数和操作码,验证运算器的正确性和稳定性。 在实验一中,我们需要实现简单的二进制补码加法运算器。该运算器的操作数格式为8位二进制补码,运算方式为加法。具体实现步骤如下: 1. 设计运算器的电路结构,包括一个8位寄存器、一个ALU和一个控制器。其中,寄存器用于存储待运算的操作数,ALU用于执行加法运算,控制器用于控制运算器的操作。 2. 实现运算器的电路,可以使用门电路和触发器等基本电路元件。具体实现步骤包括: - 实现8位寄存器,用于存储待运算的操作数。可以使用8个D触发器实现,每个D触发器对应一个二进制位。 - 实现ALU,用于执行加法运算。可以采用串行加法器的结构,将8位操作数分别输入到每个加法器中,逐位相加得到运算结果。同时,还需要实现进位和溢出检测电路,保证加法运算的正确性。 - 实现控制器,用于控制运算器的操作。可以使用有限状态机实现,设计不同的状态和转移条件,实现运算器的控制逻辑。 3. 测试运算器的功能和性能。通过输入不同的操作数和操作码,验证运算器的正确性和稳定性。可以使用计算机辅助仿真软件进行测试,或者使用实际的电路进行测试。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值