I am a beginner when it comes to assembly language. I am using "easy 68k editor/assembler" to write 68k assembly code that asks the user for 2 values, then sum them up together and display it. The problem is that my code keeps getting halted and I am not sure how to troubleshoot/debug this problem.
Can anyone help me figure out how to track down the error? I will be grateful. Thank you in advance.
*-----------------------------------------------------------
* Program : Sum of Two Numbers
* Written by : Me
* Date : July 15, 2012
* Description: This program will read in 2 numbers the user
*inputs and find the sum.
*-----------------------------------------------------------
org $8000
START movea.l #MSG1, A3
trap #3
clr.w D2
JSR Loop
trap #2
move.w d2, d4
movea.l #msg2, a3
trap #3
clr.w d2
jsr loop
trap #2
movea.l #msg3, A3
trap #3
add.w d4, d2
JSR DISP
trap #2
trap #9
LOOP trap #0
trap #1
cmp.b #$0D, D1
BEQ BREAK
and.b #$0F, d1
mulu #10, d2
add.w d1, d2
jmp loop
Break rts
DISP clr.b d3
DISDIV divu #10, D2
move.b #16, d5
ror.l d5, d2
or.b #$30, d2
move.b d2, -(A7)
addq #1, d3
clr.w d2
ror.l d5, d2
bne DISDIV
DISDIG move.b (a7)+, D1
trap #1
subq.b #1, D3
bne DISDIG
rts
org $8100
MSG1 DC.B 'Please enter the first of two numbers (two digits) ', 0
MSG2 DC.B 'Please enter the second of two numbers (two digits) ', 0
MSG3 DC.B 'The sum of the two 2 digit numbers you entered is ', 0
end start
Your code should start with:
LEA MSG1, A1
MOVE.B #14, D0
TRAP #15
This will display the first message to the user. Check out the EASy68K home page for more information on invoking I/O traps.
Most likely the traps you are using are not those used by Easy68K. Look here for the traps used by Easy68K.
The function of the trap instructions is not defined by the 68K assembly language, but rather assigned by the operation system (if the OS makes use of the traps at all, some just ignore them). If you execute a trap instruction the 68000 just executes the code the trap vector points to. There is no "buildin" function assigned to any trap.
Related
I have a issue that I cannot seem to figure out, when it comes to 16 bit words. Below i have attached the corresponding code and the the imagine that gives a bit of a description of what I am asking help for.
.orig x3000
ld r1,n
lea r5,data
add r1,r1,#-1
loop:
str r1,r5,0
add r5,r5,r2
add r1,r1,#-1
brp loop
trap x25
data: .blkw 2
n: .fill 10
.end
Here is the image
I get the nzp codes but im not sure how to calculate the pcoffset9 so it would be greatly appreciated if someone could help with this example.
The formula to calculate the PCOffset is as follows
ADDRESS_OF_SYMBOL - (INSTRUCTION_ADDRESS + 1)
.orig x3000
LEA R0, HELLO_WORLD ; x3000
PUTS ; x3001
HALT ; x3002
HELLO_WORLD .stringz "HELLO WORLD" ; x3003
.end
so the PCOffset in the LEA instruction is as follows
ADDRESS_HELLO_WORLD - (ADDRESS_LEA + 1)
x3003 - (x3000 + 1) = 2
When the LEA instruction executes remember that the PC is already incremented as part of Fetch so PC will be at x3001. We add the 2 to it to get x3003 the address of where the label HELLO_WORLD is.
Ok, here it is guys. Before you, I have a program that performs this algorithm:
"IF X > 12 THEN X = 2*X+4 ELSE X = X + Y, OUTPUT X."
the problem is, I need it to perform this one instead:
"IF X > 12 THEN X = 2*X+4 ELSE X = X - 13, OUTPUT X."
How would I make this subtract rather than add?
ORG $1000
START: LEA PROMPT, A1
MOVE.B #14, D0 ; display string
TRAP #15
MOVE.B #4, D0 ; read from keyboard
TRAP #15
MOVE D1, D3 ; copy X
LEA STTY, A1
MOVE.B #14, D0 ; display string
TRAP #15
CMP #12, D3 ; X > 12 ?
BGT MULTADD ; branch if yes
CMP #12, D3 ; why compare again??
BRA ADDY
MULTADD
LEA XGT, A1
MOVE.B #14, D0 ; display string
TRAP #15
LEA TWOXP4, A1
MOVE.B #14, D0 ; display string
TRAP #15
MULU #2, D3 ; 2*X
ADD #4, D3 ; +4
MOVE D3, D1 ; copy to D1
MOVE.B #3, D0 ; Display decimal signed D1.L in smallest field
TRAP #15
BRA FIN
ADDY LEA XLT, A1
MOVE.B #14, D0 ; display string
TRAP #15
LEA XPY, A1
MOVE.B #14, D0 ; display string
TRAP #15
ADD Y, D3 ; X = X+Y
MOVE D3, D1
MOVE.B #3, D0 ; Display decimal signed D1.L in smallest field
TRAP #15
BRA FIN ; not needed
FIN MOVE.B #9,D0 ; terminate program
TRAP #15
* Variables and Strings
PROMPT DC.B ';Enter X: ';, 0
STTY DC.B ';Y = 4';, CR, LF, 0
XGT DC.B 'X > 12';, CR, LF, 0
XLT DC.B 'X != 12';, CR, LF, 0
TWOXP4 DC.B 2 * X + 4 = ';, CR, LF, 0
XPY DC.B 'X + Y = ';, 0
Y DC.W 4
CR EQU $0D
LF EQU $0A
END START
Tips:
Use MOVEQ to load a small number into a 32 bit register
Don't use MULU to multiply by 2
Use the .B, .W and .L instructions as default normally just 16 bits
ORG $1000
START: LEA PROMPT, A1
MOVEQ #14, D0 ; display string
TRAP #15
MOVEQ #4, D0 ; read number from keyboard
TRAP #15
MOVE.L D1,D3 ; save X
LEA STTY, A1
MOVEQ #14, D0 ; display string
TRAP #15
CMP.L #12, D3 ; X > 12 ?
BGT MULTADD ; branch if yes
ADDY LEA XLT, A1
MOVEQ #14, D0 ; display string
TRAP #15
LEA XPY, A1
MOVEQ #14, D0 ; display string
TRAP #15
ADD.L Y, D3 ; X = X+Y, change to SUB.L Y,D3
MOVE.L D3, D1
MOVEQ #3, D0 ; Display decimal signed D1.L in smallest field
TRAP #15
BRA FIN ; not needed
MULTADD
LEA XGT, A1
MOVEQ #14, D0 ; display string
TRAP #15
LEA TWOXP4, A1
MOVEQ #14, D0 ; display string
TRAP #15
ASL.L #1, D3 ; 2*X by shifting
ADDQ.L #4, D3 ; +4
MOVE.L D3, D1 ; copy to D1
MOVEQ #3, D0 ; Display decimal signed D1.L in smallest field
TRAP #15
FIN MOVEQ #9,D0 ; terminate program
TRAP #15
* Variables and Strings
CR EQU $0D
LF EQU $0A
PROMPT DC.B ';Enter X: ';, 0
STTY DC.B ';Y = 4';, CR, LF, 0
XGT DC.B 'X > 12';, CR, LF, 0
XLT DC.B 'X != 12';, CR, LF, 0
TWOXP4 DC.B 2 * X + 4 = ';, CR, LF, 0
XPY DC.B 'X + Y = ';, 0
Y DC.L 13
END START
Can't test it, but try to replace the
ADD Y, D3
With
SUB Y, D3
This may seem rather silly, but there actually are hardly any resources to learn LC-3. I can't manage to seem to find a proper in depth analysis of the subject and explain how things work, I mean sure, you can find simple definitions and what certain op/pseudo-op codes do, but nothing written in full and fully explained.
If someone could do a full analysis of the following:
; Hello name in LC-3 assembler
.orig x3000
lea r0, what
puts
lea r1, name
; typical assembly language hack coming up
add r1, r1, #-1
char getc
putc
add r2, r0, #-10
brz completed; was a newline
str r0, r1, #0
add r1, r1, #1
brnzp char
completed lea r0, hello
puts
halt
That would probably extremely lengthy, but also very appreciated. (Maybe this is the first stack post for a full analysis of LC-3 code resource?)
p.s I don't expect the person who answers to explain what each op/pseudo op code does but at least be very specific about how the operator performs and does its work
I mostly learned how LC3 worked from plugging in code and stepping through it. Though I would reference Appendix A in the book a LOT.
; Hello name in LC-3 assembler
.orig x3000 ; Starting place in memory for our code
lea r0, what ; Load the memory address of variable what
puts ; Print the string who's memory address is stored in R0
lea r1, name ; Load the memory address of the variable name into R1
; typical assembly language hack coming up
add r1, r1, #-1 ; Subtract 1 from R1, then store into R1
char getc ; Get a single char from the user, store into R0
putc ; Print that same char to the console
add r2, r0, #-10 ; R2 = R0 - 10
brz completed ; If the user presses ENTER (Ascii 10)
; and we've subtracted 10 then we'll get a 0, exit program
str r0, r1, #0 ; Store the value of R0 into memory[R1 + 0]
add r1, r1, #1 ; R1 = R1 + 1
brnzp char ; Jump to Clear no matter what
completed lea r0, hello ; Load the memory address of variable hello into R0
puts ; Print the string stored in hello
halt ; Stop the program
So, here in the following code, I am writing a code to sort numbers in ascending order.
start: nop
MVI B, 09 ; Initialize counter
LXI H, 2200H ;Initialize memory pointer
MVI C, 09H; Initialize counter 2
BACK: MOV A, M ;Get the number
INX H ;Increment memory pointer
CMP M; Compare number with next number
JC SKIP;If less, don't interchange
JZ SKIP; If equal, don't interchang
MOV D, M
MOV M, A
DCX H
MOV M, D
INX H ;Interchange two numbers
DCR C ; Decrement counter 2
JNZ BACK ;If not zero, repeat
DCR B ; Decrement counter 1
JNZ START
HLT ; Terminate program execution
This was that was taught in class.
When I try running the code in GNUSim, I get errors like :
1. Line 9: Undefined symbol.
2. Line 9: Invalid operand or symbol.Check whether operands start with a 0. Like a0H should be 0a0H.
Can somebody help?
In 8085 (js8085) I'd do it the next way (using bubble sort):
#begin 0100
#next 0100
MVI A 00
MVI B 00
MVI C 00
MVI D 00
MVI E 00
MVI H 00
MVI L 00
IN 00
out 00
DCR A
out 06
bubble: in 06
cmp c
jz finished
inr e
ldax b
mov h,a
ldax d
cmp h
jc change;
comprobation: in 00
cmp e
jz semi-fin
call bubble
semi-fin: inr c
mov a,c
mov e,c
call bubble
change: stax b
mov a,h
stax d
call comprobation
finished: hlt
In the port 00 you got the number of elements you have and the the elements themselves are starting from the position 0000 to the number of elements - 1.
I'm using Freescale Kinetis K60 and using the CodeWarrior IDE (which I believe uses GCC for the complier).
I want to multiply two 32 bit numbers (which results in a 64 bit number) and only retain the upper 32 bits.
I think the correct assembly instruction for the ARM Cortex-M4 is the SMMUL instruction. I would prefer to access this instruction from C code rather than assembly. How do I do this?
I imagine the code would ideally be something like this:
int a,b,c;
a = 1073741824; // 0x40000000 = 0.5 as a D0 fixed point number
b = 1073741824; // 0x40000000 = 0.5 as a D0 fixed point number
c = ((long long)a*b) >> 31; // 31 because there are two sign bits after the multiplication
// so I can throw away the most significant bit
When I try this in CodeWarrior, I get the correct result for c (536870912 = 0.25 as a D0 FP number). I don't see the SMMUL instruction anywhere and the multiply is 3 instructions (UMULL, MLA, and MLA -- I don't understand why it is using a unsigned multiply, but that is another question). I have also tried a right shift of 32 since that might make more sense for the SMMUL instruction, but that doesn't do anything different.
The problem you get with optimizing that code is:
08000328 <mul_test01>:
8000328: f04f 5000 mov.w r0, #536870912 ; 0x20000000
800032c: 4770 bx lr
800032e: bf00 nop
your code doesnt do anything runtime so the optimizer can just compute the final answer.
this:
.thumb_func
.globl mul_test02
mul_test02:
smull r2,r3,r0,r1
mov r0,r3
bx lr
called with this:
c = mul_test02(0x40000000,0x40000000);
gives 0x10000000
UMULL gives the same result because you are using positive numbers, the operands and results are all positive so it doesnt get into the signed/unsigned differences.
Hmm, well you got me on this one. I would read your code as telling the compiler to promote the multiply to a 64 bit. smull is two 32 bit operands giving a 64 bit result, which is not what your code is asking for....but both gcc and clang used the smull anyway, even if I left it as an uncalled function, so it didnt know at compile time that the operands had no significant digits above 32, they still used smull.
Perhaps the shift was the reason.
Yup, that was it..
int mul_test04 ( int a, int b )
{
int c;
c = ((long long)a*b) >> 31;
return(c);
}
gives
both gcc and clang (well clang recycles r0 and r1 instead of using r2 and r3)
08000340 <mul_test04>:
8000340: fb81 2300 smull r2, r3, r1, r0
8000344: 0fd0 lsrs r0, r2, #31
8000346: ea40 0043 orr.w r0, r0, r3, lsl #1
800034a: 4770 bx lr
but this
int mul_test04 ( int a, int b )
{
int c;
c = ((long long)a*b);
return(c);
}
gives this
gcc:
08000340 <mul_test04>:
8000340: fb00 f001 mul.w r0, r0, r1
8000344: 4770 bx lr
8000346: bf00 nop
clang:
0800048c <mul_test04>:
800048c: 4348 muls r0, r1
800048e: 4770 bx lr
So with the bit shift the compilers realize that you are only interested in the upper portion of the result so they can discard the upper portion of the operands which means smull can be used.
Now if you do this:
int mul_test04 ( int a, int b )
{
int c;
c = ((long long)a*b) >> 32;
return(c);
}
both compilers get even smarter, in particular clang:
0800048c <mul_test04>:
800048c: fb81 1000 smull r1, r0, r1, r0
8000490: 4770 bx lr
gcc:
08000340 <mul_test04>:
8000340: fb81 0100 smull r0, r1, r1, r0
8000344: 4608 mov r0, r1
8000346: 4770 bx lr
I can see that 0x40000000 considered as a float where you are keeping track of the decimal place, and that place is a fixed location. 0x20000000 would make sense as the answer. I cant yet decide if that 31 bit shift works universally or just for this one case.
A complete example used for the above is here
https://github.com/dwelch67/stm32vld/tree/master/stm32f4d/sample01
and I did run it on an stm32f4 to verify it works and the results.
EDIT:
If you pass the parameters into the function instead of hardcoding them within the function:
int myfun ( int a, int b )
{
return(a+b);
}
The compiler is forced to make runtime code instead of optimize the answer at compile time.
Now if you call that function from another function with hardcoded numbers:
...
c=myfun(0x1234,0x5678);
...
In this calling function the compiler may choose to compute the answer and just place it there at compile time. If the myfun() function is global (not declared as static) the compiler doesnt know if some other code to be linked later will use it so even near the call point in this file it optimizes an answer it still has to produce the actual function and leave it in the object for other code in other files to call, so you can still examine what the compiler/optimizer does with that C code. Unless you use llvm for example where you can optimize the whole project (across files) external code calling this function will use the real function and not a compile time computed answer.
both gcc and clang did what I am describing, left runtime code for the function as a global function, but within the file it computed the answer at compile time and placed the hardcoded answer in the code instead of calling the function:
int mul_test04 ( int a, int b )
{
int c;
c = ((long long)a*b) >> 31;
return(c);
}
in another function in the same file:
hexstring(mul_test04(0x40000000,0x40000000),1);
The function itself is implemented in the code:
0800048c <mul_test04>:
800048c: fb81 1000 smull r1, r0, r1, r0
8000490: 0fc9 lsrs r1, r1, #31
8000492: ea41 0040 orr.w r0, r1, r0, lsl #1
8000496: 4770 bx lr
but where it is called they have hardcoded the answer because they had all the information needed to do so:
8000520: f04f 5000 mov.w r0, #536870912 ; 0x20000000
8000524: 2101 movs r1, #1
8000526: f7ff fe73 bl 8000210 <hexstring>
If you dont want the hardcoded answer you need to use a function that is not in the same optimization pass.
Manipulating the compiler and optimizer comes down to a lot of practice and it is not an exact science as the compilers and optimizers are constantly evolving (for better or worse).
By isolating a small bit of code in a function you are causing problems in another way, larger functions are more likely to need a stack frame and evict variables from registers to the stack as it goes, smaller functions might not need to do that and the optimizers may change how the code is implemented as a result. You test the code fragment one way to see what the compiler is doing then use it in a larger function and dont get the result you want. If there is an exact instruction or sequence of instructions you want implemented....Implement them in assembler. If you were targeting a specific set of instructions in a specific instruction set/processor then avoid the game, avoid your code changing when you change computers/compilers/etc, and just use assembler for that target. if needed ifdef or otherwise use conditional compile options to build for different targets without the assembler.
GCC supports actual fixed-point types: http://gcc.gnu.org/onlinedocs/gcc/Fixed_002dPoint.html
I'm not sure what instruction it will use, but it might make you life easier.