杭电计算机组成原理课程设计-实验十一-实现R型指令的CPU设计实验_平平无奇马中伞的博客-程序员秘密_杭电计组r型cpu

技术标签: 杭电计算机组成原理课程设计  

实验内容

选以下4种系统结构之一,设计一个MIPS单周期R-CPU
(1)不带状态寄存器,8条指令
(2)带状态寄存器,8条指令
(3)不带状态寄存器,9条指令(多了sll)
(4)带状态寄存器,9条指令(多了sll)
本文选取第4种结构进行设计

具体步骤

  1. 修改寄存器堆模块,以使$0 内容恒置全零,只读。
  2. 根据所选指令系统,修改ALU模块
  3. 编写测试的汇编程序,准备验收文档(汇编、机器代码、结果)
  4. 设计取指令模块 用IP核重新设计(建议)
  5. 设计R-CPU主模块,完成各部件连接和指令译码控制单元的实现。
  6. 编写仿真测试代码,仿真验收

实验原理

在这里插入图片描述
实验流程图
在这里插入图片描述
R型指令的控制信号
在这里插入图片描述

汇编指令与.coe文件

汇编指令设计表格
地址 机器代码 汇编指令 执行结果
[0x00400000] 0x00004827 nor $9, $0, $0 R9 (t1) = ffffffff
[0x00400004] 0x0009502b sltu $10, $0, $9 R10 (t2) = 00000001
[0x00400008] 0x012a5822 sub $11, $9, $10 R11 (t3) = fffffffe
[0x0040000c] 0x012b6022 sub $12, $9, $11 R12 (t4) = 00000001
[0x00400010] 0x014c6820 add $13, $10, $12 R13 (t5) = 00000002
[0x00400014] 0x01a97004 sllv $14, $9, $13 R14 (t6) = fffffffc
[0x00400018] 0x01ad7804 sllv $15, $13, $13 R15 (t7) = 00000008
[0x0040001c] 0x01eac020 add $24, $15, $10 R24 (t8) = 00000009
[0x00400020] 0x030bc825 or $25, $24, $11 R25 (t9) = ffffffff
[0x00400024] 0x01798826 xor $17, $11, $25 R17 (s1) = 00000001
[0x00400028] 0x01d89024 and $18, $14, $24 R18 (s2) = 00000008
[0x0040002c] 0x02299820 add $19, $17, $9 R19 (s3) = 00000000
[0x00400030] 0x0253a025 or $20, $18, $19 R20 (s4) = 00000008
[0x00400034] 0x01b1a804 sllv $21, $17, $13 R21 (s5) = 00000004
[0x00400038] 0x02b1b004 sllv $22, $17, $21 R22 (s6) = 00000010
[0x0040003c] 0x016eb820 add $23, $11, $14 R23 (s7) = fffffffa
[0x00400040] 0x0009f880 sll $31, $9, 2 R31 (ra) = fffffffc

.coe文件内容

memory_initialization_radix=16;
memory_initialization_vector=00004827,0009502b,012a5822,012b6022,014c6820,01a97004,01ad7804,01eac020,030bc825,01798826,01d89024,02299820,0253a025,01b1a804,02b1b004,016eb820,0009f880,00000820,00010fff,20006789,ffff0000,0000ffff,88888888,99999999,aaaaaaaa,bbbbbbbb,12345678,23456789,3456789a,456789ab,56789abc,6789abcd,00000820,00632020,00010fff,20006789,ffff0000,0000ffff,88888888,99999999,aaaaaaaa,bbbbbbbb,12345678,23456789,3456789a,456789ab,56789abc,6789abcd,00000820,00632020,00010fff,20006789,ffff0000,0000ffff,88888888,99999999,aaaaaaaa,bbbbbbbb,12345678,23456789,3456789a,456789ab,56789abc,6789abcd;

.coe文件内容由汇编语言翻译而来,详情见 MIPS汇编器与模拟器实验
根据.coe文件创建IP核,IP核的创建详情见 ISE IP核创建教程

功能模块说明

module R_CPU(
	clk,rst,
    Inst_code,PC,
    opcode,rs,rt,rd,shamt,func,
	ALU_F,FR_ZF,FR_OF,ALU_OP,
	rs_shamt,ALU_A
    );
	 input clk;//时钟
     input rst;//清零
	 output reg [31:0]PC;//PC地址
     output [31:0]Inst_code;//取出的指令
     output [5:0]opcode,func;//指令分段
	 output [4:0]rs,rt,rd,shamt;//指令分段
	 output [31:0] ALU_F;//ALU结果
	 output reg [2:0] ALU_OP;//ALU运算的OP
	 output reg FR_ZF; //ZF储存结果
	 output reg FR_OF;//OF储存结果
	 output  [31:0]ALU_A; //ALU运算时A的数据
	 output reg rs_shamt; //控制ALU的A输入数据的信号
module REGS(R_Data_A,R_Data_B,W_Data,R_Addr_A,R_Addr_B,W_Addr,Write_Reg,rst,clk);
	input clk;//写入时钟信号
    input rst;//清零信号
    input Write_Reg;//写控制信号
    input [4:0]R_Addr_A;//A端口读寄存器地址
    input [4:0]R_Addr_B;//B端口读寄存器地址
    input [4:0]W_Addr;//写寄存器地址
    input [31:0]W_Data;//写入数据
	output [31:0]R_Data_A;//A端口读出数据
    output [31:0]R_Data_B;//B端口读出数据
module ALU(ALU_OP,A,B,F,ZF,OF);
	  input  [2:0] ALU_OP;//控制ALU运算类型的OP
	  input  [31:0] A;    //ALU运算数据A
	  input  [31:0] B;    //ALU运算数据B
	  output [31:0] F;    //ALU运算结果F
	  output  ZF;		  //零标志位
	  output  OF;		  //溢出标志位

逻辑引脚图

在这里插入图片描述

仿真时序波形图

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
Inst_code表示当前OP地址中的指令
PC表示当前OP地址
Opcode,rs,rt,rd,shamt,func皆为指令分段
ALU_F为ALU运算结果
FR_ZF,FR_OF储存ALU运算得出的ZF,OF
ALU_OP为当前ALU运算的操作码
Rs_shamt控制当前是否使用shamt进行移位
ALU_A为当前ALU的A口输入数据
Clk为时钟信号,rst为复位信号

R-I CPU 完整代码

module R_CPU(
	clk,rst,
    Inst_code,PC,
    opcode,rs,rt,rd,shamt,func,
	ALU_F,FR_ZF,FR_OF,ALU_OP,
	rs_shamt,ALU_A
    );
	input clk;//时钟
    input rst;//清零
	output reg [31:0]PC;//地址
    wire [31:0]PC_new;
    output [31:0]Inst_code;//取出的指令
    output [5:0]opcode,func;//指令分段
    output [4:0]rs,rt,rd,shamt;//指令分段
	 wire [15:0]imm,offset;//指令分段
	 wire [25:0]address;//指令分段
     output [31:0] ALU_F;//ALU结果
	 output reg [2:0] ALU_OP;//ALU结果
	 output reg FR_ZF;
	 output reg  FR_OF;
	 wire ZF,OF;
	 output  [31:0]ALU_A;
	 reg Write_Reg;
	 wire [31:0]R_Data_A;
	 wire [31:0]R_Data_B;
	 reg Set_ZF;
	 reg Set_OF;
	 wire [31:0]shamt_kz;
	 output reg rs_shamt;
	 
	 assign shamt_kz={
    {
    16{
    1'b0}},shamt};
	 initial PC = 32'h00000000;
	 assign PC_new = PC + 4;
	 

Inst_Rom ROM2 (
  .clka(clk), // input clka
  .addra(PC[7:2]), // input [5 : 0] addra
  .douta(Inst_code) // output [31 : 0] douta
);
	always @(negedge clk or posedge rst)
  begin
	if (rst)
		PC = 32'h00000000; //PC复位;
	else
		PC = PC_new; //PC更新为PC+4;
end;

	assign opcode =  Inst_code[31:26];
	assign rs =  Inst_code[25:21];
	assign rt =  Inst_code[20:16];
	assign rd=  Inst_code[15:11];
	assign shamt = Inst_code[10:6];
	assign func =  Inst_code[5:0];
	 
	 always @(*)
		begin
    ALU_OP = 3'b000;
    Write_Reg = 1'b0;
	rs_shamt=1'b0;
    if (opcode==6'b000000)    //R指令
     begin
		Write_Reg = 1'b1;   //结果送寄存器
	case (func) 
		6'b100000:begin ALU_OP=3'b100;Set_ZF=1;Set_OF=1; end
		6'b100010:begin ALU_OP=3'b101;Set_ZF=1;Set_OF=1; end
		6'b100100:begin ALU_OP=3'b000;Set_ZF=1;Set_OF=0; end
		6'b100101:begin ALU_OP=3'b001;Set_ZF=1;Set_OF=0; end
		6'b100110:begin ALU_OP=3'b010;Set_ZF=1;Set_OF=0; end
		6'b100111:begin ALU_OP=3'b011;Set_ZF=1;Set_OF=0; end
		6'b101011:begin ALU_OP=3'b110;Set_ZF=1;Set_OF=0; end
		6'b000100:begin ALU_OP=3'b111;Set_ZF=1;Set_OF=0; end
		6'b000000:begin ALU_OP=3'b111;Set_ZF=1;Set_OF=0;rs_shamt=1'b1; end
	endcase
    end
end;
	
	 REGS REGS_1(R_Data_A,R_Data_B,ALU_F,rs,rt,rd,Write_Reg,rst,~clk);
	 assign ALU_A = (rs_shamt)?shamt_kz:R_Data_A;
	 ALU ALU_1(ALU_OP,ALU_A,R_Data_B,ALU_F,ZF,OF);
	 
  always @(negedge clk or posedge rst)
  if (rst)
  begin
    FR_OF <= 1'b0;
	 FR_ZF <= 1'b0;
  end
  else
  begin
      if (Set_ZF) 
	   FR_ZF <= ZF;
      if (Set_OF)
	   FR_OF <= OF;
  end
endmodule

module REGS(R_Data_A,R_Data_B,W_Data,R_Addr_A,R_Addr_B,W_Addr,Write_Reg,rst,clk);
	input clk;//写入时钟信号
    input rst;//清零信号
    input Write_Reg;//写控制信号
    input [4:0]R_Addr_A;//A端口读寄存器地址
    input [4:0]R_Addr_B;//B端口读寄存器地址
    input [4:0]W_Addr;//写寄存器地址
    input [31:0]W_Data;//写入数据
	output [31:0]R_Data_A;//A端口读出数据
    output [31:0]R_Data_B;//B端口读出数据
	 
	 integer i;
	 reg [31:0] REG_Files[0:31];  
    initial
        for(i=0;i<32;i=i+1) REG_Files[i]<=0;
    [email protected](posedge clk or posedge rst)
    begin
        if(rst)
                for(i=0;i<32;i=i+1) REG_Files[i]<=0;
        else
                if(Write_Reg&&W_Addr!=32'd0) REG_Files[W_Addr]<=W_Data;
    end
    assign R_Data_A=REG_Files[R_Addr_A];
    assign R_Data_B=REG_Files[R_Addr_B];

endmodule

module ALU(ALU_OP,A,B,F,ZF,OF);
	  input  [2:0] ALU_OP;
	  input  [31:0] A;
	  input  [31:0] B;
	  output [31:0] F;
	  output  ZF;
	  output  OF;
	  reg [31:0] F;
	  reg    C,ZF;
	  
	 [email protected](*)
	  begin
		C=0;
		case(ALU_OP)
			3'b000:begin F=A&B; end
			3'b001:begin F=A|B; end
			3'b010:begin F=A^B; end
			3'b011:begin F=~(A|B); end 
			3'b100:begin {
    C,F}=A+B; end 
			3'b101:begin {
    C,F}=A-B; end 
			3'b110:begin F=A<B; end
			3'b111:begin F=B<<A; end
		endcase
		ZF = F==0;
		end
		assign OF = ((ALU_OP==3'b100)||(ALU_OP==3'b101))&&(A[31] ^ B[31] ^ F[31] ^ C); 
endmodule

测试用例代码

always #50 clk=~clk;
	initial begin
		// Initialize Inputs
		clk=0;
		rst=1;
		#5;
		rst = 0;
	end
endmodule

探索与思考(非标准答案)

  1. sll rd, rt, shamt 指令将 rt 寄存器的数据进行逻辑左移,左移的位数则是由字段shamt 指定。试着实现该指令,谈谈你的实现方法。
    答:加入rs_shamt信号,控制位移量是rs地址数据还是shamt。
    assign ALU_A = (rs_shamt)?shamt_kz:R_Data_A;
    ALU ALU_1(ALU_OP,ALU_A,R_Data_B,ALU_F,ZF,OF);
    在case(func)中加入:
    6’b000000:begin ALU_OP=3’b111;Set_ZF=1;Set_OF=0;rs_shamt=1’b1; end

  2. 本实验实现的 sltu 指令是对无符号数的比较置位指令,如果需要实现有符号数的比较置位指令——slt 指令,请问应该如何实现?
    答:若想实现有符号数的比较置位指令,可以先根据有符号数的最高位进行分类:
    若两正,则和无符号数比较置位无异,若一正一负,则可轻易得出结论。若两负,则将余下位数进行比较置位,再将结果取反即可。

  3. srav 是对(有符号)数据的算术右移指令,考虑如何实现它?
    答:读取数据符号位,设右移位数为n,从数据最右边开始,将其每一位覆盖为其左边n位的数的数值,当其左边n位数不存在时,改为复制符号位即可。

  4. 在所设计的CPU基础上,添加一个输入设备(逻辑开关)和一个输出设备(LED 灯),假如直接用指令来实现输入输出功能,输入指令 in 和输出指令 out 的格式也是 R 型指令,
    请画出修改后的系统结构图,并写出这两条指令对应令对应的控制信号。
    在这里插入图片描述
    在这里插入图片描述
    设IN和OUT的func分别为110000,110001
    输入输出对应的设备号由rs的低2位控制
    IO_R=1时,执行输入指令
    IO_W=1时,执行输出指令
    增加信号alu_IO_s,控制寄存器W_Data的写入数据。
    alu_IO_s=1时,数据由输入设备输入,为0时,数据由ALU运算结果输入。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_43971710/article/details/107497085

智能推荐

小程序酒店日历_qq_22718203的博客-程序员秘密

之前做了个时间日历比较简单的把,如果要加价格什么的也可以稍微看着加加,之前写过这样的一个博客,只不过那个照片太丑然后又有点变化,就重新写过了。如图那个时间点是入口。这个呢是未选中的样子。这个是选了连续的样式,这个是选了好多个时间的样式。其实还有些中间不可选的样式,只不过是调接口获取的,不过接口已经挂了所以就没办法显示出来了,大概就是有些已经满课的然后选的时间范围内有满课的就提示这个时间段不能选,接下来就是展示代码的时刻了。首先还是看view&lt;view class="page"..

iOS9 WKWebView清除缓存方法_天行哥哥的博客-程序员秘密

自iOS8以来新出的WKWebView,大大优化了UIWebView的内存飙升问题,使得开发者迫不及待的用它来替换掉UIWebView,iOS8刚出,作者我就赶紧把项目里的webView都替换成WKWebView了,然而....当我替换完后发现...我去!WKWebView并没有清除缓存的功能,即使使用了以下代码:NSHTTPCookie *cookie;NSHTTPCookieStorag

学习笔记-DOM解析和sax解析区别_liononon的博客-程序员秘密

DOM解析是把文档所有内容都加载进内存,解析成DOM树,有根节点(Element)、子孙节点,文本节点(Text),属性节点(Attr)。SAX解析是从上往下读一行解析一行,不能往回读。优缺点:DOM占用内存比较多,适合做CRUD(create,read,update,delete);SAX速度快,对内存几乎没压力,只适合做读操作。

http,https 请求配置代理的常见方式_https.proxy_天马行空-的博客-程序员秘密

常用的java 发送http请求的方式有两种1、通过HttpsURLConnection 自己去发送请求2、 用spring框架提供的RestTemplate (import org.springframework.web.client.RestTemplate;) 对象发送请求第一种方式配置代理服务器关键代码: int PROXY_PORT = 80;// 改成你自己的代理服务器端口 String PROXY_HOST = "127.0.0.1";// 改成你自己的代理...

曾国藩家训:三个地方看一个家庭的兴败_SAP剑客的博客-程序员秘密

第一看:  看子孙睡到几点,假如睡到太阳都已经升得很高的时候才起来,那代表这个家族会慢慢懈怠下来;  第二看:  看子孙有没有做家务,因为勤劳、劳动的习惯影响一个人一辈子;  第三看:  看后代子孙有没有在读圣贤的经典,"人不学,不知义,不知道"。  畅游史海,可以看到"盛不过三代"是大多数官宦之家很难逾越的魔咒。而曾氏家族却代有英才层出不穷,出现了

Weblogic 常见错误解决_weixin_34044273的博客-程序员秘密

为什么80%的码农都做不了架构师?&gt;&gt;&gt; ...

随便推点

在Ubuntu应用程序菜单中自行增加程序菜单项_denlee的博客-程序员秘密

今天下载了一个软件,解压后即可直接使用,可是每次都要到软件所在目录下执行,比较麻烦。于是看了看,发现可以在桌面增加启动器,这样就可以双击桌面的图标运行程序;但是如果能增加到应用程序菜单中,那就更方便了。研究了一下已有的desktop文件,找到了方法,以我下载的psq软件为例,我将下载的psq软件解压到/usr/share文件夹内。1、首先建立可执行(脚本)程序的连接到/usr/bin文件夹sudo

linux 行长度_如何在Linux中按长度对行进行排序?_cuma2369的博客-程序员秘密

linux 行长度I have a text file with many lines of text. 我有一个包含多行文本的文本文件。 In Linux, how to sort the lines by their length? 在Linux中 ,如何按行长排序? You can make use of awk together with the sort program like 您...

初识JVM--java虚拟机的基本知识_weixin_30318645的博客-程序员秘密

JVM运行时的内存块pc寄存器:(线程独有)保存线程运行的java方法地址Java 虚拟接栈(线程独有):用于存储线程的栈帧Java堆(全局共享):随着Java虚拟机的启动 创建 存储着所有对象的实例以及数组对象,而且内置gc(垃圾回收机制)方法区:运行常量池本地方法栈:线程独有。在jvm中gc(垃圾回收机制)是Java立足点之一。垃圾自动回收可以让Java程...

VBA--类与对象的简单理解_vba类和对像_OYQ697的博客-程序员秘密

1.首先我们打开VBA编程的界面,在工程资源管理器中右键添加类模块,并且命名为person,这样我们就创建了一个类2.接下来,我们要在类里面填加字段来保存内容,最好使用的是private,如果使用public所保存的内容就没有约束性Private sname As String '姓名Private sgender As String '性别Private sage As String '年龄3....

2019-05-13 使用X5制作页面调SpringBoot(EasyWeb)接口遇到的登录问题_weixin_33739541的博客-程序员秘密

【最初做法】1. 跟平时一样写Spring Boot的Controller2. X5页面使用Ajax调用3. 处理跨域请求问题【初步结果】第一个调用的是登录接口,没有问题第二个是查询列表,可是浏览器控制台打印的结果是EasyWeb中的登录页代码(也就是需要重新登录)【问题分析】打开Network查看请求信息可以看到的是后面的请求并没有带上cookie...

【重学maven】构建标准清晰地java工程_java构建maven工程_码不停Ti的博客-程序员秘密

文章目录intro构建工具:解放程序员的双手构建一个软件项目通常包含下面的一步或多步。Maven 的好处Maven 能够提供的信息如下。Maven的命根子pom.xml文件Maven 如何使用 POM 文件?POM 文件构建生命周期、构建阶段、构建目标依赖和仓库构建插件构建配置文件pom.xml文件案例Maven的目录结构Maven 的生命周期构建生命周期构建阶段构建目标Maven 项目快速创建使用「原型(Archetype)」快速 创建 Maven 项目运行 maven 项目Maven pom快速配置Ma

推荐文章

热门文章

相关标签