自己动手写CPU之第八阶段(4)——转移指令实现过程2
将陆续上传本人写的新书《自己动手写CPU》,今天是第36篇,我尽量每周四篇
开展晒书评送书活动,在亚马逊、京东、当当三大图书站点上,发表《自己动手写CPU》书评的前十名读者,均可获赠《步步惊芯——软核处理器内部设计分析》一书,大家踊跃參与吧!活动时间:2014-9-11至2014-10-20
8.4.3 改动运行阶段的EX 模块
參考图8-6可知,EX模块须要添加一些接口,添加的接口描写叙述如表8-4所看到的。
EX模块的代码主要改动例如以下,完整代码请參考本书附带光盘Code\Chapter8文件夹下的ex.v文件。
module ex(
......
// 处于运行阶段的转移指令要保存的返回地址
input wire[`RegBus] link_address_i,
// 当前运行阶段的指令是否位于延迟槽
input wire is_in_delayslot_i,
......
);
......
always @ (*) begin
......
case ( alusel_i )
`EXE_RES_LOGIC: begin
wdata_o <= logicout;
end
`EXE_RES_SHIFT: begin
wdata_o <= shiftres;
end
`EXE_RES_MOVE: begin
wdata_o <= moveres;
end
`EXE_RES_ARITHMETIC: begin
wdata_o <= arithmeticres;
end
`EXE_RES_MUL: begin
wdata_o <= mulres[31:0];
end
`EXE_RES_JUMP_BRANCH: begin
wdata_o <= link_address_i;
end
default: begin
wdata_o <= `ZeroWord;
end
endcase
end
......
endmodule
假设alusel_o为EXE_RES_JUMP_BRANCH,那么就将返回地址link_address_i作为要写入目的寄存器的值赋给wdata_o。
注意一点,此处并没有利用输入的信号is_in_delayslot_i,该信号表示当前处于运行阶段的指令是否是延迟槽指令,这个信号会在异常处理过程中使用到,本章临时不须要。
8.4.4 改动OpenMIPS模块
由于有一些模块加入了接口,所以须要改动顶层模块OpenMIPS,以将这些新添加的接口依照图8-6所看到的的关系连接起来。详细改动也非常easy,不在书中列出,读者能够參考本书附带光盘Code\Chapter8文件夹下的openmips.v文件。
8.5 測试转移指令的实现效果
本节将通过两个測试程序验证转移指令是否实现正确,这两个測试程序分别验证跳转指令、分支指令。
8.5.1 測试跳转指令
測试代码例如以下,源文件是本书光盘Code\Chapter8\AsmTest\Test1文件夹下的inst_rom.S文件。
.org 0x0
.set noat
.set noreorder # 加入这个伪操作,指示编译器不要对程序做出不论什么优化或是修改
.set nomacro
.global _start
_start:
ori $1,$0,0x0001 # (1)$1 = 0x1
j 0x20 # 转移到0x20处
ori $1,$0,0x0002 # (2)$1 = 0x2,这是延迟槽指令
ori $1,$0,0x1111
ori $1,$0,0x1100
.org 0x20
ori $1,$0,0x0003 # (3)$1 = 0x3
jal 0x40 # 转移到0x40处,同一时候设置$31为0x2c
div $zero,$31,$1 # (4)此时$31 = 0x2c, $1 = 0x3,所以得到除法结果
# HI = 0x2, LO = 0xe,这是延迟槽指令
ori $1,$0,0x0005 # (6)$1 = 0x5
ori $1,$0,0x0006 # (7)$1 = 0x6
j 0x60 # 转移到0x60处
nop
.org 0x40
jalr $2,$31 # 此时$31为0x2c,所以转移到0x2c,同一时候设置$2为0x48
or $1,$2,$0 # (5)$1 = 0x48,这是延迟槽指令
ori $1,$0,0x0009 # (10)$1 = 0x9
ori $1,$0,0x000a # (11)$1 = 0xa
j 0x80 # 转移到0x80处
nop
.org 0x60
ori $1,$0,0x0007 # (8)$1 = 0x7
jr $2 # 此时$2为0x48,所以转移到0x48处
ori $1,$0,0x0008 # (9)$1 = 0x8,这是延迟槽指令
ori $1,$0,0x1111
ori $1,$0,0x1100
.org 0x80
nop
_loop:
j _loop
nop
8.5.2 測试分支指令
測试代码例如以下,源文件是本书光盘Code\Chapter8\AsmTest\Test2文件夹下的inst_rom.S文件。
.org 0x0
.set noat
.set noreorder
.set nomacro
.global _start
_start:
ori $3,$0,0x8000
sll $3,16 # 设置$3 = 0x80000000
ori $1,$0,0x0001 #(1)$1 = 0x1
b s1 # 转移到s1处
ori $1,$0,0x0002 #(2)$1 = 0x2,这是延迟槽指令
1:
ori $1,$0,0x1111
ori $1,$0,0x1100
.org 0x20
s1:
ori $1,$0,0x0003 #(3)$1 = 0x3
bal s2 # 转移到s2处,同一时候设置$31为0x2c
div $zero,$31,$1 #(4)此时$31 = 0x2c, $1 = 0x3,所以除法结果为
# HI = 0x2, LO = 0xe,这是延迟槽指令
ori $1,$0,0x1100
ori $1,$0,0x1111
bne $1,$0,s3
nop
ori $1,$0,0x1100
ori $1,$0,0x1111
.org 0x50
s2:
ori $1,$0,0x0004 #(5)$1 = 0x4
beq $3,$3,s3 # $3等于$3,所以会发生转移,目的地址是s3
or $1,$31,$0 #(6)$1 = 0x2c,这是延迟槽指令
ori $1,$0,0x1111
ori $1,$0,0x1100
2:
ori $1,$0,0x0007 #(9)$1 = 0x7
ori $1,$0,0x0008 #(10)$1 = 0x8
bgtz $1,s4 # 此时$1为0x8,大于0,所以转移至标号s4处
ori $1,$0,0x0009 #(11)$1 = 0x9,这是延迟槽指令
ori $1,$0,0x1111
ori $1,$0,0x1100
.org 0x80
s3:
ori $1,$0,0x0005 #(7)$1 = 0x5
bgez $1,2b # 此时$1为0x5,大于0,所以转移至前面的标号2处
ori $1,$0,0x0006 #(8)$1 = 0x6,这是延迟槽指令
ori $1,$0,0x1111
ori $1,$0,0x1100
.org 0x100
s4:
ori $1,$0,0x000a #(12)$1 = 0xa
bgezal $3,s3 # 此时$3为0x80000000,小于0,所以不发生转移
or $1,$0,$31 #(13)$1 = 0x10c
ori $1,$0,0x000b #(14)$1 = 0xb
ori $1,$0,0x000c #(15)$1 = 0xc
ori $1,$0,0x000d #(16)$1 = 0xd
ori $1,$0,0x000e #(17)$1 = 0xe
bltz $3,s5 # 此时$3为0x80000000,小于0,所以发生转移,转移至s5处
ori $1,$0,0x000f #(18)$1 = 0xf,这是延迟槽指令
ori $1,$0,0x1100
.org 0x130
s5:
ori $1,$0,0x0010 #(19)$1 = 0x10
blez $1,2b # 此时$1为0x10,大于0,所以不发生转移
ori $1,$0,0x0011 #(20)$1 = 0x11
ori $1,$0,0x0012 #(21)$1 = 0x12
ori $1,$0,0x0013 #(22)$1 = 0x13
bltzal $3,s6 # 此时$3为0x80000000,小于0,所以发生转移,转移到s6处
or $1,$0,$31 #(23)$1 = 0x14c,这是延迟槽指令
ori $1,$0,0x1100
.org 0x160
s6:
ori $1,$0,0x0014 #(24)$1 = 0x14
nop
_loop:
j _loop
nop
上面的測试程序使用到了全部的分支指令,程序的凝视给出了寄存器$1的变化情况,及指令运行顺序,注意寄存器$1的变化是依照凝视中的序号顺序进行的。ModelSim仿真结果如图8-9所看到的,观察$1的变化可知OpenMIPS正确实现了分支指令。
至此,转移指令也实现完成了,下一步将实现载入存储指令,敬请关注!
浙公网安备 33010602011771号