杭电计算机组成原理课程设计-实验十三-实现R-I-J型指令的CPU设计实验
R-I-J CPU 设计实验
实验内容
设计一个MIPS单周期R-I-J-CPU
实验原理
实验流程图
R-I-J CPU 指令大全
控制信号大全
汇编指令与.coe文件
地址 | 机器代码 | 汇编指令 |
---|---|---|
[0x00400000] | 0x00004020 | add $8, $0, $0 |
[0x00400004] | 0x20090003 | addi $9, $0, 3 |
[0x00400008] | 0x200a0005 | addi $10, $0, 5 |
[0x0040000c] | 0x200b000a | addi $11, $0, a |
[0x00400010] | 0x010b4020 | add $8, $8, $11 |
[0x00400014] | 0x2129ffff | addi $9, $9, -1 |
[0x00400018] | 0x016a5820 | add $11, $11, $10 |
[0x0040001c] | 0x11200001 | beq $9, $0, 4 [Loop2-0x0040001c] |
[0x00400020] | 0x08000004 | j 0x00400010 [Loop1] |
[0x00400024] | 0xac080020 | sw $8, 32($0) |
[0x00400028] | 0x08000000 | j 0x00400000 [main] |
.coe文件内容(beq_j)
memory_initialization_radix=16; memory_initialization_vector=00004020,20090003,200a0005,200b000a,010b4020,2129ffff,016a5820,11200001,08000004,ac080020,08000000,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,3456789a,456789ab,56789abc,6789abcd;
地址 | 机器代码 | 汇编指令 |
---|---|---|
[0x00400000] | 0x00002020 | add $4, $0, $0 |
[0x00400004] | 0x20090003 | addi $9, $0, 3 |
[0x00400008] | 0x200a0005 | addi $10, $0, 5 |
[0x0040000c] | 0x200b000a | addi $11, $0, 10 |
[0x00400010] | 0x0c00000a | jal 0x00400028 [addD] |
[0x00400014] | 0x2129ffff | addi $9, $9, -1 |
[0x00400018] | 0x016a5820 | add $11, $11, $10 |
[0x0040001c] | 0x1520fffc | bne $9, $0, -16 [Loop1-0x0040001c] |
[0x00400020] | 0xac040020 | sw $4, 32($0) |
[0x00400024] | 0x08000000 | j 0x00400000 [main] |
[0x00400028] | 0x008b2020 | add $4, $4, $11 |
[0x0040002c] | 0x03e00008 | jr $31 |
.coe文件内容(bne_jal)
memory_initialization_radix=16; memory_initialization_vector=00002020,20090003,200a0005,200b000a,0c00000a,2129ffff,016a5820,1520fffc,ac080020,08000000,008b2020,03e00008,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,3456789a,456789ab;
mem.coe文件内容 (Mem存储器)
memory_initialization_radix=16; memory_initialization_vector=00000010,00632020,00010fff,00000008,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,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_I_J_CPU( clk,rst,clk_m, Inst_code,PC, opcode,rs,rt,rd,shamt,func,imm,offset, ALU_F,ZF,OF,ALU_OP, imm_s,rt_imm_s, ALU_B,R_Data_A,W_Addr,W_Data,imm_kz,R_Data_B,M_R_Data,Write_Reg,Mem_Write,Mem_Addr, PC_s,PC_next,w_r_s,wr_data_s ); input clk;//时钟 input rst;//清零 input clk_m;//Mem时钟 output reg [31:0]PC;//当前PC地址 output reg [31:0]PC_next;//PC转移地址 wire [31:0]PC_new; //PC+4 output [31:0]Inst_code;//取出的指令 output [5:0]opcode,func;//指令分段 output [4:0]rs,rt,rd,shamt;//指令分段 output [15:0]imm,offset;//指令分段 wire [25:0]address;//指令分段 output [31:0] ALU_F;//ALU结果 output reg [2:0] ALU_OP;// ALU运算的OP output ZF,OF; //零标志位和溢出标志位 output reg Write_Reg; //寄存器写入信号 output reg Mem_Write; //MEM写入信号 output [31:0]R_Data_A; //REGS R_Data_A output [31:0]R_Data_B; //REGS R_Data_B output [31:0]M_R_Data; //MEM读出数据 M_R_Data output [7:0]Mem_Addr; //Mem地址 output reg imm_s; //控制立即数扩展方式的信号 output reg rt_imm_s; //控制ALU_B口输入数据的信号 output [4:0]W_Addr; //REGS写入地址 output [31:0]ALU_B; //ALU_B口数据 output [31:0]W_Data; //REGS写入数据 output reg [31:0]imm_kz; //扩展后的立即数 output reg [1:0]PC_s; //控制PC下一次转移为何种方式的信号 output reg[1:0]w_r_s; //控制w_addr采用何种地址的信号 output reg[1:0]wr_data_s; //控制W_Data采用哪种数据的信号
逻辑引脚图
仿真时序波形图(以beq-J组合为例)
R-I CPU 完整代码
module R_I_J_CPU( clk,rst,clk_m, Inst_code,PC, opcode,rs,rt,rd,shamt,func,imm,offset, ALU_F,ZF,OF,ALU_OP, imm_s,rt_imm_s, ALU_B,R_Data_A,W_Addr,W_Data,imm_kz,R_Data_B,M_R_Data,Write_Reg,Mem_Write,Mem_Addr, PC_s,PC_next,w_r_s,wr_data_s ); input clk;//时钟 input rst;//清零 input clk_m; output reg [31:0]PC;//地址 output reg [31:0]PC_next; wire [31:0]PC_new; output [31:0]Inst_code;//取出的指令 output [5:0]opcode,func;//指令分段 output [4:0]rs,rt,rd,shamt;//指令分段 output [15:0]imm,offset;//指令分段 wire [25:0]address;//指令分段 output [31:0] ALU_F;//ALU结果 output reg [2:0] ALU_OP;//ALU结果 output ZF,OF; output reg Write_Reg; output reg Mem_Write; output [31:0]R_Data_A; output [31:0]R_Data_B; output [31:0]M_R_Data; output [7:0]Mem_Addr; output reg imm_s; output reg rt_imm_s; output [4:0]W_Addr; output [31:0]ALU_B; output [31:0]W_Data; output reg [31:0]imm_kz; output reg [1:0]PC_s; output reg[1:0]w_r_s; output reg[1:0]wr_data_s; initial PC = 32'h00000000; assign PC_new = PC + 4; Rom_J ROM1 ( .clka(clk), // input clka .addra(PC[7:2]), // input [5 : 0] addra .douta(Inst_code) // output [31 : 0] douta ); always @(*) case (PC_s) //根据PC_s ,赋值PC_next 2'b00: PC_next = PC_new; 2'b01: PC_next = R_Data_A; 2'b10: PC_next = PC_new + (imm_kz<<2); 2'b11: PC_next = {PC_new[31:28],address,2'b00}; endcase always @(negedge clk or posedge rst) begin if (rst) PC = 32'h00000000; //PC复位; else PC = PC_next; //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]; assign imm= Inst_code[15:0]; assign offset= Inst_code[15:0]; assign address = Inst_code[25:0]; always @(*) begin ALU_OP = 3'b100; //默认做加法 imm_s = 1'b0; //默认对立即数/偏移量进行0扩展 rt_imm_s = 1'b0; //默认读出rt寄存器的数据送ALU_B Write_Reg = 1'b1; //默认写寄存器 Mem_Write = 1'b0; //默认不写存储器 PC_s = 2'b00; w_r_s = 2'b00; wr_data_s = 2'b00; if (opcode==6'b000000) //R指令 begin case (func) 6'b100000:begin ALU_OP=3'b100;end //add 6'b100010:begin ALU_OP=3'b101;end //sub 6'b100100:begin ALU_OP=3'b000;end //and 6'b100101:begin ALU_OP=3'b001;end //or 6'b100110:begin ALU_OP=3'b010;end //xor 6'b100111:begin ALU_OP=3'b011;end //nor 6'b101011:begin ALU_OP=3'b110;end //stlu 6'b000100:begin ALU_OP=3'b111;end //sllv 6'b001000:begin Write_Reg=0;Mem_Write=0;PC_s = 2'b01; end //jr endcase end else begin case(opcode) 6'b001000:begin w_r_s=2'b01;imm_s=1;rt_imm_s=1;ALU_OP=3'b100;end //addi 6'b001100:begin w_r_s=2'b01;rt_imm_s=1;ALU_OP=3'b000; end //andi 6'b001110:begin w_r_s=2'b01;rt_imm_s=1;ALU_OP=3'b010;end //xori 6'b001011:begin w_r_s=2'b01;rt_imm_s=1;ALU_OP=3'b110; end //sltiu 6'b100011:begin w_r_s=2'b01;imm_s=1;rt_imm_s=1;wr_data_s=2'b01;ALU_OP=3'b100; end //lw 6'b101011:begin imm_s=1;rt_imm_s=1;ALU_OP=3'b100;Write_Reg=0;Mem_Write=1; end //sw 6'b000100:begin ALU_OP=3'b101;PC_s = (ZF)?2'b10:2'b00; Write_Reg = 1'b0;end //beq 6'b000101:begin ALU_OP=3'b101;PC_s = (ZF)?2'b00:2'b10; Write_Reg = 1'b0;end //bne 6'b000010:begin Write_Reg=0;Mem_Write=0;PC_s = 2'b11; end //j 6'b000011:begin w_r_s=2'b10;wr_data_s=2'b10;Write_Reg=1;Mem_Write=0;PC_s = 2'b11; end //jal endcase end end; always @(*) begin if(imm_s==1'b0) begin imm_kz={{16{1'b0}},imm}; end if(imm_s==1'b1) begin case(imm[15]) 1'b1:imm_kz={{16{1'b1}},imm}; 1'b0:imm_kz={{16{1'b0}},imm}; endcase end end; REGS REGS_1(R_Data_A,R_Data_B,W_Data,rs,rt,W_Addr,Write_Reg,rst,~clk); ALU ALU_1(ALU_OP,R_Data_A,ALU_B,ALU_F,ZF,OF); RAM_B RAM1 ( .clka(clk_m), // input clka .wea(Mem_Write), // input [0 : 0] wea .addra(Mem_Addr[7:2]), // input [5 : 0] addra .dina(R_Data_B), // input [31 : 0] dina .douta(M_R_Data) // output [31 : 0] douta ); assign W_Addr=(w_r_s[1]) ? 5'b11111 : ((w_r_s[0])?rt:rd); assign ALU_B=(rt_imm_s)?imm_kz:R_Data_B; assign Mem_Addr=ALU_F[7:0]; assign W_Data = (wr_data_s[1])?PC_new :((wr_data_s[0])? M_R_Data:ALU_F); 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; always@(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; always@(*) 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 #13 clk_m=~clk_m; always #47 clk=~clk; initial begin clk = 0; rst = 1; clk_m = 0; #3; rst=0; end endmodule
探索与思考(非标准答案)
-
谈谈你是如何产生测试程序的机器码的?仔细分析测试程序中,转移指令的 offset字段和 address 字段的编码,计算出转移地址,观察是否和你的转移目标地址一致。
答:首先编写如图所示汇编指令,
之后用pcspim工具翻译机器代码,
将涉及J与jal转移指令的机器代码第6位的1改为0,即可得到相应机器代码。测试程序中,转移指令的 offset字段和 address 字段的编码,转移地址,和我的转移目标地址一致。 -
I 型指令 bltzal rs, label(branch if less than zero,and link)的功能是:若寄存器 rs 小于0,则转移并链接,相对当前指令(PC+4)转移的指令数由 offset 来决定。它的 OP编码为 6’b000001,rt 字段为 5’b10000,试着实现该指令,谈谈你的实现方法。
答:将rt_imm_s信号更改为2位信号,只有执行bltzal rs指令时改信号为2,当信号为2时,ALU_B送入数据为0,且R-I cpu执行sltiu运算,即将RS地址数据与0进行比较。当ALU_F为1时,PC_s=2,即采用PC+4与offset决定PC转移地址,否则PC_s为0,即PC=PC+4。 -
基于图 11-60 ,添加一个输入设备(逻辑开关)和一个输出设备(LED 灯),假如
直接用 I 型指令实现输入输出功能,输入指令 in 和输出指令 out 的格式也是 I 型指
令。请画出修改后的系统结构图,写出这两条指令对应的控制信号,并编程实现该结构图。
如图所示,指令设备号由rs低位控制。
当IO-R为1时,输入指令。IO-W为1时,输出指令(需CLK)。
扩展wr_data_s,执行输入指令时其为3,即W_Data写入输入指令。
- 假设有一条指令 hlt,功能是停机,请修改图 11-60 所示的系统结构图,使得 PC_new 4→PC,从而实现 hlt 指令,写出 hlt 指令对应的控制信号,并编程实现该结构图。
always @(*) case (PC_s) //根据PC_s ,赋值PC_next 2'b000: PC_next = PC_new; 2'b001: PC_next = R_Data_A; 2'b010: PC_next = PC_new + (imm_kz<<2); 2'b011: PC_next = {PC_new[31:28],address,2'b00}; 2'b100: PC_next = PC_new-4; endcase
- 杭电计算机组成原理课程设计-实验十二-实现R-I型指令的CPU设计实验
- [置顶] [计算机组成原理][R-I-J型指令CPU设计实验总结]
- [计算机组成原理][实验十.R-I-J型指令CPU设计实验总结]
- 计算机组成原理实验 单总线CPU设计(定长指令周期3级时序)(HUST)思路总结
- 计算机组成原理实验 单总线CPU设计(变长指令周期3级时序)(HUST)思路总结
- 计算机组成原理课程设计 Dais CMX16 模型机指令及微指令设计
- 计算机组成原理课程设计(vhdl语言实现)
- 计算机组成实验-第5章_R指令设计实现
- 计算机组成原理课程设计实验一:验证74LS181运算和逻辑功能
- 计算机组成原理课程设计-基本模型机的设计与实现
- 山东大学计算机组成原理实验课程设计-模型机
- 计算机组成原理课程设计 Dais CMX16 模型机指令及微指令设计
- 计算机组成原理运算器设计实验之CLA182四位先行进位电路设计
- 重学计算机组成原理(五)- "旋转跳跃"的指令实现
- 基于Dais CMX16的计算机组成原理微程序课程设计
- 计算机组成原理运算器设计实验之8位可控加减法电路设计
- 计算机组成原理 实验1 Cache模拟器的实现
- Atitit 计算机系统结构 计算机系统结构 Cpu 存储 cache 指令系统 目录 Line 56: 第2章指令系统设计 指令格式 寻址方式 1 Line 64: 第3章CPU及其实现
- 计算机组成原理课程设计基于cop2000
- 中山大学计算机组成原理多周期CPU实验