MIPS assembly writing a function from a very specific description

0

I have this specific description of how to write a function called tim2string , I have written this function but I'm unsure if I'm doing as it's Say's in the description. I have tried to run my code on MARS and I get this ERROR.NOTE the tim2string is added in the end of code.

timetemplate.asm line 99: Runtime exception at 0x00400118: address out of range 0x00005958

The description of function is the following

Name: The subroutine must be called time2string. Parameters (two): Register $a0 contains the address of an area in memory, suitably large for the output from time2string . The 16 least significant bits of register $a1 contains time-info, organized as four NBCD-coded digits of 4 bits each. All other bits in register $a1 can have any value and must be ignored.

Example: register $a0 can contain the address 0x100100017 , and register $a1 can contain the value 0x00001653. Return value: None. Required action:

The following sequence of six characters must be written to the area in memory pointed to by register $a0 .

1) Two ASCII-coded digits showing the number of minutes, according to the two more significant NBCD-coded digits of the input parameter. Example: '1', '6' (ASCII 0x31, 0x36):

2) A colon character (ASCII : , code 0x3A).

3) Two ASCII-coded digits showing the number of seconds, according to the two less significant NBCD-coded digits of the input parameter. Example: '5', '3' (ASCII 0x35, 0x33). 4. A null byte (ASCII NUL, code 0x00). Notes:You must use the function hexasc to convert each NBCD-coded digit into the corresponding ASCII code. Use the sb instruction to store each byte at the destination. The macros PUSH and POP are useful for saving and restoring registers.

  # timetemplate.asm
  # Written 2015 by F Lundevall
  # Copyright abandonded - this file is in the public domain.
.macro  PUSH (%reg)
    addi    $sp,$sp,-4
    sw  %reg,0($sp)
.end_macro

.macro  POP (%reg)
    lw  %reg,0($sp)
    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) #load the adress contained in $t0 into $a1
    jal time2string
    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
    addiu   $t0,$t0,1      # increase
    andi    $t1,$t0,0xf # check lowest digit
    sltiu   $t2,$t1,0xa # if digit < a, okay
    bnez    $t2,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
    jr  $ra                 # return
    nop

  # you can write your code for subroutine "hexasc" and  below this line
  #
hexasc:  
    andi    $a0,$a0,0xf       #only 4 least significant bits ignore other bits  
    addi    $v0,$zero,0x30    #$v0 = 0x30 ('0')
    addi    $t0,$zero,0x9     #t0 = 0x9

    ble     $a0,$t0,L1        #branch if a0 <= 0x9
    nop
    addi    $v0,$v0,0x7       #v0 = v0 +0x7

   L1:
    add     $v0,$a0,$v0       #v0 = V0 +a0
    jr      $ra
    nop
 delay:
    jr      $ra
    nop

 time2string:
    PUSH    ($t2)           
    PUSH    ($t0)
    PUSH    ($a1)

    lb      $t0, 0($a1)      #load one byte from a1     "LINE 99" ERROR
    andi    $t2, $t0,0xf     #check the 4 lowest bits ignore other
    jal     hexasc           # call hexasc
    nop
    sb      $t0, 0($a1)      #stor back that byte in a1


    lb      $t0, 1($a1)      # load the next byte
    andi    $t2, $t0,0xf0
    jal     hexasc
    nop
    sb      $t0, 1($a1)


    lb  $t0, 2($a1)
    andi    $t2, $t0,0xf00
    jal hexasc
    nop
    sb  $t0, 2($a1)


    lb  $t0, 3($a1)
    andi    $t2, $t0,0xf000
    jal hexasc
    nop
    sb  $t0, 3($a1)


    POP ($a1)
    POP ($t0)
    POP ($t2)


    jr  $ra
    nop 

Update 1.0

I had some progress to written time2string function i have come so far and still i need some help. I single step through my code it's working fine until this linesb $v0, 0($t0) #stor that 4 bits in that location that a0 points to

I get this error timetemplate.asm line 115: Runtime exception at 0x00400158: address out of range 0x00000009

Here is the updated code

time2string:
PUSH    ($t0)           
PUSH    ($t1)
PUSH    ($t2)
PUSH    ($t3)
PUSH    ($t4)
PUSH    ($t5)
PUSH    ($ra)           #nested subroutine must store $ra too

add     $t0,$0,$a0      #contaisn the adress of string (timstr)
add     $t1,$0,$a1      #contains the time-info(0x5957)

andi    $t2,$t1,0xf000      #check the 4 most signifaicant bits ignore other bits
srl     $a0,$t2,12      #shift the MSB to LSB position (hexasc take only 4 bits in the LSB position)
jal     hexasc      # call hexasc
nop     
sb      $v0, 0($t0)     #stor that 4 bits in that location that a0 points to

andi    $t3,$t1,0x0f00  #mask to get those 4 bits you and ignore other bits
srl     $a0,$t3,8       #shift those bits to the LSB position(0x000f)
jal     hexasc      
nop
sb      $v0,1($t0)      

li      t5,0x3A
sb      $t5,2($t0)


andi    $t4,$t1,0x00f0
srl     $a0,$t4,4
jal     hexasc
nop
sb      $v0,3($t0)


move    $a0,$t1
jal     hexasc
nop
sb      $v0, 4($t0)


POP ($ra)
POP ($t5)
POP ($t4)
POP ($t3)
POP ($t2)
POP ($t1)   
POP ($t0)

jr  $ra
nop 
function
assembly
mips
asked on Stack Overflow Feb 23, 2017 by (unknown user) • edited Feb 27, 2017 by (unknown user)

1 Answer

1
    lb      $t0, 0($a1)      #load one byte from a1

This will load one byte from memory from address a1.

But a1 does not contain valid address, it contains BCD time value, like 0x5958, which is meant as time 59:58.

So you don't need to load the time value from memory, you already have the values in the a1 loaded. You have to pick out each group of 4 bits separately (from low 16 bits), that's where the 4 digits are encoded.


Oh, and this:

I have tried to run my code on MARS

That's not, how people are programming in Assembly. You don't RUN your code. You step over single instruction in debugger, one by one, verifying after each single instruction, that it did change only the registers/memory which it was supposed to change, and only in the way how it was supposed to change it.

(that's why you need first English comments describing the algorithm, because otherwise you can't reason if the instruction did what you did want ... of course it will always do, what it does, according to the CPU docs, you will hardly ever in your life encounter the situation when the instruction itself fails to execute properly (although it's technically possible, when some electrons "jump" over the "walls" of supposed path, usually after being hit hard by some proton from X-rays/etc ... maybe if you will live long enough, it may happens once or twice near you ... it's very likely you will never notice, as the SW will probably survive it, or crash like it does normally from code bugs))

Also make sure you avoid the brain playing tricks on you, taking shortcuts to save it's effort, so instead of your brain reading what is on the screen, it will try to tell you, what you did want to write and see there.

Like when you write in the code sb $t0,0($a1) instead of sb $t0,0($a0), if you will try to re-read the source shortly after writing it, you will read sb $t0,0($a0), unless you focus really hard and make sure your brain is not cheating you.

Same goes for debugging and checking resulting values in registers, etc.. if you for example expect value 1 in t1, and it by accident ends in t2, you may easily miss the the fact that the 1 did change in t2, not in t1, because your brain cares mostly that the result is 1. Etc..

It's tricky. That's why people love Assembly, and code almost everything in it.

answered on Stack Overflow Feb 23, 2017 by Ped7g • edited Feb 23, 2017 by Ped7g

User contributions licensed under CC BY-SA 3.0