Casting in MIPS

2019-05-22 07:57发布

问题:

I've an interesting question!

I implemented a memorizing game in MIPS, The game starts by randomly printing a number between 10-99 on the screen, then ask the user to enter the exact number. If the user enters the number correctly, the game continues by displaying the first number and a second randomly generated number between 10-99. and the two numbers have to displayed one after another with a 3 second delay between them. The users is then is asked to enter the numbers in the correct order as they appeared on the screen. If the user enters the two numbers correctly the game continues with three numbers, then four and so on.

this is a quick summery for the game , but here is the thing.

I want to add an assistant option that if the user entered the letter 'H' , the program give him a hint.

I used this to get the input from the user that takes the numbers

li $v0,5

syscall

this 'read an integer' but once the user enter an 'H' it gives a run time error,

I though that the value of 'H' is : 72 in ASCII and I put it as the number that the user use as a hint , but unfortunately it happen that the program might generate a random number '72' and when the user enter it , it gives him a hint while he don't want the hint, he just want to continue the game

the Question:

what am looking for is a way or any trick to do such a casting in high level language. I couldn't find till now any way to solve this problem.

AND is there any way to clear the screen or the console in MIPS? because obviously it's memorizing game! so the numbers should disappear!

any suggestion or questions regarding this, are totally welcome!

回答1:

All characters may be represented as ascii when entered from keyboard to memory, but the read_int syscall will try to parse an integer from that ascii and it will fail for non-numeric characters.

The only alternative is to use strings. Create a buffer

buf: .byte 0,0,0      #10-99, last byte is for null

for the user input. After reading a string, check if the first character in the buffer is 'H'.

la $t1, buf
lb $t2, 0($t1)
li $t3, 72
beq $t2, $t3, help

If there's no 'H', proceed to parse an integer from the string.

i = buf.length-2;
j = 1;
k = 0;
while(i >= 0) {    //go in reverse
    if(buf[i] != NULL) {
        k += (buf[i] - 48) * j
        j *= 10;
    }
    i--;
}
if(k == target)print("success");

Don't forget to clear the buffer each time you prompt.



回答2:

Maybe you can use read character (code 12) instead of read integer (code 5)

If you do read character, you'll need to convert from ascii to integer. So that means some manipulation will be required. But it can be done easier than the other way around I think.


blackcompe made a good point about read character.

I guess you'll have to do read string (code 8) and then validate the user input by looping and checking for digits or an H in ascii. And then returning an error message or something if the input was invalid.


Also here's some pseudo code to convert from ascii string to number. This assumes a valid string of digits. Granted you only have two digit numbers, so this may be unnecessary, but should work.

number = 0
for(i = 0; i < str.length; i++)
    number = 10 * number + ascii(str[i]) - ascii('0');

I agree that blackcompe's answer is much better. But I just want to show that the conversion loop actually works. And I want iterate that this is only to convert an ascii string of digits to a number. It doesn't check for H and assumes that the number can be any length long. Additionally, you still need to make adjustments for it work in MIPS.

Here is an example that shows that my conversion loop actually works. Here is the example rewritten in python, so it can be tested. Granted it's kind of pointless to do in python.

def pointlesslyConvertStringToNumber(str):
    number = 0
    for c in str:
        //Note: ord is a function to convert a character to ascii
        number = 10 * number + ord(c) - ord('0')
    print number 

Let's use the number 543:

pointlesslyConvertStringToNumber("543")

Here is the step-by-step of the loop:

  1. 10 * 0 + 53 - 48 = number = 5
  2. 10 * 5 + 52 - 48 = number = 54
  3. 10 * 54 + 51 - 48 = number = 543

And here is the MIPS subroutine based off of the above. I know this works, but I'm a MIPS beginner, so please excuse any dumb mistakes. Again this assumes a valid string of digits. In other words another subroutine would validate the input first.

$a0 is the address of the string buffer that is null-terminated. The comments on the side are a slightly modified python function to better fit the MIPS code. But it is not exactly one to one.

getNumber:                                  # def getNumber(input):
    addi  $sp, $sp, -8                      #
    sw    $ra, 4($sp)                       #
    sw    $a0, 0($sp)                       #
    add   $t0, $a0, $zero                   #
    add   $t1, $zero, $zero                 # i = 0
    addi  $t4, $zero, 10                    #
gnLoop:                                     # while(input[i] != None):
    lb    $t2, 0($t0)                       #
    beq   $t2, $zero, gnEnd                 # 
    mult  $t1, $t4                          # number = 10 * number
    mflo  $t1                               # 
    addi  $t3, $t2, -48                     # 
    add   $t1, $t1, $t3                     # number += ord(input[i]) - ord('0')
    addi  $t0, $t0, 1                       # i +=1
    j     gnLoop                            #
gnEnd:                                      # 
    lw    $a0, 0($sp)                       #
    lw    $ra, 4($sp)                       #
    addi  $sp, $sp, 8                       # 
    add   $v0, $zero, $t1                   # return number  
    jr    $ra                               #