中科大OJ Verilog 在线评测题解 100-105

这篇具有很好参考价值的文章主要介绍了中科大OJ Verilog 在线评测题解 100-105。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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

Q62-99

题在哪儿

Q100 寄存器堆模块

题目描述

在RV32I中,寄存器堆指32个通用寄存器的集合,具有专门的读写端口,可并发访问不同寄存器。
中国科学技术大学用什么oj,fpga开发
我们用5位数代表寄存器的端口号,需要注意的是:当待写入寄存器端口号为0时,往x0写入的数据总是被丢弃,因为x0寄存器恒为0,不能对x0寄存器的值进行修改。设置x0寄存器,既可以提供常量0(比如RISC-V用sub rd, x0, rs来实现neg取负数指令),也可以提供一个可以丢弃结果的场所(比如RISC-V使用addi x0, x0, 0实现nop空指令)。
中国科学技术大学用什么oj,fpga开发
当A1有意义时,其对应指令中的rs1,即第15到19位;同理,当有意义时,A2对应指令中的rs2,即第20到24位;A3对应指令中的rd,即第7到11位。

输入格式

1.时钟信号clk 2.位宽为5的待读取寄存器端口号A1 3.位宽为5的待读取寄存器端口号A2 4.位宽为5的待写入寄存器端口号A3 5.位宽为32的待写入数据WD 6.位宽为1的寄存器写使能信号WE

输出格式

1.位宽为32的从A1对应的寄存器中读出的数据RD1 2.位宽为32的从A2对应的寄存器中读出的数据RD2

代码

module top_module(
input         clk,
input  [4:0]  A1,A2,A3,
input  [31:0] WD,
input 	      WE,
output [31:0] RD1,RD2
);
reg [31:0] reg_file[0:31];
//初始化寄存器堆
integer i;
initial
begin
    for(i=0;i<32;i=i+1) reg_file[i] = 0;
end

//写入寄存器
always@(posedge clk)
begin
	/*待填*/
    if(WE&A3!=0) //A3==0的情况排除?X0一直为0
        reg_file[A3]= WD;
    else ;
end

//读取寄存器
    assign RD1 = reg_file[A1]/*待填*/;
    assign RD2 = reg_file[A2]/*待填*/;

endmodule

Q101 程序计数器模块

题目描述

当执行一条指令时,首先需要根据PC中存放的指令地址,将指令由内存取到指令寄存器中,此过程称为取指。

PC全称ProgramCounter(程序计数器),它是计算机处理器中的寄存器,包含当前正在执行的指令的地址。

中国科学技术大学用什么oj,fpga开发
一般情况下,当指令被获取,程序计数器存储的地址加四(一条指令有32位,为4字节)。当遇到跳转指令(jal,jalr)或者满足分支跳转指令(所有B类指令)的跳转条件时,则将程序计数器的内容设置为转移指令规定的地址。

输入格式

1.时钟信号clk 2.复位键rst,当rst为1时将PC置零 3.位宽为1的跳转信号JUMP,当JUMP为1时将PC设为JUMP_PC 4.位宽为32的待跳转的地址JUMP_PC

输出格式

位宽为32的当前周期需要执行指令的地址pc

代码

module top_module(
input              clk,
input              rst,
input              JUMP,
input       [31:0] JUMP_PC,
output reg  [31:0] pc);
wire [31:0] pc_plus4;
assign pc_plus4 = pc + 32'h4;
//计算PC
always@(posedge clk or posedge rst)
begin
	/*待填*/
    if(rst)
       pc<=0;
    else if(JUMP)
        pc<=JUMP_PC;
    else
         pc<=pc_plus4;
        
end
endmodule

Q102 立即数扩展模块

题目描述

中国科学技术大学用什么oj,fpga开发
通过上图可知,不同类型的指令,立即数的位置不同,我们需要从原始的指令中提取出顺序正确的立即数,并依照指令的类型对立即数做相应扩展。
通过了解各指令的具体作用和指令格式,我们能得到下表:
中国科学技术大学用什么oj,fpga开发
注:符号位扩展就是对不足32位的数,在高位扩展符号位至32位的操作(符号位是1则填1,符号位为0则填0)

输入格式

位宽为32的指令inst

输出格式

经过扩展的32位立即数out

代码

module top_module(
input 	    [31:0] inst,
output reg	[31:0] out
);
wire	[6:0] opcode;
assign	opcode= inst[6:0];
//立即数扩展
always@(*)
begin
	case(opcode)
          /*待填*/
        7'b0010111:out<={inst[31:12],12'b0};
        7'b0110111:out<={inst[31:12],12'b0};
        7'b1100011:out<={{20{inst[31]}},inst[7],inst[30:25],inst[11:8],1'b0};
        7'b1101111:out<={{12{inst[31]}},inst[19:12],inst[20],inst[30:21],1'b0};
        7'b1100111:out<={{12{inst[31]}},inst[19:12],inst[20],inst[30:21],1'b0};
        7'b0000011:out<={{20{inst[31]}},inst[31:20]};
        7'b0100011:out<={{20{inst[31]}},inst[31:25],inst[11:7]};
        7'b0010011:out<={{20{inst[31]}},inst[31:20]};
        default:out<=32'h0;
	endcase
end 
endmodule

Q103 分支判断模块

题目描述

RV32I基础指令集中提供了6条B型指令,分支判断模块负责判断跳转条件是否满足,需要分支跳转时产生分支信号。
中国科学技术大学用什么oj,fpga开发
如上图,Type是代表不同比较类型的3位编码,其与输入输出的关系如下表:
中国科学技术大学用什么oj,fpga开发
注:Type并不等价于B类指令中的funct3(功能码),只是控制器处理指令后输出的一个信号。因为beq的funct3为000,而我们在编写代码时,把0作为默认值;当信号为0时,我们不做操作,这样可以有利于增强代码的容错率。

输入格式

1.位宽为32的(从寄存器中读取的)待比较数REG1 2.位宽为32的(从寄存器中读取的)待比较数REG2 3.位宽为3的Type,用于区分两个待比较数比较的类型

输出格式

位宽为1的分支跳转信号BrE

代码

module top_module(         
input [31:0]	REG1,
input [31:0] 	REG2,
input [2:0]		Type,
output     reg     BrE
);
wire signed 	[31:0] signed_REG1;
wire signed 	[31:0] signed_REG2;
wire unsigned 	[31:0] unsigned_REG1;
wire unsigned 	[31:0] unsigned_REG2;

assign signed_REG1 = REG1;
assign signed_REG2 = REG2; 
assign unsigned_REG1 = REG1;
assign unsigned_REG2 = REG2; 
always@(*)
begin
	case(Type)
    	/*待填*/ 
        3'b010:BrE<=(signed_REG1==signed_REG2?1:0);
        3'b011:BrE<=(signed_REG1!=signed_REG2?1:0);
        3'b100:BrE<=(signed_REG1<signed_REG2?1:0);
        3'b101:BrE<=(signed_REG1>=signed_REG2?1:0);
        3'b110:BrE<=(unsigned_REG1<unsigned_REG2?1:0);
        3'b111:BrE<=(unsigned_REG1>=unsigned_REG2?1:0);
        default:BrE<=1'b0;
	endcase
end
endmodule

Q104 ALU模块

题目描述

ALU全称Arithmetic and Logic Unit,即算数逻辑单元,是数字计算机中执行加、减等算术运算,执行与、或等逻辑运算,以及执行比较、移位、传送等操作的功能部件。
中国科学技术大学用什么oj,fpga开发
ALU模块如上图,其中func是区分操作类型的4位编码,其与输入输出的对应如下表:
中国科学技术大学用什么oj,fpga开发
注:上表只是一种设计,设计不唯一

输入格式

1.位宽为32的源操作数SrcA 2.位宽为32的源操作数SrcB 3.位宽为4的func,用于区分操作类型

输出格式

位宽为32的运算结果ALUout

代码

module top_module(
input [31:0] SrcA,SrcB,
input [3:0]  func,
output reg [31:0] ALUout
);

wire signed [31:0] signed_a;
wire signed [31:0] signed_b;
wire unsigned 	[31:0] unsigned_a;
wire unsigned 	[31:0] unsigned_b;

assign unsigned_a = SrcA;
assign unsigned_b = SrcB; 
assign signed_a = SrcA;
assign signed_b = SrcB;

always@(*)
begin
  case(func)
		/*待填*/
      4'b0000:ALUout<=signed_a+signed_b;
      4'b1000:ALUout<=signed_a-signed_b;
      4'b0001:ALUout<=signed_a<<signed_b[4:0];
      4'b0010:ALUout<=signed_a<signed_b?1:0;
      4'b0011:ALUout<=unsigned_a<unsigned_b?1:0;
      4'b0100:ALUout<=signed_a^signed_b;
      4'b0101:ALUout<=signed_a>>signed_b[4:0];
      4'b1101:ALUout<=signed_a>>>signed_b[4:0];
      4'b0110:ALUout<=signed_a|signed_b;
      4'b0111:ALUout<=1'b0;
      4'b1001:ALUout<=1'b0;
      4'b1010:ALUout<=1'b0;
      4'b1011:ALUout<=1'b0;
      4'b1100:ALUout<=1'b0;
      4'b1110:ALUout<=signed_b;
      4'b1111:ALUout<=1'b0;
	endcase
end 

endmodule

Q105 存储器

题目描述

存储器模块包括指令存储器和数据存储器,其中指令存储器用于存放指令,只读;数据存储器用于存放数据,可读可写;指令存储器按字节编址,按字读取;数据存储器按字节编址,可以完成对字、半字、字节的对齐存取。
中国科学技术大学用什么oj,fpga开发
因为指令存储器的容量有限(本实验中为16KB,可存储4K条指令),指令长度为32bit(即4B),因此为了判断地址是否有效,我们需要判断im_addr的31至14位以及1至0位是否为0。当im_addr有效时,im_dout输出地址对应的指令,否则输出全0。
中国科学技术大学用什么oj,fpga开发
区分读取类型的3位信号dm_rd_ctrl与读取类型的关系如下:
中国科学技术大学用什么oj,fpga开发
区分写入类型的2位信号dm_wr_ctrl与写入类型的关系如下:
中国科学技术大学用什么oj,fpga开发
数据写入时,由于需要对齐,数据不能跨字(即不能跨越两个32bit的单元)。在代码中,我们采用了四位的辅助信号byte_en,对于待覆写的32bit的单元mem[dm_addr[13:2]],我们可以把其看作四个一字节(8bit)宽度的单位,对应byte_en的四位,对应位为1表示该字节需要覆写,反之不需要,具体如下:
中国科学技术大学用什么oj,fpga开发
本系列实验使用哈佛体系结构设计,指令和数据分开存储,但地址空间是重叠的,所以设计verilog代码时可以合并成一个模块。

输入格式

1.位宽为32bit的地址im_addr 2.位宽为32bit的地址dm_addr 3.位宽为32bit的写入数据dm_din 4.区分读取类型的3位信号dm_rd_ctrl 5.区分写入类型的2位信号dm_wr_ctrl;

输出格式

1.位宽为32bit的指令im_dout 2.位宽为32bit的读出数据dm_dout文章来源地址https://www.toymoban.com/news/detail-780395.html

代码

module top_module(
input           clk,
input   [31:0]  im_addr,
output  [31:0]  im_dout,
input   [2:0]   dm_rd_ctrl,
input   [1:0]   dm_wr_ctrl,
input   [31:0]  dm_addr,
input   [31:0]  dm_din,
output reg  [31:0]  dm_dout
);

reg     [3:0]   byte_en;
reg     [31:0]  mem[0:4095];
reg     [31:0]  mem_out;
integer i;

initial
begin
    for(i=0;i<4095;i=i+1) mem[i] = 0;
end

initial
begin
  $readmemh("./problem/inst.dat",mem);
end

    assign im_dout = ((|im_addr[31:14]==0) &(|im_addr[1:0]==0))?mem[im_addr[13:2]]:32'b0;/*待填*/
//由于不能跨单位读取数据,地址最低两位的数值决定了当前单位能读取到的数据,即mem_out
always@(*)
begin
    case(dm_addr[1:0])
        2'b00:  mem_out = mem[dm_addr[13:2]][31:0];
        2'b01:  mem_out = {8'h0,mem[dm_addr[13:2]][31:8]};
        2'b10:  mem_out = {16'h0,mem[dm_addr[13:2]][31:16]};
        2'b11:  mem_out = {24'h0,mem[dm_addr[13:2]][31:24]};
    endcase
end

always@(*)
begin
    case(dm_rd_ctrl)                                         
    /*待填*/
        3'b001:  dm_dout = {{24{mem_out[7]}},mem_out[7:0]};
        3'b010:  dm_dout = {24'h0,mem_out[7:0]};
        3'b011:  dm_dout = {{16{mem_out[15]}},mem_out[15:0]};
        3'b100:  dm_dout = {16'h0,mem_out[15:0]};
    	3'b101:	 dm_dout = mem_out;
    	default:  dm_dout=32'b0;  
    endcase
end

always@(*)
begin
    if(dm_wr_ctrl == 2'b11)
        byte_en = 4'b1111;
    else if(dm_wr_ctrl == 2'b10)
    begin
        if(dm_addr[1] == 1'b1) 
            byte_en = 4'b1100;
        else
            byte_en = 4'b0011;
    end
    else if(dm_wr_ctrl == 2'b01)
    begin
        case(dm_addr[1:0])
        2'b00:  byte_en = 4'b0001;
        2'b01:  byte_en = 4'b0010;
        2'b10:  byte_en = 4'b0100;
        2'b11:  byte_en = 4'b1000;
        endcase
    end
    else
        byte_en = 4'b0000;
end

always@(posedge clk)
begin
    if((byte_en != 1'b0)&&(dm_addr[30:12]==19'b0))
    begin
        case(byte_en)
        	/*待填*/
            4'b0001:  mem[dm_addr[13:2]][7:0] =dm_din[7:0];
            4'b0010:  mem[dm_addr[13:2]][15:8] =dm_din[15:8];
            4'b0100:  mem[dm_addr[13:2]][24:16] =dm_din[24:16];
            4'b1000:  mem[dm_addr[13:2]][31:17] =dm_din[31:17];
            4'b0011:  mem[dm_addr[13:2]][15:0] =dm_din[15:0];
            4'b1100:  mem[dm_addr[13:2]][31:16] =dm_din[31:16];
            4'b1111:  mem[dm_addr[13:2]] =dm_din;
			default:  ;
        endcase
    end
end
endmodule

到了这里,关于中科大OJ Verilog 在线评测题解 100-105的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包