前言:本章内容主要是演示在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


因为作者的能力有限,所以文章可能会存在一些错误和不准确之处,恳请大家指出!