MIPS 分支寻址算法和操作码与指令二进制文件的隔离?

MIPS Branch Addressing Algorithm and Opcode isolation from instruction binary?

我只是想检查一下我对这两个概念的理解是否正确,因为我一直在努力完成一个项目,虽然一切都符合我的预期,但它总是勉强通过测试用例并引入一个随机值.. .

基本上,项目的objective就是写出一个分支指令到console,形式如下:

BranchName $S,[$t,如果适用] 0xAbsoluteAddressOfBranchTargetInstruction

编辑:澄清:我是用 MIPS 写的。这个想法是我通过我的讲师代码(我编写函数)在 $a0 中获得一个内存地址给程序。该地址用于包含 MIPS 指令的字。我要执行以下操作:

  1. 获取指令
  2. 隔离指令操作码并将其名称输出到寄存器(即:操作码5,输出BNE),如果不是分支指令则什么也不做。
  3. 根据需要隔离 $s、$t 和输出(即:bgez 没有 $t)
  4. 利用分支指令中的偏移量计算出其绝对地址(分支后目标指令的地址)并以十六进制输出。出于此计算的目的,假设分支指令的地址 ($a0) 为 $pc.

IE:

BEQ $6, $9, 0x00100008

首先,我对分支计算的理解是否正确?

  1. PC -> PC + 4
  2. 指令的低16位
  3. << 2 这些低位
  4. 添加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