流水线CPU设计。至少实现21条指令ADD、SUB、OR、AND、XOR、NOR、SLT、SLTU、SLL、SRL、SRA、LUI, ADDU、ADDIU、SUBU、LW、SW、BEQ、BNE、JAL、JR。
要求如下:
(1)CPU微结构为静态5级流水。
(2)实现MIPS架构的延迟槽技术,延迟槽可以是任意指令。
(3)控制相关由分支指令造成,通过延迟槽技术可以完美解决。
(4)结构相关即某一级流水停顿了,会阻塞上游的流水级。
(5)要求仿真运行测试程序通过
五级静态流水 CPU 结构设计及指令扩展,其目的是构建一个具备五级静态流水线结构的 CPU,以此提高 CPU 的执行效率和吞吐量,并扩展指令集,使其至少包含 21 条常用指令,以满足多种计算和控制需求,增强 CPU 的功能和通用性。其意义体现在多个方面,首先,五级静态流水线将指令执行过程划分为取指、译码、执行、访存和写回等五个阶段,不同指令的不同阶段可并行执行,显著提高了指令吞吐量和 CPU 整体性能,虽然单个指令执行时间可能略有增加,但从宏观上看,程序执行时间大大缩短,提升了计算机系统的响应速度和用户体验;其次,扩展的指令集涵盖了多种类型的运算和控制指令,能够满足多样化的计算任务和程序控制需求,适用于科学计算、图像处理、嵌入式系统等广泛领域,同时也为软件开发者提供了更多编程工具和优化手段,有利于编译器进行指令级优化,进一步提高程序执行效率;此外,这种设计实践能够推动数字电路设计、流水线技术、指令集设计等相关硬件技术的发展与创新,促进集成电路制造工艺和 EDA 工具的进步,还能吸引更多软件开发者为其开发软件,形成丰富的软件生态系统,实现硬件与软件相互促进、共同发展,推动整个计算机产业的发展。
实现的指令列表(包括指令描述)
表1指令列表
|
汇编程序 |
对应机器指令 |
|
.org 0x0 .set noat .set noreorder .global _start _start: lui $1,0x1234 #$1=0x12340000 lui $2,0x5678 #$2=0x56780000 nop nop #c s1: add $3,$1,$2 #$3=0x68ac0000 sub $4,$1,$2 #$4=0xbbbc0000 or $5,$1,$2 #$5=0x567c0000 and $6,$1,$2 #1c #$6=0x12300000 xor $7,$1,$2 #$7=0x444c0000 nor $8,$1,$2 #$8=0xa983ffff bne $1,$0,s2 #如果$1和$0不相等则跳转到s2 nop #2c lui $1,0xf760 lui $2,0x1234 s2: nop nop #3c beq $2,$1,s1 #如果$2和$1相等则跳转到s1 nop slt $9,$1,$2 #$9 =0x00000001 sltu $10,$1,$2 #4c $10=0x00000001 sll $11,$1,2 #$11=0x48d00000 srl $12,$1,16 #$12=0x00001234 sra $13,$1,2 #$13=0x048d0000 addu $14,$1,$2 #5c $14=0x68ac0000 addiu $15,$1,0x2020 #$15=0x12342020 subu $16,$1,$2 #$16=0xbbbc0000 sltu $17,$1,$2 #$17=0x00000001 sw $14,0x8($0) #6c #将$14的值(0x68ac0000)存入物理地址为0x00000008的字 lw $18,0x8($0) #$18=0x68ac0000 jal 0x80 #$31=0x0000007c nop addiu $1,$0,0x2020 #$1=0x00002020 addiu $2,$0,0x2010 #80 $2=0x00002010 addiu $3,$0,0x00a0 #$3=0x000000a0 nop nop jr $3 #90 #跳转到$3所指位置 nop add $3,$1,$2 sub $4,$1,$2 or $5,$1,$2 #a0 #jr target 0xa0 lui $31,0x0101 #$31=0x01010000 finish: nop nop |
3c011234 3c025678 00000000 00000000 00221820 00222022 00222825 00223024 00223826 00224027 14200003 00000000 3c01f760 3c021234 00000000 00000000 1041fff3 00000000 0022482a 0022502b 00015880 00016402 00016883 00227021 242f2020 00228023 0022882b ac0e0008 8c120008 8c000020 00000000 24012020 24022010 240300a0 00000000 00000000 00600008 00000000 00221820 00222022 00222825 3c1f0101 00000000 00000000 |
ADD:将两个源操作数相加,结果存放到目的操作数中,执行标准的二进制加法操作,常用于基本数学计算。
SUB:从第一个源操作数中减去第二个源操作数,差值存入目的操作数,实现减法运算,比如在计算差值、坐标变换等场景常用。
ADDU 和 SUBU:与 ADD、SUB 类似,但针对无符号数操作,适用于处理如地址计算等无需考虑符号位的场景。
ADDIU:这是一条立即数加法指令,将寄存器中的值与一个立即数相加,结果存回寄存器,方便进行常数加法操作。
逻辑运算指令:
OR:对两个源操作数按位进行或运算,只要对应位有一个为 1,则结果位为 1,常用于设置标志位、数据合并等操作。
AND:按位与运算,仅当对应位都为 1 时,结果位才为 1,可用于数据屏蔽、提取特定位等。
XOR:异或运算,对应位不同时结果为 1,相同则为 0,常用于加密、奇偶校验等领域。
NOR:先对两个源操作数按位或运算,再取反,结果存到目的操作数,在逻辑电路设计中有独特应用。
比较与移位指令:
SLT:比较两个有符号数,若第一个小于第二个,则将 1 存入目的操作数,否则存入 0,用于条件判断。
SLTU:针对无符号数进行类似 SLT 的比较操作。
SLL:将操作数逻辑左移指定的位数,右边空出位补 0,常用于乘以 2 的幂次方运算。
SRL:逻辑右移,操作数向右移动指定位数,左边空出位补 0,可实现除以 2 的幂次方。
SRA:算术右移,移动时保持符号位不变,用于有符号数的除法运算。
数据传输指令:
LW:从内存中读取一个字(32 位)的数据到寄存器,实现数据从内存到 CPU 的加载,保障数据可用性。
SW:将寄存器中的一个字数据写入内存,完成 CPU 向内存的数据存储,便于保存运算结果。
控制转移指令:
BEQ:当两个寄存器值相等时,跳转到指定的目标地址,用于条件分支,构建程序流程。
BNE:与 BEQ 相反,两个寄存器值不相等时跳转,同样是重要的流程控制手段。
JAL:无条件跳转到目标地址,同时将下一条指令的地址保存到特定寄存器,用于子程序调用。
JR:直接跳转到寄存器所指向的地址,常用于函数返回等场景,高效改变程序执行顺序。
特殊指令:
LUI:将一个 16 位的立即数左移 16 位后装入寄存器的高 16 位,低 16 位补 0,常用于初始化寄存器的高位部分。
设计总体架构

`include "defines.v"
module openmips_min_sopc(
input wire clk,
input wire rst
);
//连接指令存储器
wire[`InstAddrBus] inst_addr;
wire[`InstBus] inst;
wire rom_ce;
wire mem_we_i;
wire[`RegBus] mem_addr_i;
wire[`RegBus] mem_data_i;
wire[`RegBus] mem_data_o;
wire[3:0] mem_sel_i;
wire mem_ce_i;
openmips openmips0(
.clk(clk),
.rst(rst),
.rom_addr_o(inst_addr),
.rom_data_i(inst),
.rom_ce_o(rom_ce),
.ram_we_o(mem_we_i),
.ram_addr_o(mem_addr_i),
.ram_sel_o(mem_sel_i),
.ram_data_o(mem_data_i),
.ram_data_i(mem_data_o),
.ram_ce_o(mem_ce_i)
);
inst_rom inst_rom0(
.ce(rom_ce),
.addr(inst_addr),
.inst(inst)
);
data_ram data_ram0(
.clk(clk),
.ce(mem_ce_i),
.we(mem_we_i),
.addr(mem_addr_i),
.sel(mem_sel_i),
.data_i(mem_data_i),
.data_o(mem_data_o)
);
`include "defines.v"
module openmips(
input wire clk,
input wire rst,
input wire[`RegBus] rom_data_i,
output wire[`RegBus] rom_addr_o,
output wire rom_ce_o,
//连接数据存储器data_ram
input wire[`RegBus] ram_data_i,
output wire[`RegBus] ram_addr_o,
output wire[`RegBus] ram_data_o,
output wire ram_we_o,
output wire[3:0] ram_sel_o,
output wire[3:0] ram_ce_o
);
wire[`InstAddrBus] pc;
wire[`InstAddrBus] id_pc_i;
wire[`InstBus] id_inst_i;
//连接译码阶段ID模块的输出与ID/EX模块的输入
wire[`AluOpBus] id_aluop_o;
wire[`AluSelBus] id_alusel_o;
wire[`RegBus] id_reg1_o;
wire[`RegBus] id_reg2_o;
wire id_wreg_o;
wire[`RegAddrBus] id_wd_o;
wire id_is_in_delayslot_o;
wire[`RegBus] id_link_address_o;
wire[`RegBus] id_inst_o;
//连接ID/EX模块的输出与执行阶段EX模块的输入
wire[`AluOpBus] ex_aluop_i;
wire[`AluSelBus] ex_alusel_i;
wire[`RegBus] ex_reg1_i;
wire[`RegBus] ex_reg2_i;
wire ex_wreg_i;
wire[`RegAddrBus] ex_wd_i;
wire ex_is_in_delayslot_i;
wire[`RegBus] ex_link_address_i;
wire[`RegBus] ex_inst_i;
//连接执行阶段EX模块的输出与EX/MEM模块的输入
wire ex_wreg_o;
wire[`RegAddrBus] ex_wd_o;
wire[`RegBus] ex_wdata_o;
wire[`RegBus] ex_hi_o;
wire[`RegBus] ex_lo_o;
wire ex_whilo_o;
wire[`AluOpBus] ex_aluop_o;
wire[`RegBus] ex_mem_addr_o;
wire[`RegBus] ex_reg1_o;
wire[`RegBus] ex_reg2_o;
//连接EX/MEM模块的输出与访存阶段MEM模块的输入
wire mem_wreg_i;
wire[`RegAddrBus] mem_wd_i;
wire[`RegBus] mem_wdata_i;
wire[`RegBus] mem_hi_i;
wire[`RegBus] mem_lo_i;
wire mem_whilo_i;
wire[`AluOpBus] mem_aluop_i;
wire[`RegBus] mem_mem_addr_i;
wire[`RegBus] mem_reg1_i;
wire[`RegBus] mem_reg2_i;
//连接访存阶段MEM模块的输出与MEM/WB模块的输入
wire mem_wreg_o;
wire[`RegAddrBus] mem_wd_o;
wire[`RegBus] mem_wdata_o;
wire[`RegBus] mem_hi_o;
wire[`RegBus] mem_lo_o;
wire mem_whilo_o;
wire mem_LLbit_value_o;
wire mem_LLbit_we_o;
//连接MEM/WB模块的输出与回写阶段的输入
wire wb_wreg_i;
wire[`RegAddrBus] wb_wd_i;
wire[`RegBus] wb_wdata_i;
wire[`RegBus] wb_hi_i;
wire[`RegBus] wb_lo_i;
wire wb_whilo_i;
wire wb_LLbit_value_i;
wire wb_LLbit_we_i;
//连接译码阶段ID模块与通用寄存器Regfile模块
wire reg1_read;
wire reg2_read;
wire[`RegBus] reg1_data;
wire[`RegBus] reg2_data;
wire[`RegAddrBus] reg1_addr;
wire[`RegAddrBus] reg2_addr;
//连接执行阶段与hilo模块的输出,读取HI、LO寄存器
wire[`RegBus] hi;
wire[`RegBus] lo;
//连接执行阶段与ex_reg模块,用于多周期的MADD、MADDU、MSUB、MSUBU指令
wire[`DoubleRegBus] hilo_temp_o;
wire[1:0] cnt_o;
wire[`DoubleRegBus] hilo_temp_i;
wire[1:0] cnt_i;
wire[`DoubleRegBus] div_result;
wire div_ready;
wire[`RegBus] div_opdata1;
wire[`RegBus] div_opdata2;
wire div_start;
wire div_annul;
wire signed_div;
wire is_in_delayslot_i;
wire is_in_delayslot_o;
wire next_inst_in_delayslot_o;
wire id_branch_flag_o;
wire[`RegBus] branch_target_address;
wire[5:0] stall;
wire stallreq_from_id;
wire stallreq_from_ex;
wire LLbit_o;
//pc_reg例化
pc_reg pc_reg0(
.clk(clk),
.rst(rst),
.stall(stall),
.branch_flag_i(id_branch_flag_o),
.branch_target_address_i(branch_target_address),
.pc(pc),
.ce(rom_ce_o)
);
assign rom_addr_o = pc;
//IF/ID模块例化
if_id if_id0(
.clk(clk),
.rst(rst),
.stall(stall),
.if_pc(pc),
.if_inst(rom_data_i),
.id_pc(id_pc_i),
.id_inst(id_inst_i)
);
//译码阶段ID模块
id id0(
.rst(rst),
.pc_i(id_pc_i),
.inst_i(id_inst_i),
.ex_aluop_i(ex_aluop_o),
.reg1_data_i(reg1_data),
.reg2_data_i(reg2_data),
//处于执行阶段的指令要写入的目的寄存器信息
.ex_wreg_i(ex_wreg_o),
.ex_wdata_i(ex_wdata_o),
.ex_wd_i(ex_wd_o),
//处于访存阶段的指令要写入的目的寄存器信息
.mem_wreg_i(mem_wreg_o),
.mem_wdata_i(mem_wdata_o),
.mem_wd_i(mem_wd_o),
.is_in_delayslot_i(is_in_delayslot_i),
//送到regfile的信息
.reg1_read_o(reg1_read),
.reg2_read_o(reg2_read),
.reg1_addr_o(reg1_addr),
.reg2_addr_o(reg2_addr),
//送到ID/EX模块的信息
.aluop_o(id_aluop_o),
.alusel_o(id_alusel_o),
.reg1_o(id_reg1_o),
.reg2_o(id_reg2_o),
.wd_o(id_wd_o),
.wreg_o(id_wreg_o),
.inst_o(id_inst_o),
.next_inst_in_delayslot_o(next_inst_in_delayslot_o),
.branch_flag_o(id_branch_flag_o),
.branch_target_address_o(branch_target_address),
.link_addr_o(id_link_address_o),
.is_in_delayslot_o(id_is_in_delayslot_o),
.stallreq(stallreq_from_id)
);
//通用寄存器Regfile例化
regfile regfile1(
.clk (clk),
.rst (rst),
.we (wb_wreg_i),
.waddr (wb_wd_i),
.wdata (wb_wdata_i),
.re1 (reg1_read),
.raddr1 (reg1_addr),
.rdata1 (reg1_data),
.re2 (reg2_read),
.raddr2 (reg2_addr),
.rdata2 (reg2_data)
);
//ID/EX模块
id_ex id_ex0(
.clk(clk),
.rst(rst),
.stall(stall),
//从译码阶段ID模块传递的信息
.id_aluop(id_aluop_o),
.id_alusel(id_alusel_o),
.id_reg1(id_reg1_o),
.id_reg2(id_reg2_o),
.id_wd(id_wd_o),
.id_wreg(id_wreg_o),
.id_link_address(id_link_address_o),
.id_is_in_delayslot(id_is_in_delayslot_o),
.next_inst_in_delayslot_i(next_inst_in_delayslot_o),
.id_inst(id_inst_o),
//传递到执行阶段EX模块的信息
.ex_aluop(ex_aluop_i),
.ex_alusel(ex_alusel_i),
.ex_reg1(ex_reg1_i),
.ex_reg2(ex_reg2_i),
.ex_wd(ex_wd_i),
.ex_wreg(ex_wreg_i),
.ex_link_address(ex_link_address_i),
.ex_is_in_delayslot(ex_is_in_delayslot_i),
.is_in_delayslot_o(is_in_delayslot_i),
.ex_inst(ex_inst_i)
);
//EX模块
ex ex0(
.rst(rst),
//送到执行阶段EX模块的信息
.aluop_i(ex_aluop_i),
.alusel_i(ex_alusel_i),
.reg1_i(ex_reg1_i),
.reg2_i(ex_reg2_i),
.wd_i(ex_wd_i),
.wreg_i(ex_wreg_i),
.hi_i(hi),
.lo_i(lo),
.inst_i(ex_inst_i),
.wb_hi_i(wb_hi_i),
.wb_lo_i(wb_lo_i),
.wb_whilo_i(wb_whilo_i),
.mem_hi_i(mem_hi_o),
.mem_lo_i(mem_lo_o),
.mem_whilo_i(mem_whilo_o),
.hilo_temp_i(hilo_temp_i),
.cnt_i(cnt_i),
.div_result_i(div_result),
.div_ready_i(div_ready),
.link_address_i(ex_link_address_i),
.is_in_delayslot_i(ex_is_in_delayslot_i),
//EX模块的输出到EX/MEM模块信息
.wd_o(ex_wd_o),
.wreg_o(ex_wreg_o),
.wdata_o(ex_wdata_o),
.hi_o(ex_hi_o),
.lo_o(ex_lo_o),
.whilo_o(ex_whilo_o),
.hilo_temp_o(hilo_temp_o),
.cnt_o(cnt_o),
.div_opdata1_o(div_opdata1),
.div_opdata2_o(div_opdata2),
.div_start_o(div_start),
.signed_div_o(signed_div),
.aluop_o(ex_aluop_o),
.mem_addr_o(ex_mem_addr_o),
.reg2_o(ex_reg2_o),
.stallreq(stallreq_from_ex)
);
//EX/MEM模块
ex_mem ex_mem0(
.clk(clk),
.rst(rst),
.stall(stall),
//来自执行阶段EX模块的信息
.ex_wd(ex_wd_o),
.ex_wreg(ex_wreg_o),
.ex_wdata(ex_wdata_o),
.ex_hi(ex_hi_o),
.ex_lo(ex_lo_o),
.ex_whilo(ex_whilo_o),
.ex_aluop(ex_aluop_o),
.ex_mem_addr(ex_mem_addr_o),
.ex_reg2(ex_reg2_o),
.hilo_i(hilo_temp_o),
.cnt_i(cnt_o),
//送到访存阶段MEM模块的信息
.mem_wd(mem_wd_i),
.mem_wreg(mem_wreg_i),
.mem_wdata(mem_wdata_i),
.mem_hi(mem_hi_i),
.mem_lo(mem_lo_i),
.mem_whilo(mem_whilo_i),
.mem_aluop(mem_aluop_i),
.mem_mem_addr(mem_mem_addr_i),
.mem_reg2(mem_reg2_i),
.hilo_o(hilo_temp_i),
.cnt_o(cnt_i)
);
//MEM模块例化
mem mem0(
.rst(rst),
//来自EX/MEM模块的信息
.wd_i(mem_wd_i),
.wreg_i(mem_wreg_i),
.wdata_i(mem_wdata_i),
.hi_i(mem_hi_i),
.lo_i(mem_lo_i),
.whilo_i(mem_whilo_i),
.aluop_i(mem_aluop_i),
.mem_addr_i(mem_mem_addr_i),
.reg2_i(mem_reg2_i),
//来自memory的信息
.mem_data_i(ram_data_i),
//LLbit_i是LLbit寄存器的值
.LLbit_i(LLbit_o),
//但不一定是最新值,回写阶段可能要写LLbit,所以还要进一步判断
.wb_LLbit_we_i(wb_LLbit_we_i),
.wb_LLbit_value_i(wb_LLbit_value_i),
.LLbit_we_o(mem_LLbit_we_o),
.LLbit_value_o(mem_LLbit_value_o),
//送到MEM/WB模块的信息
.wd_o(mem_wd_o),
.wreg_o(mem_wreg_o),
.wdata_o(mem_wdata_o),
.hi_o(mem_hi_o),
.lo_o(mem_lo_o),
.whilo_o(mem_whilo_o),
//送到memory的信息
.mem_addr_o(ram_addr_o),
.mem_we_o(ram_we_o),
.mem_sel_o(ram_sel_o),
.mem_data_o(ram_data_o),
.mem_ce_o(ram_ce_o)
);
//MEM/WB模块
mem_wb mem_wb0(
.clk(clk),
.rst(rst),
.stall(stall),
//来自访存阶段MEM模块的信息
.mem_wd(mem_wd_o),
.mem_wreg(mem_wreg_o),
.mem_wdata(mem_wdata_o),
.mem_hi(mem_hi_o),
.mem_lo(mem_lo_o),
.mem_whilo(mem_whilo_o),
.mem_LLbit_we(mem_LLbit_we_o),
.mem_LLbit_value(mem_LLbit_value_o),
//送到回写阶段的信息
.wb_wd(wb_wd_i),
.wb_wreg(wb_wreg_i),
.wb_wdata(wb_wdata_i),
.wb_hi(wb_hi_i),
.wb_lo(wb_lo_i),
.wb_whilo(wb_whilo_i),
.wb_LLbit_we(wb_LLbit_we_i),
.wb_LLbit_value(wb_LLbit_value_i)
);
hilo_reg hilo_reg0(
.clk(clk),
.rst(rst),
//写端口
.we(wb_whilo_i),
.hi_i(wb_hi_i),
.lo_i(wb_lo_i),
//读端口1
.hi_o(hi),
.lo_o(lo)
);
ctrl ctrl0(
.rst(rst),
.stallreq_from_id(stallreq_from_id),
//来自执行阶段的暂停请求
.stallreq_from_ex(stallreq_from_ex),
.stall(stall)
);
div div0(
.clk(clk),
.rst(rst),
.signed_div_i(signed_div),
.opdata1_i(div_opdata1),
.opdata2_i(div_opdata2),
.start_i(div_start),
.annul_i(1'b0),
.result_o(div_result),
.ready_o(div_ready)
);
LLbit_reg LLbit_reg0(
.clk(clk),
.rst(rst),
.flush(1'b0),
//写端口
.LLbit_i(wb_LLbit_value_i),
.we(wb_LLbit_we_i),
//读端口1
.LLbit_o(LLbit_o)
);
endmodule
`include "defines.v"
module if_id(
input wire clk,
input wire rst,
//来自控制模块的信息
input wire[5:0] stall,
input wire[`InstAddrBus] if_pc,
input wire[`InstBus] if_inst,
output reg[`InstAddrBus] id_pc,
output reg[`InstBus] id_inst
);
always @ (posedge clk) begin
if (rst == `RstEnable) begin //复位信号为0,则pc、指令置0
id_pc <= `ZeroWord;
id_inst <= `ZeroWord;
end else if(stall[1] == `Stop && stall[2] == `NoStop) begin //取指完成,译码开始阶段
id_pc <= `ZeroWord; //pc置零
id_inst <= `ZeroWord; //指令置空
end else if(stall[1] == `NoStop) begin //其余情况下保持译码阶段的寄存器id_pc、id_inst不变
id_pc <= if_pc;
id_inst <= if_inst;
end
end
endmodule
`include "defines.v"
module id(
input wire rst,
input wire[`InstAddrBus] pc_i,
input wire[`InstBus] inst_i,
//处于执行阶段的指令的一些信息,用于解决load相关
input wire[`AluOpBus] ex_aluop_i,
//处于执行阶段的指令要写入的目的寄存器信息
input wire ex_wreg_i,
input wire[`RegBus] ex_wdata_i,
input wire[`RegAddrBus] ex_wd_i,
//处于访存阶段的指令要写入的目的寄存器信息
input wire mem_wreg_i,
input wire[`RegBus] mem_wdata_i,
input wire[`RegAddrBus] mem_wd_i,
input wire[`RegBus] reg1_data_i,
input wire[`RegBus] reg2_data_i,
//如果上一条指令是转移指令,那么下一条指令在译码的时候is_in_delayslot为true
input wire is_in_delayslot_i,
//送到regfile的信息
output reg reg1_read_o,
output reg reg2_read_o,
output reg[`RegAddrBus] reg1_addr_o,
output reg[`RegAddrBus] reg2_addr_o,
//送到执行阶段的信息
output reg[`AluOpBus] aluop_o,
output reg[`AluSelBus] alusel_o,
output reg[`RegBus] reg1_o,
output reg[`RegBus] reg2_o,
output reg[`RegAddrBus] wd_o,
output reg wreg_o,
output wire[`RegBus] inst_o,
output reg next_inst_in_delayslot_o,
output reg branch_flag_o,
output reg[`RegBus] branch_target_address_o,
output reg[`RegBus] link_addr_o,
output reg is_in_delayslot_o,
output wire stallreq
);
wire[5:0] op = inst_i[31:26];
wire[4:0] op2 = inst_i[10:6];
wire[5:0] op3 = inst_i[5:0];
wire[4:0] op4 = inst_i[20:16];
reg[`RegBus] imm;
reg instvalid;
wire[`RegBus] pc_plus_8;
wire[`RegBus] pc_plus_4;
wire[`RegBus] imm_sll2_signedext;
reg stallreq_for_reg1_loadrelate;
reg stallreq_for_reg2_loadrelate;
wire pre_inst_is_load;
assign pc_plus_8 = pc_i + 8;
assign pc_plus_4 = pc_i +4;
assign imm_sll2_signedext = {{14{inst_i[15]}}, inst_i[15:0], 2'b00 };
assign stallreq = stallreq_for_reg1_loadrelate | stallreq_for_reg2_loadrelate;
assign pre_inst_is_load = ((ex_aluop_i == `EXE_LB_OP) ||
(ex_aluop_i == `EXE_LBU_OP)||
(ex_aluop_i == `EXE_LH_OP) ||
(ex_aluop_i == `EXE_LHU_OP)||
(ex_aluop_i == `EXE_LW_OP) ||
(ex_aluop_i == `EXE_LWR_OP)||
(ex_aluop_i == `EXE_LWL_OP)||
(ex_aluop_i == `EXE_LL_OP) ||
(ex_aluop_i == `EXE_SC_OP)) ? 1'b1 : 1'b0;
assign inst_o = inst_i;
always @ (*) begin
if (rst == `RstEnable) begin
aluop_o <= `EXE_NOP_OP;
alusel_o <= `EXE_RES_NOP;
wd_o <= `NOPRegAddr;
wreg_o <= `WriteDisable;
instvalid <= `InstValid;
reg1_read_o <= 1'b0;
reg2_read_o <= 1'b0;
reg1_addr_o <= `NOPRegAddr;
reg2_addr_o <= `NOPRegAddr;
imm <= 32'h0;
link_addr_o <= `ZeroWord;
branch_target_address_o <= `ZeroWord;
branch_flag_o <= `NotBranch;
next_inst_in_delayslot_o <= `NotInDelaySlot;
end else begin
aluop_o <= `EXE_NOP_OP;
alusel_o <= `EXE_RES_NOP;
wd_o <= inst_i[15:11];
wreg_o <= `WriteDisable;
instvalid <= `InstInvalid;
reg1_read_o <= 1'b0;
reg2_read_o <= 1'b0;
reg1_addr_o <= inst_i[25:21];
reg2_addr_o <= inst_i[20:16];
imm <= `ZeroWord;
link_addr_o <= `ZeroWord;
branch_target_address_o <= `ZeroWord;
branch_flag_o <= `NotBranch;
next_inst_in_delayslot_o <= `NotInDelaySlot;
case (op)
`EXE_SPECIAL_INST: begin
case (op2)
5'b00000: begin
case (op3)
`EXE_OR: begin
wreg_o <= `WriteEnable; //写寄存器打开
aluop_o <= `EXE_OR_OP; //运算子类型为或
alusel_o <= `EXE_RES_LOGIC; //运算类型逻辑运算
reg1_read_o <= 1'b1; //读寄存器1打开
reg2_read_o <= 1'b1; //读寄存器2打开
instvalid <= `InstValid;
end
`EXE_AND: begin
wreg_o <= `WriteEnable; aluop_o <= `EXE_AND_OP;
alusel_o <= `EXE_RES_LOGIC; reg1_read_o <= 1'b1; reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_XOR: begin
wreg_o <= `WriteEnable; aluop_o <= `EXE_XOR_OP;
alusel_o <= `EXE_RES_LOGIC; reg1_read_o <= 1'b1; reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_NOR: begin
wreg_o <= `WriteEnable; aluop_o <= `EXE_NOR_OP;
alusel_o <= `EXE_RES_LOGIC; reg1_read_o <= 1'b1; reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_SLLV: begin
wreg_o <= `WriteEnable; aluop_o <= `EXE_SLL_OP;
alusel_o <= `EXE_RES_SHIFT; reg1_read_o <= 1'b1; reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_SRLV: begin
wreg_o <= `WriteEnable; aluop_o <= `EXE_SRL_OP;
alusel_o <= `EXE_RES_SHIFT; reg1_read_o <= 1'b1; reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_SRAV: begin
wreg_o <= `WriteEnable; aluop_o <= `EXE_SRA_OP;
alusel_o <= `EXE_RES_SHIFT; reg1_read_o <= 1'b1; reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_MFHI: begin
wreg_o <= `WriteEnable; aluop_o <= `EXE_MFHI_OP;
alusel_o <= `EXE_RES_MOVE; reg1_read_o <= 1'b0; reg2_read_o <= 1'b0;
instvalid <= `InstValid;
end
`EXE_MFLO: begin
wreg_o <= `WriteEnable; aluop_o <= `EXE_MFLO_OP;
alusel_o <= `EXE_RES_MOVE; reg1_read_o <= 1'b0; reg2_read_o <= 1'b0;
instvalid <= `InstValid;
end
`EXE_MTHI: begin
wreg_o <= `WriteDisable; aluop_o <= `EXE_MTHI_OP;
reg1_read_o <= 1'b1; reg2_read_o <= 1'b0; instvalid <= `InstValid;
end
`EXE_MTLO: begin
wreg_o <= `WriteDisable; aluop_o <= `EXE_MTLO_OP;
reg1_read_o <= 1'b1; reg2_read_o <= 1'b0; instvalid <= `InstValid;
end
`EXE_MOVN: begin
aluop_o <= `EXE_MOVN_OP;
alusel_o <= `EXE_RES_MOVE; reg1_read_o <= 1'b1; reg2_read_o <= 1'b1;
instvalid <= `InstValid;
if(reg2_o != `ZeroWord) begin
wreg_o <= `WriteEnable;
end else begin
wreg_o <= `WriteDisable;
end
end
`EXE_MOVZ: begin
aluop_o <= `EXE_MOVZ_OP;
alusel_o <= `EXE_RES_MOVE; reg1_read_o <= 1'b1; reg2_read_o <= 1'b1;
instvalid <= `InstValid;
if(reg2_o == `ZeroWord) begin
wreg_o <= `WriteEnable;
end else begin
wreg_o <= `WriteDisable;
end
end
`EXE_SLT: begin
wreg_o <= `WriteEnable; aluop_o <= `EXE_SLT_OP;
alusel_o <= `EXE_RES_ARITHMETIC; reg1_read_o <= 1'b1; reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_SLTU: begin
wreg_o <= `WriteEnable; aluop_o <= `EXE_SLTU_OP;
alusel_o <= `EXE_RES_ARITHMETIC; reg1_read_o <= 1'b1; reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_SYNC: begin
wreg_o <= `WriteDisable; aluop_o <= `EXE_NOP_OP;
alusel_o <= `EXE_RES_NOP; reg1_read_o <= 1'b0; reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_ADD: begin
wreg_o <= `WriteEnable; aluop_o <= `EXE_ADD_OP;
alusel_o <= `EXE_RES_ARITHMETIC; reg1_read_o <= 1'b1; reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_ADDU: begin
wreg_o <= `WriteEnable; aluop_o <= `EXE_ADDU_OP;
alusel_o <= `EXE_RES_ARITHMETIC; reg1_read_o <= 1'b1; reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_SUB: begin
wreg_o <= `WriteEnable; aluop_o <= `EXE_SUB_OP;
alusel_o <= `EXE_RES_ARITHMETIC; reg1_read_o <= 1'b1; reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_SUBU: begin
wreg_o <= `WriteEnable; aluop_o <= `EXE_SUBU_OP;
alusel_o <= `EXE_RES_ARITHMETIC; reg1_read_o <= 1'b1; reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_MULT: begin
wreg_o <= `WriteDisable; aluop_o <= `EXE_MULT_OP;
reg1_read_o <= 1'b1; reg2_read_o <= 1'b1; instvalid <= `InstValid;
end
`EXE_MULTU: begin
wreg_o <= `WriteDisable; aluop_o <= `EXE_MULTU_OP;
reg1_read_o <= 1'b1; reg2_read_o <= 1'b1; instvalid <= `InstValid;
end
`EXE_DIV: begin
wreg_o <= `WriteDisable; aluop_o <= `EXE_DIV_OP;
reg1_read_o <= 1'b1; reg2_read_o <= 1'b1; instvalid <= `InstValid;
end
`EXE_DIVU: begin
wreg_o <= `WriteDisable; aluop_o <= `EXE_DIVU_OP;
reg1_read_o <= 1'b1; reg2_read_o <= 1'b1; instvalid <= `InstValid;
end
`EXE_JR: begin
wreg_o <= `WriteDisable; aluop_o <= `EXE_JR_OP;
alusel_o <= `EXE_RES_JUMP_BRANCH; reg1_read_o <= 1'b1; reg2_read_o <= 1'b0;
link_addr_o <= `ZeroWord;
branch_target_address_o <= reg1_o;
branch_flag_o <= `Branch;
next_inst_in_delayslot_o <= `InDelaySlot;
instvalid <= `InstValid;
end
`EXE_JALR: begin
wreg_o <= `WriteEnable; aluop_o <= `EXE_JALR_OP;
alusel_o <= `EXE_RES_JUMP_BRANCH; reg1_read_o <= 1'b1; reg2_read_o <= 1'b0;
wd_o <= inst_i[15:11];
link_addr_o <= pc_plus_8;
branch_target_address_o <= reg1_o;
branch_flag_o <= `Branch;
next_inst_in_delayslot_o <= `InDelaySlot;
instvalid <= `InstValid;
end
default: begin
end
endcase
end
default: begin
end
endcase
end
`EXE_ORI: begin //ORI指令
wreg_o <= `WriteEnable; aluop_o <= `EXE_OR_OP;
alusel_o <= `EXE_RES_LOGIC; reg1_read_o <= 1'b1; reg2_read_o <= 1'b0;
imm <= {16'h0, inst_i[15:0]}; wd_o <= inst_i[20:16];
instvalid <= `InstValid;
end
`EXE_ANDI: begin
wreg_o <= `WriteEnable; aluop_o <= `EXE_AND_OP;
alusel_o <= `EXE_RES_LOGIC; reg1_read_o <= 1'b1; reg2_read_o <= 1'b0;
imm <= {16'h0, inst_i[15:0]}; wd_o <= inst_i[20:16];
instvalid <= `InstValid;
end
`EXE_XORI: begin
wreg_o <= `WriteEnable; aluop_o <= `EXE_XOR_OP;
alusel_o <= `EXE_RES_LOGIC; reg1_read_o <= 1'b1; reg2_read_o <= 1'b0;
imm <= {16'h0, inst_i[15:0]}; wd_o <= inst_i[20:16];
instvalid <= `InstValid;
end
`EXE_LUI: begin
wreg_o <= `WriteEnable; aluop_o <= `EXE_OR_OP;
alusel_o <= `EXE_RES_LOGIC; reg1_read_o <= 1'b1; reg2_read_o <= 1'b0;
imm <= {inst_i[15:0], 16'h0}; wd_o <= inst_i[20:16];
instvalid <= `InstValid;
end
`EXE_SLTI: begin
wreg_o <= `WriteEnable; aluop_o <= `EXE_SLT_OP;
alusel_o <= `EXE_RES_ARITHMETIC; reg1_read_o <= 1'b1; reg2_read_o <= 1'b0;
imm <= {{16{inst_i[15]}}, inst_i[15:0]}; wd_o <= inst_i[20:16];
instvalid <= `InstValid;
end
`EXE_SLTIU: begin
wreg_o <= `WriteEnable; aluop_o <= `EXE_SLTU_OP;
alusel_o <= `EXE_RES_ARITHMETIC; reg1_read_o <= 1'b1; reg2_read_o <= 1'b0;
imm <= {{16{inst_i[15]}}, inst_i[15:0]}; wd_o <= inst_i[20:16];
instvalid <= `InstValid;
end
`EXE_PREF: begin
wreg_o <= `WriteDisable; aluop_o <= `EXE_NOP_OP;
alusel_o <= `EXE_RES_NOP; reg1_read_o <= 1'b0; reg2_read_o <= 1'b0;
instvalid <= `InstValid;
end
`EXE_ADDI: begin
wreg_o <= `WriteEnable; aluop_o <= `EXE_ADDI_OP;
alusel_o <= `EXE_RES_ARITHMETIC; reg1_read_o <= 1'b1; reg2_read_o <= 1'b0;
imm <= {{16{inst_i[15]}}, inst_i[15:0]}; wd_o <= inst_i[20:16];
instvalid <= `InstValid;
end
`EXE_ADDIU: begin
wreg_o <= `WriteEnable; aluop_o <= `EXE_ADDIU_OP;
alusel_o <= `EXE_RES_ARITHMETIC; reg1_read_o <= 1'b1; reg2_read_o <= 1'b0;
imm <= {{16{inst_i[15]}}, inst_i[15:0]}; wd_o <= inst_i[20:16];
instvalid <= `InstValid;
end
`EXE_J: begin
wreg_o <= `WriteDisable; //写寄存器打开
aluop_o <= `EXE_J_OP; //运算类型为j指令
alusel_o <= `EXE_RES_JUMP_BRANCH; //运算子类型是跳转指令
reg1_read_o <= 1'b0; //读寄存器1打开
reg2_read_o <= 1'b0; //读寄存器2打开
link_addr_o <= `ZeroWord; //转移指令要保存的返回地址置零
branch_target_address_o <= {pc_plus_4[31:28], inst_i[25:0], 2'b00}; //转移地址为加4后再加差值
branch_flag_o <= `Branch; //转移标记置1
next_inst_in_delayslot_o <= `InDelaySlot; //同时当前指令后一条指令放入延迟槽中
instvalid <= `InstValid;
end
`EXE_JAL: begin
wreg_o <= `WriteEnable; aluop_o <= `EXE_JAL_OP;
alusel_o <= `EXE_RES_JUMP_BRANCH; reg1_read_o <= 1'b0; reg2_read_o <= 1'b0;
wd_o <= 5'b11111;
link_addr_o <= pc_plus_8 ;
branch_target_address_o <= {pc_plus_4[31:28], inst_i[25:0], 2'b00};
branch_flag_o <= `Branch;
next_inst_in_delayslot_o <= `InDelaySlot;
instvalid <= `InstValid;
end
`EXE_BEQ: begin
wreg_o <= `WriteDisable; aluop_o <= `EXE_BEQ_OP;
alusel_o <= `EXE_RES_JUMP_BRANCH; reg1_read_o <= 1'b1; reg2_read_o <= 1'b1;
instvalid <= `InstValid;
if(reg1_o == reg2_o) begin
branch_target_address_o <= pc_plus_4 + imm_sll2_signedext;
branch_flag_o <= `Branch;
next_inst_in_delayslot_o <= `InDelaySlot;
end
end
`EXE_BGTZ: begin
wreg_o <= `WriteDisable; aluop_o <= `EXE_BGTZ_OP;
alusel_o <= `EXE_RES_JUMP_BRANCH; reg1_read_o <= 1'b1; reg2_read_o <= 1'b0;
instvalid <= `InstValid;
if((reg1_o[31] == 1'b0) && (reg1_o != `ZeroWord)) begin
branch_target_address_o <= pc_plus_4 + imm_sll2_signedext;
branch_flag_o <= `Branch;
next_inst_in_delayslot_o <= `InDelaySlot;
end
end
`EXE_BLEZ: begin
wreg_o <= `WriteDisable; aluop_o <= `EXE_BLEZ_OP;
alusel_o <= `EXE_RES_JUMP_BRANCH; reg1_read_o <= 1'b1; reg2_read_o <= 1'b0;
instvalid <= `InstValid;
if((reg1_o[31] == 1'b1) || (reg1_o == `ZeroWord)) begin
branch_target_address_o <= pc_plus_4 + imm_sll2_signedext;
branch_flag_o <= `Branch;
next_inst_in_delayslot_o <= `InDelaySlot;
end
end
`EXE_BNE: begin
wreg_o <= `WriteDisable; aluop_o <= `EXE_BLEZ_OP;
alusel_o <= `EXE_RES_JUMP_BRANCH; reg1_read_o <= 1'b1; reg2_read_o <= 1'b1;
instvalid <= `InstValid;
if(reg1_o != reg2_o) begin
branch_target_address_o <= pc_plus_4 + imm_sll2_signedext;
branch_flag_o <= `Branch;
next_inst_in_delayslot_o <= `InDelaySlot;
end
end
`EXE_LB: begin
wreg_o <= `WriteEnable; aluop_o <= `EXE_LB_OP;
alusel_o <= `EXE_RES_LOAD_STORE; reg1_read_o <= 1'b1; reg2_read_o <= 1'b0;
wd_o <= inst_i[20:16]; instvalid <= `InstValid;
end
`EXE_LBU: begin
wreg_o <= `WriteEnable; aluop_o <= `EXE_LBU_OP;
alusel_o <= `EXE_RES_LOAD_STORE; reg1_read_o <= 1'b1; reg2_read_o <= 1'b0;
wd_o <= inst_i[20:16]; instvalid <= `InstValid;
end
`EXE_LH: begin
wreg_o <= `WriteEnable; aluop_o <= `EXE_LH_OP;
alusel_o <= `EXE_RES_LOAD_STORE; reg1_read_o <= 1'b1; reg2_read_o <= 1'b0;
wd_o <= inst_i[20:16]; instvalid <= `InstValid;
end
`EXE_LHU: begin
wreg_o <= `WriteEnable; aluop_o <= `EXE_LHU_OP;
alusel_o <= `EXE_RES_LOAD_STORE; reg1_read_o <= 1'b1; reg2_read_o <= 1'b0;
wd_o <= inst_i[20:16]; instvalid <= `InstValid;
end
`EXE_LW: begin
wreg_o <= `WriteEnable; aluop_o <= `EXE_LW_OP;
alusel_o <= `EXE_RES_LOAD_STORE; reg1_read_o <= 1'b1; reg2_read_o <= 1'b0;
wd_o <= inst_i[20:16]; instvalid <= `InstValid;
end
`EXE_LL: begin
wreg_o <= `WriteEnable; aluop_o <= `EXE_LL_OP;
alusel_o <= `EXE_RES_LOAD_STORE; reg1_read_o <= 1'b1; reg2_read_o <= 1'b0;
wd_o <= inst_i[20:16]; instvalid <= `InstValid;
end
`EXE_LWL: begin
wreg_o <= `WriteEnable; aluop_o <= `EXE_LWL_OP;
alusel_o <= `EXE_RES_LOAD_STORE; reg1_read_o <= 1'b1; reg2_read_o <= 1'b1;
wd_o <= inst_i[20:16]; instvalid <= `InstValid;
end
`EXE_LWR: begin
wreg_o <= `WriteEnable; aluop_o <= `EXE_LWR_OP;
alusel_o <= `EXE_RES_LOAD_STORE; reg1_read_o <= 1'b1; reg2_read_o <= 1'b1;
wd_o <= inst_i[20:16]; instvalid <= `InstValid;
end
`EXE_SB: begin
wreg_o <= `WriteDisable; aluop_o <= `EXE_SB_OP;
reg1_read_o <= 1'b1; reg2_read_o <= 1'b1; instvalid <= `InstValid;
alusel_o <= `EXE_RES_LOAD_STORE;
end
`EXE_SH: begin
wreg_o <= `WriteDisable; aluop_o <= `EXE_SH_OP;
reg1_read_o <= 1'b1; reg2_read_o <= 1'b1; instvalid <= `InstValid;
alusel_o <= `EXE_RES_LOAD_STORE;
end
`EXE_SW: begin
wreg_o <= `WriteDisable; aluop_o <= `EXE_SW_OP;
reg1_read_o <= 1'b1; reg2_read_o <= 1'b1; instvalid <= `InstValid;
alusel_o <= `EXE_RES_LOAD_STORE;
end
`EXE_SWL: begin
wreg_o <= `WriteDisable; aluop_o <= `EXE_SWL_OP;
reg1_read_o <= 1'b1; reg2_read_o <= 1'b1; instvalid <= `InstValid;
alusel_o <= `EXE_RES_LOAD_STORE;
end
`EXE_SWR: begin
wreg_o <= `WriteDisable; aluop_o <= `EXE_SWR_OP;
reg1_read_o <= 1'b1; reg2_read_o <= 1'b1; instvalid <= `InstValid;
alusel_o <= `EXE_RES_LOAD_STORE;
end
`EXE_SC: begin
wreg_o <= `WriteEnable; aluop_o <= `EXE_SC_OP;
alusel_o <= `EXE_RES_LOAD_STORE; reg1_read_o <= 1'b1; reg2_read_o <= 1'b1;
wd_o <= inst_i[20:16]; instvalid <= `InstValid;
alusel_o <= `EXE_RES_LOAD_STORE;
end
`EXE_REGIMM_INST: begin
case (op4)
`EXE_BGEZ: begin
wreg_o <= `WriteDisable; aluop_o <= `EXE_BGEZ_OP;
alusel_o <= `EXE_RES_JUMP_BRANCH; reg1_read_o <= 1'b1; reg2_read_o <= 1'b0;
instvalid <= `InstValid;
if(reg1_o[31] == 1'b0) begin
branch_target_address_o <= pc_plus_4 + imm_sll2_signedext;
branch_flag_o <= `Branch;
next_inst_in_delayslot_o <= `InDelaySlot;
end
end
`EXE_BGEZAL: begin
wreg_o <= `WriteEnable; aluop_o <= `EXE_BGEZAL_OP;
alusel_o <= `EXE_RES_JUMP_BRANCH; reg1_read_o <= 1'b1; reg2_read_o <= 1'b0;
link_addr_o <= pc_plus_8;
wd_o <= 5'b11111; instvalid <= `InstValid;
if(reg1_o[31] == 1'b0) begin
branch_target_address_o <= pc_plus_4 + imm_sll2_signedext;
branch_flag_o <= `Branch;
next_inst_in_delayslot_o <= `InDelaySlot;
end
end
`EXE_BLTZ: begin
wreg_o <= `WriteDisable; aluop_o <= `EXE_BGEZAL_OP;
alusel_o <= `EXE_RES_JUMP_BRANCH; reg1_read_o <= 1'b1; reg2_read_o <= 1'b0;
instvalid <= `InstValid;
if(reg1_o[31] == 1'b1) begin
branch_target_address_o <= pc_plus_4 + imm_sll2_signedext;
branch_flag_o <= `Branch;
next_inst_in_delayslot_o <= `InDelaySlot;
end
end
`EXE_BLTZAL: begin
wreg_o <= `WriteEnable; aluop_o <= `EXE_BGEZAL_OP;
alusel_o <= `EXE_RES_JUMP_BRANCH; reg1_read_o <= 1'b1; reg2_read_o <= 1'b0;
link_addr_o <= pc_plus_8;
wd_o <= 5'b11111; instvalid <= `InstValid;
if(reg1_o[31] == 1'b1) begin
branch_target_address_o <= pc_plus_4 + imm_sll2_signedext;
branch_flag_o <= `Branch;
next_inst_in_delayslot_o <= `InDelaySlot;
end
end
default: begin
end
endcase
end
`EXE_SPECIAL2_INST: begin
case ( op3 )
`EXE_CLZ: begin
wreg_o <= `WriteEnable; aluop_o <= `EXE_CLZ_OP;
alusel_o <= `EXE_RES_ARITHMETIC; reg1_read_o <= 1'b1; reg2_read_o <= 1'b0;
instvalid <= `InstValid;
end
`EXE_CLO: begin
wreg_o <= `WriteEnable; aluop_o <= `EXE_CLO_OP;
alusel_o <= `EXE_RES_ARITHMETIC; reg1_read_o <= 1'b1; reg2_read_o <= 1'b0;
instvalid <= `InstValid;
end
`EXE_MUL: begin
wreg_o <= `WriteEnable; aluop_o <= `EXE_MUL_OP;
alusel_o <= `EXE_RES_MUL; reg1_read_o <= 1'b1; reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_MADD: begin
wreg_o <= `WriteDisable; aluop_o <= `EXE_MADD_OP;
alusel_o <= `EXE_RES_MUL; reg1_read_o <= 1'b1; reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_MADDU: begin
wreg_o <= `WriteDisable; aluop_o <= `EXE_MADDU_OP;
alusel_o <= `EXE_RES_MUL; reg1_read_o <= 1'b1; reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_MSUB: begin
wreg_o <= `WriteDisable; aluop_o <= `EXE_MSUB_OP;
alusel_o <= `EXE_RES_MUL; reg1_read_o <= 1'b1; reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
`EXE_MSUBU: begin
wreg_o <= `WriteDisable; aluop_o <= `EXE_MSUBU_OP;
alusel_o <= `EXE_RES_MUL; reg1_read_o <= 1'b1; reg2_read_o <= 1'b1;
instvalid <= `InstValid;
end
default: begin
end
endcase //EXE_SPECIAL_INST2 case
end
default: begin
end
endcase //case op
if (inst_i[31:21] == 11'b00000000000) begin
if (op3 == `EXE_SLL) begin
wreg_o <= `WriteEnable; aluop_o <= `EXE_SLL_OP;
alusel_o <= `EXE_RES_SHIFT; reg1_read_o <= 1'b0; reg2_read_o <= 1'b1;
imm[4:0] <= inst_i[10:6]; wd_o <= inst_i[15:11];
instvalid <= `InstValid;
end else if ( op3 == `EXE_SRL ) begin
wreg_o <= `WriteEnable; aluop_o <= `EXE_SRL_OP;
alusel_o <= `EXE_RES_SHIFT; reg1_read_o <= 1'b0; reg2_read_o <= 1'b1;
imm[4:0] <= inst_i[10:6]; wd_o <= inst_i[15:11];
instvalid <= `InstValid;
end else if ( op3 == `EXE_SRA ) begin
wreg_o <= `WriteEnable; aluop_o <= `EXE_SRA_OP;
alusel_o <= `EXE_RES_SHIFT; reg1_read_o <= 1'b0; reg2_read_o <= 1'b1;
imm[4:0] <= inst_i[10:6]; wd_o <= inst_i[15:11];
instvalid <= `InstValid;
end
end
end //if
end //always
always @ (*) begin
stallreq_for_reg1_loadrelate <= `NoStop;
if(rst == `RstEnable) begin
reg1_o <= `ZeroWord;
end else if(pre_inst_is_load == 1'b1 && ex_wd_i == reg1_addr_o
&& reg1_read_o == 1'b1 ) begin
stallreq_for_reg1_loadrelate <= `Stop;
end else if((reg1_read_o == 1'b1) && (ex_wreg_i == 1'b1)
&& (ex_wd_i == reg1_addr_o)) begin
reg1_o <= ex_wdata_i;
end else if((reg1_read_o == 1'b1) && (mem_wreg_i == 1'b1)
&& (mem_wd_i == reg1_addr_o)) begin
reg1_o <= mem_wdata_i;
end else if(reg1_read_o == 1'b1) begin
reg1_o <= reg1_data_i;
end else if(reg1_read_o == 1'b0) begin
reg1_o <= imm;
end else begin
reg1_o <= `ZeroWord;
end
end
always @ (*) begin
stallreq_for_reg2_loadrelate <= `NoStop;
if(rst == `RstEnable) begin
reg2_o <= `ZeroWord;
end else if(pre_inst_is_load == 1'b1 && ex_wd_i == reg2_addr_o
&& reg2_read_o == 1'b1 ) begin
stallreq_for_reg2_loadrelate <= `Stop;
end else if((reg2_read_o == 1'b1) && (ex_wreg_i == 1'b1)
&& (ex_wd_i == reg2_addr_o)) begin
reg2_o <= ex_wdata_i;
end else if((reg2_read_o == 1'b1) && (mem_wreg_i == 1'b1)
&& (mem_wd_i == reg2_addr_o)) begin
reg2_o <= mem_wdata_i;
end else if(reg2_read_o == 1'b1) begin
reg2_o <= reg2_data_i;
end else if(reg2_read_o == 1'b0) begin
reg2_o <= imm;
end else begin
reg2_o <= `ZeroWord;
end
end
always @ (*) begin
if(rst == `RstEnable) begin
is_in_delayslot_o <= `NotInDelaySlot; //复位信号有效时,不放入延迟槽
end else begin
is_in_delayslot_o <= is_in_delayslot_i; //否则顺延至下一阶段
end
end
endmodule
`include "defines.v"
module regfile(
input wire clk,
input wire rst,
//写端口
input wire we,
input wire[`RegAddrBus] waddr,
input wire[`RegBus] wdata,
//读端口1
input wire re1,
input wire[`RegAddrBus] raddr1,
output reg[`RegBus] rdata1,
//读端口2
input wire re2,
input wire[`RegAddrBus] raddr2,
output reg[`RegBus] rdata2
);
reg[`RegBus] regs[0:`RegNum-1];
always @ (posedge clk) begin
if (rst == `RstDisable) begin
if((we == `WriteEnable) && (waddr != `RegNumLog2'h0)) begin //写使能有效且写地址不为零
regs[waddr] <= wdata; //寄存器相应地址写入写寄存器中数据
end
end
end
always @ (*) begin
if(rst == `RstEnable) begin
rdata1 <= `ZeroWord; //复位信号有效,1号写寄存器置零
end else if(raddr1 == `RegNumLog2'h0) begin
rdata1 <= `ZeroWord; //1号寄存器写入地址为空,则写入数据置零
end else if((raddr1 == waddr) && (we == `WriteEnable)
&& (re1 == `ReadEnable)) begin
rdata1 <= wdata; //同步读写时,读入数据直接等于写入数据,不经过寄存器
end else if(re1 == `ReadEnable) begin
rdata1 <= regs[raddr1]; //异步读写时,读入数据从寄存器指定地址读
end else begin
rdata1 <= `ZeroWord; //否则读入数据置零
end
end
always @ (*) begin
if(rst == `RstEnable) begin
rdata2 <= `ZeroWord;
end else if(raddr2 == `RegNumLog2'h0) begin
rdata2 <= `ZeroWord;
end else if((raddr2 == waddr) && (we == `WriteEnable)
&& (re2 == `ReadEnable)) begin
rdata2 <= wdata;
end else if(re2 == `ReadEnable) begin
rdata2 <= regs[raddr2];
end else begin
rdata2 <= `ZeroWord;
end
end
endmodule
`include "defines.v"
module id_ex(
input wire clk,
input wire rst,
//来自控制模块的信息
input wire[5:0] stall,
//从译码阶段传递的信息
input wire[`AluOpBus] id_aluop,
input wire[`AluSelBus] id_alusel,
input wire[`RegBus] id_reg1,
input wire[`RegBus] id_reg2,
input wire[`RegAddrBus] id_wd,
input wire id_wreg,
input wire[`RegBus] id_link_address,
input wire id_is_in_delayslot,
input wire next_inst_in_delayslot_i,
input wire[`RegBus] id_inst,
//传递到执行阶段的信息
output reg[`AluOpBus] ex_aluop,
output reg[`AluSelBus] ex_alusel,
output reg[`RegBus] ex_reg1,
output reg[`RegBus] ex_reg2,
output reg[`RegAddrBus] ex_wd,
output reg ex_wreg,
output reg[`RegBus] ex_link_address,
output reg ex_is_in_delayslot,
output reg is_in_delayslot_o,
output reg[`RegBus] ex_inst
);
always @ (posedge clk) begin
if (rst == `RstEnable) begin //复位信号有效,各数据置零
ex_aluop <= `EXE_NOP_OP;
ex_alusel <= `EXE_RES_NOP;
ex_reg1 <= `ZeroWord;
ex_reg2 <= `ZeroWord;
ex_wd <= `NOPRegAddr;
ex_wreg <= `WriteDisable;
ex_link_address <= `ZeroWord;
ex_is_in_delayslot <= `NotInDelaySlot;
is_in_delayslot_o <= `NotInDelaySlot;
ex_inst <= `ZeroWord;
end else if(stall[2] == `Stop && stall[3] == `NoStop) begin //译码结束,执行开始,各数据置零
ex_aluop <= `EXE_NOP_OP;
ex_alusel <= `EXE_RES_NOP;
ex_reg1 <= `ZeroWord;
ex_reg2 <= `ZeroWord;
ex_wd <= `NOPRegAddr;
ex_wreg <= `WriteDisable;
ex_link_address <= `ZeroWord;
ex_is_in_delayslot <= `NotInDelaySlot;
ex_inst <= `ZeroWord;
end else if(stall[2] == `NoStop) begin //处于译码阶段,各数据保留到下一阶段
ex_aluop <= id_aluop;
ex_alusel <= id_alusel;
ex_reg1 <= id_reg1;
ex_reg2 <= id_reg2;
ex_wd <= id_wd;
ex_wreg <= id_wreg;
ex_link_address <= id_link_address;
ex_is_in_delayslot <= id_is_in_delayslot;
is_in_delayslot_o <= next_inst_in_delayslot_i;
ex_inst <= id_inst;
end
end
endmodule
`include "defines.v"
module ex(
input wire rst,
//送到执行阶段的信息
input wire[`AluOpBus] aluop_i,
input wire[`AluSelBus] alusel_i,
input wire[`RegBus] reg1_i,
input wire[`RegBus] reg2_i,
input wire[`RegAddrBus] wd_i,
input wire wreg_i,
input wire[`RegBus] inst_i,
//HI、LO寄存器的值
input wire[`RegBus] hi_i,
input wire[`RegBus] lo_i,
//回写阶段的指令是否要写HI、LO,用于检测HI、LO的数据相关
input wire[`RegBus] wb_hi_i,
input wire[`RegBus] wb_lo_i,
input wire wb_whilo_i,
//访存阶段的指令是否要写HI、LO,用于检测HI、LO的数据相关
input wire[`RegBus] mem_hi_i,
input wire[`RegBus] mem_lo_i,
input wire mem_whilo_i,
input wire[`DoubleRegBus] hilo_temp_i,
input wire[1:0] cnt_i,
//与除法模块相连
input wire[`DoubleRegBus] div_result_i,
input wire div_ready_i,
//是否转移、以及link address
input wire[`RegBus] link_address_i,
input wire is_in_delayslot_i,
output reg[`RegAddrBus] wd_o,
output reg wreg_o,
output reg[`RegBus] wdata_o,
output reg[`RegBus] hi_o,
output reg[`RegBus] lo_o,
output reg whilo_o,
output reg[`DoubleRegBus] hilo_temp_o,
output reg[1:0] cnt_o,
output reg[`RegBus] div_opdata1_o,
output reg[`RegBus] div_opdata2_o,
output reg div_start_o,
output reg signed_div_o,
//下面新增的几个输出是为加载、存储指令准备的
output wire[`AluOpBus] aluop_o,
output wire[`RegBus] mem_addr_o,
output wire[`RegBus] reg2_o,
output reg stallreq
);
reg[`RegBus] logicout;
reg[`RegBus] shiftres;
reg[`RegBus] moveres;
reg[`RegBus] arithmeticres;
reg[`DoubleRegBus] mulres;
reg[`RegBus] HI;
reg[`RegBus] LO;
wire[`RegBus] reg2_i_mux;
wire[`RegBus] reg1_i_not;
wire[`RegBus] result_sum;
wire ov_sum;
wire reg1_eq_reg2;
wire reg1_lt_reg2;
wire[`RegBus] opdata1_mult;
wire[`RegBus] opdata2_mult;
wire[`DoubleRegBus] hilo_temp;
reg[`DoubleRegBus] hilo_temp1;
reg stallreq_for_madd_msub;
reg stallreq_for_div;
//aluop_o传递到访存阶段,用于加载、存储指令
assign aluop_o = aluop_i;
//mem_addr传递到访存阶段,是加载、存储指令对应的存储器地址
assign mem_addr_o = reg1_i + {{16{inst_i[15]}},inst_i[15:0]};
//将两个操作数也传递到访存阶段,也是为记载、存储指令准备的
assign reg2_o = reg2_i;
always @ (*) begin
if(rst == `RstEnable) begin
logicout <= `ZeroWord;
end else begin
case (aluop_i) //根据译码阶段传来的类型决定操作
`EXE_OR_OP: begin
logicout <= reg1_i | reg2_i;
end
`EXE_AND_OP: begin
logicout <= reg1_i & reg2_i;
end
`EXE_NOR_OP: begin
logicout <= ~(reg1_i |reg2_i);
end
`EXE_XOR_OP: begin
logicout <= reg1_i ^ reg2_i;
end
default: begin
logicout <= `ZeroWord;
end
endcase
end //if
end //always
always @ (*) begin
if(rst == `RstEnable) begin
shiftres <= `ZeroWord;
end else begin
case (aluop_i)
`EXE_SLL_OP: begin
shiftres <= reg2_i << reg1_i[4:0] ;
end
`EXE_SRL_OP: begin
shiftres <= reg2_i >> reg1_i[4:0];
end
`EXE_SRA_OP: begin
shiftres <= ({32{reg2_i[31]}} << (6'd32-{1'b0, reg1_i[4:0]}))
| reg2_i >> reg1_i[4:0];
end
default: begin
shiftres <= `ZeroWord;
end
endcase
end //if
end //always
assign reg2_i_mux = ((aluop_i == `EXE_SUB_OP) || (aluop_i == `EXE_SUBU_OP) ||
(aluop_i == `EXE_SLT_OP) )
? (~reg2_i)+1 : reg2_i;
assign result_sum = reg1_i + reg2_i_mux;
assign ov_sum = ((!reg1_i[31] && !reg2_i_mux[31]) && result_sum[31]) ||
((reg1_i[31] && reg2_i_mux[31]) && (!result_sum[31]));
assign reg1_lt_reg2 = ((aluop_i == `EXE_SLT_OP)) ?
((reg1_i[31] && !reg2_i[31]) ||
(!reg1_i[31] && !reg2_i[31] && result_sum[31])||
(reg1_i[31] && reg2_i[31] && result_sum[31]))
: (reg1_i < reg2_i);
assign reg1_i_not = ~reg1_i;
always @ (*) begin
if(rst == `RstEnable) begin
arithmeticres <= `ZeroWord;
end else begin
case (aluop_i)
`EXE_SLT_OP, `EXE_SLTU_OP: begin
arithmeticres <= reg1_lt_reg2 ;
end
`EXE_ADD_OP, `EXE_ADDU_OP, `EXE_ADDI_OP, `EXE_ADDIU_OP: begin
arithmeticres <= result_sum;
end
`EXE_SUB_OP, `EXE_SUBU_OP: begin
arithmeticres <= result_sum;
end
`EXE_CLZ_OP: begin
arithmeticres <= reg1_i[31] ? 0 : reg1_i[30] ? 1 : reg1_i[29] ? 2 :
reg1_i[28] ? 3 : reg1_i[27] ? 4 : reg1_i[26] ? 5 :
reg1_i[25] ? 6 : reg1_i[24] ? 7 : reg1_i[23] ? 8 :
reg1_i[22] ? 9 : reg1_i[21] ? 10 : reg1_i[20] ? 11 :
reg1_i[19] ? 12 : reg1_i[18] ? 13 : reg1_i[17] ? 14 :
reg1_i[16] ? 15 : reg1_i[15] ? 16 : reg1_i[14] ? 17 :
reg1_i[13] ? 18 : reg1_i[12] ? 19 : reg1_i[11] ? 20 :
reg1_i[10] ? 21 : reg1_i[9] ? 22 : reg1_i[8] ? 23 :
reg1_i[7] ? 24 : reg1_i[6] ? 25 : reg1_i[5] ? 26 :
reg1_i[4] ? 27 : reg1_i[3] ? 28 : reg1_i[2] ? 29 :
reg1_i[1] ? 30 : reg1_i[0] ? 31 : 32 ;
end
`EXE_CLO_OP: begin
arithmeticres <= (reg1_i_not[31] ? 0 : reg1_i_not[30] ? 1 : reg1_i_not[29] ? 2 :
reg1_i_not[28] ? 3 : reg1_i_not[27] ? 4 : reg1_i_not[26] ? 5 :
reg1_i_not[25] ? 6 : reg1_i_not[24] ? 7 : reg1_i_not[23] ? 8 :
reg1_i_not[22] ? 9 : reg1_i_not[21] ? 10 : reg1_i_not[20] ? 11 :
reg1_i_not[19] ? 12 : reg1_i_not[18] ? 13 : reg1_i_not[17] ? 14 :
reg1_i_not[16] ? 15 : reg1_i_not[15] ? 16 : reg1_i_not[14] ? 17 :
reg1_i_not[13] ? 18 : reg1_i_not[12] ? 19 : reg1_i_not[11] ? 20 :
reg1_i_not[10] ? 21 : reg1_i_not[9] ? 22 : reg1_i_not[8] ? 23 :
reg1_i_not[7] ? 24 : reg1_i_not[6] ? 25 : reg1_i_not[5] ? 26 :
reg1_i_not[4] ? 27 : reg1_i_not[3] ? 28 : reg1_i_not[2] ? 29 :
reg1_i_not[1] ? 30 : reg1_i_not[0] ? 31 : 32) ;
end
default: begin
arithmeticres <= `ZeroWord;
end
endcase
end
end
//取得乘法操作的操作数,如果是有符号除法且操作数是负数,那么取反加一
assign opdata1_mult = (((aluop_i == `EXE_MUL_OP) || (aluop_i == `EXE_MULT_OP) ||
(aluop_i == `EXE_MADD_OP) || (aluop_i == `EXE_MSUB_OP))
&& (reg1_i[31] == 1'b1)) ? (~reg1_i + 1) : reg1_i;
//取的乘法运算的乘数,如果是有符号乘法且乘数是负数,那么取补码
assign opdata2_mult = (((aluop_i == `EXE_MUL_OP) || (aluop_i == `EXE_MULT_OP) ||
(aluop_i == `EXE_MADD_OP) || (aluop_i == `EXE_MSUB_OP))
&& (reg2_i[31] == 1'b1)) ? (~reg2_i + 1) : reg2_i;
//得到临时乘法结果,保存在变量hilo_temp中
assign hilo_temp = opdata1_mult * opdata2_mult;
//对临时乘法结果进行修正,最终的惩罚结果保存在变量mulres中,主要有两点:
//1.如果是有符号乘法指令mult、mul,那么需要修正临时乘法结果如下:
// (1)如果被乘数与乘数两者一正一负,那么需要对临时乘法结果hilo_temp求补码,作为最终的惩罚结果,赋给变量mulres。
//(2)如果被乘数与乘数同号,那么hilo_temp的值就作为最终的惩罚结果,赋给变量mulres。
//2.如果是无符号乘法指令multu,那么hilo_temp的值就作为最终的乘法结果,赋给变量mulres
always @ (*) begin
if(rst == `RstEnable) begin
mulres <= {`ZeroWord,`ZeroWord};
end else if ((aluop_i == `EXE_MULT_OP) || (aluop_i == `EXE_MUL_OP) ||
(aluop_i == `EXE_MADD_OP) || (aluop_i == `EXE_MSUB_OP))begin
if(reg1_i[31] ^ reg2_i[31] == 1'b1) begin
mulres <= ~hilo_temp + 1;
end else begin
mulres <= hilo_temp;
end
end else begin
mulres <= hilo_temp;
end
end
//得到最新的HI、LO寄存器的值,此处要解决指令数据相关问题
always @ (*) begin
if(rst == `RstEnable) begin
{HI,LO} <= {`ZeroWord,`ZeroWord};
end else if(mem_whilo_i == `WriteEnable) begin
{HI,LO} <= {mem_hi_i,mem_lo_i};
end else if(wb_whilo_i == `WriteEnable) begin
{HI,LO} <= {wb_hi_i,wb_lo_i};
end else begin
{HI,LO} <= {hi_i,lo_i};
end
end
always @ (*) begin
stallreq = stallreq_for_madd_msub || stallreq_for_div;
end
//MADD、MADDU、MSUB、MSUBU指令
always @ (*) begin
if(rst == `RstEnable) begin
hilo_temp_o <= {`ZeroWord,`ZeroWord};
cnt_o <= 2'b00;
stallreq_for_madd_msub <= `NoStop;
end else begin
case (aluop_i)
`EXE_MADD_OP, `EXE_MADDU_OP: begin
if(cnt_i == 2'b00) begin
hilo_temp_o <= mulres;
cnt_o <= 2'b01;
stallreq_for_madd_msub <= `Stop;
hilo_temp1 <= {`ZeroWord,`ZeroWord};
end else if(cnt_i == 2'b01) begin
hilo_temp_o <= {`ZeroWord,`ZeroWord};
cnt_o <= 2'b10;
hilo_temp1 <= hilo_temp_i + {HI,LO};
stallreq_for_madd_msub <= `NoStop;
end
end
`EXE_MSUB_OP, `EXE_MSUBU_OP: begin
if(cnt_i == 2'b00) begin
hilo_temp_o <= ~mulres + 1 ;
cnt_o <= 2'b01;
stallreq_for_madd_msub <= `Stop;
end else if(cnt_i == 2'b01)begin
hilo_temp_o <= {`ZeroWord,`ZeroWord};
cnt_o <= 2'b10;
hilo_temp1 <= hilo_temp_i + {HI,LO};
stallreq_for_madd_msub <= `NoStop;
end
end
default: begin
hilo_temp_o <= {`ZeroWord,`ZeroWord};
cnt_o <= 2'b00;
stallreq_for_madd_msub <= `NoStop;
end
endcase
end
end
//DIV、DIVU指令
always @ (*) begin
if(rst == `RstEnable) begin
stallreq_for_div <= `NoStop;
div_opdata1_o <= `ZeroWord;
div_opdata2_o <= `ZeroWord;
div_start_o <= `DivStop;
signed_div_o <= 1'b0;
end else begin
stallreq_for_div <= `NoStop;
div_opdata1_o <= `ZeroWord;
div_opdata2_o <= `ZeroWord;
div_start_o <= `DivStop;
signed_div_o <= 1'b0;
case (aluop_i)
`EXE_DIV_OP: begin
if(div_ready_i == `DivResultNotReady) begin
div_opdata1_o <= reg1_i;
div_opdata2_o <= reg2_i;
div_start_o <= `DivStart;
signed_div_o <= 1'b1;
stallreq_for_div <= `Stop;
end else if(div_ready_i == `DivResultReady) begin
div_opdata1_o <= reg1_i;
div_opdata2_o <= reg2_i;
div_start_o <= `DivStop;
signed_div_o <= 1'b1;
stallreq_for_div <= `NoStop;
end else begin
div_opdata1_o <= `ZeroWord;
div_opdata2_o <= `ZeroWord;
div_start_o <= `DivStop;
signed_div_o <= 1'b0;
stallreq_for_div <= `NoStop;
end
end
`EXE_DIVU_OP: begin
if(div_ready_i == `DivResultNotReady) begin
div_opdata1_o <= reg1_i;
div_opdata2_o <= reg2_i;
div_start_o <= `DivStart;
signed_div_o <= 1'b0;
stallreq_for_div <= `Stop;
end else if(div_ready_i == `DivResultReady) begin
div_opdata1_o <= reg1_i;
div_opdata2_o <= reg2_i;
div_start_o <= `DivStop;
signed_div_o <= 1'b0;
stallreq_for_div <= `NoStop;
end else begin
div_opdata1_o <= `ZeroWord;
div_opdata2_o <= `ZeroWord;
div_start_o <= `DivStop;
signed_div_o <= 1'b0;
stallreq_for_div <= `NoStop;
end
end
default: begin
end
endcase
end
end
//MFHI、MFLO、MOVN、MOVZ指令
always @ (*) begin
if(rst == `RstEnable) begin
moveres <= `ZeroWord;
end else begin
moveres <= `ZeroWord;
case (aluop_i)
//如果是mfhi指令,那么将hi的值作为移动操作的结果
`EXE_MFHI_OP: begin
moveres <= HI;
end
//如果是mflo指令,那么将lo的值作为移动操作的结果
`EXE_MFLO_OP: begin
moveres <= LO;
end
`EXE_MOVZ_OP: begin
moveres <= reg1_i;
end
`EXE_MOVN_OP: begin
moveres <= reg1_i;
end
default : begin
end
endcase
end
end
always @ (*) begin
wd_o <= wd_i;
if(((aluop_i == `EXE_ADD_OP) || (aluop_i == `EXE_ADDI_OP) ||
(aluop_i == `EXE_SUB_OP)) && (ov_sum == 1'b1)) begin
wreg_o <= `WriteDisable;
end else begin
wreg_o <= wreg_i;
end
case ( alusel_i )
`EXE_RES_LOGIC: begin
wdata_o <= logicout;
end
`EXE_RES_SHIFT: begin
wdata_o <= shiftres;
end
`EXE_RES_MOVE: begin
wdata_o <= moveres;
end
`EXE_RES_ARITHMETIC: begin
wdata_o <= arithmeticres;
end
`EXE_RES_MUL: begin
wdata_o <= mulres[31:0];
end
`EXE_RES_JUMP_BRANCH: begin
wdata_o <= link_address_i;
end
default: begin
wdata_o <= `ZeroWord;
end
endcase
end
always @ (*) begin
if(rst == `RstEnable) begin
whilo_o <= `WriteDisable;
hi_o <= `ZeroWord;
lo_o <= `ZeroWord;
end else if((aluop_i == `EXE_MULT_OP) || (aluop_i == `EXE_MULTU_OP)) begin
whilo_o <= `WriteEnable;
hi_o <= mulres[63:32];
lo_o <= mulres[31:0];
end else if((aluop_i == `EXE_MADD_OP) || (aluop_i == `EXE_MADDU_OP)) begin
whilo_o <= `WriteEnable;
hi_o <= hilo_temp1[63:32];
lo_o <= hilo_temp1[31:0];
end else if((aluop_i == `EXE_MSUB_OP) || (aluop_i == `EXE_MSUBU_OP)) begin
whilo_o <= `WriteEnable;
hi_o <= hilo_temp1[63:32];
lo_o <= hilo_temp1[31:0];
end else if((aluop_i == `EXE_DIV_OP) || (aluop_i == `EXE_DIVU_OP)) begin
whilo_o <= `WriteEnable;
hi_o <= div_result_i[63:32];
lo_o <= div_result_i[31:0];
end else if(aluop_i == `EXE_MTHI_OP) begin
whilo_o <= `WriteEnable;
hi_o <= reg1_i;
lo_o <= LO;
end else if(aluop_i == `EXE_MTLO_OP) begin
whilo_o <= `WriteEnable;
hi_o <= HI;
lo_o <= reg1_i;
end else begin
whilo_o <= `WriteDisable;
hi_o <= `ZeroWord;
lo_o <= `ZeroWord;
end
end
endmodule
`include "defines.v"
module ex_mem(
input wire clk,
input wire rst,
//来自控制模块的信息
input wire[5:0] stall,
//来自执行阶段的信息
input wire[`RegAddrBus] ex_wd,
input wire ex_wreg,
input wire[`RegBus] ex_wdata,
input wire[`RegBus] ex_hi,
input wire[`RegBus] ex_lo,
input wire ex_whilo,
//为实现加载、访存指令而添加
input wire[`AluOpBus] ex_aluop,
input wire[`RegBus] ex_mem_addr,
input wire[`RegBus] ex_reg2,
input wire[`DoubleRegBus] hilo_i,
input wire[1:0] cnt_i,
//送到访存阶段的信息
output reg[`RegAddrBus] mem_wd,
output reg mem_wreg,
output reg[`RegBus] mem_wdata,
output reg[`RegBus] mem_hi,
output reg[`RegBus] mem_lo,
output reg mem_whilo,
//为实现加载、访存指令而添加
output reg[`AluOpBus] mem_aluop,
output reg[`RegBus] mem_mem_addr,
output reg[`RegBus] mem_reg2,
output reg[`DoubleRegBus] hilo_o,
output reg[1:0] cnt_o
);
always @ (posedge clk) begin
if(rst == `RstEnable) begin
mem_wd <= `NOPRegAddr;
mem_wreg <= `WriteDisable;
mem_wdata <= `ZeroWord;
mem_hi <= `ZeroWord;
mem_lo <= `ZeroWord;
mem_whilo <= `WriteDisable;
hilo_o <= {`ZeroWord, `ZeroWord};
cnt_o <= 2'b00;
mem_aluop <= `EXE_NOP_OP;
mem_mem_addr <= `ZeroWord;
mem_reg2 <= `ZeroWord;
end else if(stall[3] == `Stop && stall[4] == `NoStop) begin
mem_wd <= `NOPRegAddr;
mem_wreg <= `WriteDisable;
mem_wdata <= `ZeroWord;
mem_hi <= `ZeroWord;
mem_lo <= `ZeroWord;
mem_whilo <= `WriteDisable;
hilo_o <= hilo_i;
cnt_o <= cnt_i;
mem_aluop <= `EXE_NOP_OP;
mem_mem_addr <= `ZeroWord;
mem_reg2 <= `ZeroWord;
end else if(stall[3] == `NoStop) begin
mem_wd <= ex_wd;
mem_wreg <= ex_wreg;
mem_wdata <= ex_wdata;
mem_hi <= ex_hi;
mem_lo <= ex_lo;
mem_whilo <= ex_whilo;
hilo_o <= {`ZeroWord, `ZeroWord};
cnt_o <= 2'b00;
mem_aluop <= ex_aluop;
mem_mem_addr <= ex_mem_addr;
mem_reg2 <= ex_reg2;
end else begin
hilo_o <= hilo_i;
cnt_o <= cnt_i;
end //if
end //always
endmodule
`include "defines.v"
module mem(
input wire rst,
//来自执行阶段的信息
input wire[`RegAddrBus] wd_i,
input wire wreg_i,
input wire[`RegBus] wdata_i,
input wire[`RegBus] hi_i,
input wire[`RegBus] lo_i,
input wire whilo_i,
input wire[`AluOpBus] aluop_i,
input wire[`RegBus] mem_addr_i,
input wire[`RegBus] reg2_i,
//来自memory的信息
input wire[`RegBus] mem_data_i,
//LLbit_i是LLbit寄存器的值
input wire LLbit_i,
//但不一定是最新值,回写阶段可能要写LLbit,所以还要进一步判断
input wire wb_LLbit_we_i,
input wire wb_LLbit_value_i,
//送到回写阶段的信息
output reg[`RegAddrBus] wd_o,
output reg wreg_o,
output reg[`RegBus] wdata_o,
output reg[`RegBus] hi_o,
output reg[`RegBus] lo_o,
output reg whilo_o,
output reg LLbit_we_o,
output reg LLbit_value_o,
//送到memory的信息
output reg[`RegBus] mem_addr_o,
output wire mem_we_o,
output reg[3:0] mem_sel_o,
output reg[`RegBus] mem_data_o,
output reg mem_ce_o
);
reg LLbit;
wire[`RegBus] zero32;
reg mem_we;
assign mem_we_o = mem_we ;
assign zero32 = `ZeroWord;
//获取最新的LLbit的值
always @ (*) begin
if(rst == `RstEnable) begin
LLbit <= 1'b0;
end else begin
if(wb_LLbit_we_i == 1'b1) begin
LLbit <= wb_LLbit_value_i;
end else begin
LLbit <= LLbit_i;
end
end
end
always @ (*) begin
if(rst == `RstEnable) begin //复位指令有效,全部置零
wd_o <= `NOPRegAddr;
wreg_o <= `WriteDisable;
wdata_o <= `ZeroWord;
hi_o <= `ZeroWord;
lo_o <= `ZeroWord;
whilo_o <= `WriteDisable;
mem_addr_o <= `ZeroWord;
mem_we <= `WriteDisable;
mem_sel_o <= 4'b0000;
mem_data_o <= `ZeroWord;
mem_ce_o <= `ChipDisable;
LLbit_we_o <= 1'b0;
LLbit_value_o <= 1'b0;
end else begin //复位指令无效,保持原数据
wd_o <= wd_i;
wreg_o <= wreg_i;
wdata_o <= wdata_i;
hi_o <= hi_i;
lo_o <= lo_i;
whilo_o <= whilo_i;
mem_we <= `WriteDisable;
mem_addr_o <= `ZeroWord;
mem_sel_o <= 4'b1111;
mem_ce_o <= `ChipDisable;
LLbit_we_o <= 1'b0;
LLbit_value_o <= 1'b0;
case (aluop_i)
`EXE_LB_OP: begin
mem_addr_o <= mem_addr_i;
mem_we <= `WriteDisable; //加载操作,将写使能置0
mem_ce_o <= `ChipEnable; //访问数据存储器使能信号,将数据存储器使能信号置1
case (mem_addr_i[1:0]) //依据mem_addr_i最后两位确定mem_sel_o的值
2'b00: begin
wdata_o <= {{24{mem_data_i[31]}},mem_data_i[31:24]}; //从主存中读出的数据
mem_sel_o <= 4'b1000; //符号位字拓展
end
2'b01: begin
wdata_o <= {{24{mem_data_i[23]}},mem_data_i[23:16]};
mem_sel_o <= 4'b0100;
end
2'b10: begin
wdata_o <= {{24{mem_data_i[15]}},mem_data_i[15:8]};
mem_sel_o <= 4'b0010;
end
2'b11: begin
wdata_o <= {{24{mem_data_i[7]}},mem_data_i[7:0]};
mem_sel_o <= 4'b0001;
end
default: begin
wdata_o <= `ZeroWord;
end
endcase
end
`EXE_LBU_OP: begin
mem_addr_o <= mem_addr_i;
mem_we <= `WriteDisable;
mem_ce_o <= `ChipEnable;
case (mem_addr_i[1:0])
2'b00: begin
wdata_o <= {{24{1'b0}},mem_data_i[31:24]};
mem_sel_o <= 4'b1000;
end
2'b01: begin
wdata_o <= {{24{1'b0}},mem_data_i[23:16]};
mem_sel_o <= 4'b0100;
end
2'b10: begin
wdata_o <= {{24{1'b0}},mem_data_i[15:8]};
mem_sel_o <= 4'b0010;
end
2'b11: begin
wdata_o <= {{24{1'b0}},mem_data_i[7:0]};
mem_sel_o <= 4'b0001;
end
default: begin
wdata_o <= `ZeroWord;
end
endcase
end
`EXE_LH_OP: begin
mem_addr_o <= mem_addr_i;
mem_we <= `WriteDisable;
mem_ce_o <= `ChipEnable;
case (mem_addr_i[1:0])
2'b00: begin
wdata_o <= {{16{mem_data_i[31]}},mem_data_i[31:16]};
mem_sel_o <= 4'b1100;
end
2'b10: begin
wdata_o <= {{16{mem_data_i[15]}},mem_data_i[15:0]};
mem_sel_o <= 4'b0011;
end
default: begin
wdata_o <= `ZeroWord;
end
endcase
end
`EXE_LHU_OP: begin
mem_addr_o <= mem_addr_i;
mem_we <= `WriteDisable;
mem_ce_o <= `ChipEnable;
case (mem_addr_i[1:0])
2'b00: begin
wdata_o <= {{16{1'b0}},mem_data_i[31:16]};
mem_sel_o <= 4'b1100;
end
2'b10: begin
wdata_o <= {{16{1'b0}},mem_data_i[15:0]};
mem_sel_o <= 4'b0011;
end
default: begin
wdata_o <= `ZeroWord;
end
endcase
end
`EXE_LW_OP: begin
mem_addr_o <= mem_addr_i; //目的指令的地址
mem_we <= `WriteDisable; //关写使能
wdata_o <= mem_data_i; //目的数据
mem_sel_o <= 4'b1111; //
mem_ce_o <= `ChipEnable; //开读使能
end
`EXE_LWL_OP: begin
mem_addr_o <= {mem_addr_i[31:2], 2'b00};
mem_we <= `WriteDisable;
mem_sel_o <= 4'b1111;
mem_ce_o <= `ChipEnable;
case (mem_addr_i[1:0])
2'b00: begin
wdata_o <= mem_data_i[31:0];
end
2'b01: begin
wdata_o <= {mem_data_i[23:0],reg2_i[7:0]};
end
2'b10: begin
wdata_o <= {mem_data_i[15:0],reg2_i[15:0]};
end
2'b11: begin
wdata_o <= {mem_data_i[7:0],reg2_i[23:0]};
end
default: begin
wdata_o <= `ZeroWord;
end
endcase
end
`EXE_LWR_OP: begin
mem_addr_o <= {mem_addr_i[31:2], 2'b00};
mem_we <= `WriteDisable;
mem_sel_o <= 4'b1111;
mem_ce_o <= `ChipEnable;
case (mem_addr_i[1:0])
2'b00: begin
wdata_o <= {reg2_i[31:8],mem_data_i[31:24]};
end
2'b01: begin
wdata_o <= {reg2_i[31:16],mem_data_i[31:16]};
end
2'b10: begin
wdata_o <= {reg2_i[31:24],mem_data_i[31:8]};
end
2'b11: begin
wdata_o <= mem_data_i;
end
default: begin
wdata_o <= `ZeroWord;
end
endcase
end
`EXE_LL_OP: begin
mem_addr_o <= mem_addr_i;
mem_we <= `WriteDisable;
wdata_o <= mem_data_i;
LLbit_we_o <= 1'b1;
LLbit_value_o <= 1'b1;
mem_sel_o <= 4'b1111;
mem_ce_o <= `ChipEnable;
end
`EXE_SB_OP: begin
mem_addr_o <= mem_addr_i;
mem_we <= `WriteEnable;
mem_data_o <= {reg2_i[7:0],reg2_i[7:0],reg2_i[7:0],reg2_i[7:0]};
mem_ce_o <= `ChipEnable;
case (mem_addr_i[1:0])
2'b00: begin
mem_sel_o <= 4'b1000;
end
2'b01: begin
mem_sel_o <= 4'b0100;
end
2'b10: begin
mem_sel_o <= 4'b0010;
end
2'b11: begin
mem_sel_o <= 4'b0001;
end
default: begin
mem_sel_o <= 4'b0000;
end
endcase
end
`EXE_SH_OP: begin
mem_addr_o <= mem_addr_i;
mem_we <= `WriteEnable;
mem_data_o <= {reg2_i[15:0],reg2_i[15:0]};
mem_ce_o <= `ChipEnable;
case (mem_addr_i[1:0])
2'b00: begin
mem_sel_o <= 4'b1100;
end
2'b10: begin
mem_sel_o <= 4'b0011;
end
default: begin
mem_sel_o <= 4'b0000;
end
endcase
end
`EXE_SW_OP: begin
mem_addr_o <= mem_addr_i;
mem_we <= `WriteEnable;
mem_data_o <= reg2_i;
mem_sel_o <= 4'b1111;
mem_ce_o <= `ChipEnable;
end
`EXE_SWL_OP: begin
mem_addr_o <= {mem_addr_i[31:2], 2'b00};
mem_we <= `WriteEnable;
mem_ce_o <= `ChipEnable;
case (mem_addr_i[1:0])
2'b00: begin
mem_sel_o <= 4'b1111;
mem_data_o <= reg2_i;
end
2'b01: begin
mem_sel_o <= 4'b0111;
mem_data_o <= {zero32[7:0],reg2_i[31:8]};
end
2'b10: begin
mem_sel_o <= 4'b0011;
mem_data_o <= {zero32[15:0],reg2_i[31:16]};
end
2'b11: begin
mem_sel_o <= 4'b0001;
mem_data_o <= {zero32[23:0],reg2_i[31:24]};
end
default: begin
mem_sel_o <= 4'b0000;
end
endcase
end
`EXE_SWR_OP: begin
mem_addr_o <= {mem_addr_i[31:2], 2'b00};
mem_we <= `WriteEnable;
mem_ce_o <= `ChipEnable;
case (mem_addr_i[1:0])
2'b00: begin
mem_sel_o <= 4'b1000;
mem_data_o <= {reg2_i[7:0],zero32[23:0]};
end
2'b01: begin
mem_sel_o <= 4'b1100;
mem_data_o <= {reg2_i[15:0],zero32[15:0]};
end
2'b10: begin
mem_sel_o <= 4'b1110;
mem_data_o <= {reg2_i[23:0],zero32[7:0]};
end
2'b11: begin
mem_sel_o <= 4'b1111;
mem_data_o <= reg2_i[31:0];
end
default: begin
mem_sel_o <= 4'b0000;
end
endcase
end
`EXE_SC_OP: begin
if(LLbit == 1'b1) begin
LLbit_we_o <= 1'b1;
LLbit_value_o <= 1'b0;
mem_addr_o <= mem_addr_i;
mem_we <= `WriteEnable;
mem_data_o <= reg2_i;
wdata_o <= 32'b1;
mem_sel_o <= 4'b1111;
mem_ce_o <= `ChipEnable;
end else begin
wdata_o <= 32'b0;
end
end
default: begin
//什么也不做
end
endcase
end //if
end //always
endmodule
`include "defines.v"
module mem_wb(
input wire clk,
input wire rst,
//来自控制模块的信息
input wire[5:0] stall,
//来自访存阶段的信息
input wire[`RegAddrBus] mem_wd,
input wire mem_wreg,
input wire[`RegBus] mem_wdata,
input wire[`RegBus] mem_hi,
input wire[`RegBus] mem_lo,
input wire mem_whilo,
input wire mem_LLbit_we,
input wire mem_LLbit_value,
//送到回写阶段的信息
output reg[`RegAddrBus] wb_wd,
output reg wb_wreg,
output reg[`RegBus] wb_wdata,
output reg[`RegBus] wb_hi,
output reg[`RegBus] wb_lo,
output reg wb_whilo,
output reg wb_LLbit_we,
output reg wb_LLbit_value
);
always @ (posedge clk) begin
if(rst == `RstEnable) begin //若复位信号有效,则全部置零
wb_wd <= `NOPRegAddr;
wb_wreg <= `WriteDisable;
wb_wdata <= `ZeroWord;
wb_hi <= `ZeroWord;
wb_lo <= `ZeroWord;
wb_whilo <= `WriteDisable;
wb_LLbit_we <= 1'b0;
wb_LLbit_value <= 1'b0;
end else if(stall[4] == `Stop && stall[5] == `NoStop) begin //访存结束,回写开始
wb_wd <= `NOPRegAddr;
wb_wreg <= `WriteDisable;
wb_wdata <= `ZeroWord;
wb_hi <= `ZeroWord;
wb_lo <= `ZeroWord;
wb_whilo <= `WriteDisable;
wb_LLbit_we <= 1'b0;
wb_LLbit_value <= 1'b0;
end else if(stall[4] == `NoStop) begin //访存阶段,数据保持
wb_wd <= mem_wd;
wb_wreg <= mem_wreg;
wb_wdata <= mem_wdata;
wb_hi <= mem_hi;
wb_lo <= mem_lo;
wb_whilo <= mem_whilo;
wb_LLbit_we <= mem_LLbit_we;
wb_LLbit_value <= mem_LLbit_value;
end //if
end //always
endmodule
`include "defines.v"
module hilo_reg(
input wire clk,
input wire rst,
//写端口
input wire we,
input wire[`RegBus] hi_i,
input wire[`RegBus] lo_i,
//读端口1
output reg[`RegBus] hi_o,
output reg[`RegBus] lo_o
);
always @ (posedge clk) begin
if (rst == `RstEnable) begin
hi_o <= `ZeroWord;
lo_o <= `ZeroWord;
end else if((we == `WriteEnable)) begin //数据更新
hi_o <= hi_i;
lo_o <= lo_i;
end
end
endmodule
`include "defines.v"
module ctrl(
input wire rst,
input wire stallreq_from_id,
//来自执行阶段的暂停请求
input wire stallreq_from_ex,
output reg[5:0] stall
);
always @ (*) begin
if(rst == `RstEnable) begin
stall <= 6'b000000;
end else if(stallreq_from_ex == `Stop) begin
stall <= 6'b001111;
end else if(stallreq_from_id == `Stop) begin
stall <= 6'b000111;
end else begin
stall <= 6'b000000;
end //if
end //always
endmodule
`include "defines.v"
module div(
input wire clk,
input wire rst,
input wire signed_div_i,
input wire[31:0] opdata1_i,
input wire[31:0] opdata2_i,
input wire start_i,
input wire annul_i,
output reg[63:0] result_o,
output reg ready_o
);
wire[32:0] div_temp;
reg[5:0] cnt;
reg[64:0] dividend;
reg[1:0] state;
reg[31:0] divisor;
reg[31:0] temp_op1;
reg[31:0] temp_op2;
//dividend的低32位保存的是被除数、中间结果,第k次迭代结束的时候dividend【k:0】保存的就是当前得到的中间结果,dividend【31:k+1】保存的就是被除数中还没有参与运算的数据,dividend高32位是每次迭代时的被减数,所以dividend【63:32】就是图中的minuend,divisor就是图中的除数n,此处进行的就是minuend-n运算,结果保存在div_temp中
//
assign div_temp = {1'b0,dividend[63:32]} - {1'b0,divisor};
always @ (posedge clk) begin
if (rst == `RstEnable) begin
state <= `DivFree;
ready_o <= `DivResultNotReady;
result_o <= {`ZeroWord,`ZeroWord};
end else begin
case (state)
//DivFree状态
//分三种情况:
//(1)开始除法运算,但除数为0,那么进入DivByZero状态
//(2)开始除法运算,且除数不为0,那么进入DivOn状态,初始化cnt为0,如果是有符号除法,且被除数或者除数为负,那么对除数或除数取补码。除数保存到divisor中,将被除数的最高位保存到dividend的第32位,准备进行第一次迭代
//(3)没有开始除法运算,保持ready_o位DivResultNotReady,保持result_o为0
`DivFree: begin //DivFree状态
if(start_i == `DivStart && annul_i == 1'b0) begin
if(opdata2_i == `ZeroWord) begin
state <= `DivByZero;
end else begin
state <= `DivOn;
cnt <= 6'b000000;
if(signed_div_i == 1'b1 && opdata1_i[31] == 1'b1 ) begin
temp_op1 = ~opdata1_i + 1;
end else begin
temp_op1 = opdata1_i;
end
if(signed_div_i == 1'b1 && opdata2_i[31] == 1'b1 ) begin
temp_op2 = ~opdata2_i + 1;
end else begin
temp_op2 = opdata2_i;
end
dividend <= {`ZeroWord,`ZeroWord};
dividend[32:1] <= temp_op1;
divisor <= temp_op2;
end
end else begin
ready_o <= `DivResultNotReady;
result_o <= {`ZeroWord,`ZeroWord};
end
end
`DivByZero: begin //DivByZero状态
dividend <= {`ZeroWord,`ZeroWord};
state <= `DivEnd;
end
//DivOn状态
//(1)annul_i==1,取消除法运算,回到DivFree状态
//(2)annul_i==0,且cnt不为32,继续试商。若div_temp<0,迭代结果为0;反之为1.结果用diividend最低位保存,保持DivOn状态,cnt++;
//(3)annul_i==0,且cnt为32,试商结束,结果取补码。商保存在dividend的低32位,余数保存在dividend的高32位
`DivOn: begin //DivOn状态
if(annul_i == 1'b0) begin
if(cnt != 6'b100000) begin
if(div_temp[32] == 1'b1) begin
//如果div_temp【32】为1,表示(minuend-n)结果小于0,将dividend向左移一位,这样就将被除数还没有参与运算的最高位加入到下一次迭代的被减数中,同时将0追加到中间结果
dividend <= {dividend[63:0] , 1'b0};
end else begin
//如果div_temp【32】为0,表示(minuend-n)结果大于等于0,将减法的结果与被除数还没有参运算的最高位加入到下一次迭代的被减数中,同时将1追加到中间结果
dividend <= {div_temp[31:0] , dividend[31:0] , 1'b1};
end
cnt <= cnt + 1;
end else begin
if((signed_div_i == 1'b1) && ((opdata1_i[31] ^ opdata2_i[31]) == 1'b1)) begin
dividend[31:0] <= (~dividend[31:0] + 1);
end
if((signed_div_i == 1'b1) && ((opdata1_i[31] ^ dividend[64]) == 1'b1)) begin
dividend[64:33] <= (~dividend[64:33] + 1);
end
state <= `DivEnd;
cnt <= 6'b000000;
end
end else begin
state <= `DivFree;
end
end
//divend状态
//除法运算结束,result_o的宽度是64为,其最高32位存储余数,低32位存储商,设置输出信号ready_o位DivResultReady,表示除法结束,然后等待EX模块送来DivStop信号,当EX模块送来DivStop信号时,DIV模块回到DivFree状态
`DivEnd: begin //DivEnd状态
result_o <= {dividend[64:33], dividend[31:0]};
ready_o <= `DivResultReady;
if(start_i == `DivStop) begin
state <= `DivFree;
ready_o <= `DivResultNotReady;
result_o <= {`ZeroWord,`ZeroWord};
end
end
endcase
end
end
endmodule
`include "defines.v"
module LLbit_reg(
input wire clk,
input wire rst,
input wire flush,
//写端口
input wire LLbit_i,
input wire we,
//读端口1
output reg LLbit_o
);
always @ (posedge clk) begin
if (rst == `RstEnable) begin
LLbit_o <= 1'b0;
end else if((flush == 1'b1)) begin
LLbit_o <= 1'b0;
end else if((we == `WriteEnable)) begin
LLbit_o <= LLbit_i;
end
end
endmodule
`include "defines.v"
module inst_rom(
// input wire clk,
input wire ce,
input wire[`InstAddrBus] addr,
output reg[`InstBus] inst
);
reg[`InstBus] inst_mem[0:`InstMemNum-1];
initial $readmemh ( "D:/inst_rom.data", inst_mem );
always @ (*) begin
if (ce == `ChipDisable) begin
inst <= `ZeroWord;
end else begin
inst <= inst_mem[addr[`InstMemNumLog2+1:2]];
end
end
endmodule
`include "defines.v"
module data_ram(
input wire clk,
input wire ce,
input wire we,
input wire[`DataAddrBus] addr,
input wire[3:0] sel,
input wire[`DataBus] data_i,
output reg[`DataBus] data_o
);
reg[`ByteWidth] data_mem0[0:`DataMemNum-1];
reg[`ByteWidth] data_mem1[0:`DataMemNum-1];
reg[`ByteWidth] data_mem2[0:`DataMemNum-1];
reg[`ByteWidth] data_mem3[0:`DataMemNum-1];
always @ (posedge clk) begin
if (ce == `ChipDisable) begin
//data_o <= ZeroWord;
end else if(we == `WriteEnable) begin
if (sel[3] == 1'b1) begin
data_mem3[addr[`DataMemNumLog2+1:2]] <= data_i[31:24];
end
if (sel[2] == 1'b1) begin
data_mem2[addr[`DataMemNumLog2+1:2]] <= data_i[23:16];
end
if (sel[1] == 1'b1) begin
data_mem1[addr[`DataMemNumLog2+1:2]] <= data_i[15:8];
end
if (sel[0] == 1'b1) begin
data_mem0[addr[`DataMemNumLog2+1:2]] <= data_i[7:0];
end
end
end
always @ (*) begin
if (ce == `ChipDisable) begin
data_o <= `ZeroWord;
end else if(we == `WriteDisable) begin
data_o <= {data_mem3[addr[`DataMemNumLog2+1:2]],
data_mem2[addr[`DataMemNumLog2+1:2]],
data_mem1[addr[`DataMemNumLog2+1:2]],
data_mem0[addr[`DataMemNumLog2+1:2]]};
end else begin
data_o <= `ZeroWord;
end
end
endmodule
仿真测试

`include "defines.v"
`timescale 1ns/1ps
module openmips_min_sopc_tb();
reg CLOCK_50;
reg rst;
initial begin
CLOCK_50 = 1'b0;
forever #10 CLOCK_50 = ~CLOCK_50;
end
initial begin
rst = `RstEnable;
#195 rst= `RstDisable;
#4100 $stop;
end
openmips_min_sopc openmips_min_sopc0(
.clk(CLOCK_50),
.rst(rst)
);
仿真结果

inst_dom.data中的指令代码
3c011234
3c025678
00000000
00000000
00221820
00222022
00222825
00223024
00223826
00224027
14200003
00000000
3c01f760
3c021234
00000000
00000000
1041fff3
00000000
0022482a
0022502b
00015880
00016402
00016883
00227021
242f2020
00228023
0022882b
ac0e0008
8c120008
0c000020
00000000
24012020
24022010
240300a0
00000000
00000000
00600008
00000000
00221820
00222022
00222825
3c1f0101
00000000
00000000
8007fffe
00000000
00000000
00000000
00000000
00000000
参考文献
[1] 唐朔飞. 计算机组成原理(第二版)[M]. 北京:高等教育出版社,2008.
[2] 赵春蕾,乔东海. 32 位 MIPS 架构的流水线 CPU 设计[J]. 中国科学院声学研究所,2017.
[3]高小鹏,计算机组成与实现,高等教育出版社,2018
[4]袁静波等,《计算机组成与结构》,机械工业出版社,2011
[5]雷思磊. 自己动手写 CPU[M]. 北京:电子工业出版社,2014.
[6]Harris, D. M., & Harris, S. L. (2012). Digital Design and Computer Architecture. Morgan Kaufmann.
[7]Ciletti, M. D. (2010). Advanced Digital Design with the Verilog HDL, Second Edition. Prentice Hall.
1518

被折叠的 条评论
为什么被折叠?



