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

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.

Related

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 do I print a string in one line in MARIE?

I want to print a set of letters in one line in MARIE. I modified the code to print Hello World and came up with:
ORG 0 / implemented using "do while" loop
WHILE, LOAD STR_BASE / load str_base into ac
ADD ITR / add index to str_base
STORE INDEX / store (str_base + index) into ac
CLEAR / set ac to zero
ADDI INDEX / get the value at ADDR
SKIPCOND 400 / SKIP if ADDR = 0 (or null char)
JUMP DO / jump to DO
JUMP PRINT / JUMP to END
DO, STORE TEMP / output value at ADDR
LOAD ITR / load iterator into ac
ADD ONE / increment iterator by one
STORE ITR / store ac in iterator
JUMP WHILE / jump to while
PRINT, SUBT ONE
SKIPCOND 000
JUMP PR
HALT
PR, OUTPUT
JUMP WHILE
ONE, DEC 1
ITR, DEC 0
INDEX, HEX 0
STR_BASE, HEX 12 / memory location of str
STR, HEX 48 / H
HEX 65 / E
HEX 6C / L
HEX 6C / L
HEX 6F / O
HEX 0 / carriage return
HEX 57 / W
HEX 6F / O
HEX 72 / R
HEX 6C / L
HEX 64 / D
HEX 0 / NULL char
My program ends up halting past two iterations. I can't seem to figure out how to print a set of characters in one line. Thanks.
Your value of STR_BASE is almost certainly incorrect. Based on what is here I would say it needs to be 18 instead of 12. Also you would either want to remove current null char that is between "HELLO" and "WORLD" and replace it with a space or simply remove that line, depending on your intended output.

Remove leading zeroes binary

I want to basically remove my leading zeroes. When I print out a number for example 17 is 00000 0000 0000 0000 0000 0000 00001 0001 but to do remove those leading zeroes. Because in sparc machine that is what is printed out and I need to do this using some sort of loop or logic or shift function.
this is my psuedocode for printing the binary
store input, %l1 ! store my decimal number in l1
move 1,%l2 !move 1 into l2 register
shift logical left l2,31,l2 !shift my mask 1 31 times to the left
loop:
and l2,l1,l3 ! do and logic between l1 and l2 and put this in l3
compare l3,0 compare l3 zero
bne print 1 !branch not equal to zero, to print 1
if equal to 0
print zero
print 1:
print a 1
go: increment counter
compare counter 32
if counter less than 32 return to loop
shift l2 to the right to continue comparison
so this is what is being done say my input is l1 is 17
00000 0000 0000 0000 0000 0000 00001 0001
10000 0000 0000 0000 0000 0000 00000 0000 and my mask 1 shift left 31 times
this pseucode print out my input decimal into binary. But how can I make it remove leading zeroes?
because in the sparc 17 input inside the machine is
0000 0000 0000 0000 0000 0000 0001 00001
You create the labels, like go and print 1 (more commonly done in all caps and without spaces, FYI). So, starting with bne you should always be printing 1, or falling through to see if it needs to print the 0:
! same initialization
mov 0, l4 ! Initialize a flag to avoid printing
LOOP:
and l2, l1, l3 ! do and logic between l1 and l2 and put this in l3
cmp l3, 0 ! Is this a 0 digit?
bne ALWAYS_PRINT ! If it's not 0, then it must be 1 (was "bne print 1")
cmp l4, 1 ! Should we be printing the 0?
be PRINT_VALUE ! Yes, we need to print the 0 because we have seen a 1
ba INCREMENT ! We should not be printing the 0, so check the next
! digit (ba is "branch always")
ALWAYS_PRINT: !
mov 1, %l4 ! Note that we want to always print for the
! rest of the loop
PRINT_VALUE: ! Do whatever you're doing to print values
print value in l3 ! Always print the value
INCREMENT: ! Formerly your "go:" label
! same logic
! AFTER LOOP IS DONE LOGIC
cmp l4, 0 ! If the flag was never set, then the value is 0
! Alternatively, you could just compare the value to 0
! and skip the loop entirely, only printing 0 (faster)
bne DO_NOT_PRINT ! If it was set (1), then do nothing
print zero ! If it wasn't set, then print the 0
DO_NOT_PRINT:
To walk through it a little, you need to continue to initialize your values and shift the bits to figure out what the current digit is for each iteration. Since you will need another flag, then you need to use another register that is initialized to an expected value (I chose 0, which commonly represents false).
Get current digit into l3 (0 or 1)
See if it is 0
If it's not 0, then it must be 1. So go remember that we found a 1, for later, then print the value and increment/loop.
If it's 0, then see if we have found a 1 before. If so, then print the value and increment/loop. If not, then increment/loop.
For actually printing, I have no idea what you are actually doing. However, you can avoid a second comparison by using the labels. For example, ALWAYS_PRINT will always be used when the value is 1, so you can just set the flag and immediately print 1, then jump to INCREMENT. If you did that, then PRINT_VALUE would only be used to print 0, which could then fall through to INCREMENT.
From a high level language's perspective, you want:
int l2 = // value...
bool seenOneAlready = false;
if (l2 != 0)
{
// MSB first
for (int i = 31; i > -1; --i)
{
int l3 = (l2 >> i) & 1;
if (l3 == 1)
{
seenOneAlready = true;
printf("1");
}
else if (seenOneAlready)
{
printf("0");
}
}
}
else
{
printf("0");
}

MIPS: String Copy, 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

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.