前言:本章内容主要是演示在vivado下利用Verilog语言进行单周期简易CPU的设计。一步一步自己实现模型机的设计。本章先介绍单周期简易CPU中基本组合逻辑部件的设计。
💻环境:一台内存4GB以上,装有64位Windows操作系统和Vivado 2017.4以上版本软件的PC机。
💎本章所采用的指令为LoongArch之LA32R版
Ⅰ前置知识
0x00 立即数扩展模块Ext
立即数扩展模块(Ext)是一种在计算机体系结构中使用的技术,用于增加处理器的能力以支持更大范围的立即数操作。
立即数是指直接出现在指令中的常数值,例如在一个加法指令中,可以直接将两个寄存器的值相加,也可以将其中一个寄存器的值与一个立即数相加。立即数扩展模块的目的是为了扩展处理器对立即数的支持范围。
通常情况下,计算机体系结构规定了立即数的位数和取值范围。例如,一个处理器可能只支持8位的立即数,并且只能表示-128到127之间的值。这限制了在指令中可以使用的立即数的范围,可能导致无法执行某些需要更大范围立即数的操作。
立即数扩展模块通过增加额外的硬件逻辑来解决这个问题。它可以扩展处理器对立即数的位数,使得更大范围的立即数可以被支持。例如,它可以增加立即数的位数从8位扩展到16位,从而允许表示更大的值。
通过使用立即数扩展模块,处理器可以更灵活地处理更大范围的立即数操作,从而增加了指令集的功能和灵活性。这对于一些需要处理大范围立即数的应用程序非常有益。
本章介绍的立即数扩展模块的参考电路框图如下:
该模块的功能及引脚信号说明如下:
信号名称 | 功能说明 |
Datain | 32位的数据输入信号 |
Extop | 扩展方式选择信号 |
Dataout | 32位的数据输出信号 |
该模块的参考电路结构如下图所示:
0x01 32位算术逻辑运算单元(ALU)
ALU,全称为算术逻辑单元(Arithmetic Logic Unit),是计算机中一个非常重要的组件。ALU负责执行各种算术和逻辑运算,这些运算包括加法、减法、乘法、除法以及与、或、非等逻辑操作。
ALU通常是CPU中的一个核心部分,它接收输入的数据并根据指令执行相应的运算。在执行算术运算时,ALU会将两个输入值进行相应的操作,然后将结果输出。例如,当执行加法操作时,ALU会将两个输入的数值相加,并将结果返回。
除了算术运算,ALU还能执行逻辑运算。逻辑运算是基于布尔代数的操作,常见的有与、或、非等操作。通过逻辑运算,可以对输入的数据进行比特级别的操作和判断。
ALU的设计可以根据不同的需求进行优化。一些ALU还可能支持浮点运算、位移操作、条件判断等功能。因此,ALU的具体实现方式可能会有所不同,但其核心目标始终是执行各种算术和逻辑运算。
32位算术逻辑运算单元模块的参考电路框图如下:
该模块的功能及引脚信号说明如下:
信号名称 | 功能说明 |
a, b | 两个32位的数据输入 |
op | 运算类型选择输入 |
AddResult | 运算结果输出 |
Zero | 0标志位输出。运算结果AddResult为0时,Zero=1;否则Zero=0 |
Ⅱ. Verilog实现
0x00 立即数扩展模块Ext
本章所设计的立即数扩展模块实现下表所示的4种方式的立即数扩展与拼接操作,以得到一个新的32位数。
Extop | 功能 | 说明 |
0 | Dataout←SignExtend(DataIn[21:10]) | 把DataIn[21:10]进行符号位扩展 |
1 | Dataout←SignExtend(DataIn[25:10] || 2’b0) | 把DataIn[25:10]低位补2bit0后,进行符号位扩展 |
2 | Dataout←DataIn[24:5] || 12’b0 | 把DataIn[24:5]低位补12bit0 |
3 | Dataout←SignExtend(DataIn[9:0] || DataIn[25:10] || 2’b0) | 把DataIn[9:0]和 DataIn[25:10] 进行拼接,然后低位补2个0,再进行符号位扩展 |
设计代码:
module Ext (
input [31:0] DataIn,
input [1:0] Extop,
output reg [31:0] Dataout
);
always @(*) begin
case (Extop)
2'b00: Dataout = {{20{DataIn[21]}}, DataIn[21:10]};
2'b01: Dataout = {{14{DataIn[25]}} , {DataIn[25:10], 2'b0}} ;
2'b10: Dataout = {DataIn[24:5], 12'b0};
2'b11: Dataout = {{4{DataIn[25]}}, DataIn[9:0] , {DataIn[25:10] , 2'b0}};
default: Dataout = 0;
endcase
end
endmodule
在Vivado中点击”RTL ANALYSIS->Open Elaborated Design”,可以查看综合得到的逻辑电路,如图所示:
仿真代码:
module simExt( );
reg [31:0]Datain;
reg[1:0]ExtOp;
wire [31:0]Dataout;
Ext uu(Datain,ExtOp,Dataout);
// initial begin
// Datain=32'b0010_1111_0000_1010_0101_1111_1010_0001;#40;
// end
initial begin
ExtOp=0;Datain=32'b000000_1010_000000000111_00000_00001;#100;//12位立即数addi.w $r1,$r0,7 //r2<--(+7)
ExtOp=0;Datain=32'b000000_1010_111111111001_00000_00010;#100;//12位立即数addi.w $r2,$r0,-7 //r2<--(-7)
ExtOp=1;Datain=32'b010110_1111111111111111_00001_00010;#100;//16位立即数beq $r1,$r2,-1//pc<--pc-4
ExtOp=1;Datain=32'b011000_0000000000000001_00001_00010;#100;//16位立即数blt $r1,$r2,1//pc<--pc+4
ExtOp=2;Datain=32'b0001010_00000000000000000001_00011;#100;//20位立即数lui12 $r3,1 //r3<--4094
ExtOp=3;Datain=32'b010100_0000000000000010_0000000000;#100;//26位立即数b //pc<--pc+8
ExtOp=3;Datain=32'b010100_1111111111111110_1111111111;#100;//26位立即数b //pc<--pc-8
end
endmodule
测试结果:
🚩 注:
如果按照vivado默认的进制,得到的波形图不方便观察:
所以我们可以在Radix中调整为有符号的十进制,方法如下图:
0x01 32位算术逻辑运算单元(ALU)
本章设计的32位算术逻辑运算单元(ALU)具有以下功能:
要求ALU带“0状态”位Zero输出。即:当运算结果为0时,Zero=1;否则,Zero=0。
功能编号 | 功能 | 说明 |
0 | AddResult =a+b | 加法 |
1 | AddResult =a-b | 减法 |
2 | AddResult =a⋀b | 与 |
3 | AddResult =a⋁b | 或 |
4 | AddResult = | 或非 |
5 | a<b时AddResult =1 | A和B是带符号数,进行带符号数比较 |
6 | a<b时AddResult =1 | A和B是无符号数,进行无符号数比较 |
7 | AddResult =b | 直通 |
设计代码:
module alu (
input [31:0] a, b,
input [2:0] op,
output reg zero,
output reg [31:0] result
);
always @(*) begin
case (op)
3'b000: result = a + b; // Add
3'b001: result = a - b; // Subtract
3'b010: result = a & b; // Bitwise AND
3'b011: result = a | b; // Bitwise OR
3'b100: result = ~(a | b); // Bitwise NOR
//3'b101: result = (a < b) ? 32'h00000001 : 32'h00000000; // Signed comparison
3'b101:begin
if(a[31] > b[31])
result = 1;
else if(a[31] < b[31])
result = 0;
else
if(a[31] == 0)
if(a[30:0] < b[30:0])
result = 1;
else
result = 0;
else
if(a[30:0] > b[30:0])
result = 1;
else
result = 0;
end
3'b110:begin
if(a < b)
result = 1;
else
result = 0;
end
endcase
end
// Set zero flag
always @(result) begin
zero = (result == 32'h00000000) ? 1'b1 : 1'b0;
end
endmodule
在Vivado中点击”RTL ANALYSIS->Open Elaborated Design”,可以查看综合得到的逻辑电路,如图所示:
仿真代码:
module sim_aluLA32( );
reg [31:0] a,b;
reg [2:0] op;
wire [31:0] result;
wire zero;
//aluLA32 u1(a,b,op,result,zero);
//aluLA32 u2(.a(a),.b(b),.op(op),.AddResult(AddResult),.Zero(Zero));
alu dut (.a(a), .b(b), .op(op), .zero(zero), .result(result));
always begin
a = 80;b = 95;op = 0; #100;
op = 1; #100;
a = -100;b =-95;op = 5; #100;
op = 6; #100;
a = 32'h12345678; b = 32'h0000ffff;op = 2; #100;
op = 3; #100;
op = 7; #100;
end
initial begin
end
endmodule
仿真结果:
🚩注:
在编写有符号数和无符号数时,要注意不同:
END
📝 因为作者的能力有限,所以文章可能会存在一些错误和不准确之处,恳请大家指出!