Как я могу реализовать, если (условие1 && условие2) в MIPS? - PullRequest
1 голос
/ 29 марта 2019

Я написал следующую функцию, чтобы проверить, является ли символ цифрой:

# IsDigit - tests a if a character a digit or not 
# arguments:
#   $a0 = character byte
# return value:
#   $v0 =   1 - digit
#           0 - not a digit
IsDigit:
    lb $t0, ($a0) # obtain the character
    li $t1, 48 # '0' - character
    li $t2, 57 # '9' - character
    bge $t0, $t1, condition1
condition1:
    ble $t0, $t2, condition2

    li $v0, 0
    j return

condition2:
    li $v0, 1

return:                                                                                 
    # return 
    jr $ra 

Есть ли лучший способ сделать или написать это?

Редактировать: Ниже указана версия-2

IsDigit:
    lb $t0, ($a0) # obtain the character
    li $t1, 48 # '0' - character
    li $t2, 57 # '9' - character
    bge $t0, $t1, condition1

    j zero

condition1: 

    ble $t0, $t2, condition2

zero:
    li $v0, 0
    j return

condition2:
    li $v0, 1
    j return

return:                                                                                 
    # return 
    jr $ra 

Edit-2 : ниже указана версия-3

IsDigit:
    lb $t0, ($a0) # obtain the character
    li $t1, 48 # '0' - character
    li $t2, 57 # '9' - character


    bge $t0, $t1, con1_fulfilled #bigger tha or equal to 0  
    j con1_not_fulfilled

con1_fulfilled:
    ble $t0, $t2, con2_fullfilled #less than or equal to 9
    j con2_not_fulfilled

con2_fullfilled:
    li $v0, 1
    j return

con1_not_fulfilled:
con2_not_fulfilled:
    li $v0, 0

return:                                                                     
    # return 
    jr $ra 

1 Ответ

1 голос
/ 29 марта 2019

В общем случае вы используете 2 ветви, которые идут до тела if().Если один из них взят, тело if не работает.В сборке вы обычно хотите использовать отрицание условия C, потому что вы перепрыгиваете через тело цикла, чтобы оно не запускалось.Ваша более поздняя версия делает это в обратном направлении, поэтому также необходимы безусловные инструкции j, что делает ваш код более сложным.

Противоположностью <= (le) является > (GT).Для C, написанного для использования включающих диапазонов (le и ge), asm, использующий одинаковые числовые значения, должен переходить в противоположные условия, используя исключительные диапазоны (исключая случай eq ual).Или вы можете настроить свои константы и bge $t0, '9'+1 или что-то еще, что может быть полезно в конце того, что вписывается в 16-битный немедленный.

# this does assemble with MARS or clang, handling pseudo-instructions
# and I think it's correct.
IsDigit:
    lb  $t0, ($a0)    # obtain the character

    blt   $t0, '0', too_low    # if(   $t0 >= '0'  
    bgt   $t0, '9', too_high   #    && $t0 <= '9')
      # fall through into the if body
    li    $v0, 1
    jr    $ra                    # return 1

too_low:
too_high:                    # } else {
    li    $v0, 0

#end_of_else:
    jr    $ra                # return 0

Если это не было в концефункции, вы можете j end_of_else с конца тела if, чтобы перепрыгнуть через блок else.Или в этом случае мы могли бы поставить li $v0, 0 перед первым blt, чтобы заполнить слот задержки загрузки вместо остановки конвейера.(Конечно, настоящий MIPS также имеет слоты задержки ветвления, и у вас не может быть параллельных ветвей. Но bgt - это в любом случае псевдоинструкция, так что на самом деле нет обратной связи.назад разветвляется.)

Кроме того, вместо того, чтобы перейти к общему jr $ra, я просто продублировал jr $ra в другом пути возврата.Если вам нужно больше очистить, вы можете перейти к одному общему пути возврата.В противном случае дублирование хвоста - хорошая вещь для упрощения ветвления.


В этом конкретном случае ваши условия связаны: вы делаете проверку диапазона, поэтому вам нужно только 1 subи затем 1 без знака - сравнение с длиной диапазона. См. В чем идея ^ = 32, которая преобразует строчные буквы в верхние и наоборот? для получения дополнительной информации о проверках диапазона в ASCIIсимволов.

и , так как вы возвращаете логическое 0/1, вы вообще не хотите переходить , а вместо этого используйте sltu, чтобы превратить условие в 0 или1 в регистрах.(Это то, что MIPS использует вместо регистра FLAGS, такого как x86 или ARM).Инструкции типа ble между двумя регистрами в любом случае являются псевдоинструкциями для slt + bne;MIPS имеет blez и bltz в аппаратном обеспечении, а также bne и beq между двумя регистрами.


И кстати, комментарии к вашему IsDigit не совпадаюткод: они говорят, что $a0 - это символ, но на самом деле вы используете $a0 в качестве указателя для загрузки символа.Так что вы передаете char по ссылке без видимой причины , или передаете строку и берете первый символ.

# IsDigit - tests a if a character a digit or not 
# arguments:
#   $a0 = character byte (must be zero-extended, or sign-extended which is the same thing for low ASCII bytes like '0'..'9')
# return value:
#   $v0 = boolean: 1 -> it is an ASCII decimal digit in [0-9]

IsDigit:
    addiu   $v0, $a0, -'0'            # wraps to a large unsigned value if below '0'
    sltiu   $v0, $v0, 10              # $v0 = bool($v0 < 10U)  (unsigned compare)
    jr      $ra

Ассемблер MARS отказывается собирать -'0' какнемедленно, вы должны написать это как -48 или -0x30.Ассемблер clang не имеет проблем с addiu $v0, $a0, -'0'.

Если вы напишите subiu $v0, $a0, '0', MARS создаст '0', используя braindead lui + ori, потому что это очень упрощенно для расширенных псевдоинструкций, которые большинство ассемблеров не делаютслужба поддержки.(MIPS не имеет инструкции subi, только addi / addiu, обе из которых требуют немедленного расширения знака).

...