6设计指令流水线-2【FPGA模型机课程设计】
- 前言
- 推荐
- 6设计指令流水线-2
- 安排
- 测试与结果
- 指令流水线理论
- MIPS的一种简单实现
- 基本的MIPS流水线
- 指令流水线实现
- MIPS五段流水CPU设计
- 视频中的测试代码
- 设计分析
- 设计思路
- 问题回答
- 代码设计
- ID
- EX
- MEM
- RegFile
- MIPS
- InstMem
- 附录
- 3 ID 译码
- 4 EX 执行
- 5 MEM 访存
- 7 RegFile 存取
- 8 MIPS 封装
- 9 InstMem 指令存储器
- 最后
前言
6设计指令流水线-2
安排
第二周周一:
设计指令流水线,按照指令周期不同阶段进行划分,实现指令基本流水处理功能。注意数据相关冲突的解决。编写机器指令程序,对指令逐一进行测试,可以使用原有的测试程序,但检测结果时需注意功能和时序的对应关系。
前篇只是实现了基本的流水线的功能
该篇实现数据冲突
分支和中断异常之后实现
测试与结果
//测试流水
//ori R0,1100 -- R1 --00001100
instmem [0] = 32'h34011100;
//ori R0,0020 -- R2 --00000020
instmem [1] = 32'h34020020;
//ori R0,ff00 -- R3 --0000ff00
instmem [2] = 32'h3403ff00;
//ori R0,ffff -- R4 --0000ffff
instmem [3] = 32'h3404ffff;
//相邻两条指令 //ori R4,0000 -- R5 --0000ffff
instmem [4] = 32'h34850000;
//相隔一条指令 //ori R4,0000 -- R6 --0000ffff
instmem [5] = 32'h34860000;
//相隔两条指令 //ori R4,0000 -- R7 --0000ffff
instmem [6] = 32'h34870000;
//load 相关
//mem[0]=(r1)
instmem[7]=32'b101011_00000_00001_0000_0000_0000_0000; //sw r1,0x0(r0)
//(r8)=mem[0]
instmem[8]=32'b100011_00000_01000_0000_0000_0000_0000; //lw r8,0x0(r0)
instmem[9]=32'b001101_01000_01001_0000_0000_0000_0000; // ori r9 r8,0000
对比单周期CPU的结果
流水线的结果
load相关有点问题
load处理类似于
但是,在停顿周期pc=28时
regaRead与regaAddr清0了
指令流水线理论
MIPS的一种简单实现
MIPS的一种简单实现
主要理解MIPS的五个功能段的作用
基本的MIPS流水线
基本的MIPS流水线
主要理解MIPS的数据通路
各个功能段怎么传递数据
指令流水线实现
MIPS五段流水CPU设计
MIPS五段流水CPU设计
主要理解MIPS的流水线的设计
分别需要掌握数据通路
- 支持基本R型运算的流水cpu数据通路图
- 支持除了跳转指令的基本流水cpu通路图,需要分别理解R型运算、移位指令、I型运算、访存指令
- 相邻指令间存在数据相关,判断依据:寄存器地址
- 将EX段的执行结果通过反馈回路反馈给ID段,也要传递地址让ID段进行比较判断是否产生了相关
- 相隔一条指令间存在数据相关,判断依据:寄存器地址
- 将MEM段的执行结果通过反馈回路反馈给ID段,也要传递地址让ID段进行比较判断是否产生了相关
- 相隔两条指令间存在数据相关
- 所以,让写回段以时钟下降沿写入,提前送入regs
- 出现Load相关,反馈无法解决,必须CPU暂停
- 判断条件:操作码为Lw且产生结果寄存器与后面指令源寄存器一致的情况
视频中的测试代码
_start: or $1, $0, $0
addi $4, $1, 0x40
ori $1, $1, 0x1
addi $11,$0, 0x50
loop1: sw $1, 0($4)
add $1, $1, $1 #0x1 0x2 0x4 0x8 0x10
bne $4, $11,loop1
addi $4, $4, 4
jal sum
addi $5, $0, 5
return: sw $2, 0($4) # store 0x1f
lw $9, 0($4) # load 0x1f
sub $15, $9, $2 # 0x00000000
addi $5, $0, 0 # 0x00000000
lui $1, 0xffff
ori $1, $1, 0xffff
or $15, $5, $1 # 0xffffffff
xori $15, $15, 0xaaaa # 0xffff5555
lui $2, 0x0000
ori $2, $2, 0xffff #0x0000ffff
add $10, $2, $1 # 0x0000fffe
andi $7, $1, 0x3333 # 0x00003333
or $6, $10, $15 # 0xffffffff
xor $8, $6, $10 # 0xffff0001
and $7, $10, $6 # 0x0000fffe
beq $5, $0, shift_addr
nop
sum: or $15, $0, $0
ori $4, $0, 0x50
loop: lw $9, 0($4) # 0x10 0x8 0x4 0x2 0x1
add $15, $15, $9
addi $5, $5, -1
bne $5, $0, loop
addi $4, $4, -4
jr $31
ori $2, $15, 0
shift_addr: addi $5, $0, -1
sll $15, $5, 15 # 0xffff8000
sll $15, $15, 16 # 0x80000000
sra $15, $15, 15 # 0xffff0000
srl $15, $15, 16 # 0x0000ffff
end: j end
nop
设计分析
设计思路
结合视频资料,进行设计分析
相邻指令间存在数据相关,判断依据:寄存器地址
先写后读相关
不做处理的话,会读到写之前的旧数据
将EX段的执行结果通过反馈回路反馈给ID段,也要传递地址让ID段进行比较判断是否产生了相关
23:14
把EX段的执行结果通过反馈回路反馈给ID段,
类似于定向技术:数据真正产生的地方送到数据真正需要的地方
此时MUX的输入不仅是IF传送的信号,还有EX反馈的信号
EX执行的结果反馈给ID段
ID段就变成了三选一的输入
问题1:所以ID段和EX的连线设计需要怎么设计?
相隔一条指令间存在数据相关,判断依据:寄存器地址
在写回没有完成之前,读的仍是旧数据
将MEM段的执行结果通过反馈回路反馈给ID段,也要传递地址让ID段进行比较判断是否产生了相关
所以在MEM段依然要反馈给ID段
26:33
问题2:所以ID段和MEM的连线设计需要怎么设计?
相隔两条指令间存在数据相关
在写回没有完成之前,读的仍是旧数据
所以,让写回段以时钟下降沿写入,提前送入regs
在clk到达regFile之前,加了反向器
01:17
问题3:所以MEM段和regFIle的连线设计需要怎么设计?
出现Load相关,反馈无法解决,必须CPU暂停
没有办法提前传寄存器的值
使用停顿
可以看到译码停顿了两个周期
判断条件:操作码为Lw且产生结果寄存器与后面指令源寄存器一致的情况
CPU暂停是什么意思?
ID检测到Load相关,
产生stall_req信号
传送到ctrl模块
ctrl产生stall信号
使得流水寄存器写入无效
流水线的数据通路:07:52
问题回答
对于相邻WAR冲突
问题1:所以ID段的引脚设计需要怎么设计?
回答1:需要增加一个反馈接口从EX输出到ID输入
对于相隔一条WAR冲突
问题2:所以ID段和MEM的连线设计需要怎么设计?
回答2:需要增加一个反馈接口从MEM输出到ID输入
对于相隔两条WAR冲突
问题3:所以MEM段和regFIle的连线设计需要怎么设计?
回答3:需要增加一个反向器连接regFile的clk输入
对于相邻Load相关
判断是否是Load冲突,停顿
代码设计
按照设计分析进行代码设计
ID
input wire[5:0] ex_op_i, //ex 反馈 id op码
input wire[4:0] ex_wd_to_id_i, //ex 反馈 id 写地址
input wire ex_wreg_to_id_i, //ex 反馈 给 id 写信号
input wire [31:0] ex_wdata_to_id_i, //ex 反馈 给 id 写数据
input wire[4:0] mem_wd_to_id_i, //mem 反馈 id写地址
input wire mem_wreg_to_id_i, //mem 反馈 给 id 写信号
input wire [31:0] mem_wdata_to_id_i //mem 反馈 给 id 写数据
//流水线
reg stall_for_rega_loadreleate;
reg stall_for_regb_loadreleate;
wire pre_inst_is_load;
wire stall_for_loadreleate=stall_for_rega_loadreleate|stall_for_regb_loadreleate;
assign pre_inst_is_load =(ex_op_i==`Lw)?1'b1:1'b0;
//原子-修改
//流水线需要有反馈数据的输入 选择器
always@(*)
begin
stall_for_rega_loadreleate=`NoStop;
if(rst == `RstEnable)
regaData = `Zero;
//load相关 如果上一条指令是load 结果寄存器 == 当前指令源寄存器
else if(pre_inst_is_load==1'b1 && ex_wd_to_id_i==regaAddr &®aRead==`Valid)
stall_for_rega_loadreleate =`Stop;
//相邻指令的冲突WAR
else if(regaRead==`Valid&&ex_wreg_to_id_i==`Invalid&&ex_wd_to_id_i==regaAddr)
regaData=ex_wdata_to_id_i;
//相隔一条指令的冲突WAR
else if(regaRead==`Valid&&mem_wreg_to_id_i==`Invalid&&mem_wd_to_id_i==regaAddr)
regaData=mem_wdata_to_id_i;
else if(op == `Lw || op == `Sw || op==`Ll || op==`Sc)
regaData = regaData_i + imm;
else if(regaRead == `Valid)
regaData = regaData_i;
else
regaData = imm;
end
always@(*)
begin
stall_for_regb_loadreleate=`NoStop;
if(rst == `RstEnable)
regbData = `Zero;
//load相关 如果上一条指令是load 结果寄存器 == 当前指令源寄存器
else if(pre_inst_is_load==1'b1 && ex_wd_to_id_i==regbAddr &®bRead==`Valid)
stall_for_regb_loadreleate =`Stop;
//相邻指令的冲突WAR
else if(regbRead==`Valid&&ex_wreg_to_id_i==`Valid&&ex_wd_to_id_i==regbAddr)
regbData=ex_wdata_to_id_i;
//相隔一条指令的冲突WAR
else if(regbRead==`Valid&&mem_wreg_to_id_i==`Valid&&mem_wd_to_id_i==regbAddr)
regbData=mem_wdata_to_id_i;
else if(regbRead == `Valid)
regbData = regbData_i;
else
regbData = imm;
end
EX
output reg[5:0] ex_op_o, //ex 反馈 给 id op码
output reg [4:0] ex_wd_to_id_o, //ex 反馈 给 id 读地址
output reg ex_wreg_to_id_o, //ex 反馈 给 id 读信号
output reg [31:0] ex_wdata_to_id_o //ex 反馈 给 id 读数据
always@(*)
begin
ex_op_o=op_i;
ex_wd_to_id_o=regcAddr;
ex_wreg_to_id_o=regcWrite;
ex_wdata_to_id_o=regcData;
end
MEM
output reg [4:0] mem_wd_to_id_o, //mem 反馈 给 id 读地址
output reg mem_wreg_to_id_o, //mem 反馈 给 id 读信号
output reg [31:0] mem_wdata_to_id_o //mem 反馈 给 id 读数据
always@(*)
begin
mem_wd_to_id_o=regcAddr;
mem_wreg_to_id_o=regcWr;
mem_wdata_to_id_o=regData;
end
RegFile
input wire[31:0] inst, //流水线
MIPS
//流水线
wire[5:0] ex_op; //ex 反馈 id op码
wire[4:0] ex_wd_to_id; //ex 反馈 id读地址
wire ex_wreg_to_id; //ex 反馈 给 id 读信号
wire [31:0] ex_wdata_to_id; //ex 反馈 给 id 读数据
wire[4:0] mem_wd_to_id; //mem 反馈 id读地址
wire mem_wreg_to_id; //mem 反馈 给 id 读信号
wire [31:0] mem_wdata_to_id; //mem 反馈 给 id 读数据
//中断修改
//流水线修改
ID id0(
.ex_op_i(ex_op), //ex 反馈 id op码
.ex_wd_to_id_i(ex_wd_to_id), //ex 反馈 id读地址
.ex_wreg_to_id_i(ex_wreg_to_id), //ex 反馈 给 id 读信号
.ex_wdata_to_id_i(ex_wdata_to_id), //ex 反馈 给 id 读数据
.mem_wd_to_id_i(mem_wd_to_id), //mem 反馈 id读地址
.mem_wreg_to_id_i(mem_wreg_to_id), //mem 反馈 给 id 读信号
.mem_wdata_to_id_i(mem_wdata_to_id) //mem 反馈 给 id 读数据
);
//乘除md-修改EX实例化
//中断修改
//流水线修改
EX ex0(
.ex_op_o(ex_op), //ex 反馈 给 id op码
.ex_wd_to_id_o(ex_wd_to_id), //ex 反馈 给 id 读地址
.ex_wreg_to_id_o(ex_wreg_to_id), //ex 反馈 给 id 读信号
.ex_wdata_to_id_o(ex_wdata_to_id) //ex 反馈 给 id 读数据
);
//新增Mem实例化
//修改Mem实例化 llsc
//流水线修改
MEM mem0(
.mem_wd_to_id_o(mem_wd_to_id), //mem 反馈 给 id 读地址
.mem_wreg_to_id_o(mem_wreg_to_id), //mem 反馈 给 id 读信号
.mem_wdata_to_id_o(mem_wdata_to_id) //mem 反馈 给 id 读数据
);
//修改RegFile实例化
//流水线修改
RegFile regfile0(
.clk(~clk), //反向器
);
InstMem
本人有点强迫症,但是已经累了,不想改了
以下指令不对,请忽略
//指令测试
instmem[0]= 32'b000000_00000_00000_00001_00000_100101; //_start: or $1, $0, $0
instmem[1] = 32'b001000_00001_00100_0000_0000_0100_0000; //addi $4, $1, 0x40
instmem[2] = 32'b001101_00001_00001_0000_0000_0000_0001; //ori $1, $1, 0x1
instmem[3] = 32'b001000_00000_01011_0000_0000_0101_0000; //addi $11,$0, 0x50
instmem[4] = 32'b101011_00100_00001_0000_0000_0000_0000;//loop1: sw $1, 0($4)
instmem[5] = 32'b000000_00001_00001_00001_00000_100000;// add $1, $1, $1 #0x1 0x2 0x4 0x8 0x10
instmem[6] = 32'b000100_00100_01011_1111_1111_1111_1101;// beq $4, $11,loop1 fffd(-3)
instmem[7] = 32'b001100_00100_00100_0000_0000_0000_0100;// addi $4, $4, 4
instmem[8] = 32'b000011_000000_0000_0000_0000_0001_1010;// jal sum
instmem[9] = 32'b001100_00101_00101_0000_0000_0000_0000;// addi $5, $0, 5
instmem[10] = 32'b101011_00100_00010_0000_0000_0000_0000;//return: sw $2, 0($4) # store 0x1f
instmem[11] = 32'b100011_00100_01001_0000_0000_0000_0000;// lw $9, 0($4) # load 0x1f
instmem[12] = 32'b000000_01001_00010_01111_00000_100010;// sub $15, $9, $2 # 0x00000000
instmem[13] = 32'b001100_00000_00101_0000_0000_0000_0100;// addi $5, $0, 0 # 0x00000000
instmem[14] = 32'b001111_00000_00001_1111_1111_1111_1111;// lui $1, 0xffff
instmem[15] = 32'b100101_00001_00001_1111_1111_1111_1111;// ori $1, $1, 0xffff
//相邻两条指令
instmem[16] = 32'b00000_00101_00001_01111_00000_100101;// or $15, $5, $1 # 0xffffffff
instmem[17] = 32'b100110_01111_01111_1010_1010_1010_1010; // xori $15, $15, 0xaaaa # 0xffff5555
instmem[18] = 32'b001111_00000_00010_0000_0000_0000_0000;// lui $2, 0x0000
instmem[19] = 32'b100101_00010_00010_1111_1111_1111_1111;// ori $2, $2, 0xffff #0x0000ffff
//相隔一条指令
instmem[20] = 32'b000000_00010_00001_01010_00000_100000;// add $10, $2, $1 # 0x0000fffe
instmem[21] = 32'b001100_00001_00111_0011_0011_0011_0011;// andi $7, $1, 0x3333 # 0x00003333
instmem[22] = 32'b000000_01010_01111_00110_00000_100101;// or $6, $10, $15 # 0xffffffff
instmem[23] = 32'b000000_00110_01010_01000_00000_000000;// xor $8, $6, $10 # 0xffff0001
instmem[24] = 32'b000000_01010_00110_00111_00000_100100;// and $7, $10, $6 # 0x0000fffe
instmem[25] = 32'b000100_00101_00000_0000_0000_0000_1010;// beq $5, $0, shift_addr
instmem[26] = 32'b00000_00000_00000_00000_00000_100101;// nop
instmem[27] = 32'b00000_00000_00000_01111_00000_100101;//sum: or $15, $0, $0
instmem[28] = 32'b100101_00000_00100_0000_0000_0101_0000;// ori $4, $0, 0x50
instmem[29] = 32'b100011_00100_01001_0000_0000_0000_0000;//loop: lw $9, 0($4) # 0x10 0x8 0x4 0x2 0x1
instmem[30] = 32'b000000_01111_01001_01111_00000_100000;// add $15, $15, $9
instmem[31] = 32'b001100_00101_00101_1111_1111_1111_1111;// addi $5, $5, -1 ffff
instmem[32] = 32'b001100_00101_00000_1111_1111_1111_1100;// bne $5, $0, loop fffc
instmem[33] = 32'b001100_00100_00100_1111_1111_1111_1100;// addi $4, $4, -4 fffc
instmem[34] = 32'b000000_11111_00000_00000_00000_001000;//jr $31
instmem[35] = 32'b100101_01111_00010_0000_0000_0000_0000;// ori $2, $15, 0
instmem[36] = 32'b001100_00000_00101_0000_0000_0000_0000;//shift_addr: addi $5, $0, -1
instmem[37] = 32'b000000_00000_00101_01111_01111_000000;// sll $15, $5, 15 # 0xffff8000
instmem[38] = 32'b000000_00000_01111_01111_10000_000000;// sll $15, $15, 16 # 0x80000000
instmem[39] = 32'b000000_00000_01111_01111_01111_000011;// sra $15, $15, 15 # 0xffff0000
instmem[40] = 32'b000000_00000_01111_01111_10000_000010;// srl $15, $15, 16 # 0x0000ffff
instmem[41] = 32'b000010_0000000_0000_0000_0000_0010_0111;//end: j end
instmem[42] = 32'b00000_00000_00000_00000_00000_100101;// nop
请使用以下测试
//测试流水
//ori R0,1100 -- R1 --00001100
instmem [0] = 32'h34011100;
//ori R0,0020 -- R2 --00000020
instmem [1] = 32'h34020020;
//ori R0,ff00 -- R3 --0000ff00
instmem [2] = 32'h3403ff00;
//ori R0,ffff -- R4 --0000ffff
instmem [3] = 32'h3404ffff;
//相邻两条指令 //ori R4,0000 -- R5 --0000ffff
instmem [4] = 32'h34850000;
//相隔一条指令 //ori R4,0000 -- R6 --0000ffff
instmem [5] = 32'h34860000;
//相隔两条指令 //ori R4,0000 -- R7 --0000ffff
instmem [6] = 32'h34870000;
//load 相关
//mem[0]=(r1)
instmem[7]=32'b101011_00000_00001_0000_0000_0000_0000; //sw r1,0x0(r0)
//(r8)=mem[0]
instmem[8]=32'b100011_00000_01000_0000_0000_0000_0000; //lw r8,0x0(r0)
instmem[9]=32'b001101_01000_01001_0000_0000_0000_0000; // ori r9 r8,0000
流水线的结果
load相关没有解决
但是有停顿出现
load处理类似于
附录
3 ID 译码
`include "define.v";
//ID 译码模块
//2、为操作数做准备
module ID (
input wire rst,
// input wire [31:0] pc, //J型
// input wire [31:0] inst,
input wire [31:0] regaData_i,
input wire [31:0] regbData_i,
output reg [5:0] op,
output reg [31:0] regaData,
output reg [31:0] regbData,
output reg regaRead,
output reg regbRead,
output reg regcWrite,
output reg [4:0] regaAddr,
output reg [4:0] regbAddr,
output reg [4:0] regcAddr,
output reg [31:0] jAddr, //J型
output reg jCe,//J型
input wire [31:0] pc_i,//将原来输入pc变为pc_i
output wire[31:0] pc,//新增输出pc
output wire[31:0] excptype,//异常信息记录
input wire[31:0] inst_i, //接受
output reg[31:0] inst_o, //传送
output wire stallreq, //to Ctrl
input wire[5:0] ex_op_i, //ex 反馈 id op码
input wire[4:0] ex_wd_to_id_i, //ex 反馈 id 写地址
input wire ex_wreg_to_id_i, //ex 反馈 给 id 写信号
input wire [31:0] ex_wdata_to_id_i, //ex 反馈 给 id 写数据
input wire[4:0] mem_wd_to_id_i, //mem 反馈 id写地址
input wire mem_wreg_to_id_i, //mem 反馈 给 id 写信号
input wire [31:0] mem_wdata_to_id_i //mem 反馈 给 id 写数据
);
//方便修改
wire [31:0] inst=inst_i;
//操作指令
wire [5:0] inst_op = inst[31:26];
//扩展的立即数
reg [31:0] imm;
//用于R型指令
wire[5:0] func = inst[5:0];
//用于J型指令
wire [31:0] npc = pc + 4;
//中断
reg is_syscall;
reg is_eret;
assign pc = pc_i;
assign excptype= {22'b0, is_eret, is_syscall,8'b0};
//流水线
reg stall_for_rega_loadreleate;
reg stall_for_regb_loadreleate;
wire pre_inst_is_load;
//对stall先不处理
assign stallreq=stall_for_rega_loadreleate|stall_for_regb_loadreleate;
assign pre_inst_is_load =(ex_op_i==`Lw)?1'b1:1'b0;
always@(*)
inst_o=inst_i;
always@(*)
if(rst == `RstEnable)
begin
op = `Nop;
regaRead = `Invalid;
regbRead = `Invalid;
regcWrite = `Invalid;
regaAddr = `Zero;
regbAddr = `Zero;
regcAddr = `Zero;
imm = `Zero;
jCe = `Invalid;//J型
jAddr = `Zero;//J型
is_eret = `Invalid;//中断
is_syscall = `Invalid;//中断
end
else if(inst == `Inst_eret)
begin
op =`Eret;
regaRead = `Invalid;
regbRead = `Invalid;
regcWrite= `Invalid;
regaAddr = `Zero;
regbAddr = `Zero;
regcAddr = `Zero;
imm= `Zero;
jCe=`Invalid;
jAddr=`Zero;
is_eret = `Valid;
is_syscall = `Invalid;
end
else if(inst == `Inst_syscall)
begin
op = `Syscall;
regaRead = `Invalid;
regbRead= `Invalid;
regcWrite = `Invalid;
regaAddr = `Zero;
regbAddr = `Zero;
regcAddr = `Zero;
imm= `Zero;
jCe=`Invalid;
jAddr=`Zero;
is_eret = `Invalid;
is_syscall = `Valid;
end
else
begin//后面的end
jCe = `Invalid;//J型
jAddr = `Zero;//J型
is_eret = `Invalid;//中断
is_syscall = `Invalid;//中断
case(inst_op)
`Inst_cp0:
case(inst[25:21])
`Inst_mfc0:
begin
op = `Mfc0;
regaRead = `Invalid;
regbRead = `Invalid;
regcWrite = `Valid;
regaAddr = `Zero;
regbAddr = `Zero;
regcAddr = inst[20:16];
imm= {27'h0, inst[15:11]};
end
`Inst_mtc0:
begin
op =`Mtc0;
regaRead = `Invalid;
regbRead = `Valid;
regcWrite = `Invalid;
regaAddr = `Zero;
regbAddr = inst[20:16];
regcAddr = `Zero;
imm= {27'h0, inst[15:11]};
end
default:
begin
op= `Nop;
regaRead = `Invalid;
regbRead = `Invalid;
regcWrite = `Invalid;
regaAddr = `Zero;
regbAddr = `Zero;
regcAddr = `Zero;
imm= `Zero;
end
endcase
`Inst_ori:
begin
op = `Or;
regaRead = `Valid;
regbRead = `Invalid;
regcWrite = `Valid;
regaAddr = inst[25:21];
regbAddr = `Zero;
regcAddr = inst[20:16];
imm = {16'h0, inst[15:0]};
end
`Inst_andi:
begin
op = `And;
regaRead = `Valid;
regbRead = `Invalid;
regcWrite = `Valid;
regaAddr = inst[25:21];
regbAddr = `Zero;
regcAddr = inst[20:16];
imm = {16'h0, inst[15:0]};
end
`Inst_xori:
begin
op = `Xor;
regaRead = `Valid;
regbRead = `Invalid;
regcWrite = `Valid;
regaAddr = inst[25:21];
regbAddr = `Zero;
regcAddr = inst[20:16];
imm = {16'h0, inst[15:0]};
end
`Inst_addi:
begin
op = `Add;
regaRead = `Valid;
regbRead = `Invalid;
regcWrite = `Valid;
regaAddr = inst[25:21];
regbAddr = `Zero;
regcAddr = inst[20:16];
imm = {{16{inst[15]}}, inst[15:0]};
end
// `Inst_subi:
// begin
// op = `Sub;
// regaRead = `Valid;
// regbRead = `Invalid;
// regcWrite = `Valid;
// regaAddr = inst[25:21];
// regbAddr = `Zero;
// regcAddr = inst[20:16];
// imm = {{16{inst[15]}}, inst[15:0]};
// end
`Inst_lui:
begin
op = `Lui;
regaRead = `Valid;
regbRead = `Invalid;
regcWrite = `Valid;
regaAddr = inst[25:21];
regbAddr = `Zero;
regcAddr = inst[20:16];
imm = {inst[15:0],16'h0};
end
`Inst_reg:
case(func)
`Inst_add:
begin
op = `Add;
regaRead = `Valid;
regbRead = `Valid;
regcWrite = `Valid;
regaAddr = inst[25:21];
regbAddr = inst[20:16];
regcAddr = inst[15:11];
imm = `Zero;
end
`Inst_or:
begin
op = `Or;
regaRead = `Valid;
regbRead = `Valid;
regcWrite = `Valid;
regaAddr = inst[25:21];
regbAddr = inst[20:16];
regcAddr = inst[15:11];
imm = `Zero;
end
`Inst_sub:
begin
op = `Sub;
regaRead = `Valid;
regbRead = `Valid;
regcWrite = `Valid;
regaAddr = inst[25:21];
regbAddr = inst[20:16];
regcAddr = inst[15:11];
imm = `Zero;
end
`Inst_and:
begin
op = `And;
regaRead = `Valid;
regbRead = `Valid;
regcWrite = `Valid;
regaAddr = inst[25:21];
regbAddr = inst[20:16];
regcAddr = inst[15:11];
imm = `Zero;
end
`Inst_xor:
begin
op = `Xor;
regaRead = `Valid;
regbRead = `Valid;
regcWrite = `Valid;
regaAddr = inst[25:21];
regbAddr = inst[20:16];
regcAddr = inst[15:11];
imm = `Zero;
end
`Inst_sll:
begin
op = `Sll;
regaRead = `Invalid;
regbRead = `Valid;
regcWrite = `Valid;
regaAddr = `Zero;
regbAddr = inst[20:16];
regcAddr = inst[15:11];
imm = {27'b0,inst[10:6]};//移位复用imm
end
`Inst_srl:
begin
op = `Srl;
regaRead = `Invalid;
regbRead = `Valid;
regcWrite = `Valid;
regaAddr = `Zero;
regbAddr = inst[20:16];
regcAddr = inst[15:11];
imm = {27'b0,inst[10:6]};//移位复用imm
end
`Inst_sra:
begin
op = `Sra;
regaRead = `Invalid;
regbRead = `Valid;
regcWrite = `Valid;
regaAddr = `Zero;
regbAddr = inst[20:16];
regcAddr = inst[15:11];
imm = {27'b0,inst[10:6]};//移位复用imm
end
//JR型指令
`Inst_jr:
begin
op = `J;
regaRead = `Valid;//需要读rs
regbRead = `Invalid;
regcWrite = `Invalid;
regaAddr = inst[25:21];
regbAddr = `Zero;
regcAddr = `Zero;
jAddr = regaData;//regaData=(regaAddr)
jCe = `Valid;
imm = `Zero;
end
`Inst_jalr:
begin
op = `Jal;
regaRead = `Valid;
regbRead = `Invalid;
regcWrite = `Valid;
regaAddr = inst[25:21];
regbAddr = `Zero;
regcAddr = 5'b11111;
jAddr = regaData;
jCe = `Valid;
imm = npc;//regbData中存imm npc
end
//12条整数指令
`Inst_slt:
begin
op = `Slt;
regaRead = `Valid;
regbRead = `Valid;
regcWrite = `Valid;
regaAddr = inst[25:21];
regbAddr = inst[20:16];
regcAddr = inst[15:11];
imm = `Zero;
end
//乘除指令
`Inst_mult:
begin
op = `Mult;
regaRead = `Valid;
regbRead = `Valid;
regcWrite = `Invalid;//写到HILO寄存器中,而不是通用寄存器中
regaAddr = inst[25:21];
regbAddr = inst[20:16];
regcAddr = `Zero;
imm = `Zero;
end
`Inst_multu:
begin
op = `Multu;
regaRead = `Valid;
regbRead = `Valid;
regcWrite = `Invalid;//写到HILO寄存器中,而不是通用寄存器中
regaAddr = inst[25:21];
regbAddr = inst[20:16];
regcAddr = `Zero;
imm = `Zero;
end
`Inst_div:
begin
op = `Div;
regaRead = `Valid;
regbRead = `Valid;
regcWrite = `Invalid;//写到HILO寄存器中,而不是通用寄存器中
regaAddr = inst[25:21];
regbAddr = inst[20:16];
regcAddr = `Zero;
imm = `Zero;
end
`Inst_divu:
begin
op = `Divu;
regaRead = `Valid;
regbRead = `Valid;
regcWrite = `Invalid;//写到HILO寄存器中,而不是通用寄存器中
regaAddr = inst[25:21];
regbAddr = inst[20:16];
regcAddr = `Zero;
imm = `Zero;
end
//后4条指令
`Inst_mfhi:
begin
op = `Mfhi;
regaRead = `Invalid;
regbRead = `Invalid;
regcWrite = `Valid;//从HILO寄存器中,写到通用寄存器中
regaAddr = `Zero;
regbAddr = `Zero;
regcAddr = inst[15:11];
imm = `Zero;//HiLo的数据在EX中得到
end
`Inst_mflo:
begin
op = `Mflo;
regaRead = `Invalid;
regbRead = `Invalid;
regcWrite = `Valid;//从HILO寄存器中,写到通用寄存器中
regaAddr = `Zero;
regbAddr = `Zero;
regcAddr = inst[15:11];
imm = `Zero;//HiLo的数据在EX中得到
end
`Inst_mthi:
begin
op = `Mthi;
regaRead = `Valid;//从通用寄存器读出
regbRead = `Invalid;
regcWrite = `Invalid;//写到HILO寄存器中,而不是通用寄存器中
regaAddr = inst[25:21];
regbAddr = `Zero;
regcAddr = `Zero;
imm = `Zero;
end
`Inst_mtlo:
begin
op = `Mtlo;
regaRead = `Valid;//从通用寄存器读出
regbRead = `Invalid;
regcWrite = `Invalid;//写到HILO寄存器中,而不是通用寄存器中
regaAddr = inst[25:21];
regbAddr = `Zero;
regcAddr = `Zero;
imm = `Zero;
end
default:
begin
regaRead = `Invalid;
regbRead = `Invalid;
regcWrite = `Invalid;
regaAddr = `Zero;
regbAddr = `Zero;
regcAddr = `Zero;
imm = `Zero;
end
endcase
//J型指令
`Inst_j:
begin
op = `J;
regaRead = `Invalid;
regbRead = `Invalid;
regcWrite = `Invalid;//不需要写
regaAddr = `Zero;
regbAddr = `Zero;
regcAddr = `Zero;
jAddr = {npc[31:28], inst[25:0], 2'b00};
jCe = `Valid;
imm = `Zero;
end
`Inst_jal:
begin
op = `Jal;
regaRead = `Invalid;
regbRead = `Invalid;
regcWrite = `Valid;//需要把npc写入R31中
regaAddr = `Zero;
regbAddr = `Zero;
regcAddr = 5'b11111;
jAddr = {npc[31:28], inst[25:0], 2'b00};
jCe = `Valid;
imm = npc;
end
//J+型指令
`Inst_beq:
begin
op = `Beq;
regaRead = `Valid;
regbRead = `Valid;
regcWrite = `Invalid;
regaAddr = inst[25:21];
regbAddr = inst[20:16];
regcAddr = `Zero;
jAddr = npc+{{14{inst[15]}},inst[15:0], 2'b00};
if(regaData==regbData)
jCe = `Valid;//等于有效
else
jCe = `Invalid;
imm = `Zero;
end
`Inst_bne:
begin
op = `Beq;
regaRead = `Valid;
regbRead = `Valid;
regcWrite = `Invalid;
regaAddr = inst[25:21];
regbAddr = inst[20:16];
regcAddr = `Zero;
jAddr = npc+{{14{inst[15]}},inst[15:0], 2'b00};
if(regaData!=regbData)
jCe = `Valid;//等于有效
else
jCe = `Invalid;
imm = `Zero;
end
`Inst_bltz:
begin
op = `Bltz;
regaRead = `Valid;
regbRead = `Valid;//若regbRead无效,则regbData=imm=0
regcWrite = `Invalid;
regaAddr = inst[25:21];
regbAddr = inst[20:16];
regcAddr = `Zero;
jAddr = npc+{{14{inst[15]}},inst[15:0], 2'b00};
if(regaData<regbData)
jCe = `Valid;//小于有效
else
jCe = `Invalid;
imm = 32'b0;
end
`Inst_bgtz:
begin
op = `Bgtz;
regaRead = `Valid;
//regbRead = `Valid;//若regbRead有效,则regbData=(regbAddr)
regbRead = `Invalid;//若regbRead无效,则regbData=imm=0
regcWrite = `Invalid;
regaAddr = inst[25:21];
regbAddr = inst[20:16];
regcAddr = `Zero;
jAddr = npc+{{14{inst[15]}},inst[15:0], 2'b00};
if(regaData>regbData)
jCe = `Valid;//大于有效
else
jCe = `Invalid;
imm = 32'b0;
end
//Load Store指令
`Inst_lw:
begin
op = `Lw;
regaRead = `Valid;
regbRead = `Invalid;
regcWrite = `Valid;
regaAddr = inst[25:21];
regbAddr = `Zero;
regcAddr = inst[20:16];
imm = {{16{inst[15]}},inst[15:0]};
end
`Inst_sw:
begin
op = `Sw;
regaRead = `Valid;
regbRead = `Valid;
regcWrite = `Invalid;
regaAddr = inst[25:21];
regbAddr = inst[20:16];
regcAddr = `Zero;
imm = {{16{inst[15]}},inst[15:0]};
end
//ll sc
`Inst_ll:
begin
op = `Ll;
regaRead = `Valid;
regbRead = `Invalid;
regcWrite = `Valid;
regaAddr = inst[25:21];
regbAddr = `Zero;
regcAddr = inst[20:16];
imm = {{16{inst[15]}},inst[15:0]};
end
`Inst_sc:
begin
op = `Sc;
regaRead = `Valid;
regbRead = `Valid;
regcWrite = `Valid;//还需给rt赋值为1
regaAddr = inst[25:21];
regbAddr = inst[20:16];
regcAddr = inst[20:16];//还需给rt赋值为1
imm = {{16{inst[15]}},inst[15:0]};
end
default:
begin
op = `Nop;
regaRead = `Invalid;
regbRead = `Invalid;
regcWrite = `Invalid;
regaAddr = `Zero;
regbAddr = `Zero;
regcAddr = `Zero;
imm = `Zero;
end
endcase
end
/*
//二选一 regaData= regaData_i : imm
always@(*)
if(rst == `RstEnable)
regaData = `Zero;
else if(regaRead == `Valid)
regaData = regaData_i;
else
regaData = imm;
//二选一 regbData= regbData_i : imm
always@(*)
if(rst == `RstEnable)
regbData = `Zero;
else if(regbRead == `Valid)
regbData = regbData_i;
else
regbData = imm;
*/
/*
always@(*)
if(rst == `RstEnable)
regaData = `Zero;
else if(op == `Lw || op == `Sw)
regaData = regaData_i + imm;
else if(regaRead == `Valid)
regaData = regaData_i;
else
regaData = imm;
*/
/*
//原子-修改
always@(*)
if(rst == `RstEnable)
regaData = `Zero;
else if(op == `Lw || op == `Sw || op==`Ll || op==`Sc)
regaData = regaData_i + imm;
else if(regaRead == `Valid)
regaData = regaData_i;
else
regaData = imm;
always@(*)
if(rst == `RstEnable)
regbData = `Zero;
else if(regbRead == `Valid)
regbData = regbData_i;
else
regbData = imm;
*/
/*
//原子-修改
always@(*)
if(rst == `RstEnable)
regaData = `Zero;
else if(op == `Lw || op == `Sw || op==`Ll || op==`Sc)
regaData = regaData_i + imm;
else if(regaRead == `Valid)
regaData = regaData_i;
else
regaData = imm;
always@(*)
if(rst == `RstEnable)
regbData = `Zero;
else if(regbRead == `Valid)
regbData = regbData_i;
else
regbData = imm;
*/
//原子-修改
//流水线需要有反馈数据的输入 选择器
always@(*)
begin
stall_for_rega_loadreleate=`NoStop;
if(rst == `RstEnable)
regaData = `Zero;
//load相关 如果上一条指令是load 结果寄存器 == 当前指令源寄存器
else if(pre_inst_is_load==1'b1 && ex_wd_to_id_i==regaAddr &®aRead==`Valid)
stall_for_rega_loadreleate =`Stop;
//相隔一条指令的冲突WAR
else if(regaRead==`Valid&&ex_wreg_to_id_i==`Valid&&ex_wd_to_id_i==regaAddr)
regaData=ex_wdata_to_id_i;
//相隔两条指令的冲突WAR
else if(regaRead==`Valid&&mem_wreg_to_id_i==`Valid&&mem_wd_to_id_i==regaAddr)
regaData=mem_wdata_to_id_i;
else if(op == `Lw || op == `Sw || op==`Ll || op==`Sc)
regaData = regaData_i + imm;
else if(regaRead == `Valid)
regaData = regaData_i;
else
regaData = imm;
end
always@(*)
begin
stall_for_regb_loadreleate=`NoStop;
if(rst == `RstEnable)
regbData = `Zero;
//load相关 如果上一条指令是load 结果寄存器 == 当前指令源寄存器
else if(pre_inst_is_load==1'b1 && ex_wd_to_id_i==regbAddr &®bRead==`Valid)
stall_for_regb_loadreleate =`Stop;
//相邻指令的冲突WAR
else if(regbRead==`Valid&&ex_wreg_to_id_i==`Valid&&ex_wd_to_id_i==regbAddr)
regbData=ex_wdata_to_id_i;
//相隔一条指令的冲突WAR
else if(regbRead==`Valid&&mem_wreg_to_id_i==`Valid&&mem_wd_to_id_i==regbAddr)
regbData=mem_wdata_to_id_i;
else if(regbRead == `Valid)
regbData = regbData_i;
else
regbData = imm;
end
endmodule
4 EX 执行
`include "define.v";
//3、执行指令模块
module EX (
input wire rst,
//input wire [5:0] op,
input wire [5:0] op_i,
input wire [31:0] regaData,
input wire [31:0] regbData,
input wire regcWrite_i,
input wire [4:0] regcAddr_i,
input wire [31:0] rHiData,//乘除 读hi数据
input wire [31:0] rLoData,//乘除 读hi数据
output reg [31:0] regcData,
output wire regcWrite,
output wire [4:0] regcAddr,
output wire [5:0] op,
output wire [31:0] memAddr,
output wire [31:0] memData,
output reg whi, //乘除 写hi使能
output reg wlo, //乘除 写lo使能
output reg [31:0] wHiData, //乘除 写hi数据
output reg [31:0] wLoData, //乘除 写lo数据
output reg cp0we, //CPO寄存器的写信号
output reg [4:0] cp0Addr, //CPO寄存器的地址信号
output reg [31:0] cp0wData, //CPO寄存器的写入数据
input wire[31:0] cp0rData, //CPO寄存器的读出数据
input wire[31:0] pc_i, //当前指令地址
input wire [31:0] excptype_i,//输入的异常或中断信息记录
output reg [31:0] excptype, //输出的异常或中断信息记录
output wire [31:0] epc, //输出的epc值,用于eret 指令
output wire [31:0] pc, //输出的pc值,用于异常或中断响应
input wire [31:0] cause, //输入的cause寄存器值
input wire [31:0] status, //输入的status寄存器值
input wire[31:0] inst_i, //接受
output reg[31:0] inst_o, //传送
output reg[5:0] ex_op_o, //ex 反馈 给 id op码
output reg [4:0] ex_wd_to_id_o, //ex 反馈 给 id 读地址
output reg ex_wreg_to_id_o, //ex 反馈 给 id 读信号
output reg [31:0] ex_wdata_to_id_o //ex 反馈 给 id 读数据
);
assign op = op_i;
assign memAddr = regaData;
assign memData = regbData;
//中断
assign pc = pc_i;
assign op = (excptype == `Zero) ?
op_i : `Nop;
assign regcWrite =(excptype == `Zero) ?
regcWrite_i : `Invalid;
always@(*)
inst_o=inst_i;
always@(*)
begin
ex_op_o=op_i;
ex_wd_to_id_o=regcAddr;
ex_wreg_to_id_o=regcWrite;
ex_wdata_to_id_o=regcData;
end
always@(*)
if(rst == `RstEnable)
begin
regcData = `Zero;
whi=`Invalid;
wlo=`Invalid;
wHiData=`Zero;
wLoData=`Zero;
end
else
begin
regcData = `Zero;
whi=`Invalid;
wlo=`Invalid;
wHiData=`Zero;
wLoData=`Zero;
cp0we=`Invalid;
cp0wData= `Zero;
cp0Addr =`CP0_epc;
//case(op)
case(op_i)
`Or:
regcData = regaData | regbData;
`And:
regcData = regaData & regbData;
`Xor:
regcData = regaData ^ regbData;
`Add:
regcData = regaData + regbData;
`Sub:
regcData = regaData - regbData;
`Lui:
begin
regcData = regaData | regbData;
end
`Sll:
regcData = regbData << regaData;
`Srl:
regcData = regbData >> regaData;
`Sra:
regcData = ($signed(regbData)) >>> regaData;
//J- JR型
`J:
regcData = `Zero;
`Jal:
regcData = regbData;//regaData有其他用处 jr给pc=jaddr=(rs)
//J+型
`Beq:
regcData = `Zero;
`Bne:
regcData = `Zero;
`Bltz:
regcData = `Zero;
`Bgtz:
regcData = `Zero;
//12条整数指令
`Slt:
begin
if($signed(regaData)<$signed(regbData))
regcData={{31{0}},1};
else
regcData={32{0}};
end
//乘除指令
`Mult:
begin
whi=`Valid;
wlo=`Valid;
{wHiData,wLoData}=
$signed(regaData)*$signed(regbData);
end
`Multu:
begin
whi=`Valid;
wlo=`Valid;
{wHiData,wLoData}=regaData*regbData;
end
`Div:
begin
whi=`Valid;
wlo=`Valid;
wHiData=$signed(regaData)%$signed(regbData);
wLoData=$signed(regaData)/$signed(regbData);
end
`Divu:
begin
whi=`Valid;
wlo=`Valid;
wHiData=regaData%regbData;
wLoData=regaData/regbData;
end
//剩余4条指令
`Mfhi:
regcData = rHiData;
`Mflo:
regcData = rLoData;
`Mthi:
begin
whi=`Valid;
wHiData = regaData;
end
`Mtlo:
begin
wlo=`Valid;
wLoData = regaData;
end
//原子
`Sc:
regcData = 32'b1;
//中断
`Mfc0:
begin
cp0Addr = regaData[4:0];
regcData = cp0rData;
end
`Mtc0:
begin
regcData= `Zero;
cp0we = `Valid;
cp0Addr = regaData[4:0];
cp0wData = regbData;
end
default:
regcData = `Zero;
endcase
end
/*增加关于中断查询和响应的代码*/
//tips:cp0rData默认读出的是epc的地址
assign epc = (excptype == 32'h0000_0200) ? cp0rData : `Zero;
always@(*)
if(rst ==`RstEnable)
excptype = `Zero;
//Cause's IP[2] Status's IM[2]; Status EXL, IE
else if(cause[10]&& status[10]== 1'b1 && status[1:0] == 2'b01)
//timerInt
excptype = 32'h0000_0004;
else if(excptype_i[8] == 1'b1 && status[1] == 1'b0)
//Syscall
excptype = 32'h00000100;
else if(excptype_i[9]== 1'b1)
//Eret
excptype = 32'h0000_0200;
else
excptype = `Zero;
assign regcWrite = regcWrite_i;
assign regcAddr = regcAddr_i;
endmodule
5 MEM 访存
`include "define.v";
//访存(mem)模块设计
module MEM(
input wire rst,
input wire [5:0] op,
input wire [31:0] regcData,
input wire [4:0] regcAddr,
input wire regcWr,
input wire [31:0] memAddr_i,
input wire [31:0] memData,
input wire [31:0] rdData,
input wire rLLbit, //llsc
output wire [4:0] regAddr,
output wire regWr,
output wire [31:0] regData,
output wire [31:0] memAddr,
output reg [31:0] wtData,
output reg memWr,
output reg memCe,
output reg wbit, //llsc
output reg wLLbit, //llsc
input wire[31:0] inst_i, //接受
output reg[31:0] inst_o, //传送
output reg [4:0] mem_wd_to_id_o, //mem 反馈 给 id 读地址
output reg mem_wreg_to_id_o, //mem 反馈 给 id 读信号
output reg [31:0] mem_wdata_to_id_o //mem 反馈 给 id 读数据
);
assign regAddr = regcAddr;
assign regWr = regcWr;
// assign regData = (op == `Lw) ? rdData : regcData;
//因为regData是wire型的,所以为了不修改原来的代码,就不使用always
//而是修改regcData的值,来传到regData
//二选一,选出Sc指令的rt<-1或rt<0
wire [31:0]regDataLL= (rLLbit==`SetFlag) ? 32'b1 : 32'b0;
//二选一,存往regFile的值 sc指令存的值regcDataLL 还是 寄存器传入的值regcData
wire [31:0]regcDataLL= (op == `Sc ) ? regDataLL : regcData;
//二选一,存往regFile的值 lw取得的值rdData 还是 寄存器传入的值regcData
assign regData = (op == `Lw) ? rdData : regcDataLL;
assign memAddr = memAddr_i;
always@(*)
inst_o=inst_i;
always@(*)
begin
mem_wd_to_id_o=regcAddr;
mem_wreg_to_id_o=regcWr;
mem_wdata_to_id_o=regData;
end
always @ (*)
if(rst == `RstEnable)
begin
wtData = `Zero;
memWr = `RamUnWrite;
memCe = `RamDisable;
wbit= `Invalid;
wLLbit=`ClearFlag;
end
else
begin
wtData = `Zero;
memWr = `RamUnWrite;
memCe = `RamDisable;
wbit= `Invalid;
wLLbit=`ClearFlag;
case(op)
`Lw:
begin
wtData = `Zero;
memWr = `RamUnWrite;
memCe = `RamEnable;
end
`Sw:
begin
wtData = memData;
memWr = `RamWrite;
memCe = `RamEnable;
end
//Ll Sc
`Ll:
begin
//rt<-datamem[addr]
//不需要写到DataMem中
wtData = `Zero;
memWr = `RamUnWrite;
memCe = `RamEnable;
//LLbit<-1
wbit=`Valid;
wLLbit = `SetFlag;
end
`Sc:
begin
if(rLLbit==`SetFlag)
begin
//datamem[addr]<-rt
wtData = memData;
memWr = `RamWrite;
memCe = `RamEnable;
//rt<-1
//在EX中实现
//LLbit<-0
wbit=`Valid;
wLLbit = `ClearFlag;
end
else
begin
wbit=`Valid;
wLLbit = `ClearFlag;
end
end
default:
begin
wtData = `Zero;
memWr = `RamUnWrite;
memCe = `RamDisable;
wbit= `Invalid;
wLLbit=`ClearFlag;
end
endcase
end
endmodule
7 RegFile 存取
`include "define.v";
//4、为操作数取值存值模块
//取值 regaData regbData
//存值 wdata
module RegFile(
input wire clk,
input wire rst,
input wire we,
input wire[31:0] inst, //流水线
input wire [4:0] waddr,
input wire [31:0] wdata,
input wire regaRead,
input wire regbRead,
input wire [4:0] regaAddr,
input wire [4:0] regbAddr,
output reg [31:0] regaData,
output reg [31:0] regbData
);
reg [31:0] reg32 [31 : 0];
always@(*)
if(rst == `RstEnable)
regaData = `Zero;
else if(regaAddr == `Zero)
regaData = `Zero;
else
regaData = reg32[regaAddr];
always@(*)
if(rst == `RstEnable)
regbData = `Zero;
else if(regbAddr == `Zero)
regbData = `Zero;
else
regbData = reg32[regbAddr];
always@(posedge clk)
if(rst == `RstDisable)
if((we == `Valid) && (waddr != `Zero))
reg32[waddr] = wdata;
else ;
else ;
endmodule
8 MIPS 封装
`include "define.v";
//5、MIPS封装
//修改EX实例化,新增Mem实例化
//新增端口rdData wtData memAddr memCe memWr
//原op变为op_i
//新增ls内部变量
module MIPS(
input wire clk,
input wire rst,
input wire [31:0] instruction,
input wire [31:0] rdData,//ls
output wire romCe,
output wire [31:0] instAddr,
output wire [31:0] wtData,//ls
output wire [31:0] memAddr,//ls
output wire memCe,//ls
output wire memWr,//ls
input wire[5:0] intr, //硬件中断的输入信号
output wire intimer //定时中断的输出信号
);
wire [31:0] regaData_regFile, regbData_regFile;
wire [31:0] regaData_id, regbData_id;
wire [31:0] regcData_ex;
//wire [5:0] op;
wire [5:0] op_id; //ls
wire regaRead, regbRead;
wire [4:0] regaAddr, regbAddr;
wire regcWrite_id, regcWrite_ex;
wire [4:0] regcAddr_id, regcAddr_ex;
//J型
wire [31:0] jAddr;
wire jCe;
//ls
wire [5:0] op_ex;
wire[31:0] memAddr_ex,memData_ex;
wire [4:0] regAddr_mem;
wire [31:0] regData_mem;
wire regWr_mem;
//md-hl
wire [31:0] wHiData_ex;
wire [31:0] wLoData_ex;
wire whi;
wire wlo;
wire [31:0] rHiData_ex;
wire [31:0] rLoData_ex;
//llsc
wire excpt;
wire wbit;
wire wLLbit;
wire rLLbit;
//中断
wire cp0we;
wire[4:0] cp0Addr;
wire[31:0] cp0wData;
wire[31:0] cp0rData;
wire[31:0] epc_ex , ejpc;
wire[31:0] excptype_id,excptype_ex;
wire[31:0] cause, status;
wire[31:0] pc_id, pc_ex;
wire regcWrite_o;
wire [4:0] regcAddr_o;
//流水线
wire stall_id;//from id to ctrl
wire [5:0] stall_o;//form ctrl to 流水寄存器
//IF_ID输出 ID输入
wire [31:0] instruction_o_ifid;
//ID输出 ID_EX输入
wire[31:0] instruction_o_id;
//ID_EX输出 EX输入
wire[31:0] instruction_o_idex;
wire[31:0] excptype_o;
wire [5:0] op_o;
wire[31:0] pc_o;
wire [31:0] regaData_o, regbData_o;
wire regcWrite_o_ex;
wire [4:0]regcAddr_o_ex;
//EX输出 EX_MEM输入
wire [31:0] instruction_o_ex;
//EX_MEM输出 MEM输入
wire[31:0] instruction_o_exmem;
wire [31:0] regcData_o_exmem;
wire regcWrite_o_exmem;
wire [4:0] regcAddr_o_exmem;
wire [5:0] op_o_exmem;
wire [31:0] memAddr_o_exmem;
wire [31:0] memData_o_exmem;
//MEM 输出 MEM_WB 输入
wire [31:0] instruction_o_mem;
//MEM_WB 输出 regFile 输入
wire [31:0] instruction_o_memwb;
wire [4:0] regAddr_memwb;
wire regWr_memwb;
wire [31:0] regData_memwb;
//流水线
wire[5:0] ex_op; //ex 反馈 id op码
wire[4:0] ex_wd_to_id; //ex 反馈 id读地址
wire ex_wreg_to_id; //ex 反馈 给 id 读信号
wire [31:0] ex_wdata_to_id; //ex 反馈 给 id 读数据
wire[4:0] mem_wd_to_id; //mem 反馈 id读地址
wire mem_wreg_to_id; //mem 反馈 给 id 读信号
wire [31:0] mem_wdata_to_id; //mem 反馈 给 id 读数据
//中断修改
//流水线修改
IF if0(
.clk(clk),
.rst(rst),
.jAddr(jAddr),//J型
.jCe(jCe),//J型
.ce(romCe),
.pc(instAddr),
.ejpc(ejpc),//异常或中断转移地址
.excpt(excpt),//异常或中断信号
.stall(stall_o)
);
//流水线-添加
IF_ID if_id0(
.clk(clk),
.rst(rst),
.stall(stall_o), //Ctrl input
.pc_i(instAddr), //from IF
.inst_i(instruction), //from instMem
.pc_o(pc_id), //to ID
.inst_o(instruction_o_ifid) //to ID
);
//中断修改
//流水线修改
ID id0(
.rst(rst),
// .pc(instAddr),//J型
// .inst(instruction_o), //流水线修改
.regaData_i(regaData_regFile),
.regbData_i(regbData_regFile),
//.op(op),
.op(op_id),//ls
.regaData(regaData_id),
.regbData(regbData_id),
.regaRead(regaRead),
.regbRead(regbRead),
.regaAddr(regaAddr),
.regbAddr(regbAddr),
.regcWrite(regcWrite_id),
.regcAddr(regcAddr_id),
.jAddr(jAddr),//J型
.jCe(jCe),//J型
.pc_i(instAddr),//pc的输入信号
.pc(pc_id), //pc的输出信号
.excptype(excptype_id),//中断或异常的记录信息
.inst_i(instruction_o_ifid),
.inst_o(instruction_o_id),
.stallreq(stall_id),
.ex_op_i(ex_op), //ex 反馈 id op码
.ex_wd_to_id_i(ex_wd_to_id), //ex 反馈 id读地址
.ex_wreg_to_id_i(ex_wreg_to_id), //ex 反馈 给 id 读信号
.ex_wdata_to_id_i(ex_wdata_to_id), //ex 反馈 给 id 读数据
.mem_wd_to_id_i(mem_wd_to_id), //mem 反馈 id读地址
.mem_wreg_to_id_i(mem_wreg_to_id), //mem 反馈 给 id 读信号
.mem_wdata_to_id_i(mem_wdata_to_id) //mem 反馈 给 id 读数据
);
//流水线-添加
ID_EX id_ex0(
.clk(clk),
.rst(rst),
.stall(stall_o), //from Ctrl
//id to ID_EX input
.inst_i(instruction_o_id),
.excptype_i(excptype_id),
.op_i(op_id),
.pc_i(pc_id),
.regaData_i(regaData_id),
.regbData_i(regbData_id),
.regcWrite_i(regcWrite_id),
.regcAddr_i(regcAddr_id),
//ID_EX to EX output
.inst_o(instruction_o_idex),
.excptype_o(excptype_o),
.op_o(op_o),
.pc_o(pc_o),
.regaData_o(regaData_o),
.regbData_o(regbData_o),
.regcWrite_o(regcWrite_o_ex),
.regcAddr_o(regcAddr_o_ex)
);
//乘除md-修改EX实例化
//中断修改
//流水线修改
EX ex0(
.rst(rst),
//.op(op),
.op_i(op_o),
.regaData(regaData_o),
.regbData(regbData_o),
.regcWrite_i(regcWrite_o_ex),
.regcAddr_i(regcAddr_o_ex),
.rHiData(rHiData_ex),//md
.rLoData(rLoData_ex),//md
.regcData(regcData_ex),
.regcWrite(regcWrite_ex),
.regcAddr(regcAddr_ex),
.op(op_ex),//ls
.memAddr(memAddr_ex),//ls
.memData(memData_ex),//ls
.whi(whi_ex),//md
.wlo(wlo_ex),//md
.wHiData(wHiData_ex),//md
.wLoData(wLoData_ex),//md
.cp0we(cp0we),//CPO的写信号
.cp0Addr(cp0Addr),//CPO的地址信息
.cp0wData(cp0wData),//CPO的写入数据
.cp0rData(cp0rData),//CPO的读出数据
.pc_i(pc_o),//pc的输入值
.excptype_i(excptype_o),//异常或中断的记录信息输入值
.excptype(excptype_ex),//异常或中断的记录信息输出值
.epc(epc_ex),//epc的输出值
.pc(pc_ex),//pc的输出值
.cause(cause),//cause的输入值
.status(status),//status的输入值
.inst_i(instruction_o_idex),
.inst_o(instruction_o_ex),
.ex_op_o(ex_op), //ex 反馈 给 id op码
.ex_wd_to_id_o(ex_wd_to_id), //ex 反馈 给 id 读地址
.ex_wreg_to_id_o(ex_wreg_to_id), //ex 反馈 给 id 读信号
.ex_wdata_to_id_o(ex_wdata_to_id) //ex 反馈 给 id 读数据
);
EX_MEM ex_mem0(
.clk(clk),
.rst(rst),
.stall(stall_o), //from Ctrl
//EX to EX_MEM input
.inst_i(instruction_o_ex), //根据数据通路,所有流水寄存器必须要加的
.regcData_i(regcData_ex),
.regcWrite_i(regcWrite_ex),
.regcAddr_i(regcAddr_ex),
.op_i(op_ex),
.memAddr_i(memAddr_ex),
.memData_i(memData_ex),
//EX_MEM to MEM output
.inst_o(instruction_o_exmem), //根据数据通路,所有流水寄存器必须要加的
.regcData_o(regcData_o_exmem),
.regcWrite_o(regcWrite_o_exmem),
.regcAddr_o(regcAddr_o_exmem),
.op_o(op_o_exmem),
.memAddr_o(memAddr_o_exmem),
.memData_o(memData_o_exmem)
);
//新增HiLo寄存器
HiLo hilo0(
.rst(rst),
.clk(clk),
.wHiData(wHiData_ex),
.wLoData(wLoData_ex),
.whi(whi_ex),
.wlo(wlo_ex),
.rHiData(rHiData_ex),
.rLoData(rLoData_ex)
);
//新增Mem实例化
//修改Mem实例化 llsc
//流水线修改
MEM mem0(
.rst(rst),
.op(op_o_exmem),
.regcData(regcData_o_exmem),
.regcAddr(regcAddr_o_exmem),
.regcWr(regcWrite_o_exmem),
.memAddr_i(memAddr_o_exmem),
.memData(memData_o_exmem),
.rdData(rdData),
.rLLbit(rLLbit),//llsc
.regAddr(regAddr_mem),
.regWr(regWr_mem),
.regData(regData_mem),
.memAddr(memAddr),
.wtData(wtData),
.memWr(memWr),
.memCe(memCe),
.wbit(wbit), //llsc
.wLLbit(wLLbit),//llsc
.inst_i(instruction_o_exmem),
.inst_o(instruction_o_mem),
.mem_wd_to_id_o(mem_wd_to_id), //mem 反馈 给 id 读地址
.mem_wreg_to_id_o(mem_wreg_to_id), //mem 反馈 给 id 读信号
.mem_wdata_to_id_o(mem_wdata_to_id) //mem 反馈 给 id 读数据
);
//新增流水线寄存器
MEM_WB mem_wb0(
.clk(clk),
.rst(rst),
.stall(stall_o), //from Ctrl
//MEM to MEM_WB input
.inst_i(instruction_o_mem), //根据数据通路,所有流水寄存器必须要加的
.regAddr(regAddr_mem),
.regWr(regWr_mem),
.regData(regData_mem),
//MEM_WB to regFile output
.inst_o(instruction_o_memwb), //根据数据通路,所有流水寄存器必须要加的
.we(regWr_memwb),
.waddr(regAddr_memwb),
.wdata(regData_memwb)
);
//新增LLbit实例化 llsc
LLbit llbit0(
.clk(clk),
.rst(rst),
.excpt(excpt),
.wbit(wbit),
.wLLbit(wLLbit),
.rLLbit(rLLbit)
);
//修改RegFile实例化
//流水线修改
RegFile regfile0(
.clk(~clk), //反向器
.rst(rst),
.inst(instruction_o_memwb),
.we(regWr_memwb),
.waddr(regAddr_memwb),
.wdata(regData_memwb),
.regaRead(regaRead),
.regbRead(regbRead),
.regaAddr(regaAddr),
.regbAddr(regbAddr),
.regaData(regaData_regFile),
.regbData(regbData_regFile)
);
//中断-新增加模块
CP0 cp0(
.clk(clk),
.rst(rst),
.cp0we(cp0we),
.cp0wData(cp0wData),
.cp0Addr(cp0Addr),
.cp0rData(cp0rData),
.intr(intr),
.intimer(intimer),
.pc(pc_ex),
.excptype(excptype_ex),
.cause(cause),
.status(status)
);
//中断-新增加模块
//流水线-修改
Ctrl ctrl0(
.rst(rst),
.ejpc(ejpc),
.excpt(excpt),
.excptype(excptype_ex),
.epc(epc_ex),
.stall_id(stall_id), //from id
.stall_o(stall_o) //to 流水寄存器
);
endmodule
9 InstMem 指令存储器
`include "define.v";
//6、指令存储器
module InstMem(
input wire ce,
input wire [31:0] addr,
output reg [31:0] data
);
reg [31:0] instmem [1023 : 0];
always@(*)
if(ce == `RomDisable)
data = `Zero;
else
data = instmem[addr[11 : 2]];
initial
begin
//测试流水
//ori R0,1100 -- R1 --00001100
instmem [0] = 32'h34011100;
//ori R0,0020 -- R2 --00000020
instmem [1] = 32'h34020020;
//ori R0,ff00 -- R3 --0000ff00
instmem [2] = 32'h3403ff00;
//ori R3,ffff -- R4 --0000ffff
instmem [3] = 32'h3464ffff;
//相邻两条指令 //ori R4,0000 -- R5 --0000ffff
instmem [4] = 32'h34850000;
//相隔一条指令 //ori R3,0000 -- R6 --0000ff00
instmem [5] = 32'h34660000;
//相隔两条指令 //ori R5,0000 -- R7 --0000ffff
instmem [6] = 32'h34A70000;
//load 相关
//mem[0]=(r1)
instmem[7]=32'b101011_00000_00001_0000_0000_0000_0000; //sw r1,0x0(r0)
//(r8)=mem[0]
instmem[8]=32'b100011_00000_01000_0000_0000_0000_0000; //lw r8,0x0(r0)
instmem[9]=32'b001101_01000_01001_0000_0000_0000_0000; // ori r9 r8,0000
end
endmodule
标签:课程设计,wire,FPGA,Zero,inst,ex,流水线,id,op From: https://blog.51cto.com/u_15719556/6407686