6设计指令流水线【FPGA模型机课程设计】
- 前言
- 推荐
- 修改
- 6设计指令流水线
- 安排
- 测试与结果
- 指令流水线理论
- MIPS的一种简单实现
- 基本的MIPS流水线
- 指令流水线实现
- MIPS五段流水CPU设计
- 视频中的测试代码
- 基于单周期CPU的流水线设计
- 代码设计
- 流水寄存器的引脚设计
- IF_ID
- ID_EX
- EX_MEM
- MEM_WB
- 流水寄存器的功能设计
- IF_ID
- ID_EX
- EX_MEM
- MEM_WB
- 原来模块的改造
- IF
- ID
- EX
- MEM
- Ctrl
- regFile
- MIPS
- 测试设计
- 测试数据连接是否正确
- 测试功能
- 附录
- 0 框架
- 2 IF 取指
- I IF_ID 流水寄存器
- 3 ID 译码
- II ID_EX 流水寄存器
- 4 EX 执行
- III EX_MEM 流水寄存器
- 5 MEM 访存
- D Ctrl 控制模块
- IV MEM_WB 流水寄存器
- 7 RegFile 存取
- 8 MIPS 封装
- 最后
前言
2023-5-25 09:25:05
推荐
0集中实践环节计划书【FPGA模型机课程设计】
修改
2023-5-30 16:03:03
添加MEM_WB模块
2023-5-30 19:00:25
IF模块添加stall
2023-5-30 21:08:26
修改stall相关的处理
在id ctrl 流水寄存器中修改
因为原来没有理解stall[5:0]是什么意思
它的意思就是
当id传入stallreq(1bit)
做一些处理使其扩展为6bit
stall[0]控制pc寄存器,此处是if模块取值
stall[1]控制if_id
stall[2]控制id_ex
stall[3]控制ex_mem
stall[4]控制mem_wb
如果当前是Stop但是下一个stall是NoStop,意味着只停顿一个周期
所以多一个stall[5]
所以在Ctrl中stall和stallreq是左移寄存器的关系
2023-5-30 21:32:36
修改一些Warning
一些信号的位数不匹配
现在,仿真时应该是0Error 0Warning
提示:博客中的代码可能没有修改到位
6设计指令流水线
安排
第二周周一:
设计指令流水线,按照指令周期不同阶段进行划分,实现指令基本流水处理功能。注意数据相关冲突的解决。编写机器指令程序,对指令逐一进行测试,可以使用原有的测试程序,但检测结果时需注意功能和时序的对应关系。
测试与结果
不知道我到底是实现了流水线的功能吗
好像是已经实现了流水功能
但是现在只是基本的流水线的功能
数据冲突和分支和中断异常没有实现
原来的单周期CPU的波形
一个周期产生一个数据
现在的流水CPU的设计波形
流水线满载(C)后,一个周期产生一个数据
修改:增加MEM_WB
因为多了一个流水寄存器
所以满载的时候会多一个时钟周期
发现R5 没有结果,因为有数据冲突
可以看到以下测试代码
//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;
//R1=00001100 R2=00000020
instmem [4] = 32'b000000_00001_00010_00101_00000_100000;//add,R5,R1,R2 00001120
instmem [5] = 32'b000000_00001_00010_00110_00000_100101;//or,R6,R1,R2 00001120
可以看到inst[1]和inst[4],中间隔离两条命令,所以有了数据冲突
当inst1执行到MEM时,准备写回R2时
inst4在ID段读出R2,还是没有值的,所以它的R5结果不对
但是inst5的R6结果是对的,因为这个时候R2的结果已经写入进去了
2023-5-30 16:38:36
指令流水线理论
参考:教学资料
MIPS的一种简单实现
实现MIPS指令子集的一种简单数据通路。
该数据通路的操作分成5个时钟周期
- 取指令
- 指令译码/读寄存器
- 执行/有效地址计算
- 存储器访问/分支完成
- 写回
只讨论整数指令的实现(包括:load和store,等于0转移,整数ALU指令等。)
一条MIPS指令最多需要以下5个时钟周期:
取指令周期(IF)
- IR←Mem[PC]
- NPC←PC+4
指令译码/读寄存器周期(ID)
- A ← Regs[rs]
- B ← Regs[rt]
- Imm ← ((IR16)16##IR16…31)
指令的译码操作和读寄存器操作是并行进行的。
原因:在MIPS指令格式中,操作码字段以及rs、rt
字段都是在固定的位置。
这种技术称为固定字段译码技术。
执行/有效地址计算周期(EX)
不同指令所进行的操作不同:
- 存储器访问指令
ALUo←A + Imm - 寄存器-寄存器ALU指令
ALUo←A func B - 寄存器-立即值ALU指令
ALUo←A op Imm - 分支指令
ALUo←NPC+(Imm<<2);
cond←(A = = 0)
将有效地址计算周期和执行周期合并为一个时钟周期,这是因为MIPS指令集采用load/store结构,没有任何指令需要同时进行数据有效地址的计算、转移目标地址的计算和对数据进行运算。
存储器访问/分支完成周期(MEM)
- 所有指令都要在该周期对PC进行更新。
除了分支指令,其他指令都是做PC←NPC - 在该周期内处理的MIPS指令仅仅有load、store和分支三种指令。
- 存储器访问指令
LMD←Mem[ALUo]
或者 Mem[ALUo]←B - 分支指令
if (cond) PC ←ALUo else PC←NPC
写回周期(WB)
不同的指令在写回周期完成的工作也不一样。
- 寄存器-寄存器ALU指令
Regs[rd]← ALUo - 寄存器-立即数ALU指令
Regs[rt]← ALUo - load指令
Regs[rt]← LMD
基本的MIPS流水线
每一个时钟周期完成的工作看作是流水线的一段,每个时钟周期启动一条新的指令。
1.流水实现的数据通路
设置了流水寄存器
- 段与段之间设置流水寄存器
- 流水寄存器的命名
用其相邻的两个段的名称拼合而成。
例如:ID段与EX段之间的流水寄存器用ID/EX表示 - 每个流水寄存器是由若干个寄存器构成的
- 寄存器的命名形式为:x.y
- 所包含的字段的命名形式为:x.y[s]
其中:x:流水寄存器名称
y:具体寄存器名称
s:字段名称
例如:
ID/EX.IR:流水寄存器ID/EX中的子寄存器IR
IRID/EX.IR[op]:该寄存器的op字段(即操作码字段) - 流水寄存器的作用
将各段的工作隔开,使得它们不会互相干扰。
保存相应段的处理结果。
例如:
EX/MEM.ALUo:保存EX段ALU的运算结果
MEM/WB.LMD:保存MEM段从数据存储器读出的数据
向后传递后面将要用到的数据或者控制信息
所有有用的数据和控制信息每个时钟周期
会随着指令在流水线中的流动往后流动一段。
增加了向后传递IR和从MEM/WB.IR回送到通用寄存
器组的连接。将对PC的修改移到了IF段,以便PC能及时地加
4,为取下一条指令做好准备。
2.每一个流水段进行的操作
- IR[rs]=IR6…10
- IR[rt]=IR11…15
- IR[rd]=IR16…20
3.流水线的控制
主要是如何控制4个多路选择器。
- MUX2:若ID/EX.IR中的指令是分支指令,则选择ID/EX.NPC,否则选ID/EX.A。
- MUX3:若ID/EX.IR中的指令是寄存器-寄存器型ALU指令,则选ID/EX.B,否则选ID/EX.Imm。
- MUX1:若EX/MEM.IR中的指令是分支指令,而且EX/MEM.cond为真,则选EX/MEM.ALUo,即分支目标地址,否则选PC+4。
- MUX4:若MEM/WB.IR中的指令是load指令,则选MEM/WB.LMD,否则选MEM/WB.ALUo。
- 第5个多路器:从MEM/WB回传至通用寄存器组的写入地址应该是从MEM/WB.IR[rd] 和MEM/WB.IR[rt]中选一个。
- 寄存器-寄存器型ALU指令:选择MEM/WB.IR[rd] ;
- 寄存器-立即数型ALU指令和load指令:选择MEM/WB.IR[rt] 。
4.控制冲突
分支指令的条件测试和分支目标地址计算在EX段完成,对PC的修改在MEM段完成。
它所带来的分支延迟是3个时钟周期。
减少分支延迟:
(把上述工作提前到ID段进行)
- 在ID段增设一个加法器,用于计算分支目标地址。
- 把条件测试“=0?”的逻辑电路移到ID段。
- 这些结果直接回送到IF段的MUX1。
- 改进后的流水线对分支指令的处理。
指令流水线实现
参考:教学资料
MIPS五段流水CPU设计
五段流水线CPU通路基本构成
流水线设计的时候,必须增加流水寄存器
单周期、多周期、流水执行方式
单周期的每一条指令执行周期必须是一样的,取决于最长指令执行的时间
多周期的每一条指令执行周期长度可以不同
多周期的执行效率比单周期的高
流水线各个功能段大多数的情况下不会有空闲
流水寄存器的作用
支持基本R型运算的流水cpu数据通路图
流水寄存器的功能
数据通路
支持除了跳转指令的基本流水cpu通路图,需要分别理解R型运算、移位指令、I型运算、访存指令
ID中需要SA移位数据字段、imm(扩展)立即数字段
EX需要有效地址的计算
Mem需要写读DataMem
对比于单周期,流水CPU增加了4个流水寄存器
ID段产生所有的控制信号,并一级一级往需要的地方传送
传送最远的信号是wreg写寄存器信号
有些资料里会把MUX放到WB之后进行
相邻指令间存在数据相关,判断依据:寄存器地址
先写后读相关
不做处理的话,会读到写之前的旧数据
将EX段的执行结果通过反馈回路反馈给ID段,也要传递地址让ID段进行比较判断是否产生了相关
把EX段的执行结果通过反馈回路反馈给ID段,
类似于定向技术:数据真正产生的地方送到数据真正需要的地方
此时MUX的输入不仅是IF传送的信号,还有EX反馈的信号
相隔一条指令间存在数据相关,判断依据:寄存器地址
在写回没有完成之前,读的仍是旧数据
将MEM段的执行结果通过反馈回路反馈给ID段,也要传递地址让ID段进行比较判断是否产生了相关
所以在MEM段依然要反馈给ID段
相隔两条指令间存在数据相关
在写回没有完成之前,读的仍是旧数据
所以,让写回段以时钟下降沿写入,提前送入regs
在clk到达regFile之前,加了反向器
出现Load相关,反馈无法解决,必须CPU暂停
没有办法提前传寄存器的值
使用停顿
可以看到译码停顿了两个周期
判断条件:操作码为Lw且产生结果寄存器与后面指令源寄存器一致的情况
CPU暂停是什么意思?
ID检测到Load相关,
产生stall_req信号
传送到ctrl模块
ctrl产生stall信号
使得流水寄存器写入无效
目前的电路图:
针对20条基本指令
MIOC和IO为下版增加的模块
ID段判断数据先写后读数据相关的代码
视频中的测试代码
_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
另外,针对分支指令
还需才要延迟分支的原理来进行设计
或者使用停顿技术
当分支有效地址计算出来,再进行分支
基于单周期CPU的流水线设计
2023-5-28 10:32:14
以下是我设计中遇到的困难
主要是学习通里的流水线视频的设计框图,和原来单周期的设计框图不一样
他们两个的信号名称不一样
导致设计难度增加
视频中流水线的设计框图
原来的单周期的设计框图
按我的理解是:
流水寄存器中输入输出的信号与前后两个模块相关
比如IF_ID:
输入信号:就是原IF给原ID传递的信号
输出信号:就是原ID接受原IF的信号
另外添加:clk与rst控制与存储inst取到的指令
在IF_ID模块不需要inst,因为还没有得到此信号
所以,IF_ID引脚设计是这样的
input wire clk,
input wire rst,
input wire[5:0] stall, //Ctrl input
input wire [31:0] pc_i, //IF to
input wire[31:0] inst_i,//IF to
output reg [31:0] pc_o, //to ID
output reg [31:0] inst_o//to ID
主要原理就是这样,
但是,如果一些接口细节可能想不全,极有可能会不能正确地实现功能。
以下是按我的想法进行设计
参考视频中的顶层框图与流水CPU的数据通路
改造单周期的CPU设计,添加流水寄存器
代码设计
流水寄存器的引脚设计
按我的理解是:
流水寄存器中输入输出的信号与前后两个模块相关
比如IF_ID:
输入信号:就是原IF给原ID传递的信号
输出信号:就是原ID接受原IF的信号
另外添加:clk与rst控制与存储inst取到的指令
在IF_ID模块不需要inst,因为还没有得到此信号
另外,结合了数据通路实现
IF_ID
module IF_ID(
input wire clk,
input wire rst,
input wire[5:0] stall, //Ctrl input
input wire [31:0] pc_i, //from IF
input wire[31:0] inst_i,//from instMem
output reg [31:0] pc_o, //to ID
output reg [31:0] inst_o//to ID
);
endmodule
ID_EX
module ID_EX(
input wire clk,
input wire rst,
input wire[5:0] stall, //from Ctrl
//id to ID_EX input
input wire[31:0] inst_i, //根据数据通路,所有流水寄存器必须要加的
input wire [31:0] excptype_i,//输入的异常或中断信息记录
input wire [5:0] op_i,
input wire [31:0] pc_i,
input wire [31:0] regaData_i,
input wire [31:0] regbData_i,
input wire regcWrite_i,
input wire [4:0] regcAddr_i,
//ID_EX to EX output
output reg[31:0] inst_o, //根据数据通路,所有流水寄存器必须要加的
output reg [31:0] excptype_o,//输入的异常或中断信息记录
output reg [5:0] op_o,
output reg [31:0] pc_o,
output reg [31:0] regaData_o,
output reg [31:0] regbData_o,
output reg regcWrite_o,
output reg [4:0] regcAddr_o
);
endmodule
EX_MEM
module EX_MEM(
input wire clk,
input wire rst,
input wire[5:0] stall, //from Ctrl
//EX to EX_MEM input
input wire[31:0] inst_i, //根据数据通路,所有流水寄存器必须要加的
input reg [31:0] regcData_i,
input wire regcWrite_i,
input wire [4:0] regcAddr_i,
input wire [5:0] op_i,
input wire [31:0] memAddr_i,
input wire [31:0] memData_i,
//EX_MEM to MEM output
output wire[31:0] inst_o, //根据数据通路,所有流水寄存器必须要加的
output reg [31:0] regcData_o,
output wire regcWrite_o,
output wire [4:0] regcAddr_o,
output wire [5:0] op_o,
output wire [31:0] memAddr_o,
output wire [31:0] memData_o
);
endmodule
MEM_WB
module MEM_WB(
input wire clk,
input wire rst,
input wire[5:0] stall, //from Ctrl
//MEM to MEM_WB input
input wire[31:0] inst_i, //根据数据通路,所有流水寄存器必须要加的
input wire [4:0] regAddr,
input wire regWr,
input wire [31:0] regData,
//MEM_WB to regFile output
output reg[31:0] inst_o, //根据数据通路,所有流水寄存器必须要加的
output reg we,
output reg [4:0] waddr,
output reg [31:0] wdata
);
流水寄存器的功能设计
以下是简单的功能设计,没有实现流水功能
就是根据时钟信号
如果是复位信号有效,输出清零数据
如果是停顿信号有效,输出停顿数据
否则,输出传送数据
IF_ID
12:37
`include "define.v";
//IF_ID 流水寄存器
module IF_ID(
input wire clk,
input wire rst,
input wire[5:0] stall, //Ctrl input
input wire [31:0] pc_i, //from IF
input wire[31:0] inst_i,//from instMem
output reg [31:0] pc_o, //to ID
output reg [31:0] inst_o//to ID
);
always@(posedge clk)
if(rst == `RstEnable)
begin
inst_o<=`ZeroWord;
pc_o<=`ZeroWord;
end
else if(stall[1]==`Stop&&stall[2]==`NoStop)//停顿周期
begin
inst_o<=`ZeroWord;
pc_o<=`ZeroWord;
end
else if(stall[1]==`NoStop)
begin
inst_o<=inst_i;
pc_o<=pc_i;
end
endmodule
ID_EX
`include "define.v";
//ID_EX 流水寄存器
module ID_EX(
input wire clk,
input wire rst,
input wire[5:0] stall, //from Ctrl
//id to ID_EX input
input wire[31:0] inst_i, //根据数据通路,所有流水寄存器必须要加的
input wire [31:0] excptype_i,
input wire [5:0] op_i,
input wire [31:0] pc_i,
input wire [31:0] regaData_i,
input wire [31:0] regbData_i,
input wire regcWrite_i,
input wire [4:0] regcAddr_i,
//ID_EX to EX output
output reg[31:0] inst_o, //根据数据通路,所有流水寄存器必须要加的
output reg [31:0] excptype_o,//
output reg [5:0] op_o,
output reg [31:0] pc_o,
output reg [31:0] regaData_o,
output reg [31:0] regbData_o,
output reg regcWrite_o,
output reg [4:0] regcAddr_o
);
always@(posedge clk)
begin
if(rst==`RstEnable)
begin
inst_o=`ZeroWord;
excptype_o=excptype_i;
op_o=`Nop;
pc_o=`Zero;
regaData_o=`Zero;
regbData_o=`Zero;
regcWrite_o=`Invalid;
regcAddr_o=`Zero;
end
else if(stall[2]==`Stop&&stall[3]==`NoStop)//停顿周期
begin
inst_o=`ZeroWord;
excptype_o=excptype_i;
op_o=`Nop;
pc_o=`Zero;
regaData_o=`Zero;
regbData_o=`Zero;
regcWrite_o=`Invalid;
regcAddr_o=`Zero;
end
else if(stall[2]==`NoStop)
begin
inst_o<=inst_i;
excptype_o=excptype_i;
op_o=op_i;
pc_o=pc_i;
regaData_o=regaData_i;
regbData_o=regbData_i;
regcWrite_o=regcWrite_i;
regcAddr_o=regcAddr_i;
end
end
endmodule
EX_MEM
`include "define.v"
//EX_MEM 流水寄存器
module EX_MEM(
input wire clk,
input wire rst,
input wire[5:0] stall, //from Ctrl
//EX to EX_MEM input
input wire[31:0] inst_i, //根据数据通路,所有流水寄存器必须要加的
input reg [31:0] regcData_i,
input wire regcWrite_i,
input wire [4:0] regcAddr_i,
input wire [5:0] op_i,
input wire [31:0] memAddr_i,
input wire [31:0] memData_i,
//EX_MEM to MEM output
output reg[31:0] inst_o, //根据数据通路,所有流水寄存器必须要加的
output reg [31:0] regcData_o,
output reg regcWrite_o,
output reg [4:0] regcAddr_o,
output reg [5:0] op_o,
output reg [31:0] memAddr_o,
output reg [31:0] memData_o
);
always@(posedge clk)
begin
if(rst==`RstEnable)
begin
inst_o=`ZeroWord;
regcData_o=`Zero;
regcWrite_o=`Invalid;
regcAddr_o=`Zero;
op_o=`Nop;
memAddr_o=`Zero;
memData_o=`Zero;
end
else if(stall[3]==`Stop&&stall[4]==`NoStop)//停顿周期
begin
inst_o=`ZeroWord;
regcData_o=`Zero;
regcWrite_o=`Invalid;
regcAddr_o=`Zero;
op_o=`Nop;
memAddr_o=`Zero;
memData_o=`Zero;
end
else if(stall[3]==`NoStop)
begin
inst_o=inst_i;
regcData_o=regcData_i;
regcWrite_o=regcWrite_i;
regcAddr_o=regcAddr_i;
op_o=op_i;
memAddr_o=memAddr_i;
memData_o=memData_i;
end
end
endmodule
MEM_WB
`include "define.v"
//MEM_WB 流水寄存器
module MEM_WB(
input wire clk,
input wire rst,
input wire[5:0] stall, //from Ctrl
//MEM to MEM_WB input
input wire[31:0] inst_i, //根据数据通路,所有流水寄存器必须要加的
input wire [5:0] regAddr,
input wire regWr,
input wire [31:0] regData,
//MEM_WB to regFile output
output reg[31:0] inst_o, //根据数据通路,所有流水寄存器必须要加的
output reg we,
output reg [5:0] waddr,
output reg [31:0] wdata
);
always@(posedge clk)
begin
if(rst==`RstEnable)
begin
inst_o=`ZeroWord;
wdata=`Zero;
we=`Invalid;
waddr=`Zero;
end
else if(stall[4]==`Stop&&stall[5]==`NoStop)//停顿周期
begin
inst_o=`ZeroWord;
wdata=`Zero;
we=`Invalid;
waddr=`Zero;
end
else if(stall[4]==`NoStop)
begin
inst_o=inst_i;
wdata=regData;
we=regWr;
waddr=regAddr;
end
end
endmodule
原来模块的改造
多了个inst的处理
取得上一个流水寄存器的值inst_i
传送下一个流水寄存器的值inst_o
IF
11:25
对应教学视频的PC寄存器
input wire[5:0] stall //流水线
//程序执行 pc+=4
//中断-修改
//流水线修改
always@(posedge clk)
if(ce == `RomDisable)
pc = `Zero;
else if(stall[0]==`NoStop) //流水线
begin
if(excpt == 1'b1)
pc <=ejpc;//异常或中断的转移地址更新pc
else if(jCe == `Valid)//J型
pc = jAddr;
else
pc = pc + 4;
end
ID
14:31
最复杂的模块
译码出所有的控制信号
// input wire [31:0] inst,
input wire[31:0] inst_i, //接受
output reg[31:0] inst_o, //传送
output wire stallreq //to Ctrl
//方便修改
wire [31:0] inst=inst_i;
//对stall先不处理
assign stallreq =1'b0;
always@(*)
inst_o=inst_i;
EX
input wire[31:0] inst_i, //接受
output reg[31:0] inst_o //传送
always@(*)
inst_o=inst_i;
MEM
input wire[31:0] inst_i, //接受
output reg[31:0] inst_o //传送
always@(*)
inst_o=inst_i;
Ctrl
input wire stall_id, //from id
output reg[5:0] stall_o //to 流水寄存器
//左移寄存器
always@(*)
if(rst == `RstEnable)
stall_o=6'b0;
else
stall_o={stall_o[4:0],stall_id};
regFile
input wire[31:0] inst, //流水线
MIPS
需要把相邻两个模块拆开,用流水寄存器相联
举例:说明怎么修改
比如:ID ID_EX EX
原来:ID输出–>EX输入
(一条线连接)
修改:
把原ID输出的信号–>ID_EX输入
把ID_EX的输出信号–>原EX输入
(两条线连接)
对比来看,把原EX输入信号量与ID_EX输入相连
并且新增连线
把ID_EX的输出信号与原EX输入连接起来
下面代码可能会遗漏,会连线错误
如若发现,请指正
//流水线
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;
//中断修改
//流水线修改
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)
);
//流水线-添加
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_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)
);
//新增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_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)
);
//流水线修改
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)
);
测试设计
测试数据连接是否正确
如果是以下连线
代表MIPS内部连线没有问题
算了,附个图,好看点吧
以下流水线,应该能看懂吧
流水寄存器获取上一个模块的信号是时序逻辑
模块获取上一个流水寄存器的信号是组合逻辑
所以
另外说明:此处IF只执行pc+4(时序逻辑),IF_ID根据pc从instMem中取出inst(组合逻辑)
IF_ID:inst_o=inst_i[clk↑]
ID:inst_o=inst_i
ID_EX:inst_o=inst_i[clk↑]
EX:inst_o=inst_i
EX_MEM:inst_o=inst_i[clk↑]
MEM:inst_o=inst_i
因为模块的组合逻辑
ID_EX.inst_i与ID.inst_i(ID.inst_o)相同
EX_MEM.inst_i与EX.inst_i(ID.inst_o)相同
下图没有画出,仿真图有此体现
增加MEM_WB之后的结果
因为多了一个流水寄存器
所以满载的时候会多一个时钟周期
流水图如下
测试功能
原来的单周期CPU的波形
一个周期产生一个数据
现在的流水CPU的设计波形
流水线满载(C)后,一个周期产生一个数据
修改:增加MEM_WB
因为多了一个流水寄存器
所以满载的时候会多一个时钟周期
发现R5 没有结果,因为有数据冲突
pc=14时
可以看到inst4在ID段
但是inst1在WB段
在时钟上升沿
真正写入regFile
2023-5-30 16:59:31
附录
其余与上篇一样
0 框架
顶层设计
代码框架
2 IF 取指
`include "define.v";
//IF 取指模块
//1、控制PC,程序计数器
module IF(
input wire clk,
input wire rst,
input wire [31:0] jAddr,//J型
input wire jCe,//J型
output reg ce,
output reg [31:0] pc,
input wire[31:0] ejpc, //异常或中断转移地址
input wire excpt, //异常或中断有效信号
input wire[5:0] stall
);
always@(*)
if(rst == `RstEnable)
ce = `RomDisable;
else
ce = `RomEnable;
//程序执行 pc+=4
//中断-修改
always@(posedge clk)
if(ce == `RomDisable)
pc = `Zero;
else if(stall[0]==`NoStop)
begin
if(excpt == 1'b1)
pc <=ejpc;//异常或中断的转移地址更新pc
else if(jCe == `Valid)//J型
pc = jAddr;
else
pc = pc + 4;
end
endmodule
I IF_ID 流水寄存器
`include "define.v";
//IF_ID 流水寄存器
module IF_ID(
input wire clk,
input wire rst,
input wire[5:0] stall, //Ctrl input
input wire [31:0] pc_i, //from IF
input wire[31:0] inst_i,//from instMem
output reg [31:0] pc_o, //to ID
output reg [31:0] inst_o//to ID
);
always@(posedge clk)
if(rst == `RstEnable)
begin
inst_o<=`ZeroWord;
pc_o<=`ZeroWord;
end
else if(stall[1]==`Stop&&stall[2]==`NoStop)//停顿周期
begin
inst_o<=`ZeroWord;
pc_o<=`ZeroWord;
end
else if(stall[1]==`NoStop)
begin
inst_o<=inst_i;
pc_o<=pc_i;
end
endmodule
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
);
//方便修改
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};
//对stall先不处理
assign stallreq =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;
endmodule
II ID_EX 流水寄存器
`include "define.v";
//ID_EX 流水寄存器
module ID_EX(
input wire clk,
input wire rst,
input wire[5:0] stall, //from Ctrl
//id to ID_EX input
input wire[31:0] inst_i, //根据数据通路,所有流水寄存器必须要加的
input wire [31:0] excptype_i,
input wire [5:0] op_i,
input wire [31:0] pc_i,
input wire [31:0] regaData_i,
input wire [31:0] regbData_i,
input wire regcWrite_i,
input wire [4:0] regcAddr_i,
//ID_EX to EX output
output reg[31:0] inst_o, //根据数据通路,所有流水寄存器必须要加的
output reg [31:0] excptype_o,//
output reg [5:0] op_o,
output reg [31:0] pc_o,
output reg [31:0] regaData_o,
output reg [31:0] regbData_o,
output reg regcWrite_o,
output reg [4:0] regcAddr_o
);
always@(posedge clk)
begin
if(rst==`RstEnable)
begin
inst_o=`ZeroWord;
excptype_o=excptype_i;
op_o=`Nop;
pc_o=`Zero;
regaData_o=`Zero;
regbData_o=`Zero;
regcWrite_o=`Invalid;
regcAddr_o=`Zero;
end
else if(stall[1]==`Stop&&stall[2]==`NoStop)//停顿周期
begin
inst_o=`ZeroWord;
excptype_o=excptype_i;
op_o=`Nop;
pc_o=`Zero;
regaData_o=`Zero;
regbData_o=`Zero;
regcWrite_o=`Invalid;
regcAddr_o=`Zero;
end
else if(stall[1]==`NoStop)
begin
inst_o<=inst_i;
excptype_o=excptype_i;
op_o=op_i;
pc_o=pc_i;
regaData_o=regaData_i;
regbData_o=regbData_i;
regcWrite_o=regcWrite_i;
regcAddr_o=regcAddr_i;
end
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 //传送
);
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@(*)
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
III EX_MEM 流水寄存器
`include "define.v"
//EX_MEM 流水寄存器
module EX_MEM(
input wire clk,
input wire rst,
input wire[5:0] stall, //from Ctrl
//EX to EX_MEM input
input wire[31:0] inst_i, //根据数据通路,所有流水寄存器必须要加的
input reg [31:0] regcData_i,
input wire regcWrite_i,
input wire [4:0] regcAddr_i,
input wire [5:0] op_i,
input wire [31:0] memAddr_i,
input wire [31:0] memData_i,
//EX_MEM to MEM output
output reg[31:0] inst_o, //根据数据通路,所有流水寄存器必须要加的
output reg [31:0] regcData_o,
output reg regcWrite_o,
output reg [4:0] regcAddr_o,
output reg [5:0] op_o,
output reg [31:0] memAddr_o,
output reg [31:0] memData_o
);
always@(posedge clk)
begin
if(rst==`RstEnable)
begin
inst_o=`ZeroWord;
regcData_o=`Zero;
regcWrite_o=`Invalid;
regcAddr_o=`Zero;
op_o=`Nop;
memAddr_o=`Zero;
memData_o=`Zero;
end
else if(stall[1]==`Stop&&stall[2]==`NoStop)//停顿周期
begin
inst_o=`ZeroWord;
regcData_o=`Zero;
regcWrite_o=`Invalid;
regcAddr_o=`Zero;
op_o=`Nop;
memAddr_o=`Zero;
memData_o=`Zero;
end
else if(stall[1]==`NoStop)
begin
inst_o=inst_i;
regcData_o=regcData_i;
regcWrite_o=regcWrite_i;
regcAddr_o=regcAddr_i;
op_o=op_i;
memAddr_o=memAddr_i;
memData_o=memData_i;
end
end
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 //传送
);
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 @ (*)
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
D Ctrl 控制模块
`include "define.v"
//控制模块
module Ctrl(
input wire rst, //复位信号
input wire[31:0] excptype, //异常或中断信息记录
input wire [31:0] epc, //输入epc的值,用于eret 指令
output reg [31:0] ejpc, //输出ejpc的值
output reg excpt, //中断或异常有效信号
input wire stall_id, //from id
output reg[5:0] stall_o //to 流水寄存器
);
//左移寄存器
always@(*)
if(rst == `RstEnable)
stall_o=6'b0;
else
stall_o={stall_o[4:0],stall_id};
always@(*)
if(rst == `RstEnable)
begin
excpt = `Invalid;
ejpc = `Zero;
end
else
begin
excpt = `Valid;
case(excptype)
//timerInt
32'h0000_0004:
ejpc = 32'h00000050;//自己指定:中断服务地址 50h右移2位(即除以4)=20 instMem
//Syscall
32'h0000_0100:
ejpc= 32'h00000040;//自己指定:中断服务地址 40h右移2位(即除以4)=16 instMem
//Eret
32'h0000_0200:
ejpc = epc;
default:
begin
ejpc= `Zero;
excpt = `Invalid;
end
endcase
end
endmodule
IV MEM_WB 流水寄存器
`include "define.v"
//MEM_WB 流水寄存器
module MEM_WB(
input wire clk,
input wire rst,
input wire[5:0] stall, //from Ctrl
//MEM to MEM_WB input
input wire[31:0] inst_i, //根据数据通路,所有流水寄存器必须要加的
input wire [4:0] regAddr,
input wire regWr,
input wire [31:0] regData,
//MEM_WB to regFile output
output reg[31:0] inst_o, //根据数据通路,所有流水寄存器必须要加的
output reg we,
output reg [4:0] waddr,
output reg [31:0] wdata
);
always@(posedge clk)
begin
if(rst==`RstEnable)
begin
inst_o=`ZeroWord;
wdata=`Zero;
we=`Invalid;
waddr=`Zero;
end
else if(stall[1]==`Stop&&stall[2]==`NoStop)//停顿周期
begin
inst_o=`ZeroWord;
wdata=`Zero;
we=`Invalid;
waddr=`Zero;
end
else if(stall[1]==`NoStop)
begin
inst_o=inst_i;
wdata=regData;
we=regWr;
waddr=regAddr;
end
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;
//中断修改
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)
);
//流水线-添加
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_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_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
最后
2023-5-28 16:21:39
添加MEM_WB
2023-5-30 16:42:28
修改没有问题了
2023-5-30 22:57:15
你对我百般注视,
并不能构成万分之一的我,
却是一览无余的你。
标签:课程设计,wire,FPGA,output,31,Zero,inst,input,流水线 From: https://blog.51cto.com/u_15719556/6408245