打印
[RISC-V MCU 创新应用比赛]

从零开始设计RISC-V处理器——单周期处理器的设计

[复制链接]
楼主: 9dome猫
手机看帖
扫描二维码
随时随地手机跟帖
21
9dome猫|  楼主 | 2022-6-28 14:22 | 只看该作者 |只看大图 回帖奖励 |倒序浏览
模块的输入输出端口定义如下:

使用特权

评论回复
22
9dome猫|  楼主 | 2022-6-28 14:23 | 只看该作者
代码如下:

`include "define.v"
module instr_decode(
        input [31:0]instr,
        output [6:0]opcode,
        output [2:0]func3,
        output func7,
        output [4:0]Rs1,
        output [4:0]Rs2,
        output [4:0]Rd,
        output [31:0]imme
         );
         
        wire I_type;
        wire U_type;
        wire J_type;
        wire B_type;
        wire S_type;
       
        wire [31:0]I_imme;
        wire [31:0]U_imme;
        wire [31:0]J_imme;
        wire [31:0]B_imme;
        wire [31:0]S_imme;
       
       
        assign opcode=instr[6:0];
        assign func3=instr[14:12];
        assign func7=instr[30];
        assign Rs1=instr[19:15];
        assign Rs2=instr[24:20];
        assign Rd =instr[11:7];
       
        assign I_type=(instr[6:0]==`jalr) | (instr[6:0]==`load) | (instr[6:0]==`I_type);
        assign U_type=(instr[6:0]==`lui) | (instr[6:0]==`auipc);
        assign J_type=(instr[6:0]==`jal);
        assign B_type=(instr[6:0]==`B_type);
        assign S_type=(instr[6:0]==`store);
       
       
        assign I_imme={{20{instr[31]}},instr[31:20]};
        assign U_imme={instr[31:12],{12{1'b0}}};
        assign J_imme={{12{instr[31]}},instr[19:12],instr[20],instr[30:21],1'b0};   
        assign B_imme={{20{instr[31]}},instr[7],instr[30:25],instr[11:8],1'b0};
        assign S_imme={{20{instr[31]}},instr[31:25],instr[11:7]};
       
        assign imme= I_type?I_imme :
                                 U_type?U_imme :
                                 J_type?J_imme :
                                 B_type?B_imme :
                                 S_type?S_imme : 32'd0;


endmodule


使用特权

评论回复
23
9dome猫|  楼主 | 2022-6-28 14:36 | 只看该作者
3.ALU模块
ALU模块主要进行数据的运算,根据ALU的控制模块产生的控制信ALU_CTL决定ALU进行的运算类型。

使用特权

评论回复
24
9dome猫|  楼主 | 2022-6-28 14:38 | 只看该作者
ALU_CTL对应的运算关系如下:

使用特权

评论回复
25
9dome猫|  楼主 | 2022-6-28 14:46 | 只看该作者
由以上表格可以看出,ALU的运算类型分为加法运算,逻辑运算,小于置一,移位运算,根据ALU_CTL的高两位便可以判断出要执行的运算类型。

使用特权

评论回复
26
9dome猫|  楼主 | 2022-6-28 14:48 | 只看该作者
(1)加法运算:由加法器实现,减法实质上也是加法。
对于A-B,可以看作A+(-B)。
对于补码表示的二进制数,天然地有如下关系:
A+(~A)=32’b1111_1111_1111_1111_1111_1111_1111_1111=-1;
因此,-A=(~A)+1,这便是我们常说的补码等于反码加1,其实更严谨的说法应该是,一个数的相反数,等于这个数按位取反再加一。
于是,对于减法运算,可以做如下转换:
A-B=A+(-B)=A+(B的补码)+1;

使用特权

评论回复
27
9dome猫|  楼主 | 2022-6-28 14:49 | 只看该作者
另外,加法运算还应检测是否溢出,检测依据就是:当数为负数时,最左侧的位为0,或者数为正数时,最左侧的位为1。
具体细分位以下四种情况:
a.正数+正数=负数,则溢出
b.负数+负数=正数,则溢出
c.正数-负数=负数,则溢出
d.负数-正数=正数,则溢出

使用特权

评论回复
28
9dome猫|  楼主 | 2022-6-28 14:53 | 只看该作者
(2)逻辑运算,用逻辑门阵列实现即可。

使用特权

评论回复
29
9dome猫|  楼主 | 2022-6-28 14:54 | 只看该作者
(3)小于置一,实质上是减法运算。根据加法器的运算结果,进一步判断是否小于。

使用特权

评论回复
30
9dome猫|  楼主 | 2022-6-28 14:54 | 只看该作者
(4)移位运算,这里直接使用移位运算符(>>,<<)。

使用特权

评论回复
31
9dome猫|  楼主 | 2022-6-28 14:55 | 只看该作者
以上就是ALU的主要运算部件的设计,可以看到,加法器和移位运算比较复杂,但这里直接用Verilog的运算符实现的,后续会尝试设计超前进位加法器代替“+”以及用位拼接运算代替“>>,<<”,以提升CPU的性能。

使用特权

评论回复
32
9dome猫|  楼主 | 2022-6-28 14:56 | 只看该作者
模块的输入输出端口定义如下:

使用特权

评论回复
33
9dome猫|  楼主 | 2022-6-28 14:59 | 只看该作者
代码如下:
module alu(
           ALU_DA,
       ALU_DB,
       ALU_CTL,
       ALU_ZERO,
       ALU_OverFlow,
       ALU_DC   
        );
        input [31:0]    ALU_DA;
    input [31:0]    ALU_DB;
    input [3:0]     ALU_CTL;
    output          ALU_ZERO;
    output          ALU_OverFlow;
    output reg [31:0]   ALU_DC;
                  
//********************generate ctr***********************
wire SUBctr;
wire SIGctr;
wire Ovctr;
wire [1:0] Opctr;
wire [1:0] Logicctr;
wire [1:0] Shiftctr;

assign SUBctr = (~ ALU_CTL[3]  & ~ALU_CTL[2]  & ALU_CTL[1]) | ( ALU_CTL[3]  & ~ALU_CTL[2]);
assign Opctr = ALU_CTL[3:2];
assign Ovctr = ALU_CTL[0] & ~ ALU_CTL[3]  & ~ALU_CTL[2] ;
assign SIGctr = ALU_CTL[0];
assign Logicctr = ALU_CTL[1:0];
assign Shiftctr = ALU_CTL[1:0];

//********************************************************

//*********************logic op***************************
reg [31:0] logic_result;

always@(*) begin
    case(Logicctr)
        2'b00:logic_result = ALU_DA & ALU_DB;
        2'b01:logic_result = ALU_DA | ALU_DB;
        2'b10:logic_result = ALU_DA ^ ALU_DB;
        2'b11:logic_result = ~(ALU_DA | ALU_DB);
        endcase
end

//********************************************************
//************************shift op************************
wire [4:0]     ALU_SHIFT;
wire [31:0] shift_result;
assign ALU_SHIFT=ALU_DB[4:0];

Shifter Shifter(.ALU_DA(ALU_DA),
                .ALU_SHIFT(ALU_SHIFT),
                                .Shiftctr(Shiftctr),
                                .shift_result(shift_result));

//********************************************************
//************************add sub op**********************
wire [31:0] BIT_M,XOR_M;
wire ADD_carry,ADD_OverFlow;
wire [31:0] ADD_result;

assign BIT_M={32{SUBctr}};
assign XOR_M=BIT_M^ALU_DB;

Adder Adder(.A(ALU_DA),
            .B(XOR_M),
                        .Cin(SUBctr),
                        .ALU_CTL(ALU_CTL),
                        .ADD_carry(ADD_carry),
                        .ADD_OverFlow(ADD_OverFlow),
                        .ADD_zero(ALU_ZERO),
                        .ADD_result(ADD_result));

assign ALU_OverFlow = ADD_OverFlow & Ovctr;

//********************************************************
//**************************slt op************************
wire [31:0] SLT_result;
wire LESS_M1,LESS_M2,LESS_S,SLT_M;

assign LESS_M1 = ADD_carry ^ SUBctr;
assign LESS_M2 = ADD_OverFlow ^ ADD_result[31];
assign LESS_S = (SIGctr==1'b0)?LESS_M1:LESS_M2;
assign SLT_result = (LESS_S)?32'h00000001:32'h00000000;

//********************************************************
//**************************ALU result********************
always @(*)
begin
  case(Opctr)
     2'b00:ALU_DC<=ADD_result;
     2'b01:ALU_DC<=logic_result;
     2'b10:ALU_DC<=SLT_result;
     2'b11:ALU_DC<=shift_result;
  endcase
end

//********************************************************
endmodule


//********************************************************
//*************************shifter************************
module Shifter(input [31:0] ALU_DA,
               input [4:0] ALU_SHIFT,
                           input [1:0] Shiftctr,
                           output reg [31:0] shift_result);
                          

     wire [5:0] shift_n;
         assign shift_n = 6'd32 - Shiftctr;
     always@(*) begin
           case(Shiftctr)
           2'b00:shift_result = ALU_DA << ALU_SHIFT;
           2'b01:shift_result = ALU_DA >> ALU_SHIFT;
           2'b10:shift_result = ({32{ALU_DA[31]}} << shift_n) | (ALU_DA >> ALU_SHIFT);
           default:shift_result = ALU_DA;
           endcase
         end


endmodule

//*************************************************************
//***********************************adder*********************
module Adder(input [31:0] A,
             input [31:0] B,
                         input Cin,
                         input [3:0] ALU_CTL,
                         output ADD_carry,
                         output ADD_OverFlow,
                         output ADD_zero,
                         output [31:0] ADD_result);


    assign {ADD_carry,ADD_result}=A+B+Cin;
   assign ADD_zero = ~(|ADD_result);
   assign ADD_OverFlow=((ALU_CTL==4'b0001) & ~A[31] & ~B[31] & ADD_result[31])
                      | ((ALU_CTL==4'b0001) & A[31] & B[31] & ~ADD_result[31])
                      | ((ALU_CTL==4'b0011) & A[31] & ~B[31] & ~ADD_result[31])
                                          | ((ALU_CTL==4'b0011) & ~A[31] & B[31] & ADD_result[31]);
endmodule



使用特权

评论回复
34
9dome猫|  楼主 | 2022-6-28 14:59 | 只看该作者
4.PC寄存器
PC寄存器用以更新pc的值。
顺序执行时,pc_new=pc+4,条件跳转时,pc_new=pc+imme。
jalr时,pc_new=data(Rs1)+imme。

使用特权

评论回复
35
9dome猫|  楼主 | 2022-6-28 15:07 | 只看该作者
模块的输入输出端口定义如下:

使用特权

评论回复
36
9dome猫|  楼主 | 2022-6-28 15:08 | 只看该作者
代码如下:
`include "define.v"
module pc_reg(
        clk,
        rst_n,
        pc_new,
        pc_out
    );
        input clk;
        input rst_n;
        input [31:0]pc_new;
       
        output reg [31:0]pc_out;
       
        always@(posedge clk or negedge rst_n)
        begin
                if(!rst_n)
                        pc_out<=`zero_word;
                else
                        pc_out<=pc_new;
        end       

endmodule



使用特权

评论回复
37
9dome猫|  楼主 | 2022-6-28 15:09 | 只看该作者
5.数据通路
数据通路就是将以上的几个关键的部件进行连接,为了形成完整的数据通路,还必须添加一些多路选择器,作用是对不同信号的来源进行选择,并输出到相应的模块。
比如:写入寄存器的数据来源有5个,分别是:ALU的运算结果,数据存储器读出的数据,pc+4,lui的立即数 ,auipc的pc+imme。

使用特权

评论回复
38
9dome猫|  楼主 | 2022-6-28 15:10 | 只看该作者
pc的来源有3个:pc+4,pc+imme,Read_data1+imme。
另外,还需要加入两个加法器,分别计算pc+4和pc+imme。

使用特权

评论回复
39
9dome猫|  楼主 | 2022-6-28 15:11 | 只看该作者
模块的输入输出端口定义如下:

使用特权

评论回复
40
9dome猫|  楼主 | 2022-6-28 15:11 | 只看该作者

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则