是否可以使用 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 的代码序列将:
- 规范化输入(例如减去 'A'),1 条指令(
addiu
)
- 检查是否大于 table 大小,还有 2 条指令(
sltiu
/ bnez
用于无符号比较)
- 数组索引(移位、加载地址、添加)MARS 上的 4 条指令(3 条带有
%hi(table)
/ %lo(table)
的汇编程序,让您将 table 地址的一部分留给lw
立即数),
- 加载数据指针,1条指令
- 跳转到寄存器中的数据指针,1 条指令
对于总共 9 条指令(或 8 条)和可能的数据高速缓存未命中,尽管乱序机器能够并行执行 2 range-check 条指令。 (或者 in-order 超标量,如果你安排得当的话。)
你的beq
系列是10条指令(beq
有一个常量是一个伪指令,它扩展为首先加载立即数,然后比较和分支),虽然不是all 将始终执行,并且可以订购它们以提高性能。 (最常见的在前。)
所以,如果有超过 20 个案例,我可能会切换到 table 版本,因为在 20 个案例中,平均会执行 10 条指令(假设平均分配,如果可以的话更好已知分布的顺序。)
如果“默认”情况最常见,range-check and/or 像 0x12345 & (1<<c)
这样的位图检查可以快速排除特殊情况之一,而无需经过它们全部.
我想在 MIPS 中练习使用 switch/cases 和 JumpTables。目前,我能够通过将几个 BEQ 命令依次堆叠来实现类似的逻辑。我更愿意将其切换为对案例使用单个 switch 语句。不幸的是,这些案例不是按顺序排列的。有一个用户菜单,他们可以在其中输入字符(ascii 值)并根据该字符执行操作。例如,他们可以选择 'A'、'D'、'N'、'X'。显然,这不符合顺序......我正在考虑存储一个带有选项的数组并将其视为一个 ENUM(据我所知,它在 MIPS 中不存在)这将解决非顺序问题并且可以更轻松地将大小写转换为正确的字符。
这是我目前的一些代码,可以帮助解决问题: 请注意,问题出在 switch/jump 而不是案例
中执行的实际 logic/actionC++ 示例:
//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 的代码序列将:
- 规范化输入(例如减去 'A'),1 条指令(
addiu
) - 检查是否大于 table 大小,还有 2 条指令(
sltiu
/bnez
用于无符号比较) - 数组索引(移位、加载地址、添加)MARS 上的 4 条指令(3 条带有
%hi(table)
/%lo(table)
的汇编程序,让您将 table 地址的一部分留给lw
立即数), - 加载数据指针,1条指令
- 跳转到寄存器中的数据指针,1 条指令
对于总共 9 条指令(或 8 条)和可能的数据高速缓存未命中,尽管乱序机器能够并行执行 2 range-check 条指令。 (或者 in-order 超标量,如果你安排得当的话。)
你的beq
系列是10条指令(beq
有一个常量是一个伪指令,它扩展为首先加载立即数,然后比较和分支),虽然不是all 将始终执行,并且可以订购它们以提高性能。 (最常见的在前。)
所以,如果有超过 20 个案例,我可能会切换到 table 版本,因为在 20 个案例中,平均会执行 10 条指令(假设平均分配,如果可以的话更好已知分布的顺序。)
如果“默认”情况最常见,range-check and/or 像 0x12345 & (1<<c)
这样的位图检查可以快速排除特殊情况之一,而无需经过它们全部.