Test if two numbers are equal using Easy68K - 68000

I'm trying to create a program in Easy68K that is able to test if two numbers entered by the user are equal. I know roughly how to get the input from the user, and load it into a data register, and I think I need to use a while loop that will test whether the two numbers are equal.
I'm not asking for people to write the program for me, I just really need some advice.
This is the code I have so far:
*-----------------------------------------------------------
* Title : Number Comparison
* Written by : Robert Dudley
* Date : 23/04/2017
* Description: Compares two numbers and determines if they are equal
*-----------------------------------------------------------
ORG $1000
START: ; first instruction of program
* Put program code here
LEA enterFirst,A1 ; load message into adreg A1
MOVE.B #14,D0
TRAP #15
MOVE.B #4,D0 ; read number from keyboard into D1.L
TRAP #15
LEA enterSecond,A1
MOVE.B #14,D0
TRAP #15
MOVE.B #4,D0
TRAP #15
SIMHALT ; halt simulator
* Put variables and constants here
enterFirst DC.B 'Enter first number: ',0
enterSecond DC.B 'Enter second number: ',0
END START ; last line of source
NOTE: Also, how do I move the input from D1.L to another register?

The keyboard input routine most probably leaves the entered number in some register, let's assume it's D1. Entering the second value will destroy the first one if not saved somewhere else. (I guess this is why you asked how to move a value from one register to the other)
Insert the following line after the second TRAP 15:
MOVE.L d1,d7
Make sure none of the traps changes this register value - otherwise you will lose it.
After the second keyboard input, you will have the second number in d1, the first one (hopefully) still in d7. CoMPare the two registers, and use a conditional branch to whatever [non]equality output routine you might write

Here is code that can serve as a reference. It compares if a number is greater, less or equal to another number:
START: ; first instruction of program
LEA SELECCION, A1
MOVE.B #14, D0
TRAP #15
MOVE.B #4, D0
TRAP #15
CMP.L #5, D1
BEQ ESCINCO
CMP.L #5, D1
BGT MAYORQUE
CMP.L #5, D1
BLT MENORQUE
MAYORQUE
LEA MAYOR, A1
MOVE.B #14, D0
TRAP #15
MOVE.B #9, D0
TRAP #15
MAYOR DC.B 'EL VALOR EL MAYO QUE 5',0
rts
MENORQUE
LEA MENOR, A1
MOVE.B #14, D0
TRAP #15
MOVE.B #9, D0
TRAP #15
MENOR DC.B 'EL VALOR ES MENOR QUE 5',0
rts
ESCINCO
LEA IGUALACION, A1
MOVE.B #14, D0
TRAP #15
MOVE.B #9, D0
TRAP #15
IGUALACION DC.B 'EL VALOR ES 5',0
rts
SELECCION DC.B 'INGRESE DIGITOS ENTRE 0 Y 9: ',0
END START
END START ; last line of source

Related

Armv7 Assembly - Extra console prompt "pi#raspberrypi:~ $ " when I press enter?

I get this output from my program which takes a user input, and replaces the linefeed with a null terminating and prints it back out to the console
pi#raspberrypi:~ $ ./tester
Please enter 4 different numbers between 1-5 together without space or special characters.
1234
1234
pi#raspberrypi:~ $
pi#raspberrypi:~ $
But when I type 123 I only get a single line prompt which is what I'm looking for when I enter 1234.
pi#raspberrypi:~ $ ./tester
Please enter 4 different numbers between 1-5 together without space or special characters.
123
123
pi#raspberrypi:~ $
This is the code I'm executing, it's as minimum as I could get it for minimum functional requirements.
.global _start
_start:
LDR r1, =prompt
BL _sPrint
LDR r1, =userInput # point to the space allocated for input
MOV r2, #4 # set the limit of character to read in
BL _sInput
LDR r1, =userInput
BL _sPrint
Ldr r1, =newline
BL _sPrint
B _exit
#_sPrint prints out a string based on it's variable length determined by _strlen
#strlen, and findEnd are both needed for _sPrint.
_sPrint:
MOV r7, #4 #sets r7 to console STDOUT
MOV r0, #1 #set WRITE destination to STDOUT (terminal)
PUSH {r0, r1, lr}
BL _strLen #gets the stringlength and the end
POP {r0, r1, lr}
SWI 0
mov pc, lr
_strLen:
mov r2, #0
#find end of strlen finds the end of the string and stores the length in r2 for console output
findEnd:
LDRB r0, [r1], #1
ADD r2, r2, #1
CMP r0, #0
BNE findEnd
SUB r2, r2, #1
MOV pc, lr
_sInput:
PUSH {R1-R8, lr}
MOV r7, #3 #register r7 being set to 3 to indicate message being read in (read syscall)
MOV r0, #0 #Set READ device to the STDIN (keyboard)
SWI 0
POP {R1-R8, lr}
#String fix takes a string value at r1's address and changes the line feed to be null termianted.
strfx:
LDRB r0, [r1],#1 #loads a single byte from r1 (r1 is dereferenced), which is the _sInput to r0
CMP r0, #10 #is r0 our newline?
BNE strfx
MOV r0, #0 #set r0 to null
STRB r0, [r1, #-1] #store r0's value back into r1's current address location. The final address
MOV PC, LR #location of r1 newline to be the NULL in r1.
_exit:
MOV r7, #1
SWI #0
.data
prompt: .asciz "\nPlease enter 4 different numbers between 1-5 together without space or special characters. \n \n"
newline: .asciz "\n"
userInput: .space 6
You're reading four characters. When the user enters "1234\n" (five characters), the newline is left in the input buffer to be read by the shell. When the user enters "123\n", the newline is actually read by you. Since you have newline-handling code, the solution is simple: you need to read five characters, not four.

MIPS (Bare Mode) String Won't Print

Recently while starting to learn MIPS in university, I've come across a problem while trying to print 1 string, accept a user input, and then print another string and accept a user input. Both user inputs should be stored to registers a0 and a1 respectively.
The names of each string are promptD for the Dividend input, and enterD for the Divisor input (you might guess this is an unsigned division calculator program).
In my debugging attempts, I have narrowed the problem to a small snippet of the code, posted below.
I think I am incorrectly offsetting my first .data register to reach my 2nd .data register. The problem I am noticing as I've tried QTspim, xspim, PCspim, and MARS is that all 4 of these give the first string in .data a different initial register address.
For example: The string "Enter Dividend" will be in reg address 0x10010000 in MARS but will start in 0x10000000 in PCspim. The following register address for "Enter Divisor" will be in either 0x10010011 in MARS or 0x10000010 in PCspim.
In its current state thru MARS, the program snippet below asks the user to input dividend, and it will store the value. Immediately after storing to a0, the code will fail due to a line 37 (which is just the 3rd syscall) runtime exception at 0x00400024: address out of range 0x00000004. It is not prompting "Enter Divisor" at all.
To really see the problem in action, I think running this in MARS would help make it more clear. Is it a offsetting issue? Am I clobbering a register without seeing it? I haven't found much MIPS help on here that deals with problems without pseudo-instructions. I realize with them, I could load an address directly (la)...but I can't use them here.
Thanks
.globl main
.data #for the data
promptD: .asciiz "Enter Dividend \n"
enterD: .asciiz "Enter Divisor \n"
# result: .asciiz "Result = "
.text #for the instructions
main:
#for Dividend
addi $v0, $0, 4 #store string instr to v0
lui $a0, 0x1001 #address of promptD
syscall #display promptD
addi $v0, $0, 5 #store input instr to v0
syscall # Get dividend
add $a0, $0, $v0 # Dividend to $a0
#for Divisor
addi $v0, $0, 4 #store string instr to v0
lui $a1, 0x1001 #Where I think the problem is...
#Address of first string followed by add offset?
addi $a1, $a1, 33 #Maybe incorrect offset?
syscall #display enterD
addi $v0, $0, 5 #store input instr to v0
syscall # Get divisor
add $a1, $0, $v0 # Divisor to $a1
#end snippet
Here's the problematic code:
lui $a1, 0x1001 #Where I think the problem is...
#Address of first string followed by add offset?
addi $a1, $a1, 33 #Maybe incorrect offset?
You're using the wrong register. The argument for syscall 4 should be placed in $a0, not $a1.
The offset 33 is incorrect. If you look at the Data Segment viewer in Mars you can see that the NUL-terminator byte for promptD is located at 0x10010010, and that the enterD string begins at 0x10010011 (if you have a hard time reading hexadecimal ASCII codes you can tick the "ASCII" checkbox in the Data Segment viewer to view the data as characters). So the offset you should be using is 0x11 (17 decimal).

Program crashes on STRB instruction on ARMv6

While learning ARMv6 ASM (using raspberry pi) I was trying to implement a loop which would modify the contents of a string, however I cannot seem to store the modified byte back to memory.
Using GDB and breaking at various points shows me all registry values are working perfectly until it comes to the STRB instruction. Then it crashes for some unknown reason.
The loop should decrement all bytes by 1 in reverse order.
.text
.global _start
_start:
/* Thumb mode */
.code 32
add r6, pc, #1
bx r6
.code 16
mov r4, #6
mov r0, pc
add r0, #16
loop:
/*load, modify, store*/
ldrb r3, [r0]
sub r3, #1
strb r3, [r0] /*THIS IS BROKEN*/
sub r0, #1
sub r4, r4, #1
bne loop
bx lr
.data
string:
asciz "HiThere"
The STRB instruction seems to crash the program, I am using an old book to learn from, am I missing something obvious here?
EDIT: yes I know that isnt the best way to load r0 but it works...i guess it could use a label in future.
EDIT2: Sorry I know my question was badly written, Ive included more code for clarity. Still crashes on STRB when stepping through in gdb.
EDIT: rather than increasing r0, your loop decreases it. So, rather than scrolling through the string, you are scrolling up straight into your code, overwriting instructions with less-by-one byte values. Once you overwrite the strb instruction, SIGILL happens.
Replace
sub r0, #1
with
add r0, #1
PREVIOUS: I see r0 being initialized to a memory location in the code section, past pc. Is that a writable memory block? I'm not so sure.
Place the string in the data section instead.
EDIT: there's another thing; your loop has no exit condition. SUB doesn't set flags unless told to; so replace
sub r4, r4, #1
with
subs r4, r4, #1

Assembly Language Storing Issue

I'm trying to make an Assembly program concatenate two Strings. Here's my program.
AREA Assignment4, CODE, READONLY
ENTRY
;;;;;;;;;;Setting Up
ADR r0, StrF ;Address of first block in destination
;;;String 1
ADR r1, Str1 ;Address of first string
ADR r2, EoS ;Address of EoS1
SUBS r2, r2,r1 ;Length of str1, counter
;;;;String2
ADR r3, Str2 ;Address of second string
ADR r4, EoS2 ;Address of EoS2
SUBS r4, r4,r3 ;Length of Str2
;;;;;;;;;;Performing Actions
;;;;First String
Loop LDRB r5,[r1],#1 ;Load next bit of "r1" in r5
STRB r5,[r0],#1 ;Store prev bit in memory at r0
SUBS r2, r2, #1 ;Decrement counter
CMP r2, #0 ;Compare our counter
BNE Loop ;Branch if counter != 0
;;;;;Second String
Loop2 LDRB r5,[r3],#1 ;Load next bit of "r3" to r5
STRB r0,[r5],#1 ;Store this bit in r0
SUBS r4, r4, #1 ;Decrement length counter
CMP r4, #0 ;Compare our counter
BNE Loop2 ;Branch if counter != 0
;; Testing the memory - Delete these lines later
ADR r0, StrF
loop3 LDRB r1,[r0],#1
B loop3
Finished B Finished
Str1 DCB "This is a test string1" ;Str1
EoS DCB 0x00
Str2 DCB "This is a test string2" ;Str2
EoS2 DCB 0x00
StrF DCB 0x00 ;Saving this
END
My problem is on lines 22 + 29. I don't know how to successfully store the current byte onto the memory; more specifically the memory in register r0, initialized initially by StrF.
Any ideas on how to fix my STRB or STR?
I get this once I pass that line:
"error 65: access violation at 0x00000082 : no 'write' permission"
thats the memory address that at StrF that im trying to save into.
You see that big "READONLY" in the first line?
Since strF is located in the same area as the code declared as readonly, it of course doesn't work.
You should put strF in a differnt area declared as readwrite, but you won't be able to use adr then.
All in all, you should design the routines in a way that they receive memory addresses as parameters from the callers.
i had this problem, so if you are using keil, when u in debug mode go to debug -> memorymap, then add memory range manually
0x00000048 ,0x0000011A
and check on read, write a/o execute
check this page
DEBUGGER: ERROR 65 (ACCESS VIOLATION)

ARM - Infinite Loop While Searching String

Can anybody point out why? I can't see the problem.
String to search: "aassaas"
String to search with: "as"
SEARCHSTRING:
STMFD SP!, {R4-R7, LR}
MOV R6, #0 #Matches found
MOV R3, #0 #Placeholder
LOOP: LDRB R4, [R0] #R4 = String to search
LDRB R5, [R1] #R5 = String to search with
CMP R4, R5 #Do they match?
ADDEQ R3, R3, #1 #If yes, increase placeholder
LDREQB R4, [R0, #1]! #Get next char
LDREQB R5, [R1, #1]! #Get next char
BLNE RESET #If not, reset placeholder and strings.
#R0 is nevertheless initial pos+1
CMP R5, #0 #Is string to search with at the end?
ADDEQ R6, R6, #1 #If so, add +1 to matches
BLEQ RESET #Reset placeholder and strings.
CMP R4, #0 #Is the string to search finished?
BNE LOOP #If not, start over.
MOV R0, R6 #If so, move answer into R0.
LDMFD SP!, {R4-R7, PC} #Jump back.
RESET:
STMFD SP!, {LR}
CMP R3, #0 #Is the placeholder at 0? (initial position)
SUBNE R0, R0, R3 #If not, subtract from String to search pos
SUBNE R1, R1, R3 #And string to be searched pos
ADDNE R0, R0, #1 #Increment string to search+1 so we don't start at the same spot
MOVNE R3, #0 #Empty the placeholder
LDMFD SP!, {PC} #Jump back
I don't understand why a) you're writing this in assembler instead of C, and b) why you're not using some routine based on strstr. The most likely scenario is that this is a homework problem, or some other form of learning exercise, so I don't want to give too much away. In any event, there are a couple of problems that I noticed. The first bit I notice is in the RESET routine:
RESET:
STMFD SP!, {LR}
CMP R3, #0 #Is the placeholder at 0? (initial position)
SUBNE R0, R0, R3 #If not, subtract from String to search pos
SUBNE R1, R1, R3 #And string to be searched pos
ADDNE R0, R0, #1 #Increment string to search+1 so we don't start at the same spot
MOVNE R3, #0 #Empty the placeholder
LDMFD SP!, {PC} #Jump back
The CMP is unnecessary - consider what the effect of the SUBNE calls will be if R3 is 0, and you'll see that you can perform the subtractions unconditionally. You want to run ADD R0, R0, #1 unconditionally - in fact, this is a big part of the reason you have an infinite loop. If you get to the RESET subroutine, and R3 is 0, then it doesn't change any state. I also notice that the STMFD / LDMFD pair is really not necessary - LR won't be modified in this subroutine, so it doesn't need to go on the stack.
Next, I notice that you're not careful enough about when to terminate your loop. Consider what happens if you give two empty strings as arguments to SEARCHSTRING. Call it with two empty strings as arguments, and single-step through your assembly code to see the problem. The general form of a for loop, when compiled to assembly, will be something like:
for(initial; comparison; increment) {
body;
}
INITIAL:
MOV R0, #0 #initialize variables
B CONDITION #jump to condition check
BODY:
LDR R1, [R0]
INCREMENT: #really, part of the for-loop body.
ADD R0, R0, #1
CONDITION:
CMP BLAH, BLAH #test-condition
BLT BODY #restart loop if condition indicates we should do so.
hopefully this will help you to reorganize the code in a more straightforward way.

Resources