杭电计算机组成原理课程设计-实验十一-实现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

智能推荐

Hadoop、Hbase、Hive版本兼容性_hadoop3.34和hive3.1.3兼容吗_铭霏的博客-程序员秘密

装Spark的时候想当然的装了Hadoop的最新版 2.6.x结果后面再安装HBase和Hive的时候  遇到了 彼此无法兼容的问题  总有一个安装无法连接其他 ..现在记录一下这三者的关系

dbvisivuser连oracle数据库报错没有权限_zhaot1993的博客-程序员秘密

原因:数据库从11g升级为19c了解决:ojdbc.jar也要换成最新的,导致报错的旧jar包2M大小,换成新jar包3M大小。替换jar包要将 dbvisivuser的tool driverManager 的jar包加载项优先等级改一下。...

PHP后端接收javascript通过XMLHttpRequest提交json数据_achejq的博客-程序员秘密

post的后端数据一直接收不到,折腾了好半天,还是格式不对,做个记录function uploadData() { var data = JSON.stringify(arrayData, undefined, 2); var url = "http://XXXXXXXXXXXXXXX"; xhr = new XMLHttpRequest(); xhr.ope...

拉格朗日插值法 C语言实现_拉格朗日插值c语言_KDF5000的博客-程序员秘密

/**作者:KDF5000*功能:利用拉格朗日插值法求解近似值*时间:2013.4.15*/#include #include #include //存放插值节点struct Data{ double x; double y; struct Data *next;};/***************************************************

安装weblogic 11g报‘Exception in thread "winRegistry" java.lang.NoClassDefFoundError’_徐长亮的博客-程序员秘密

E:\08-软件\3_wls>java -jar wls1036_generic.jarException in thread "winRegistry" java.lang.NoClassDefFoundError: Could not initialize class com.bea.plateng.common.jni.dispatch.CFunction        at c

android判断两个图片相同,android中比较两张图片的相似度_子钅名的博客-程序员秘密

public static String similarity (Bitmap b,Bitmap viewBt) {//把图片转换为BitmapBitmap bm_one = b;Bitmap bm_two = viewBt;//保存图片所有像素个数的数组,图片宽×高int[] pixels_one = new int[bm_one.getWidth()*bm_one.getHeight()];i...

随便推点

mysql的一些知识点--------------------一_id name   1 小王 2 小李 3 小刘 b表 id a_id job 1 2 老师 2 4_我是小白猿的博客-程序员秘密

左连接(left join):返回 包括左表的全部记录与右表连接字段相等的记录  A表             id  name    1  小王  2  小李  3  小刘   B表   id  A_id   job  1   2    老师  2   4    程序员**select a.name , b.job form A a left join...

关于端口被占用而又找不到被占用的程序的解决办法_windows端口被占用但找不到进程_一只咕咚的博客-程序员秘密

在使用sts里Pivotal tc Server Developer Edition v3.2时经常碰到端口被占用, 网上经常出现的两种解决办法 一是修改服务器里的端口。打开servers里的服务器,双击出现窗口 找到properties里修改端口号 这种方法虽然简单,但是治标不治本,每次都是遇到端口被占用,一直在改...

我们是程序员,我们的征途是星辰大海_人类像程序员,我们的目标是星辰大海_喜洋洋爱上灰太狼的博客-程序员秘密

我们每个人都对自己的未来有所思量,因为我们每个人都怀揣着高远的梦想,我们每天都在打理着我们的生活,日复一日,年复一年。梦想是什么? 百度百科说:梦想,是对未来的一种期望,指在现在想未来的事或是可以达到但必须努力才可以达到的情况,梦想就是一种让你感到坚持就是幸福的东西,甚至其可以视为一种信仰。 而作为程序员,我们的梦想是什么,写代码不出BUG,不再加班,工资越来越多,或者我们根

MMA7361三轴加速度模块使用注意的问题_Geekjin的博客-程序员秘密

MMA7361这个模块很多种类,看似长得都一样,用起来还是有区别的。对比三种用过的MMA7361模块1.龙丘(龙邱)科技的MMA7361各轴的信号在不运动或不被重力作用的作用的状态下(0g),其输出为1.65V。如果沿着某个方向(轴向、径向平行、径向垂直)活动或受到重力作用,输出电压就会根据其运动方向以及设定的传感器灵敏度而改变其输出电压。用单片机的A/D转换器读取此输出信号,就可...

c语言按行读取文件_锅锅是锅锅的博客-程序员秘密

在做项目需要配置的参数一般保存在文件,读取文件配置比较简单的方法就是按行读取测试文件config.txt编译测试

推荐文章

热门文章

相关标签