MIPS 分支寻址算法和操作码与指令二进制文件的隔离?
MIPS Branch Addressing Algorithm and Opcode isolation from instruction binary?
我只是想检查一下我对这两个概念的理解是否正确,因为我一直在努力完成一个项目,虽然一切都符合我的预期,但它总是勉强通过测试用例并引入一个随机值.. .
基本上,项目的objective就是写出一个分支指令到console,形式如下:
BranchName $S,[$t,如果适用] 0xAbsoluteAddressOfBranchTargetInstruction
编辑:澄清:我是用 MIPS 写的。这个想法是我通过我的讲师代码(我编写函数)在 $a0 中获得一个内存地址给程序。该地址用于包含 MIPS 指令的字。我要执行以下操作:
- 获取指令
- 隔离指令操作码并将其名称输出到寄存器(即:操作码5,输出BNE),如果不是分支指令则什么也不做。
- 根据需要隔离 $s、$t 和输出(即:bgez 没有 $t)
- 利用分支指令中的偏移量计算出其绝对地址(分支后目标指令的地址)并以十六进制输出。出于此计算的目的,假设分支指令的地址 ($a0) 为 $pc.
IE:
BEQ $6, $9, 0x00100008
首先,我对分支计算的理解是否正确?
- PC -> PC + 4
- 指令的低16位
- << 2 这些低位
- 添加PC+4和左移低16位(尽管只有低16位)。
其次,有人可以告诉我需要隔离哪些位才能知道我正在处理哪种分支吗?我想我有它们(前 6 个用于 BEQ/BNE,前 16 个 $s 为其他人屏蔽)但我想仔细检查。
哦,最后...我是否应该期望 SPIM 在 Intel x86 Windows 系统和 Intel x86 Linux 系统上与 运行 有偏差?我遇到了一个愚蠢的故障,我似乎无法将它与我手工计算的地址隔离开来,但它只会在我 运行 我的教授给我们的测试脚本 Linux (.sh ); 运行在任何一个 OS 上直接在 spim 中宁似乎都有效...只要我对如何进行手算(如上所列)的理解是正确的。
16位立即数符号扩展为32位,然后移位。我不知道这是否会影响你的程序;但是,这是我注意到的唯一潜力 "mistake"。
这是我的各种评论的序言。
这是一个正确计算地址的示例程序。它不执行分支指令类型解码,因此您必须将此版本的部分内容与您的版本组合在一起。
请注意,它使用 mars
系统调用 34 以十六进制打印值。这在 spim
下不可用,因此您可能需要使用系统调用 1 以十进制输出或编写您自己的十六进制值输出函数 [如果您还没有]
.data
msg_best: .asciiz "correct target address: "
msg_tgt: .asciiz "current target address: "
msg_nl: .asciiz "\n"
.text
.globl main
main:
la $s0,inst # pointer to branch instruction
la $s1,einst # get end of instructions
subu $s1,$s1,$s0 # get number of bytes
srl $s1,$s1,2 # get number of instruction words
la $s2,loop # the correct target address
la $a0,msg_best
move $a1,$s2
jal printaddr
loop:
move $a0,$s0
jal showme # decode and print instruction
addiu $s0,$s0,4
sub $s1,$s1,1
bnez $s1,loop # more to do? yes, loop
li $v0,10
syscall
# branch instructions to decode
inst:
bne $s0,$s1,loop
beq $s0,$s1,loop
beqz $s1,loop
bnez $s1,loop
bgtz $s1,loop
bgez $s1,loop
bltz $s1,loop
blez $s1,loop
einst:
# showme -- decode and print data about instruction
#
# NOTE: this does _not_ decode the instruction type
#
# arguments:
# a0 -- instruction address
#
# registers:
# t5 -- raw instruction word
# t4 -- branch offset
# t3 -- absolute address of branch target
showme:
subu $sp,$sp,4
sw $ra,0($sp)
lw $t5,0($a0) # get inst word
addiu $t3,$a0,4 # get PC + 4
sll $t4,$t5,16 # shift offset left
sra $t4,$t4,16 # shift offset right (sign extend)
sll $t4,$t4,2 # get byte offset
addu $t3,$t3,$t4 # add in offset
# NOTE: as a diagnostic, we could compare t3 against s2 -- it should
# always match
la $a0,msg_tgt
move $a1,$t3
jal printaddr
lw $ra,0($sp)
addu $sp,$sp,4
jr $ra
# printaddr -- print address
#
# arguments:
# a0 -- message
# a1 -- address value
printaddr:
li $v0,4
syscall
# NOTE: only mars supports this syscall
# to use spim, use a syscall number of 1, which outputs in decimal and
# then hand convert
# or write your own hex output function
move $a0,$a1
li $v0,34 # output number in hex (mars _only_)
syscall
la $a0,msg_nl
li $v0,4
syscall
jr $ra
我只是想检查一下我对这两个概念的理解是否正确,因为我一直在努力完成一个项目,虽然一切都符合我的预期,但它总是勉强通过测试用例并引入一个随机值.. .
基本上,项目的objective就是写出一个分支指令到console,形式如下:
BranchName $S,[$t,如果适用] 0xAbsoluteAddressOfBranchTargetInstruction
编辑:澄清:我是用 MIPS 写的。这个想法是我通过我的讲师代码(我编写函数)在 $a0 中获得一个内存地址给程序。该地址用于包含 MIPS 指令的字。我要执行以下操作:
- 获取指令
- 隔离指令操作码并将其名称输出到寄存器(即:操作码5,输出BNE),如果不是分支指令则什么也不做。
- 根据需要隔离 $s、$t 和输出(即:bgez 没有 $t)
- 利用分支指令中的偏移量计算出其绝对地址(分支后目标指令的地址)并以十六进制输出。出于此计算的目的,假设分支指令的地址 ($a0) 为 $pc.
IE:
BEQ $6, $9, 0x00100008
首先,我对分支计算的理解是否正确?
- PC -> PC + 4
- 指令的低16位
- << 2 这些低位
- 添加PC+4和左移低16位(尽管只有低16位)。
其次,有人可以告诉我需要隔离哪些位才能知道我正在处理哪种分支吗?我想我有它们(前 6 个用于 BEQ/BNE,前 16 个 $s 为其他人屏蔽)但我想仔细检查。
哦,最后...我是否应该期望 SPIM 在 Intel x86 Windows 系统和 Intel x86 Linux 系统上与 运行 有偏差?我遇到了一个愚蠢的故障,我似乎无法将它与我手工计算的地址隔离开来,但它只会在我 运行 我的教授给我们的测试脚本 Linux (.sh ); 运行在任何一个 OS 上直接在 spim 中宁似乎都有效...只要我对如何进行手算(如上所列)的理解是正确的。
16位立即数符号扩展为32位,然后移位。我不知道这是否会影响你的程序;但是,这是我注意到的唯一潜力 "mistake"。
这是我的各种评论的序言。
这是一个正确计算地址的示例程序。它不执行分支指令类型解码,因此您必须将此版本的部分内容与您的版本组合在一起。
请注意,它使用 mars
系统调用 34 以十六进制打印值。这在 spim
下不可用,因此您可能需要使用系统调用 1 以十进制输出或编写您自己的十六进制值输出函数 [如果您还没有]
.data
msg_best: .asciiz "correct target address: "
msg_tgt: .asciiz "current target address: "
msg_nl: .asciiz "\n"
.text
.globl main
main:
la $s0,inst # pointer to branch instruction
la $s1,einst # get end of instructions
subu $s1,$s1,$s0 # get number of bytes
srl $s1,$s1,2 # get number of instruction words
la $s2,loop # the correct target address
la $a0,msg_best
move $a1,$s2
jal printaddr
loop:
move $a0,$s0
jal showme # decode and print instruction
addiu $s0,$s0,4
sub $s1,$s1,1
bnez $s1,loop # more to do? yes, loop
li $v0,10
syscall
# branch instructions to decode
inst:
bne $s0,$s1,loop
beq $s0,$s1,loop
beqz $s1,loop
bnez $s1,loop
bgtz $s1,loop
bgez $s1,loop
bltz $s1,loop
blez $s1,loop
einst:
# showme -- decode and print data about instruction
#
# NOTE: this does _not_ decode the instruction type
#
# arguments:
# a0 -- instruction address
#
# registers:
# t5 -- raw instruction word
# t4 -- branch offset
# t3 -- absolute address of branch target
showme:
subu $sp,$sp,4
sw $ra,0($sp)
lw $t5,0($a0) # get inst word
addiu $t3,$a0,4 # get PC + 4
sll $t4,$t5,16 # shift offset left
sra $t4,$t4,16 # shift offset right (sign extend)
sll $t4,$t4,2 # get byte offset
addu $t3,$t3,$t4 # add in offset
# NOTE: as a diagnostic, we could compare t3 against s2 -- it should
# always match
la $a0,msg_tgt
move $a1,$t3
jal printaddr
lw $ra,0($sp)
addu $sp,$sp,4
jr $ra
# printaddr -- print address
#
# arguments:
# a0 -- message
# a1 -- address value
printaddr:
li $v0,4
syscall
# NOTE: only mars supports this syscall
# to use spim, use a syscall number of 1, which outputs in decimal and
# then hand convert
# or write your own hex output function
move $a0,$a1
li $v0,34 # output number in hex (mars _only_)
syscall
la $a0,msg_nl
li $v0,4
syscall
jr $ra