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
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.
User contributions licensed under CC BY-SA 3.0