MIPS: String Copy, Pass-by-reference - pass-by-reference

I am looking to implement string copy and I am not doing it correctly. I am given a string 'x' and I want to
1] copy the entire string 'x' into 'y'
2] copy the first 5 characters of 'x' into 'y'
and I want to pass arguments by reference.
.data
x: .asciiz "Hi, How do you do?"
y: .word 0:5
.text
.globl main
_copy:
lw $t0, ($a0)
la $a0, y
sw $t0, ($a0)
li $v0, 4
syscall
jr $ra
main:
la $a0, x
jal _copy
jr $ra
nop

Related

Is there a way in MIPS to read input from a user that can be either an integer or a character?

I am writing a program in MIPS to convert a temperature in Celsius input by the user to Fahrenheit. The program loops to allow the user to do as many conversions as they want. To exit the program they are supposed to enter q. Is there a way to take input that can be either an integer or a character? One possible solution I thought of is reading a string and converting it to an int, but I am a bit unsure how to go about doing that. Is there a simple way of doing that conversion?
.globl main
.data
prompt: .asciiz "Please input a Celsius temperature: "
num: .word 32
li $t4, 0
.text
main:
li $v0, 4
la $a0, prompt # prints Prompt
syscall
li $v0, 5 # user input
syscall
move $a0, $v0 # moves input value in $a0
lw $s0, num # Loads 32 in $s0
li $t0, 0 # Sets up 9/5
li $t1, 0
mtc1 $t0, $f2 # Converts into float point numbers
mtc1 $t1, $f30
move $a1, $t3
move $a2, $s0
jal Temp # jumps to function Temp
move $s4, $v0
li $v0, 1
move $a0, $s4
syscall
li $v0, 10
syscall
Temp:
mul $t0, $a0, 9 # 9 * userInput Should equal 180
div $t4, $t0, 5 # value of register in t0 divided by 5
add $t1, $t4, $a2 # Answer above + 32
move $v0, $t1 # places in return register
jr $ra # Jumps to line after function call
I have provided an example program that only takes the temperature input in Celsius from the user and converts it into Fahrenheit. Your idea can be implemented using while loop.
for example:
la $t0,str #str can be the string char "q"
loop: lb $a0,0($t0)
beq $a0,$0,exit
# your main code
addi $t0,$t0,1
j loop
exit:
however it isnt easy but doable task.

How do I write MIPS code for vector multiplication

Define vector mul(vector v, float t). It returns a vector by multiplying it by t.
If a=4i+3j+12k then mul(a,0.5) will return 2i+1.5j+6k.
Here's the code I've written:
.globl main
.text
main:
la $s0,t #loading t into s1
lw $s1,0($s0)
ori $s2,$zero,0
la $s3,v
#la $s0,v
#lw $s3,0($s0)
la $s0,s
lw $s4,0($s0)
jal f
f:
#if <cond>
bge $s2,$s4,DONE
#<for body>
lw $s5, 0($s3)
mul $s3,$s3,$s1
li $v0,10
syscall
j UPDATE
UPDATE:
addi $s2,$s2,1 #i=i+1
addi $s3,$s3,4 #moving address 4 bytes since int
j f
DONE:
li $v0,10
syscall
.data
s: .word 3
v: .word 4 3 12 #hard coding vector coefficients
t: .word 2 #value to be multiplied by
When I run this on SPIM simulator, the registers don't produce any value. Is my code wrong or do I need to add something?
mul $s3,$s3,$s1 : this instruction is wrong because $s3 register contains the address of the vector and no the value .
li $v0,10 ; syscall And remove these lines just ahead the jump to UPDATE .
Otherwise , a program will multiply only once
.data
s: .word 3
v: .word 14 3 12 #hard coding vector coefficients
t: .word 2 #value to be multiplied by
.globl main
.text
main:
la $s0,t #loading t into $s0
lw $s1,0($s0) # $s1=2
ori $s2,$zero,0 # $s2=0
la $s3,v # loading v into $s3
li $s7,0
la $s0,s # loading s into $s0
lw $s4,0($s0) # $s4 = 3
j f
f:
#if <cond>
bge $s2,$s4,DONE
#<for body>
lw $s5, ($s3) # $s5= 4
mulu $s5,$s5,$s1
addu $s7,$s7,$s5 # result stored into $s7
j UPDATE
UPDATE:
addiu $s2,$s2,1 #i=i+1
addiu $s3,$s3,4 #moving address 4 bytes since int
j f
DONE:
li $v0,10
syscall

How to remove '0x' in hex and get 2 digits

I am having a hex output "Res" which looks like this:
Res = 0x0 0x1a 0x9 0x14 0x13 0x0
I want to
- remove the '0x' from the beginning of each
-have 2 digits
- and to remove the spaces in between
i.e I want to have the Res like this: 001a09141300
I tried .join but then I want to have 2 digits first.
This is one way to approach it:
res='0x0 0x1a 0x9 0x14 0x13 0x0'
newStr=''
for x in res.split(' '):
x=x[2:]
if len(x)<2:
x='0'+x
newStr=newStr+x
print(newStr)
Output:
001a09141300
How about this:
res = '0x0 0x1a 0x9 0x14 0x13 0x0'
li = [int(s, 16) for s in res.split()] # [0, 26, 9, 20, 19, 0]
ls = [f"{i:0>2x}" for i in li] # ['00', '1a', '09', '14', '13', '00']
result = "".join(ls)
print(result) # 001a09141300
You need Python 3.6 or higher to use f-string.
If your Python version is lower than that, you may use ls = ["{:0>2x}".format(i) for i in li] instead.
Explanation of f"{i:0>2x}":
>2: Right align with width 2
0 on the left: Fill the empty space with 0
x on th right: Represent as hexadecimal form
res='0x0 0x1a 0x9 0x14 0x13 0x0'
hex_ls=[x.replace('0x','0') if len(x)<4 else x.replace('0x','') for x in res.split(" ")]
print("".join(hex_ls))
The output is 001a09141300
res ='0x0 0x1a 0x9 0x14 0x13 0x0'
res = res.replace('0x', '')
res = res.zfill(4)

NASM local variables - are they, in fact, global macros?

I've been using the %local directive in NASM to define local variables and thus avoid typing [ebp - 8], [ebp - 24] etc. all the time.
However, I noticed that a local variable defined in one function between the preprocessor context %push and %pop is still available in the rest of the code, which may result in unexpected parsing errors.
Here, I've written a minimal example demonstrating the problem:
struc Rect
.left resd 1
.top resd 1
.width resd 1
.height resd 1
endstruc
%define RECT(x) g_rect + Rect. %+ x
segment .bss
g_rect resd 4
segment .text
; ================================================
function1:
%push
%stacksize flat
%assign %$localsize 0
%local width:dword ; defines local var "width"
push ebp
mov ebp, esp
sub esp, 4
pusha
; ...
popa
leave
ret
%pop
; ================================================
function2:
push ebp
mov ebp, esp
pusha
; ...
mov eax, RECT(height) ; OK
mov ebx, RECT(width) ; Parse error
; ...
popa
leave
ret
The exact error is:
nasm -f elf -d ELF_TYPE -g test.asm
test.asm:42: error: comma, colon, decorator or end of line expected after operand
Obviously, it happens because width is getting substituted with something else, and if I remove the local param definition, the problem goes away.
As you can see, the variable width is still available after the %pop. This doesn't look very local to me! I'd expect NASM to undefine width when the %pop is executed.
Is there a way to use %local but avoid these leaking macros? At the moment they act as a simple %define statement which is confusing.

How to make string input in Assembly language?

Please, does anybody know how to code string input in assembly language? I'm using int 21 to display and input characters.
You can use function 0Ah to read buffered input. Given a string buffer in ds:dx it reads a string of up to length 255. The buffer layout is:
Byte 0 String length (0-255)
Byte 1 Bytes read (0-255, filled by DOS on return)
Bytes 2-..Length+2 (The character string including newline as read by DOS).
An example of a small COM file that reads a string and then echos it back to the user:
org 0x100
start:
push cs
pop ds ; COM file, ds = cs
mov ah, 0x0A ; Function 0Ah Buffered input
mov dx, string_buf ; ds:dx points to string buffer
int 0x21
movzx si, byte [string_buf+1] ; get number of chars read
mov dx, string_buf + 2 ; start of actual string
add si, dx ; si points to string + number of chars read
mov byte [si], '$' ; Terminate string
mov ah, 0x09 ; Function 09h Print character string
int 0x21 ; ds:dx points to string
; Exit
mov ax, 0x4c00
int 0x21
string_buf:
db 255 ; size of buffer in characters
db 0 ; filled by DOS with actual size
times 255 db 0 ; actual string
Note that it will overwrite the input line (and it thus might not look the program is doing anything!)
Alternatively you can use function 01h and read the characters yourself in a loop. Something like this (note it will overflow later buffers if more than 255 characters are entered):
org 0x100
start:
push cs
pop ax
mov ds, ax
mov es, ax; make sure ds = es = cs
mov di, string ; es:di points to string
cld ; clear direction flag (so stosb incremements rather than decrements)
read_loop:
mov ah, 0x01 ; Function 01h Read character from stdin with echo
int 0x21
cmp al, 0x0D ; character is carriage return?
je read_done ; yes? exit the loop
stosb ; store the character at es:di and increment di
jmp read_loop ; loop again
read_done:
mov al, '$'
stosb ; 'Make sure the string is '$' terminated
mov dx, string ; ds:dx points to string
mov ah, 0x09 ; Function 09h Print character string
int 0x21
; Exit
mov ax, 0x4c00
int 0x21
string:
times 255 db 0 ; reserve room for 255 characters
A string is just a series of characters, so you can use your int 21 code inside of a loop to get a string, one character at a time. Create a label in the data segment to hold your string, and each time you read a character, copy it to that label (incrementing an offset each time so your characters get stored sequentially). Stop looping when a certain character is read (perhaps enter).
Doing all this manually is tedious (think about how backspace will work) but you can do it. Alternatively, you can link against stdio, stdlib, etc. and call library functions to do much of the work for you.