是否可以使用可用于非顺序选项的Jumpterable使用MIPS进行开关/情况?

发布于 2025-01-27 15:25:01 字数 1904 浏览 3 评论 0原文

我想在MIPS中使用开关/盒子和夹具练习。目前,我能够通过彼此堆叠几个BEQ命令来实现类似的逻辑。我更喜欢将其切换到使用Case的单个开关语句。不幸的是,案例不是按顺序排列的。有一个用户菜单在其中输入字符(ASCII值),并基于该字符,发生了一个操作。例如,他们可以选择“ a”,'d','n','x'。显然,这不是在井井有条...我正在考虑将选项存储一个数组,并将其视为枚举(据我所知,在MIP中不存在),这将解决非序列问题并更容易将案例转换为适当的字符。

到目前为止,这是我的代码,以帮助清理问题: 请注意,问题是在开关/跳转中而不是在情况下执行的实际逻辑/操作

示例:

//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, $0 #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

这样我应该是理论上我应该是能够加载第一个字节并比较它...然后移至下一个字节等。 然后,问题将成为如何使它们对应的(从用户输入)到可夹具的偏移,然后再进行选择案例。

I want to practice using switch/cases and JumpTables in MIPS. Currently, I am able to achieve a similar logic via stacking several BEQ commands after each other. I'd prefer to switch it over to using a single switch statement with cases. Unfortunately, the cases are not in sequential order. There is a user-menu where they enter a character (ascii value) and based on that character, an action occurs. For example, they can choose 'A', 'D', 'N', 'X'. Obviously, that is not in order... I am considering to store an array with the options and treat it as an ENUM (which doesn't exist in MIPS as far as I'm aware) which would solve the non-sequential issue and have an easier time converting the case to the proper character.

This is a bit of my code as of now to help clear things up:
Note that the issue is with the switch/jump rather than the actual logic/action performed in the cases

C++ Example:

//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;
}

and my current mips solution:

.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, $0 #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

Edit: The menu an probably be stored as follows:

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

or as such:

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

EndOps: #hold end spot

Then theoretically I should be able to load in the first byte and compare it ... then move on to the next one etc.
The question would then become on how to have them correspond (from the user input) to the JumpTable offset and then to picking cases.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

莫多说 2025-02-03 15:25:01

beq s系列与相当分散的少数情况一样好(例如a - x )。


代码指针的数据表必须有24个条目,许多条目将访问默认情况(无匹配)。

使用表的代码顺序将:

  1. 将输入(例如减去A')归一化,1个指令(addiu
  2. 检查是否大于表大小,2个指令(sltiu) / bnez 用于未签名的比较)
  3. 数组索引(移位,加载地址,添加)MARS上的4个指令(3带有> %hi(table)hi(table)/ %%的汇编器lo(表)让您留下lw即时的表地址的一部分,
  4. 加载数据指针,1个指令
  5. 分支到寄存器中的数据指针,1个指令

总计9指令(或8)和可能的数据缓存遗漏,尽管订购机可以并行化2个范围检查指令的执行。 (或者如果适当安排它们,则是按级超量表。)


beq的系列是10个指令(beq带常数的 是伪指令扩展到立即加载,然后比较分支),尽管并非所有人都会执行,并且可以订购绩效。 (最常见。)

因此,如果有20个以上的情况,我可能会切换到表版本,因为在20个情况下,平均有10个说明将执行(假设分布相等,更好,如果您可以订购已知的说明分发。)

如果“默认”情况最常见,则范围检查和/或比特图检查,例如0x12345&amp; (1&lt;&lt; c)可以简单地排除是特殊情况之一,而无需全部浏览。

The series of beqs is as good as you're going to get for a small number of cases that are fairly spread out (e.g. A - X).


A data table of pointers to code would have to have 24 entries, many going to the default (no match) case.

Code sequence to use the table would:

  1. Normalize the input (e.g. subtract 'A'), 1 instruction (addiu)
  2. Check if greater than table size, 2 more instructions (sltiu / bnez for unsigned compare)
  3. Array index (shift, load address, add) 4 instructions on MARS (3 with an assembler with %hi(table) / %lo(table) to let you leave part of the table address for the lw immediate),
  4. Load the data pointer, 1 instruction
  5. Branch to data pointer in register, 1 instruction

For a total of 9 instructions (or 8) and a possible data cache miss, though an out of order machine would be able to parallelize execution of the 2 range-check instructions. (Or an in-order superscalar if you schedule them appropriately.)


The series of beq's for your set is 10 instructions (beq with a constant is a pseudo instruction that expands to first load the immediate, then compare & branch), though not all will always execute, and they can be ordered for performance. (Most common first.)

So, I would probably switch to the table version if there were more than 20 or so cases, since at 20 cases, on average, 10 instructions would execute (assuming equal distribution, better if you can order for known distribution.)

If the "default" case is most common, a range-check and/or a bitmap check like 0x12345 & (1<<c) could rule out being one of the special cases quickly, without going through them all.

孤单情人 2025-02-03 15:25:01

谢谢Erik的回答,我能够自己弄清楚这一点:

我只在这里放置最相关的信息,您需要将两个阵列加载到寄存器中,然后继续进行此操作。请注意,ASCIIZ自动以 /0结束(null终结器),以了解字符串已完成(因此,用户输入的情况不在表中)...然后发送错误消息。

这些将在.data中

Cases: .asciiz  "ADMNX"
JT: .word  L1,L2,L3,L4,L5

,这将在.text中

la $t2, Cases #get ascii values 

        search:
            lbu $t5, 0($t2) #load in current byte
            beq $t5, $zero, invalid #hit the end of the ascii string, value not found
            beq $t5, $t1, found #found the value 
            addi $t2, $t2, 1 #increment to next byte 
            j search #continue loop
            
        found:
            la $t6, Operations #get ascii values again
            sub $t2, $t2, $t6 
            sll $t2, $t2, 2 #multiply by 4 
            la $t4, JT #load the operation JT labels
            add $t4, $t4, $t2 
            lw $t4, 0($t4) 
            jr $t4 #jump to operation 


#put cases here, then call the respective fns
        L1:
            jal Add #run to function
            j Break #then add the result and print 
            
        L2: 
            jal Sub
            j Break 
    

        Break: #break - as in switch cases
            j Exit  #finished case

Thank you Erik for your answer, I was able to figure it out a bit differently on my own:

I am only putting here the most relevant bits of information, you will need to load both arrays into a register and then proceed before doing this. Note that asciiz automatically ends with /0 (null terminator) to know that the string is finished being read (and therefore the user entered case is not in the table)... then send an error message.

These will be in .data

Cases: .asciiz  "ADMNX"
JT: .word  L1,L2,L3,L4,L5

and this will be in .text

la $t2, Cases #get ascii values 

        search:
            lbu $t5, 0($t2) #load in current byte
            beq $t5, $zero, invalid #hit the end of the ascii string, value not found
            beq $t5, $t1, found #found the value 
            addi $t2, $t2, 1 #increment to next byte 
            j search #continue loop
            
        found:
            la $t6, Operations #get ascii values again
            sub $t2, $t2, $t6 
            sll $t2, $t2, 2 #multiply by 4 
            la $t4, JT #load the operation JT labels
            add $t4, $t4, $t2 
            lw $t4, 0($t4) 
            jr $t4 #jump to operation 


#put cases here, then call the respective fns
        L1:
            jal Add #run to function
            j Break #then add the result and print 
            
        L2: 
            jal Sub
            j Break 
    

        Break: #break - as in switch cases
            j Exit  #finished case
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文