[RISC-V MCU 创新应用比赛] 从零开始设计RISC-V处理器——单周期处理器的设计

[复制链接]
 楼主| 9dome猫 发表于 2022-6-28 14:22 | 显示全部楼层
模块的输入输出端口定义如下:
2124262ba9e247310d.png
 楼主| 9dome猫 发表于 2022-6-28 14:23 | 显示全部楼层
代码如下:

  1. `include "define.v"
  2. module instr_decode(
  3.         input [31:0]instr,
  4.         output [6:0]opcode,
  5.         output [2:0]func3,
  6.         output func7,
  7.         output [4:0]Rs1,
  8.         output [4:0]Rs2,
  9.         output [4:0]Rd,
  10.         output [31:0]imme
  11.          );
  12.          
  13.         wire I_type;
  14.         wire U_type;
  15.         wire J_type;
  16.         wire B_type;
  17.         wire S_type;
  18.        
  19.         wire [31:0]I_imme;
  20.         wire [31:0]U_imme;
  21.         wire [31:0]J_imme;
  22.         wire [31:0]B_imme;
  23.         wire [31:0]S_imme;
  24.        
  25.        
  26.         assign opcode=instr[6:0];
  27.         assign func3=instr[14:12];
  28.         assign func7=instr[30];
  29.         assign Rs1=instr[19:15];
  30.         assign Rs2=instr[24:20];
  31.         assign Rd =instr[11:7];
  32.        
  33.         assign I_type=(instr[6:0]==`jalr) | (instr[6:0]==`load) | (instr[6:0]==`I_type);
  34.         assign U_type=(instr[6:0]==`lui) | (instr[6:0]==`auipc);
  35.         assign J_type=(instr[6:0]==`jal);
  36.         assign B_type=(instr[6:0]==`B_type);
  37.         assign S_type=(instr[6:0]==`store);
  38.        
  39.        
  40.         assign I_imme={{20{instr[31]}},instr[31:20]};
  41.         assign U_imme={instr[31:12],{12{1'b0}}};
  42.         assign J_imme={{12{instr[31]}},instr[19:12],instr[20],instr[30:21],1'b0};   
  43.         assign B_imme={{20{instr[31]}},instr[7],instr[30:25],instr[11:8],1'b0};
  44.         assign S_imme={{20{instr[31]}},instr[31:25],instr[11:7]};
  45.        
  46.         assign imme= I_type?I_imme :
  47.                                  U_type?U_imme :
  48.                                  J_type?J_imme :
  49.                                  B_type?B_imme :
  50.                                  S_type?S_imme : 32'd0;


  51. endmodule


 楼主| 9dome猫 发表于 2022-6-28 14:36 | 显示全部楼层
3.ALU模块
ALU模块主要进行数据的运算,根据ALU的控制模块产生的控制信ALU_CTL决定ALU进行的运算类型。
 楼主| 9dome猫 发表于 2022-6-28 14:38 | 显示全部楼层
ALU_CTL对应的运算关系如下:
5705562baa1cc8b8f5.png
 楼主| 9dome猫 发表于 2022-6-28 14:46 | 显示全部楼层
由以上表格可以看出,ALU的运算类型分为加法运算,逻辑运算,小于置一,移位运算,根据ALU_CTL的高两位便可以判断出要执行的运算类型。
 楼主| 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;
 楼主| 9dome猫 发表于 2022-6-28 14:49 | 显示全部楼层
另外,加法运算还应检测是否溢出,检测依据就是:当数为负数时,最左侧的位为0,或者数为正数时,最左侧的位为1。
具体细分位以下四种情况:
a.正数+正数=负数,则溢出
b.负数+负数=正数,则溢出
c.正数-负数=负数,则溢出
d.负数-正数=正数,则溢出
 楼主| 9dome猫 发表于 2022-6-28 14:53 | 显示全部楼层
(2)逻辑运算,用逻辑门阵列实现即可。
 楼主| 9dome猫 发表于 2022-6-28 14:54 | 显示全部楼层
(3)小于置一,实质上是减法运算。根据加法器的运算结果,进一步判断是否小于。
 楼主| 9dome猫 发表于 2022-6-28 14:54 | 显示全部楼层
(4)移位运算,这里直接使用移位运算符(>>,<<)。
 楼主| 9dome猫 发表于 2022-6-28 14:55 | 显示全部楼层
以上就是ALU的主要运算部件的设计,可以看到,加法器和移位运算比较复杂,但这里直接用Verilog的运算符实现的,后续会尝试设计超前进位加法器代替“+”以及用位拼接运算代替“>>,<<”,以提升CPU的性能。
 楼主| 9dome猫 发表于 2022-6-28 14:56 | 显示全部楼层
模块的输入输出端口定义如下:
9489662baa5f0e503b.png
 楼主| 9dome猫 发表于 2022-6-28 14:59 | 显示全部楼层
代码如下:
  1. module alu(
  2.            ALU_DA,
  3.        ALU_DB,
  4.        ALU_CTL,
  5.        ALU_ZERO,
  6.        ALU_OverFlow,
  7.        ALU_DC   
  8.         );
  9.         input [31:0]    ALU_DA;
  10.     input [31:0]    ALU_DB;
  11.     input [3:0]     ALU_CTL;
  12.     output          ALU_ZERO;
  13.     output          ALU_OverFlow;
  14.     output reg [31:0]   ALU_DC;
  15.                   
  16. //********************generate ctr***********************
  17. wire SUBctr;
  18. wire SIGctr;
  19. wire Ovctr;
  20. wire [1:0] Opctr;
  21. wire [1:0] Logicctr;
  22. wire [1:0] Shiftctr;

  23. assign SUBctr = (~ ALU_CTL[3]  & ~ALU_CTL[2]  & ALU_CTL[1]) | ( ALU_CTL[3]  & ~ALU_CTL[2]);
  24. assign Opctr = ALU_CTL[3:2];
  25. assign Ovctr = ALU_CTL[0] & ~ ALU_CTL[3]  & ~ALU_CTL[2] ;
  26. assign SIGctr = ALU_CTL[0];
  27. assign Logicctr = ALU_CTL[1:0];
  28. assign Shiftctr = ALU_CTL[1:0];

  29. //********************************************************

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

  32. always@(*) begin
  33.     case(Logicctr)
  34.         2'b00:logic_result = ALU_DA & ALU_DB;
  35.         2'b01:logic_result = ALU_DA | ALU_DB;
  36.         2'b10:logic_result = ALU_DA ^ ALU_DB;
  37.         2'b11:logic_result = ~(ALU_DA | ALU_DB);
  38.         endcase
  39. end

  40. //********************************************************
  41. //************************shift op************************
  42. wire [4:0]     ALU_SHIFT;
  43. wire [31:0] shift_result;
  44. assign ALU_SHIFT=ALU_DB[4:0];

  45. Shifter Shifter(.ALU_DA(ALU_DA),
  46.                 .ALU_SHIFT(ALU_SHIFT),
  47.                                 .Shiftctr(Shiftctr),
  48.                                 .shift_result(shift_result));

  49. //********************************************************
  50. //************************add sub op**********************
  51. wire [31:0] BIT_M,XOR_M;
  52. wire ADD_carry,ADD_OverFlow;
  53. wire [31:0] ADD_result;

  54. assign BIT_M={32{SUBctr}};
  55. assign XOR_M=BIT_M^ALU_DB;

  56. Adder Adder(.A(ALU_DA),
  57.             .B(XOR_M),
  58.                         .Cin(SUBctr),
  59.                         .ALU_CTL(ALU_CTL),
  60.                         .ADD_carry(ADD_carry),
  61.                         .ADD_OverFlow(ADD_OverFlow),
  62.                         .ADD_zero(ALU_ZERO),
  63.                         .ADD_result(ADD_result));

  64. assign ALU_OverFlow = ADD_OverFlow & Ovctr;

  65. //********************************************************
  66. //**************************slt op************************
  67. wire [31:0] SLT_result;
  68. wire LESS_M1,LESS_M2,LESS_S,SLT_M;

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

  73. //********************************************************
  74. //**************************ALU result********************
  75. always @(*)
  76. begin
  77.   case(Opctr)
  78.      2'b00:ALU_DC<=ADD_result;
  79.      2'b01:ALU_DC<=logic_result;
  80.      2'b10:ALU_DC<=SLT_result;
  81.      2'b11:ALU_DC<=shift_result;
  82.   endcase
  83. end

  84. //********************************************************
  85. endmodule


  86. //********************************************************
  87. //*************************shifter************************
  88. module Shifter(input [31:0] ALU_DA,
  89.                input [4:0] ALU_SHIFT,
  90.                            input [1:0] Shiftctr,
  91.                            output reg [31:0] shift_result);
  92.                           

  93.      wire [5:0] shift_n;
  94.          assign shift_n = 6'd32 - Shiftctr;
  95.      always@(*) begin
  96.            case(Shiftctr)
  97.            2'b00:shift_result = ALU_DA << ALU_SHIFT;
  98.            2'b01:shift_result = ALU_DA >> ALU_SHIFT;
  99.            2'b10:shift_result = ({32{ALU_DA[31]}} << shift_n) | (ALU_DA >> ALU_SHIFT);
  100.            default:shift_result = ALU_DA;
  101.            endcase
  102.          end


  103. endmodule

  104. //*************************************************************
  105. //***********************************adder*********************
  106. module Adder(input [31:0] A,
  107.              input [31:0] B,
  108.                          input Cin,
  109.                          input [3:0] ALU_CTL,
  110.                          output ADD_carry,
  111.                          output ADD_OverFlow,
  112.                          output ADD_zero,
  113.                          output [31:0] ADD_result);


  114.     assign {ADD_carry,ADD_result}=A+B+Cin;
  115.    assign ADD_zero = ~(|ADD_result);
  116.    assign ADD_OverFlow=((ALU_CTL==4'b0001) & ~A[31] & ~B[31] & ADD_result[31])
  117.                       | ((ALU_CTL==4'b0001) & A[31] & B[31] & ~ADD_result[31])
  118.                       | ((ALU_CTL==4'b0011) & A[31] & ~B[31] & ~ADD_result[31])
  119.                                           | ((ALU_CTL==4'b0011) & ~A[31] & B[31] & ADD_result[31]);
  120. endmodule



 楼主| 9dome猫 发表于 2022-6-28 14:59 | 显示全部楼层
4.PC寄存器
PC寄存器用以更新pc的值。
顺序执行时,pc_new=pc+4,条件跳转时,pc_new=pc+imme。
jalr时,pc_new=data(Rs1)+imme。
 楼主| 9dome猫 发表于 2022-6-28 15:07 | 显示全部楼层
模块的输入输出端口定义如下:
7407362baa6ebda188.png
 楼主| 9dome猫 发表于 2022-6-28 15:08 | 显示全部楼层
代码如下:
  1. `include "define.v"
  2. module pc_reg(
  3.         clk,
  4.         rst_n,
  5.         pc_new,
  6.         pc_out
  7.     );
  8.         input clk;
  9.         input rst_n;
  10.         input [31:0]pc_new;
  11.        
  12.         output reg [31:0]pc_out;
  13.        
  14.         always@(posedge clk or negedge rst_n)
  15.         begin
  16.                 if(!rst_n)
  17.                         pc_out<=`zero_word;
  18.                 else
  19.                         pc_out<=pc_new;
  20.         end       

  21. endmodule



 楼主| 9dome猫 发表于 2022-6-28 15:09 | 显示全部楼层
5.数据通路
数据通路就是将以上的几个关键的部件进行连接,为了形成完整的数据通路,还必须添加一些多路选择器,作用是对不同信号的来源进行选择,并输出到相应的模块。
比如:写入寄存器的数据来源有5个,分别是:ALU的运算结果,数据存储器读出的数据,pc+4,lui的立即数 ,auipc的pc+imme。
 楼主| 9dome猫 发表于 2022-6-28 15:10 | 显示全部楼层
pc的来源有3个:pc+4,pc+imme,Read_data1+imme。
另外,还需要加入两个加法器,分别计算pc+4和pc+imme。
 楼主| 9dome猫 发表于 2022-6-28 15:11 | 显示全部楼层
模块的输入输出端口定义如下:
1857862baa9878b831.png
 楼主| 9dome猫 发表于 2022-6-28 15:11 | 显示全部楼层
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 在线客服 返回列表 返回顶部