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

[复制链接]
 楼主| 9dome猫 发表于 2022-6-28 15:13 | 显示全部楼层
代码如下:
  1. module datapath(
  2.         input         clk,
  3.         input   rst_n,
  4.         input   [31:0]instr,


  5.         input   MemtoReg,
  6.         input   ALUSrc,
  7.         input   RegWrite,
  8.         input   lui,
  9.         input   U_type,
  10.         input   jal,
  11.         input   jalr,
  12.         input   beq,
  13.         input   bne,
  14.         input   blt,
  15.         input   bge,
  16.         input   bltu,
  17.         input   bgeu,
  18.         input   [3:0]ALUctl,
  19.        
  20.         input [31:0]Rd_mem_data,
  21.         output  [7:0]rom_addr,
  22.         output [31:0]Wr_mem_data,
  23.         output [31:0]ALU_result,
  24.         output [6:0]opcode,
  25.         output [2:0]func3,
  26.         output func7
  27.        
  28.        
  29.     );
  30.        
  31.        
  32.        
  33.        
  34.        
  35.        
  36.         wire [4:0]Rs1;
  37.         wire [4:0]Rs2;
  38.         wire [4:0]Rd;
  39.         wire [31:0]imme;
  40.        
  41.         wire [31:0] Wr_reg_data;
  42.         wire [31:0] Rd_data1;
  43.         wire [31:0] Rd_data2;
  44.        
  45.         wire zero;
  46.        
  47.         wire [31:0]pc_order;
  48.         wire [31:0]pc_jump;
  49.        
  50.         wire   [31:0]pc_new;
  51.         wire [31:0]pc_out;
  52.        
  53.         wire jump_flag;
  54.        
  55.         wire [31:0]ALU_DB;
  56.         wire [31:0]WB_data;
  57.        
  58.         wire reg_sel;
  59.         wire [31:0]Wr_reg_data1;
  60.         wire [31:0]Wr_reg_data2;
  61.         wire [31:0]pc_jump_order;
  62.         wire [31:0]pc_jalr;
  63.        
  64.        
  65.         assign reg_sel=jal | jalr ;
  66.         assign Wr_mem_data=Rd_data2;
  67.         assign rom_addr=pc_out[9:2];
  68.         assign pc_jalr={ALU_result[31:1],1'b0};
  69.        
  70.         pc_reg pc_reg_inst (
  71.     .clk(clk),
  72.     .rst_n(rst_n),
  73.     .pc_new(pc_new),
  74.     .pc_out(pc_out)
  75.     );

  76.        
  77.         instr_decode instr_decode_inst (
  78.     .instr(instr),
  79.     .opcode(opcode),
  80.     .func3(func3),
  81.     .func7(func7),
  82.     .Rs1(Rs1),
  83.     .Rs2(Rs2),
  84.     .Rd(Rd),
  85.     .imme(imme)
  86.     );
  87.        
  88.     registers registers_inst (
  89.     .clk(clk),
  90.     .W_en(RegWrite),
  91.     .Rs1(Rs1),
  92.     .Rs2(Rs2),
  93.     .Rd(Rd),
  94.     .Wr_data(Wr_reg_data),
  95.     .Rd_data1(Rd_data1),
  96.     .Rd_data2(Rd_data2)
  97.     );

  98.        
  99.         alu alu_inst (
  100.     .ALU_DA(Rd_data1),
  101.     .ALU_DB(ALU_DB),
  102.     .ALU_CTL(ALUctl),
  103.     .ALU_ZERO(zero),
  104.     .ALU_OverFlow(),
  105.     .ALU_DC(ALU_result)
  106.     );

  107.         branch_judge branch_judge_inst (
  108.     .beq(beq),
  109.     .bne(bne),
  110.     .blt(blt),
  111.     .bge(bge),
  112.     .bltu(bltu),
  113.     .bgeu(bgeu),
  114.     .jal(jal),
  115.     .jalr(jalr),
  116.     .zero(zero),
  117.     .ALU_result(ALU_result),
  118.     .jump_flag(jump_flag)
  119.     );

  120.        

  121.        
  122. //pc+4       
  123.         cla_adder32 pc_adder_4 (
  124.     .A(pc_out),
  125.     .B(32'd4),
  126.     .cin(1'd0),
  127.     .result(pc_order),
  128.     .cout()
  129.     );
  130.        
  131. /pc+imme
  132.         cla_adder32 pc_adder_imme (
  133.     .A(pc_out),
  134.     .B(imme),
  135.     .cin(1'd0),
  136.     .result(pc_jump),
  137.     .cout()
  138.     );
  139.        

  140. /pc_sel
  141.         mux pc_mux (
  142.     .data1(pc_jump),
  143.     .data2(pc_order),
  144.     .sel(jump_flag),
  145.     .dout(pc_jump_order)
  146.     );
  147. ///pc_jalr
  148.         mux pc_jalr_mux (
  149.     .data1(pc_jalr),
  150.     .data2(pc_jump_order),
  151.     .sel(jalr),
  152.     .dout(pc_new)
  153.     );

  154.        
  155.        
  156. ALUdata_sel       
  157.         mux ALU_data_mux (
  158.     .data1(imme),
  159.     .data2(Rd_data2),
  160.     .sel(ALUSrc),
  161.     .dout(ALU_DB)
  162.     );
  163.        
  164.        
  165. /ALU_result or datamem       
  166.         mux WB_data_mux (
  167.     .data1(Rd_mem_data),
  168.     .data2(ALU_result),
  169.     .sel(MemtoReg),
  170.     .dout(WB_data)
  171.     );
  172.        
  173.        
  174. Wr_data_sel
  175.         mux jalr_mux (
  176.     .data1(pc_order),
  177.     .data2(WB_data),
  178.     .sel(reg_sel),
  179.     .dout(Wr_reg_data2)
  180.     );
  181.        
  182.         mux lui_mux (
  183.     .data1(imme),
  184.     .data2(pc_jump),
  185.     .sel(lui),
  186.     .dout(Wr_reg_data1)
  187.     );
  188.        
  189.         mux Wr_reg_mux (
  190.     .data1(Wr_reg_data1),
  191.     .data2(Wr_reg_data2),
  192.     .sel(U_type),
  193.     .dout(Wr_reg_data)
  194.     );

  195. endmodule

 楼主| 9dome猫 发表于 2022-6-28 15:14 | 显示全部楼层
四.控制器
1.主控制器
由于不同类型的指令所经过的数据通路不同,所以需要有控制信号控制数据通路,使得数据经过正确的通路,得到正确的运算结果。
 楼主| 9dome猫 发表于 2022-6-28 15:14 | 显示全部楼层
本设计将控制器分为两级控制,主控制器产生大部分的控制信号,子控制器是ALU控制器,产生控制ALU进行正确运算的信号。
 楼主| 9dome猫 发表于 2022-6-28 15:15 | 显示全部楼层
模块的输入输出端口定义如下:
169362baaa7b07e78.png
 楼主| 9dome猫 发表于 2022-6-28 15:16 | 显示全部楼层
代码如下:
  1. module main_control(
  2.         opcode,
  3.         func3,
  4.         MemRead,
  5.         MemtoReg,
  6.         ALUop,
  7.         MemWrite,
  8.         ALUSrc,
  9.         RegWrite,
  10.         lui,
  11.         U_type,
  12.         jal,
  13.         jalr,
  14.         beq,
  15.         bne,
  16.         blt,
  17.         bge,
  18.         bltu,
  19.         bgeu,
  20.         RW_type
  21.     );
  22.         input [6:0]opcode;
  23.         input [2:0]func3;
  24.        
  25.         output   MemRead;
  26.         output   MemtoReg;
  27.         output   [1:0]ALUop;
  28.         output   MemWrite;
  29.         output   ALUSrc;
  30.         output   RegWrite;
  31.         output   lui;
  32.         output   U_type;
  33.         output   jal;
  34.         output   jalr;
  35.         output   beq;
  36.         output   bne;
  37.         output   blt;
  38.         output   bge;
  39.         output   bltu;
  40.         output   bgeu;
  41.         output   [2:0]RW_type;
  42.        
  43.         wire branch;
  44.         wire R_type;
  45.         wire I_type;
  46.         wire load;
  47.         wire store;
  48.         wire lui;
  49.         wire auipc;

  50.        
  51.         assign branch=(opcode==`B_type)?1'b1:1'b0;
  52.         assign R_type=(opcode==`R_type)?1'b1:1'b0;
  53.         assign I_type=(opcode==`I_type)?1'b1:1'b0;
  54.         assign U_type=(lui | auipc)? 1'b1:1'b0;
  55.         assign load=(opcode==`load)?1'b1:1'b0;
  56.         assign store=(opcode==`store)?1'b1:1'b0;
  57.        
  58.         assign jal=(opcode==`jal)?1'b1:1'b0;
  59.         assign jalr=(opcode==`jalr)?1'b1:1'b0;
  60.         assign lui=(opcode==`lui)?1'b1:1'b0;
  61.         assign auipc=(opcode==`auipc)?1'b1:1'b0;
  62.         assign beq= branch & (func3==3'b000);
  63.         assign bne= branch & (func3==3'b001);
  64.         assign blt= branch & (func3==3'b100);
  65.         assign bge= branch & (func3==3'b101);
  66.         assign bltu= branch & (func3==3'b110);
  67.         assign bgeu= branch & (func3==3'b111);
  68.         assign RW_type=func3;
  69.        
  70.        
  71.         enable
  72.         assign MemRead= load;
  73.         assign MemWrite= store;
  74.         assign RegWrite= jal| jalr | load | I_type |R_type | U_type;
  75.        
  76.         MUX
  77.         assign ALUSrc=load | store |I_type | jalr;  //select imme
  78.         assign MemtoReg= load;  //select datamemory data
  79.        
  80.         ALUop
  81.         assign ALUop[1]= R_type|branch; //R 10 I 01 B 11 add 00
  82.         assign ALUop[0]= I_type|branch;
  83.        
  84.        
  85. endmodule
 楼主| 9dome猫 发表于 2022-6-28 15:16 | 显示全部楼层
2.子控制器
子控制器根据主控制器产生的ALUop信号,结合func3和func7信号来产生ALUctl信号。

ALUop信号的设置如下:
9034362baaad15c2c0.png
 楼主| 9dome猫 发表于 2022-6-28 15:17 | 显示全部楼层
ALUctl信号设置如下:
6449462baaae662e7a.png
 楼主| 9dome猫 发表于 2022-6-28 15:18 | 显示全部楼层
模块的输入输出端口定义如下:
5315262baab097d3f3.png
 楼主| 9dome猫 发表于 2022-6-28 15:19 | 显示全部楼层
代码如下:
  1. module alu_control(
  2.         ALUop,
  3.         func3,
  4.         func7,
  5.         ALUctl
  6.     );
  7.         input [1:0]ALUop;
  8.         input [2:0]func3;
  9.         input func7;
  10.         output [3:0]ALUctl;
  11.        
  12.         wire [3:0]branchop;
  13.         reg  [3:0]RIop;
  14.        
  15.        
  16.        
  17.         assign branchop=(func3[2] & func3[1])? `SLTU : (func3[2] ^ func3[1])? `SLT : `SUB;
  18.        
  19.         always@(*)
  20.         begin
  21.                 case(func3)
  22.                         3'b000: if(ALUop[1] & func7) //R
  23.                                         RIop=`SUB;
  24.                                         else                 //I
  25.                                         RIop=`ADD;
  26.                         3'b001: RIop=`SLL;
  27.                         3'b010: RIop=`SLT;
  28.                         3'b011: RIop=`SLTU;
  29.                         3'b100: RIop=`XOR;
  30.                         3'b101: if(func7)
  31.                                         RIop=`SRA;
  32.                                         else
  33.                                         RIop=`SRL;
  34.                         3'b110: RIop=`OR;
  35.                         3'b111: RIop=`AND;
  36.                         default:RIop=`ADD;
  37.                 endcase
  38.         end
  39.        
  40.         assign ALUctl=(ALUop[1]^ALUop[0])? RIop:(ALUop[1]&ALUop[0])?branchop:`ADD;

  41. endmodule

 楼主| 9dome猫 发表于 2022-6-28 15:19 | 显示全部楼层
3.控制器
将主控制模块和子控制模块进行实例化,得到控制模块。
代码如下:
  1. `include "define.v"
  2. module control(
  3.         opcode,
  4.         func3,
  5.         func7,
  6.         MemRead,
  7.         MemtoReg,
  8.         MemWrite,
  9.         ALUSrc,
  10.         RegWrite,
  11.         lui,
  12.         U_type,
  13.         jal,
  14.         jalr,
  15.         beq,
  16.         bne,
  17.         blt,
  18.         bge,
  19.         bltu,
  20.         bgeu,
  21.         RW_type,
  22.         ALUctl

  23.     );
  24.         input          [6:0]opcode;
  25.         input          [2:0]func3;
  26.         input          func7;
  27.         output   MemRead;
  28.         output   MemtoReg;
  29.         output   MemWrite;
  30.         output   ALUSrc;
  31.         output   RegWrite;
  32.         output   lui;
  33.         output   U_type;
  34.         output   jal;
  35.         output   jalr;
  36.         output   beq;
  37.         output   bne;
  38.         output   blt;
  39.         output   bge;
  40.         output   bltu;
  41.         output   bgeu;
  42.         output   [2:0]RW_type;
  43.         output   [3:0]ALUctl;
  44.        
  45.         wire [1:0]ALUop;
  46.        
  47.         main_control main_control_inst(
  48.         .opcode(opcode),
  49.         .func3(func3),
  50.         .MemRead(MemRead),
  51.         .MemtoReg(MemtoReg),
  52.         .ALUop(ALUop),
  53.         .MemWrite(MemWrite),
  54.         .ALUSrc(ALUSrc),
  55.         .RegWrite(RegWrite),
  56.         .lui(lui),
  57.         .U_type(U_type),
  58.         .jal(jal),
  59.         .jalr(jalr),
  60.         .beq(beq),
  61.         .bne(bne),
  62.         .blt(blt),
  63.         .bge(bge),
  64.         .bltu(bltu),
  65.         .bgeu(bgeu),
  66.         .RW_type(RW_type)
  67.     );
  68.        
  69.         alu_control alu_control_inst(
  70.         .ALUop(ALUop),
  71.         .func3(func3),
  72.         .func7(func7),
  73.         .ALUctl(ALUctl)
  74.     );
  75.        
  76. endmodule

 楼主| 9dome猫 发表于 2022-6-28 15:24 | 显示全部楼层
五.CPU的实现
1. RISC-V核心
将数据通路和及控制信号连接。
 楼主| 9dome猫 发表于 2022-6-28 15:26 | 显示全部楼层
模块的输入输出端口定义如下:
1627362baacb12bf3d.png
 楼主| 9dome猫 发表于 2022-6-28 15:27 | 显示全部楼层
代码如下:
  1. module riscv(
  2.         input clk,
  3.         input rst_n,
  4.         input [31:0]instr,
  5.         input [31:0]Rd_mem_data,
  6.        
  7.         output [7:0]rom_addr,
  8.        
  9.         output [31:0]Wr_mem_data,
  10.         output W_en,
  11.         output R_en,
  12.         output [31:0]ram_addr,
  13.         output [2:0]RW_type
  14.     );
  15.        
  16.         wire [6:0]opcode;
  17.         wire [2:0]func3;
  18.         wire func7;
  19.         wire MemtoReg;
  20.         wire ALUSrc;
  21.         wire RegWrite;
  22.         wire lui;
  23.         wire U_type;
  24.         wire jal;
  25.         wire jalr;
  26.         wire beq;
  27.         wire bne;
  28.         wire blt;
  29.         wire bge;
  30.         wire bltu;
  31.         wire bgeu;
  32.         wire [3:0]ALUctl;
  33.        
  34.        
  35.        
  36.         control control_inst (
  37.     .opcode(opcode),
  38.     .func3(func3),
  39.     .func7(func7),
  40.     .MemRead(R_en),
  41.     .MemtoReg(MemtoReg),
  42.     .MemWrite(W_en),
  43.     .ALUSrc(ALUSrc),
  44.     .RegWrite(RegWrite),
  45.         .lui(lui),
  46.         .U_type(U_type),
  47.     .jal(jal),
  48.     .jalr(jalr),
  49.     .beq(beq),
  50.     .bne(bne),
  51.     .blt(blt),
  52.     .bge(bge),
  53.     .bltu(bltu),
  54.     .bgeu(bgeu),
  55.     .RW_type(RW_type),
  56.     .ALUctl(ALUctl)
  57.     );
  58.        
  59.         datapath datapath_inst (
  60.     .clk(clk),
  61.     .rst_n(rst_n),
  62.     .instr(instr),
  63.     .MemtoReg(MemtoReg),
  64.     .ALUSrc(ALUSrc),
  65.     .RegWrite(RegWrite),
  66.         .lui(lui),
  67.         .U_type(U_type),
  68.     .jal(jal),
  69.     .jalr(jalr),
  70.     .beq(beq),
  71.     .bne(bne),
  72.     .blt(blt),
  73.     .bge(bge),
  74.     .bltu(bltu),
  75.     .bgeu(bgeu),
  76.     .ALUctl(ALUctl),
  77.     .Rd_mem_data(Rd_mem_data),
  78.     .rom_addr(rom_addr),
  79.     .Wr_mem_data(Wr_mem_data),
  80.         .ALU_result(ram_addr),
  81.         .opcode(opcode),
  82.         .func3(func3),
  83.         .func7(func7)
  84.     );

  85. endmodule

 楼主| 9dome猫 发表于 2022-6-28 15:28 | 显示全部楼层
2.完整CPU
接入指令存储器和数据存储器。
代码如下:
  1. module riscv_top(
  2.         input clk,
  3.         input rst_n,
  4.         output [7:0]rom_addr
  5.     );

  6. //        wire [7:0]rom_addr;
  7.         wire [31:0]ram_addr;
  8.         wire [31:0]instr;
  9.         wire [31:0]Rd_mem_data;
  10.         wire [31:0]Wr_mem_data;
  11.         wire W_en;
  12.         wire R_en;
  13.         wire [2:0]RW_type;
  14.        
  15.         instr_memory instr_memory_inst (
  16.     .addr(rom_addr),
  17.     .instr(instr)
  18.     );

  19.         riscv riscv_inst (
  20.     .clk(clk),
  21.     .rst_n(rst_n),
  22.     .instr(instr),
  23.     .Rd_mem_data(Rd_mem_data),
  24.     .rom_addr(rom_addr),
  25.     .Wr_mem_data(Wr_mem_data),
  26.     .W_en(W_en),
  27.     .R_en(R_en),
  28.     .ram_addr(ram_addr),
  29.     .RW_type(RW_type)
  30.     );

  31.        
  32.        
  33.        
  34.         data_memory data_memory_inst (
  35.     .clk(clk),
  36.     .rst_n(rst_n),
  37.     .W_en(W_en),
  38.     .R_en(R_en),
  39.     .addr(ram_addr),
  40.     .RW_type(RW_type),
  41.     .din(Wr_mem_data),
  42.     .dout(Rd_mem_data)
  43.     );       

  44. endmodule

 楼主| 9dome猫 发表于 2022-6-28 15:29 | 显示全部楼层
3.整体预览
最终的代码结构如下:
9601362baadad55b7d.png
 楼主| 9dome猫 发表于 2022-6-28 15:29 | 显示全部楼层
FPGA工具生成的RTL图如下:
8570162baadd62753e.png
吾要单片机 发表于 2022-6-28 15:38 | 显示全部楼层
很好!支持楼主!
janewood 发表于 2022-8-16 19:53 | 显示全部楼层
单周期处理器有什么特点呢
robincotton 发表于 2022-8-17 15:52 | 显示全部楼层
这个单片机需要学习Verilog吗
cashrwood 发表于 2022-8-20 16:00 | 显示全部楼层
RISC-V处理器好用吗   
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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