中科大OJ Verilog 在线评测题解 106-107

近跟着老师学习Verilog,做了中科大的练习题,将答案记录一下

Q106 控制器

题目描述

控制器模块负责产生各种控制信号。


与寄存器堆模块相关的:

1.rf_wr_en:1位使能信号,连接到寄存器堆的写使能端口(WE)。

查RISC-V手册可得,需要写寄存器的指令有U型指令,J型指令,I型指令,R型指令。
2.rf_wr_sel:2位选择信号,控制寄存器堆写数据的选择。其与指令的关系如下:


与pc模块相关的:
do_jump:一位控制信号,当指令为jalr或者jal时为1。当指令为jal或者jalr或者B型指令且满足分支条件时,pc模块的JUMP信号为1。


与分支跳转模块相关的:
BrType:三位,指明分支指令类型。由于之前我们为了提高代码容错率,没有直接使用B型指令的功能码作为控制信号,而是设置BrType为0时不进行操作,所以信号与指令对应如下:


与ALU模块相关:
1.alu_a_sel:ALU模块SrcA端口的选择信号;
2.alu_b_sel:ALU模块SrcB端口的选择信号;

通过查RISC-V中文手册可得:
指令为R型或I型或S型时,ALU模块输入SrcA端口连接寄存器输出端口RD1,即ALU模块其中一个操作数为寄存器rs1中的值;
指令为R型时,ALU模块输入SrcB端口连接寄存器输出端口RD2,即ALU模块另一个操作数为寄存器rs2中的值;
(ps:并不是说指令里有rs2就代表alu_b_sel为0,如B型指令里有rs2,但比较过程是在branch模块进行的,不是经过ALU模块)
3.alu_ctrl:四位,控制ALU模块运算类型的信号,具体如下:

(ps:load型指令即lb,lh,lw,lbu,lhu)


与存储器模块相关:
1.dm_rd_ctrl:三位,指明数据存储器读方式。具体如下:

2.dm_wr_ctrl:两位,指明数据存储器写方式。具体如下:

输入格式

32位的指令inst

输出格式

1.位宽为1bit的rf_wr_en:寄存器堆的写使能信号 2.位宽为2bit的rf_wr_sel:输入寄存器堆的数据的选择信号 3.位宽为1bit的do_jump:无条件跳转信号 4.位宽为3bit的BrType:分支指令类型的控制信号 5.位宽为1bit的alu_a_sel:ALU模块SrcA端口的选择信号 6.位宽为1bit的alu_b_sel:ALU模块SrcB端口的选择信号 7.位宽为4bit的alu_ctrl:ALU模块运算类型的控制信号 8.位宽为3bit的dm_rd_ctrl:存储器读类型的控制信号 9.位宽为2bit的dm_wr_ctrl:存储器写类型的控制信号

代码

module top_module(
input     [31:0]  inst,
output            rf_wr_en,
output reg    [1:0]   rf_wr_sel,
output            do_jump,
output reg    [2:0]   BrType,
output            alu_a_sel,
output            alu_b_sel,
output reg    [3:0]   alu_ctrl,
output reg    [2:0]   dm_rd_ctrl,
output reg    [1:0]   dm_wr_ctrl
);
wire    [6:0]   opcode;
wire    [2:0]   funct3;
wire    [6:0]   funct7;

wire    is_lui;
wire    is_auipc;
wire    is_jal;
wire    is_jalr;
wire    is_beq;
wire    is_bne;
wire    is_blt;
wire    is_bge;
wire    is_bltu;
wire    is_bgeu;
wire    is_lb;
wire    is_lh;
wire    is_lw;
wire    is_lbu;
wire    is_lhu;
wire    is_sb;
wire    is_sh;
wire    is_sw;
wire    is_addi;
wire    is_slti;
wire    is_sltiu;
wire    is_xori;
wire    is_ori;
wire    is_andi;
wire    is_slli;
wire    is_srli;
wire    is_srai;
wire    is_add;
wire    is_sub;
wire    is_sll;
wire    is_slt;
wire    is_sltu;
wire    is_xor;
wire    is_srl;
wire    is_sra;
wire    is_or;
wire    is_and;

wire    is_add_type;
wire    is_u_type;
wire    is_jump_type;
wire    is_b_type;
wire    is_r_type;
wire    is_i_type;
wire    is_s_type;

assign  opcode  = inst[6:0];
assign  funct7  = inst[31:25];
assign  funct3  = inst[14:12];

assign  is_lui  = (opcode == 7'h37) ;
assign  is_auipc= (opcode == 7'h17) ;
assign  is_jal  = (opcode == 7'h6F) ;
assign  is_jalr = (opcode == 7'h67) && (funct3 ==3'h0) ;
assign  is_beq  = (opcode == 7'h63) && (funct3 ==3'h0) ;
assign  is_bne  = (opcode == 7'h63) && (funct3 ==3'h1) ;
assign  is_blt  = (opcode == 7'h63) && (funct3 ==3'h4) ;
assign  is_bge  = (opcode == 7'h63) && (funct3 ==3'h5) ;
assign  is_bltu = (opcode == 7'h63) && (funct3 ==3'h6) ;
assign  is_bgeu = (opcode == 7'h63) && (funct3 ==3'h7) ;
assign  is_lb   = (opcode == 7'h03) && (funct3 ==3'h0) ;
assign  is_lh   = (opcode == 7'h03) && (funct3 ==3'h1) ;
assign  is_lw   = (opcode == 7'h03) && (funct3 ==3'h2) ;
assign  is_lbu  = (opcode == 7'h03) && (funct3 ==3'h4) ;
assign  is_lhu  = (opcode == 7'h03) && (funct3 ==3'h5) ;
assign  is_sb   = (opcode == 7'h23) && (funct3 ==3'h0) ;
assign  is_sh   = (opcode == 7'h23) && (funct3 ==3'h1) ;
assign  is_sw   = (opcode == 7'h23) && (funct3 ==3'h2) ;
assign  is_addi = (opcode == 7'h13) && (funct3 ==3'h0) ;
assign  is_slti = (opcode == 7'h13) && (funct3 ==3'h2) ;
assign  is_sltiu= (opcode == 7'h13) && (funct3 ==3'h3) ;
assign  is_xori = (opcode == 7'h13) && (funct3 ==3'h4) ;
assign  is_ori  = (opcode == 7'h13) && (funct3 ==3'h6) ;
assign  is_andi = (opcode == 7'h13) && (funct3 ==3'h7) ;
assign  is_slli = (opcode == 7'h13) && (funct3 ==3'h1) && (funct7 == 7'h00);
assign  is_srli = (opcode == 7'h13) && (funct3 ==3'h5) && (funct7 == 7'h00);
assign  is_srai = (opcode == 7'h13) && (funct3 ==3'h5) && (funct7 == 7'h20);
assign  is_add  = (opcode == 7'h33) && (funct3 ==3'h0) && (funct7 == 7'h00);
assign  is_sub  = (opcode == 7'h33) && (funct3 ==3'h0) && (funct7 == 7'h20);
assign  is_sll  = (opcode == 7'h33) && (funct3 ==3'h1) && (funct7 == 7'h00);
assign  is_slt  = (opcode == 7'h33) && (funct3 ==3'h2) && (funct7 == 7'h00);
assign  is_sltu = (opcode == 7'h33) && (funct3 ==3'h3) && (funct7 == 7'h00);
assign  is_xor  = (opcode == 7'h33) && (funct3 ==3'h4) && (funct7 == 7'h00);
assign  is_srl  = (opcode == 7'h33) && (funct3 ==3'h5) && (funct7 == 7'h00);
assign  is_sra  = (opcode == 7'h33) && (funct3 ==3'h5) && (funct7 == 7'h20);
assign  is_or   = (opcode == 7'h33) && (funct3 ==3'h6) && (funct7 == 7'h00);
assign  is_and  = (opcode == 7'h33) && (funct3 ==3'h7) && (funct7 == 7'h00);

assign  is_add_type = is_auipc | is_jal | is_jalr | is_b_type | is_s_type 
                    | is_lb | is_lh | is_lw | is_lbu | is_lhu | is_add | is_addi ;
assign  is_u_type   = is_lui | is_auipc ;
assign  is_jump_type= is_jal ;
assign  is_b_type   = is_beq | is_bne | is_blt | is_bge | is_bltu | is_bgeu ;
assign  is_r_type   = is_add | is_sub | is_sll | is_slt | is_sltu | is_xor 
                    | is_srl | is_sra | is_or | is_and ;
assign  is_i_type   = is_jalr | is_lb | is_lh | is_lw | is_lbu | is_lhu 
                    | is_addi | is_slti | is_sltiu | is_xori | is_ori | is_andi
                    | is_slli | is_srli | is_srai ;
assign  is_s_type   = is_sb | is_sh | is_sw ;
//rf_wr_en  
assign rf_wr_en     =  is_u_type|is_jump_type|is_i_type|is_r_type;  /*待填*/ 
  
//[1:0]rf_wr_sel
always@(*)
begin
     /*待填*/
    if(is_jalr|is_jal)
       rf_wr_sel=2'b01;
    else if(is_addi | is_slti | is_sltiu | is_xori | is_ori | is_andi
                    | is_slli | is_srli | is_srai|is_r_type|is_u_type)
        rf_wr_sel=2'b10;
     else if(is_lb | is_lh | is_lw | is_lbu | is_lhu)
          rf_wr_sel=2'b11;
    else
        rf_wr_sel=2'b00;
end  
  
//do_jump
assign do_jump      =   is_jump_type|is_jalr|is_jal;/*待填*/
  
//[2:0]BrType
always@(*)
begin
    case({is_beq, is_bne, is_blt, is_bge, is_bltu, is_bgeu})
      	6'b100000:  BrType=3'b010;
        6'b010000:  BrType=3'b011;
        6'b001000:  BrType=3'b100;
        6'b000100:  BrType=3'b101;
        6'b000010:  BrType=3'b110;
        6'b000001:  BrType=3'b111;
        6'b000000:  BrType=3'b000;       
    endcase
end
  
//alu_a_sel
assign alu_a_sel    =  is_s_type|is_i_type|is_r_type;/*待填*/

//alu_b_sel  
assign alu_b_sel    = ~is_r_type ;/*待填题干要求是R型实际波形是反的*/
  
//alu_ctrl
always@(*)
begin
     /*待填*/
    case({(is_auipc|is_jal|is_jalr|is_b_type|is_s_type|is_lb|is_lh|is_lw|is_lbu|is_lhu|is_add|is_addi),is_sub,(is_sll|is_slli),(is_srl|is_srli),(is_sra|is_srai),(is_slt|is_slti),(is_sltu|is_sltiu),(is_xor|is_xori),(is_or|is_ori),(is_and|is_andi),is_lui})
      	11'b10000000000:  alu_ctrl=4'b0000;
        11'b01000000000:  alu_ctrl=4'b1000;
        11'b00100000000:  alu_ctrl=4'b0001;
        11'b00010000000:  alu_ctrl=4'b0101;
        11'b00001000000:  alu_ctrl=4'b1101;
        11'b00000100000:  alu_ctrl=4'b0010;
        11'b00000010000:  alu_ctrl=4'b0011;
        11'b00000001000:  alu_ctrl=4'b0100;
        11'b00000000100:  alu_ctrl=4'b0110;
        11'b00000000010:  alu_ctrl=4'b0111;
        11'b00000000001:  alu_ctrl=4'b1110;   
    endcase
end
  
//[2:0]dm_rd_ctrl
always@(*)
begin
     /*待填*/
    case({is_lb,is_lbu,is_lh,is_lhu,is_lw})
      	5'b10000:  dm_rd_ctrl=3'b001;
        5'b01000:  dm_rd_ctrl=3'b010;
        5'b00100:  dm_rd_ctrl=3'b011;
        5'b00010:  dm_rd_ctrl=3'b100;
        5'b00001:  dm_rd_ctrl=3'b101;
        default:dm_rd_ctrl=3'b000;
    endcase
end

//[1:0]dm_wr_ctrl
always@(*)
begin
    /*待填*/
    case({is_sb,is_sh,is_sw})
      	3'b100:  dm_wr_ctrl=2'b01;
        3'b010:  dm_wr_ctrl=2'b10;
        3'b001:  dm_wr_ctrl=2'b11;
        default:dm_wr_ctrl=2'b00;
    endcase
end  
endmodule

Q107 RISC-V单周期CPU

题目描述

我们先后完成了寄存器堆模块,程序计数器模块,立即数扩展模块,分支跳转模块,ALU模块,存储器模块,控制器模块的verilog代码,在这个题目中,我们只需要在顶层模块调用子模块(定义子模块的文件已经存在于OJ系统的后台中了),就可以实现单周期的CPU了。

输入格式

1.时钟周期clk 2.复位键rst

输出格式

代码

module top_module(
input clk,
input rst
);
wire        clk;
wire        rst;
wire    [31:0]  inst;

wire    [1:0]   rf_wr_sel;
reg     [31:0]  rf_wd;  
wire            rf_wr_en;
wire    [31:0]  rf_rd1,rf_rd2;
  
wire [31:0] pc;
wire [31:0] pc_plus4;
wire do_jump;
wire JUMP;
  
wire    [31:0]  imm_out;
  
wire    [2:0]   comp_ctrl;
wire		BrE;

wire            alu_a_sel;
wire            alu_b_sel;
wire    [31:0]  alu_a,alu_b,alu_out; 
wire    [3:0]   alu_ctrl;
  
wire    [2:0]   dm_rd_ctrl;
wire    [1:0]   dm_wr_ctrl;
wire    [31:0]  dm_dout;
  
always@(*)
begin
    case(rf_wr_sel)
    2'b00:  rf_wd = 32'h0;
    2'b01:  rf_wd = pc_plus4;
    2'b10:  rf_wd = alu_out;
    2'b11:  rf_wd = dm_dout;
    default:rf_wd = 32'h0;
    endcase
end
assign		pc_plus4 = pc + 32'h4;
assign		JUMP = BrE || do_jump;
assign      alu_a = alu_a_sel ? rf_rd1 : pc ;
assign      alu_b = alu_b_sel ? imm_out : rf_rd2 ;

reg_file reg_file0(
	.clk        (clk),
    .A1         (inst[19:15]),//rs1
    .A2         (inst[24:20]),//rs2
    .A3         (inst[11:7]),//rd
	.WD         (rf_wd),
    .WE         (rf_wr_en),//1位使能信号,连接到寄存器堆的写使能端口(WE)
	.RD1        (rf_rd1),
	.RD2        (rf_rd2)
);
pc	pc0(
	.clk        (clk),
	.rst		(rst),
    .JUMP		(JUMP),
    .JUMP_PC    (alu_out),//应该有问题
	.pc         (pc)
);
imm	imm0(
	.inst		(inst),
	.out    	(imm_out)
);
branch branch0(
    .REG1		(rf_rd1),//寄存器的输出
    .REG2		(rf_rd2),//寄存器的输出
    .Type		(comp_ctrl),//接控制器的输出
 	.BrE		(BrE)
);
alu alu0(
    .SrcA     	(alu_a),
	.SrcB      	(alu_b),
    .func   	(alu_ctrl),//运算控制
	.ALUout    	(alu_out)
);
mem mem0(
	.clk        (clk),
    .im_addr    (pc),//输入应该是PC
    .im_dout    (inst),//输出指令
	.dm_rd_ctrl (dm_rd_ctrl),
	.dm_wr_ctrl (dm_wr_ctrl),
    .dm_addr    (alu_out),//一般接ALU的结果
    .dm_din     (rf_rd2),//一般接寄存器
    .dm_dout    (dm_dout)//给寄存器输入选择器
);
ctrl ctrl0(
	.inst       (inst),
	.rf_wr_en   (rf_wr_en),
    .rf_wr_sel  (rf_wr_sel),
	.do_jump    (do_jump),
    .BrType		(comp_ctrl),//输出给分支控制
	.alu_a_sel  (alu_a_sel),
    .alu_b_sel  (alu_b_sel),
	.alu_ctrl   (alu_ctrl),
	.dm_rd_ctrl (dm_rd_ctrl),
	.dm_wr_ctrl (dm_wr_ctrl)
);

endmodule

  • 21
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值