是否可以使用 JumpTable 为非顺序选项创建一个带有 mips 的 switch/case?

Is it possible to have a switch/case with mips using a JumpTable for non sequential options?

我想在 MIPS 中练习使用 switch/cases 和 JumpTables。目前,我能够通过将几个 BEQ 命令依次堆叠来实现类似的逻辑。我更愿意将其切换为对案例使用单个 switch 语句。不幸的是,这些案例不是按顺序排列的。有一个用户菜单,他们可以在其中输入字符(ascii 值)并根据该字符执行操作。例如,他们可以选择 'A'、'D'、'N'、'X'。显然,这不符合顺序......我正在考虑存储一个带有选项的数组并将其视为一个 ENUM(据我所知,它在 MIPS 中不存在)这将解决非顺序问题并且可以更轻松地将大小写转换为正确的字符。

这是我目前的一些代码,可以帮助解决问题: 请注意,问题出在 switch/jump 而不是案例

中执行的实际 logic/action

C++ 示例:

//switch case sample based on char 
char ch;
cout << "Enter a character: ";
cin >> ch;
switch (ch)
{
case 'N':
    //action to perform
    cout << "N: " << endl;
    break;
case 'A':
    //action 
    cout << "A: " << endl;
    break;
default:
    cout << "You entered an invalid character" << endl;
    break;
}

和我当前的 mips 解决方案:

.data
 .asciiz 
 enterMenu: "Enter a menu option (N,A,M,D,X):\n"

.word 
JT: N,A,M,D,X #all the possible cases we want to deal with 
 .text 
la $a0, enterMenu #load meu prompt
li $v0, 4 #print prompt 
syscall 

li $v0, 12 #read char from user
syscall 

add $t0, $v0, [=12=] #move the character to a temporary register (holds switch value)

#switch (k) k = $s5
slti    $t3, $t0, 65    # Test if k < 65 (A's ascii value)
bne     $t3, $zero, Exit # if k < A, go to Exit

slti    $t3, $t0, 90    #Test if k > 90 (Z's ascii value)
beq $t3, $zero, Exit    # if k > Z, go to Exit


beq     $t0, 65, A  # if k = A, go to A
beq    $t0, 68 , D  # if k = D, go to D
beq    $t0, 77, M   # if k = M, go to M
beq    $t0, 78, N   # if k = N, go to n
beq    $t0, 88, X   # if k = X, go to X

编辑:菜单可能存储如下:

  Cases: .byte  'N','A','M','D','X' #added this in after

或这样:

JumpTable .word  POW, DIV, MULT, PLUS, MINUS, PRINT, EXIT #different cases 
Operations: .byte  '^', '/', '*', '+', '-', '@', 'x'

EndOps: #hold end spot

那么理论上我应该能够加载第一个字节并进行比较……然后继续下一个字节等等。 那么问题就变成了如何让它们(从用户输入)对应于 JumpTable 偏移量,然后对应于挑选案例。

beq 的系列与您将获得的少数相当分散的案例一样好(例如 A - X)。


指向代码的指针的数据 table 必须有 24 个条目,其中许多进入默认(不匹配)情况。

使用 table 的代码序列将:

  1. 规范化输入(例如减去 'A'),1 条指令(addiu
  2. 检查是否大于 table 大小,还有 2 条指令(sltiu / bnez 用于无符号比较)
  3. 数组索引(移位、加载地址、添加)MARS 上的 4 条指令(3 条带有 %hi(table) / %lo(table) 的汇编程序,让您将 table 地址的一部分留给lw 立即数),
  4. 加载数据指针,1条指令
  5. 跳转到寄存器中的数据指针,1 条指令

对于总共 9 条指令(或 8 条)和可能的数据高速缓存未命中,尽管乱序机器能够并行执行 2 range-check 条指令。 (或者 in-order 超标量,如果你安排得当的话。)


你的beq系列是10条指令(beq有一个常量是一个伪指令,它扩展为首先加载立即数,然后比较和分支),虽然不是all 将始终执行,并且可以订购它们以提高性能。 (最常见的在前。)

所以,如果有超过 20 个案例,我可能会切换到 table 版本,因为在 20 个案例中,平均会执行 10 条指令(假设平均分配,如果可以的话更好已知分布的顺序。)

如果“默认”情况最常见,range-check and/or 像 0x12345 & (1<<c) 这样的位图检查可以快速排除特殊情况之一,而无需经过它们全部.