本学期计算机组成原理实验的prj1是完成一个由32个32bit寄存器组成的寄存器堆和一个能够完成加、减、与、或和比较大小功能的ALU(arithmetic and logic unit,算术逻辑单元),二者都是CPU的重要部件。
这部分要求不是寄存器堆和ALU实现的硬性要求,只是老师给出的要求,读者可按照自己需求进行取舍(之所以列出这些要求是为了方便下一届的学弟学妹找到符合要求的代码来参考,如果他们不觉得我的代码水平低的话)
两读一写端口,并要求实现“异步读,同步写”(读取数据随时可以进行,而写入数据由时钟信号控制);
复位信号采用同步复位方式;
在复位信号有效时,仅对0号寄存器清零;
组合逻辑中不使用always语句,不使用initial语句,不使用for循环语句;
使用同一套加法器逻辑;
代码中不出现"-" “<” “>”
`timescale 10 ns / 1 ns
`define DATA_WIDTH 32
`define ADDR_WIDTH 5
`define NUM 32
module reg_file(
input clk, //时钟信号
input rst, //复位信号
input [`ADDR_WIDTH - 1:0] waddr, //需写入的地址
input [`ADDR_WIDTH - 1:0] raddr1, //需读取的地址1
input [`ADDR_WIDTH - 1:0] raddr2, //需读取的地址2
input wen, //写使能信号
input [`DATA_WIDTH - 1:0] wdata, //待写入数据
output [`DATA_WIDTH - 1:0] rdata1, //地址1的读数
output [`DATA_WIDTH - 1:0] rdata2 //地址2的读数
);
reg [`DATA_WIDTH:1]REG_Files[0:`NUM-1];
always@(posedge clk)
begin
if(rst)
REG_Files[0]<=0;
else
if(wen && waddr!=0)
REG_Files[waddr]<=wdata;
end
assign rdata1=REG_Files[raddr1];
assign rdata2=REG_Files[raddr2];
endmodule
`timescale 10 ns / 1 ns
`define DATA_WIDTH 32
module alu(
input [`DATA_WIDTH - 1:0] A, //输入数据A
input [`DATA_WIDTH - 1:0] B, //输入数据B
input [2:0] ALUop, //控制信号,决定ALU做何种运算
output Overflow, //溢出
output CarryOut, //进位
output Zero, //判断结果是否为0
output [`DATA_WIDTH - 1:0] Result //输出运算结果
);
wire [`DATA_WIDTH:0] m;
wire [`DATA_WIDTH - 1:0] real_Result;
wire [`DATA_WIDTH - 1:0] B_comp;
assign B_comp=(ALUop == 3'b110 || ALUop==3'b111)?~B+32'b1:B;
assign m=A+B_comp;
assign and_Result =A&B;
assign or_Result=A|B;
assign {CarryOut,real_Result}=m;
assign Result=(ALUop==3'b000)?and_Result:(ALUop==3'b001)?or_Result:(ALUop==3'b010||ALUop==3'b110)?real_Result:(ALUop==3'b111)?slt_Result:1'b0;
assign Overflow = (A[31]^~B_comp[31])&(real_Result[31]^A[31]);
assign slt_Result=(ALUop==3'b111)?(real_Result[31]^Overflow):1'b0;
assign Zero = (Result==0)?1 : 0;
assign CarryOut=(ALUop==3'b010)?CarryOut:(ALUop==3'b110)?~CarryOut:1'b0;
endmodule
对ALU的要求做一些简单的说明。
因为加法和减法需要使用同一套加法器逻辑来完成,因此统一使用B_comp来表示实际进行运算的B,然后根据不同的ALUop对B进行处理:如果是做加法,那就把B的值赋给B_comp;如果是做减法,就相当于做加法A+(-B),利用补码运算的规则,将-B转换为~B+1 ,再赋值给B_comp即可。
做比较大小也是类似的道理,只需考虑A-B到底是大于0还是小于0。
需要注意的是,加减运算的输入是无符号数,而比较运算的输入是有符号数,此外还需要考虑溢出对结果正确性的影响。
本次实验中我们的任务是完成两个模块的代码编写,并在老师们搭建的FPGA云平台上进行测试。测试结果显示代码的正确性是可靠的,因此不再提供testbench的代码,感兴趣的读者可以自行编写test文件来观察波形。
由于我对这些内容理解不够到位,因此本篇博客的详细程度不能使我感到满意,以后理解加深了会进行补充,补充内容会以类似日志的形式在文末列出。
欢迎各位指出其中的错误或是分享自己的观点。我还需要感谢我的两位同学,他们在我完成实验以及撰写博客的过程中提供了很有用的帮助。
2020-3-30 20:57 第一次编辑
2020-3-31 08:39 第二次编辑
优化了同一套加法器的代码;用宏来表示参数;