首页 > 其他分享 >6设计指令流水线-1【FPGA模型机课程设计】

6设计指令流水线-1【FPGA模型机课程设计】

时间:2023-06-03 17:04:03浏览次数:40  
标签:课程设计 wire FPGA output 31 Zero inst input 流水线



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设计指令流水线-1【FPGA模型机课程设计】_寄存器

6设计指令流水线

安排

第二周周一:

设计指令流水线,按照指令周期不同阶段进行划分,实现指令基本流水处理功能。注意数据相关冲突的解决。编写机器指令程序,对指令逐一进行测试,可以使用原有的测试程序,但检测结果时需注意功能和时序的对应关系。

测试与结果

不知道我到底是实现了流水线的功能吗

好像是已经实现了流水功能

但是现在只是基本的流水线的功能
数据冲突和分支和中断异常没有实现

原来的单周期CPU的波形

一个周期产生一个数据

6设计指令流水线-1【FPGA模型机课程设计】_fpga开发_02

现在的流水CPU的设计波形

流水线满载(C)后,一个周期产生一个数据

6设计指令流水线-1【FPGA模型机课程设计】_fpga开发_03

修改:增加MEM_WB

因为多了一个流水寄存器
所以满载的时候会多一个时钟周期

发现R5 没有结果,因为有数据冲突

6设计指令流水线-1【FPGA模型机课程设计】_数据_04


可以看到以下测试代码

//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的结果已经写入进去了

6设计指令流水线-1【FPGA模型机课程设计】_寄存器_05

2023-5-30 16:38:36

指令流水线理论

参考:教学资料

MIPS的一种简单实现

实现MIPS指令子集的一种简单数据通路。
该数据通路的操作分成5个时钟周期

  • 取指令
  • 指令译码/读寄存器
  • 执行/有效地址计算
  • 存储器访问/分支完成
  • 写回

只讨论整数指令的实现(包括:load和store,等于0转移,整数ALU指令等。)

6设计指令流水线-1【FPGA模型机课程设计】_数据_06


一条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表示
  • 每个流水寄存器是由若干个寄存器构成的

6设计指令流水线-1【FPGA模型机课程设计】_数据_07

  • 寄存器的命名形式为: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

6设计指令流水线-1【FPGA模型机课程设计】_fpga开发_08


6设计指令流水线-1【FPGA模型机课程设计】_课程设计_09

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。
  • 改进后的流水线对分支指令的处理。

6设计指令流水线-1【FPGA模型机课程设计】_寄存器_10


6设计指令流水线-1【FPGA模型机课程设计】_课程设计_11

指令流水线实现

参考:教学资料

MIPS五段流水CPU设计

五段流水线CPU通路基本构成

流水线设计的时候,必须增加流水寄存器

6设计指令流水线-1【FPGA模型机课程设计】_数据通路_12


单周期、多周期、流水执行方式

单周期的每一条指令执行周期必须是一样的,取决于最长指令执行的时间
多周期的每一条指令执行周期长度可以不同

多周期的执行效率比单周期的高

流水线各个功能段大多数的情况下不会有空闲

流水寄存器的作用

6设计指令流水线-1【FPGA模型机课程设计】_寄存器_13

支持基本R型运算的流水cpu数据通路图

流水寄存器的功能

数据通路

6设计指令流水线-1【FPGA模型机课程设计】_课程设计_14


支持除了跳转指令的基本流水cpu通路图,需要分别理解R型运算、移位指令、I型运算、访存指令

ID中需要SA移位数据字段、imm(扩展)立即数字段

EX需要有效地址的计算

Mem需要写读DataMem

对比于单周期,流水CPU增加了4个流水寄存器
ID段产生所有的控制信号,并一级一级往需要的地方传送
传送最远的信号是wreg写寄存器信号

有些资料里会把MUX放到WB之后进行

6设计指令流水线-1【FPGA模型机课程设计】_数据通路_15

相邻指令间存在数据相关,判断依据:寄存器地址

先写后读相关
不做处理的话,会读到写之前的旧数据

6设计指令流水线-1【FPGA模型机课程设计】_寄存器_16

将EX段的执行结果通过反馈回路反馈给ID段,也要传递地址让ID段进行比较判断是否产生了相关

把EX段的执行结果通过反馈回路反馈给ID段,
类似于定向技术:数据真正产生的地方送到数据真正需要的地方
此时MUX的输入不仅是IF传送的信号,还有EX反馈的信号

6设计指令流水线-1【FPGA模型机课程设计】_fpga开发_17


相隔一条指令间存在数据相关,判断依据:寄存器地址

在写回没有完成之前,读的仍是旧数据

6设计指令流水线-1【FPGA模型机课程设计】_寄存器_18

将MEM段的执行结果通过反馈回路反馈给ID段,也要传递地址让ID段进行比较判断是否产生了相关

所以在MEM段依然要反馈给ID段

6设计指令流水线-1【FPGA模型机课程设计】_寄存器_19

相隔两条指令间存在数据相关

在写回没有完成之前,读的仍是旧数据

6设计指令流水线-1【FPGA模型机课程设计】_寄存器_20


所以,让写回段以时钟下降沿写入,提前送入regs

在clk到达regFile之前,加了反向器

6设计指令流水线-1【FPGA模型机课程设计】_寄存器_21

出现Load相关,反馈无法解决,必须CPU暂停

没有办法提前传寄存器的值

6设计指令流水线-1【FPGA模型机课程设计】_数据_22


使用停顿

可以看到译码停顿了两个周期

6设计指令流水线-1【FPGA模型机课程设计】_数据通路_23

判断条件:操作码为Lw且产生结果寄存器与后面指令源寄存器一致的情况

CPU暂停是什么意思?

ID检测到Load相关,
产生stall_req信号
传送到ctrl模块
ctrl产生stall信号
使得流水寄存器写入无效

6设计指令流水线-1【FPGA模型机课程设计】_寄存器_24

目前的电路图:

针对20条基本指令

MIOC和IO为下版增加的模块

6设计指令流水线-1【FPGA模型机课程设计】_数据通路_25

ID段判断数据先写后读数据相关的代码

6设计指令流水线-1【FPGA模型机课程设计】_数据通路_26

视频中的测试代码

_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

以下是我设计中遇到的困难

主要是学习通里的流水线视频的设计框图,和原来单周期的设计框图不一样
他们两个的信号名称不一样
导致设计难度增加

视频中流水线的设计框图

6设计指令流水线-1【FPGA模型机课程设计】_课程设计_27

原来的单周期的设计框图

6设计指令流水线-1【FPGA模型机课程设计】_课程设计_28

按我的理解是:
流水寄存器中输入输出的信号与前后两个模块相关

比如IF_ID:
输入信号:就是原IF给原ID传递的信号
输出信号:就是原ID接受原IF的信号

另外添加:clk与rst控制与存储inst取到的指令
在IF_ID模块不需要inst,因为还没有得到此信号

6设计指令流水线-1【FPGA模型机课程设计】_数据通路_29

所以,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

6设计指令流水线-1【FPGA模型机课程设计】_数据通路_29

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

6设计指令流水线-1【FPGA模型机课程设计】_课程设计_31

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

6设计指令流水线-1【FPGA模型机课程设计】_寄存器_32

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

);

6设计指令流水线-1【FPGA模型机课程设计】_数据通路_33

流水寄存器的功能设计

以下是简单的功能设计,没有实现流水功能

就是根据时钟信号
如果是复位信号有效,输出清零数据
如果是停顿信号有效,输出停顿数据
否则,输出传送数据

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内部连线没有问题

6设计指令流水线-1【FPGA模型机课程设计】_寄存器_34

算了,附个图,好看点吧

以下流水线,应该能看懂吧

流水寄存器获取上一个模块的信号是时序逻辑
模块获取上一个流水寄存器的信号是组合逻辑

所以
另外说明:此处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)相同

下图没有画出,仿真图有此体现

6设计指令流水线-1【FPGA模型机课程设计】_数据通路_35

增加MEM_WB之后的结果

因为多了一个流水寄存器

所以满载的时候会多一个时钟周期

6设计指令流水线-1【FPGA模型机课程设计】_寄存器_36

流水图如下

6设计指令流水线-1【FPGA模型机课程设计】_数据_37

测试功能

原来的单周期CPU的波形

一个周期产生一个数据

6设计指令流水线-1【FPGA模型机课程设计】_fpga开发_02

现在的流水CPU的设计波形

流水线满载(C)后,一个周期产生一个数据

6设计指令流水线-1【FPGA模型机课程设计】_fpga开发_03

修改:增加MEM_WB

因为多了一个流水寄存器
所以满载的时候会多一个时钟周期

发现R5 没有结果,因为有数据冲突

6设计指令流水线-1【FPGA模型机课程设计】_数据_04


pc=14时

可以看到inst4在ID段
但是inst1在WB段

在时钟上升沿
真正写入regFile

6设计指令流水线-1【FPGA模型机课程设计】_fpga开发_41

2023-5-30 16:59:31

附录

其余与上篇一样

0 框架

顶层设计

6设计指令流水线-1【FPGA模型机课程设计】_寄存器_42

代码框架

6设计指令流水线-1【FPGA模型机课程设计】_数据_43

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

相关文章

  • 6设计指令流水线-3【FPGA模型机课程设计】
    6设计指令流水线-3【FPGA模型机课程设计】前言推荐6设计指令流水线-3安排测试与结果指令流水线理论MIPS的一种简单实现基本的MIPS流水线指令流水线实现MIPS五段流水CPU设计基于单周期CPU的流水线设计乘除流水线的设计原子流水线的设计代码设计EX_Mem附录0框架最后前言2023-5-25......
  • 单周期CPU模型机下载【FPGA模型机课程设计】
    模型机下载【FPGA模型机课程设计】前言推荐单周期CPU模型机下载安排测试与结果5.7.2模型机下载FPGA设计代码设计MIOCIOIO1SoCInstMem附录0框架EMIOC接口FIO外设IO1测试MIOC分流9InstMem指令存储器10SoC顶层最后前言2023-5-2707:55:09周六早上睡不着了起来学习推荐5模......
  • 数据结构与算法分析课程设计
    1.设计目的数据结构课程设计是学习了数据结构课程后的一个综合性实践教学环节,是对课程理论和课程实验的综合和补充。它主要培养学生综合运用已学过的理论和技能去分析和解决实际问题的能力,对加深课程理论的理解和应用、切实加强学生的实践动手能力和创新能力具有重要意义。2.设计要......
  • 3.6 流水线逻辑控制
    加载/使用冒险:在一条从内存中读出一个值的指令和一条使用该值的指令之间,流水线必须暂停一个周期。处理ret:流水线必须暂停直到ret指令到达写回阶段。预测错误的分支:在分支逻辑发现不应该选择分支之前,分支目标处的几条指令已经进入流水线了。必须取消这些指令,并从跳转指令后面的那......
  • javaweb课程设计——商城项目
    目录本项目前端成员csdn地址:一、项目截图二、前端项目介绍最后源码地址本项目前端成员csdn地址:【后端】【前端】一、项目截图二、前端项目介绍ChangeAtWill:前台项目ChangeAtWill-admin:后台项目前端需要环境nodejsv16版本下载链接https://nodejs.org/download/release/v16......
  • 6设计指令流水线-2【FPGA模型机课程设计】
    6设计指令流水线-2【FPGA模型机课程设计】前言推荐6设计指令流水线-2安排测试与结果指令流水线理论MIPS的一种简单实现基本的MIPS流水线指令流水线实现MIPS五段流水CPU设计视频中的测试代码设计分析设计思路问题回答代码设计IDEXMEMRegFileMIPSInstMem附录3ID译码4EX执行5MEM......
  • 3.5 Y84-64的流水线实现
    我们终于准备好要开始本章的主要任务——设计一个流水线化的Y86-64处理器。首先,对顺序的SEQ处理器做一点小的改动,将PC的计算挪到取指阶段。然后,在各个阶段之间加上流水线寄存器。到这个时候,我们的尝试还不能正确处理各种数据和控制相关。不过,做一些修改,就能实现我们的目标——一个......
  • m基于FPGA的RGB转ycrcb颜色空间转换算法实现,包含testbench,对比三种转换方法
    1.算法仿真效果vivado2019.2仿真结果如下:其中1为直接乘法公式计算;2为移位法计算;3为分布式计算;2.算法涉及理论知识概要人类获得信息的主要方式是视觉,通常情况下颜色有2种描述方式,一种是RGB色度空间表示,一种是YCbCr色度空间表示。然而,普通的RGB颜色空间对视频的显示存在......
  • m基于FPGA的RGB转ycrcb颜色空间转换算法实现,包含testbench,对比三种转换方法
    1.算法仿真效果vivado2019.2仿真结果如下: 其中1为直接乘法公式计算; 2为移位法计算; 3为分布式计算; 2.算法涉及理论知识概要        人类获得信息的主要方式是视觉,通常情况下颜色有2种描述方式,一种是RGB色度空间表示,一种是YCbCr色度空间表示。然而,普通......
  • C/C++数据结构课程设计[2023-05-31]
    C/C++数据结构课程设计[2023-05-31]数据结构课程设计实验(训)指导书所在学院:计算机科学与工程学院编写说明一.实验总体目标《数据结构》是一门实践性较强的课程,为了学好这门课程,必须在掌握理论知识的同时,加强上机实践。本实验的目标是,学生能正确理解和熟练掌握常用数据结构和算......