assembly 如何更新时间时,使一个简单的时钟上组装

wyyhbhjk  于 2023-10-19  发布在  其他
关注(0)|答案(1)|浏览(91)

通过编写delay和time2string子程序完成时钟程序。time2string的说明:寄存器$a0包含内存中某个区域的地址,对于time2string的输出来说,该地址的大小是合适的。寄存器$a1的16个最低有效位包含时间信息,其被组织为四个每个4位的NBCD编码数字。寄存器$a1中的所有其他位可以具有任何值,必须忽略。
这就是我到目前为止所做的,代码的其他部分没有问题,因为它们是给定的。我只写了hexasc,time2string,delay。

.macro  PUSH (%reg)   #  reg defines a parameter
    addi    $sp,$sp,-4    # reserve space for that data
    sw  %reg,0($sp)   # Stores  the register specified by %reg at the memory location pointed to by $sp. 
.end_macro

.macro  POP (%reg)
    lw  %reg,0($sp) #loads from memory to register %reg
    addi    $sp,$sp,4
.end_macro

    .data
    .align 2
mytime: .word 0x5957
timstr: .ascii "text more text lots of text\0"
    .text
main:
    # print timstr
    la  $a0,timstr
    li  $v0,4
    syscall
    nop
    # wait a little
    li  $a0,2
    jal delay
    nop
    # call tick
    la  $a0,mytime
    jal tick
    nop
    # call your function time2string
    la  $a0,timstr
    la  $t0,mytime
    lw  $a1,0($t0)
    jal time2string    #it calls on the funciton and return memory is saved
    nop
    # print a newline
    li  $a0,10
    li  $v0,11
    syscall
    nop
    # go back and do it all again
    j   main
    nop
# tick: update time pointed to by $a0
tick:   lw  $t0,0($a0)  # get time    loads data from the data memory and it access the from memory location from $a0
    addiu   $t0,$t0,1   # increase     unsigned addition
    andi    $t1,$t0,0xf # check lowest digit
    sltiu   $t2,$t1,0xa # if digit < a, okay      performs unsigned comparisson then t2 will either be 1 or 0
    bnez    $t2,tiend      # if not equal to 0, then jump to tiend
    nop
    addiu   $t0,$t0,0x6 # adjust lowest digit
    andi    $t1,$t0,0xf0    # check next digit
    sltiu   $t2,$t1,0x60    # if digit < 6, okay
    bnez    $t2,tiend
    nop
    addiu   $t0,$t0,0xa0    # adjust digit
    andi    $t1,$t0,0xf00   # check minute digit
    sltiu   $t2,$t1,0xa00   # if digit < a, okay
    bnez    $t2,tiend
    nop
    addiu   $t0,$t0,0x600   # adjust digit
    andi    $t1,$t0,0xf000  # check last digit
    sltiu   $t2,$t1,0x6000  # if digit < 6, okay
    bnez    $t2,tiend
    nop
    addiu   $t0,$t0,0xa000  # adjust last digit
tiend:  sw  $t0,0($a0)  # save updated result       sw= stores 4-byte word  0($a0): This part specifies the memory address where the contents of $t0 will be stored.
    jr  $ra     # return
    nop

  # you can write your code for subroutine "hexasc" below this line
  #
  
  
hexasc:

       andi  $v0, $a0, 15     #15 is 1111, so 

       slti  $t0, $v0, 10     #if t0 is less than 10, it sets it 1 otherwise 0

       beq   $t0, 1, low      #if t0 is equal to 1 then call the subroutine low

       beq   $t0, 0, high     #if t0 is 0 then call the subroutine high

low:
       addi $v0, $v0, 0x30    # 0x30 is 48 in base 16, add the input v0
       jr $ra                 #we jump back to main

high:
       addi $v0, $v0, 0x37    #0x37 = 55 in base 10, then we add the input v0
       jr $ra                #jump back to main
       
       
delay:
       jr $ra
       nop
       
    

       

time2string: 
            PUSH ($s0)
            PUSH ($s1)
            PUSH ($ra)

            add $s0, $a0, 0
            add $s1, $a1, 0
            
            addi $t1, $s1, 0xf000
            srl  $a1, $s1, 12 
            jal hexasc
            sb $v0, 0($s0)
            
            addi $t1, $s1, 0x0f00
            srl  $a1, $s1, 8 
            jal hexasc
            sb $v0, 1($s0)
            
            li $t0, 0x3A
            sb $t0, 2($s0)

            addi $t1, $s1, 0x00f0
            srl  $a1, $s1, 4
            jal hexasc
            sb $v0, 3($s0)
            
            addi $t1, $s1, 0xf000
            srl  $a1, $s1, 12 
            jal hexasc
            sb $v0, 4($s0)                          

###############################################################

        
###############################################################

            li  $t1, 0x00           
            sb  $t1, 5($s0)
########################################################
            POP ($ra)
        POP ($s1)
        POP ($s0)   
        jr   $ra
1aaf6o9v

1aaf6o9v1#

  • 您的讲师的代码在任何调用、jal ...或返回jr $ra之后都始终使用nop,因此您也应该这样做,因为延迟分支似乎可能会针对您的模拟器情况设置为启用/打开。因此,在执行跳转或分支的任何地方插入nop s-请注意,这包括beqbne。(如果正在使用延迟分支,并且您忘记在某个地方使用nop,那么可能会非常混乱,无法确定发生了什么或出了什么问题。
  • 您正在使用addi提取您想要使用andi的数字,所以只是操作码中的一个错字(但您应该能够观察到这些并没有按照您的意图工作,并建议您不是单步调试)。
  • 虽然这可能会工作,但控制流过多且效率低下,尽管这只是一个小问题:
beq   $t0, 1, low      #if t0 is equal to 1 then call the subroutine low
 beq   $t0, 0, high     #if t0 is 0 then call the subroutine high

您只需要一个条件分支来测试一个条件,而不需要使用另一个分支来测试完全相反的条件。你能想出一个能在那里工作的分支吗?不要忘记在分支后使用nop
此外,应该尽可能测试0而不是1,并且,0作为$0-beq $t0, 1, low会更好地作为bne $t0, $0, low(与我们在这里知道的值相同,t0必须是0或1),就像你的beq $t0, 0, high作为beq $t0, $0, high一样。
有了这些变化,你应该更接近正确的时钟。然而,还有其他的bug,你应该学会单步调试来观察每一行代码的执行,看看它的结果是否如预期的那样。调试汇编与调试其他代码基本相同:单步运行每一行,观察这一行对程序状态的影响,并与您认为这一行应该做的或应该做的进行比较。

相关问题