Here we are again. For my first tutorial, see Assembly #1 Reverse a string. Bill set me up for a second challenge, and I took it up. This is another great bite sized exercise to learn how to compare blocks of memory. In this exercise we will compare 2 strings and let the user know if they are equal. We will make use of BASIC again to:
The purpose of this project is to write another simple assembly language program, and learn to use a few more assembly mnemonics. Specifically the ones for comparing values. You will want to make sure you use the $JR
compiler directive to make jumps easier.
The mnemonics for comparing are:
MNEMONIC OPERATION FLAGS EFFECTED
CPIM n [P] - n C,Z
CPIA n A - n C,Z
CPMA [P] - A C,Z
Use the following truth table to figure out what flags will be set.
TRUTH TABLE
EXAMPLE FLAGS MEANING
4 - 5 C=1,Z=0 left < right
5 - 5 C=0,Z=1 left = right
6 - 5 C=0,Z=0 left > right
You’re likely to find CPMA
is the real workhorse when dealing with data. CPIA
and CPIM
are used when dealing with known values; Like if you want to see if something equals 0.
Once you have compared, you will use a branch mnemonic to jump to a new piece of code.
MNEMONIC OPERATION
JPNZ nm jump to nm if Z=0
JPNC nm jump to nm if C=0
JPZ nm jump to nm if Z=1
JPC nm jump to nm if C=1
JP nm jump to nm regardless of flags
As an example, lets say you want to see if the A reg
equals the number 5. You would use the following code:
CMIA 5 # A - n, check if A reg is 5
JPZ PLACE1
# continue as A is not 5
RTN
PLACE1: # A is 5
RTN
JPZ
jumps to PLACE1
if the zero flag was set, which according to the truth table means A equals 5.
This will be our memory setup. Program start is 49217.
ADDRESS ASM VAR COMMENT
49200 RESULT Result (1 equal | 0 not equal)
49201 - 49207 SRC1 String 1
49208 SRCLEN1 Length of string 1
49209 - 49215 SRC2 String 2
49216 SRCLEN2 Length of string 2
49217 Program start
Our assembly program will compare the 2 strings SRC1
and SRC2
, making note of the string lengths SRCLEN1
& SRCLEN2
, and store the result in address RESULT
(49200).
Compile and load at address 49200 (&C030). bin2wav.exe --type=bin --pc=1360 --addr=0xC030 output.bin
and CLOAD M
on your pocket computer.
##############################################################################
# Compare the strings SRC1 and SRC2 to see if they
# are equal. Store 0 in RESULT if no, 1 if they are.
##############################################################################
$JR
org &C030
I_REG EQU 0 # Internal Registers
J_REG EQU 1
A_REG EQU 2
B_REG EQU 3
XL_REG EQU 4
XH_REG EQU 5
YL_REG EQU 6
YH_REG EQU 7
K_REG EQU 8
L_REG EQU 9
M_REG EQU 10
N_REG EQU 11
PORTC EQU 95
# define data and put some dummy data in place
RESULT: DB 0
SRC1: DB 48 49 50 51 52 53 54
SRCLEN1: DB 1
SRC2: DB 65 66 67 68 69 70 71
SRCLEN2: DB 1
START:
# Point the X register to SRC1
LP XH_REG # P [P]
LP XL_REG # P [P] => X now contains SRC1
DX # prep for ++X inside check1
# Point the Y register to SRC2
LP YH_REG # P [P]
LP YL_REG # P [P] => Y now contains SRC2
DY # prep for ++Y inside check1
# put srclen1 into A and srclen2 into B
LIDP SRCLEN2
LDD # [DP] -> A - srclen -> A
EXAB # A B - B contains srclen2
LIDP SRCLEN1
LDD # A contains srclen1
# check if strings are the same length
LP B_REG # P points to B reg
CPMA # [P] - A -> C,Z # compare A and B
JPNZ NOT_EQUAL
# check byte by byte to see if the strings are the same length
lp K_REG
exam # K now contains srclen1
check1:
# put src1 bytes into A, src2 bytes into B, then compare A & B
# load B from Y
iy # ++Y -> DP
ldd # [Y] -> A
exab # B contains [Y]
# load A from X
ixl # ++X -> DP, [DP] -> A
lp B_REG
cpma # compare A and B
jpnz not_equal
# decrement K reg
deck
jpnz check1 # keep checking
# fall through into equal
equal:
lidp result
lia 1
std
rtn
not_equal:
lidp result
ra # 0 -> A
std
rtn
You can type RUN
to start this program once loaded.
100 "S" WAIT 0
110 A=49201:R=49200
120 INPUT "String 1:";X$
130 INPUT "String 2:";Y$
135 PRINT "POKING"
140 K = LEN X$
150 L = LEN Y$
200 FOR I=1 TO K
205 V = ASC(MID$(X$,I,1))
210 POKE A,V
220 A=A+1
230 NEXT I
240 A=49209
250 FOR I=1 TO L
265 V = ASC(MID$(Y$,I,1))
270 POKE A,V
280 A=A+1
290 NEXT I
295 POKE 49208,K : POKE 49216,L
300 PRINT "CALLING ML"
310 CALL 49217
320 IF PEEK 49200 = 0 PRINT "NOT EQUAL"
330 IF PEEK 49200 = 1 PRINT "EQUAL"
Feel free to drop me a line at eightbit at axorion dot com. You can also start a thread on Simons Pocket Computer Forum. Best to let me know you did though, in case I don’t see your forum entry right away.
I was a little surprised to find the 1360 didn't have any instructions for multiplication or division. I especially found this hard to believe because this is a scientific calculator. What the heck? Lucky for me, this presented a perfect opportunity to write a couple simple assembly routines. This time we will forgo the BASIC code, and just stick with the assembly. To interact with the routines, we will just `PEEK` and `POKE` memory. You can also check out * [Assembly #1: Reverse a string](http://www.axorion.com/?f=blog&pageId=45) * [Assembly #2: String compare](http://www.axorion.com/?f=blog&pageId=46) # Getting Started # The purpose of this project is to write 2 routines. One will multiply 2 numbers and produce a product, the other will divide 2 numbers and return a quotient and remainder. # Memory Map # Our memory map. ADDRESS ASM VAR 49205 dividend 49204 divisor 49205 quotient 49206 remainder 49207 multiplicand 49208 multiplier 49209 product 49210 division entry point 49249 multiplication entry point # Assembly Source # Multiplication without a multiply instruction is easy. We just keep adding the multiplicand to itself multiplier times. Division by subtraction is a little more interesting. Let's say you want to divide 60 by 12. Using subtraction you would: 60-12=48 count 1 48-12=36 count 2 36-12=24 count 3 24-12=12 count 4 12-12=0 count 5 Thus, 60÷12=5. You can even handle remainders: 64-12=52 count 1 52-12=40 count 2 40-12=28 count 3 28-12=16 count 4 16-12=4 count 5 4 < 12, so 64÷12 is 5 with a remainder of 4. > **Note:** > > Remember that this is only 8-bit math, and we don't handle overflow. So 128*3 will produce the answer 128 instead of 384. ############################################################################## # Math.asm # Sample multiplication and division routines for 8-bit numbers. # Does not handle overflow. So 128*3 will equal 128 instead of 384. # Division will produce a quotient and remainder. # # Division routine: # INPUT: Poke 8-bit numbers to dividend and divisor addresses # OUTPUT: Peek the 8-bit result at quotient and remainder addresses. # # Example: # Divide 17 by 5. Answer is 3 with a remainder of 2 # # PEEK 49205 RETURNS 0 # PEEK 49206 RETURNS 0 # # POKE 49203,17 # POKE 49204,5 # # CALL 49210 # # PEEK 49205 RETURNS 3 # PEEK 49206 RETURNS 2 # # Multiplication routine: # INPUT: Poke 8-bit numbers to dividend and divisor addresses # OUTPUT: Peek the 8-bit result at quotient and remainder addresses. # # Example: # Multiply 5 times 7. Answer is 35. # # PEEK 49209 RETURNS 35 # # POKE 49207,5 # POKE 49208,7 # # CALL 49249 # # PEEK 49209 RETURNS 35 # # http://www.axorion.com ############################################################################## $JR org &C030 I_REG equ 0 # Internal Registers J_REG equ 1 A_REG equ 2 B_REG equ 3 XL_REG equ 4 XH_REG equ 5 YL_REG equ 6 YH_REG equ 7 K_REG equ 8 L_REG equ 9 M_REG equ 10 N_REG equ 11 PORTC equ 95 jp start # skip over allocated memory right into division dividend: db 10 # a number divisor: db 5 # divided by this quotient: db 0 # equals the answer remainder: db 0 # with a remainder multiplicand: db 3 multiplier: db 7 product: db 0 # &45 069 SBM [P] - A -> [P] 1 3 C,Z # &DA 218 EXAB A B 1 3 # &DB 219 EXAM A [P] 1 3 # &63 099 CPIM n [P] - n -> C,Z 2 4 C,Z # &67 103 CPIA n A - n -> C,Z 2 4 C,Z # &C7 199 CPMA [P] - A -> C,Z 1 3 C,Z # To divide 60 by 12 using subtraction: # B A # 60-12=48 count 1 # 48-12=36 count 2 # 36-12=24 count 3 # 24-12=12 count 4 # 12-12=0 count 5. # Thus, 60÷12=5. # You can even handle remainders: # 64-12=52count 1 # 52-12=40count 2 # 40-12=28count 3 # 28-12=16count 4 # 16-12=4 count 5. # 4 < 12, so 64÷12 is 5 with a remainder of 4. start: divide: lp K_REG ra # clear a exam # 0 -> K, K will be our quotient lidp dividend # loading B with dividend ldd exab # A B, B now contains the dividend lidp divisor # loading A with divisor ldd # A now contains the divisor add1: inck # increment the quotient lp B_REG # Point P to B reg sbm # [P] - A -> [P], B=B-A #if B=0 we are done cpim 0 # B == 0? jpz done1 # yup, B == 0 #if B < A we are done, and B will be the remainder cpma # compare B and A jpc done1 # B < A jp add1 done1: lidp quotient # storing the quotient lp K_REG exam # A [P], A now contains K, the quotient std # quotient is now stored lidp remainder # storing the remainer exab # A B, A now contains the remainder std # remainder is now stored rtn multiply: lidp multiplicand # load multiplicand into B ldd exab # B now contains multiplicand lidp multiplier # load multiplier into A ldd deca # correction for loop jpc doneZero # multipling by 0 # keep adding A to B push # push A onto stack for loop, to add B to B A times lidp multiplicand # load multiplicand into A now, so A+B is same as B+B ldd lp B_REG # point to B reg add2: adm # [P] + A -> [P], B=B+A loop add2 sbm # [P] - A -> P,B=B-A to correct for one extra addition in loop done2: exab # A B, A now contains product lidp product # storing A to product std # A -> [DP] store A rtn doneZero: ra # store 0 into product lidp product std rtn Feel free to drop me a line at eightbit at axorion dot com. You can also start a thread on [Simons Pocket Computer Forum](http://30122.forumromanum.com/member/forum/forum.php?action=std_tindex&USER=user_30122&threadid=2). Best to let me know you did though, in case I don't see your forum entry right away.
Here we are again. For my first tutorial, see Assembly #1 Reverse a string. Bill set me up for a second challenge, and I took it up. This is another great bite sized exercise to learn how to compare blocks of memory. In this exercise we will compare 2 strings and let the user know if they are equal. We will make use of BASIC again to:
The purpose of this project is to write another simple assembly language program, and learn to use a few more assembly mnemonics. Specifically the ones for comparing values. You will want to make sure you use the $JR
compiler directive to make jumps easier.
The mnemonics for comparing are:
MNEMONIC OPERATION FLAGS EFFECTED
CPIM n [P] - n C,Z
CPIA n A - n C,Z
CPMA [P] - A C,Z
Use the following truth table to figure out what flags will be set.
TRUTH TABLE
EXAMPLE FLAGS MEANING
4 - 5 C=1,Z=0 left < right
5 - 5 C=0,Z=1 left = right
6 - 5 C=0,Z=0 left > right
You’re likely to find CPMA
is the real workhorse when dealing with data. CPIA
and CPIM
are used when dealing with known values; Like if you want to see if something equals 0.
Once you have compared, you will use a branch mnemonic to jump to a new piece of code.
MNEMONIC OPERATION
JPNZ nm jump to nm if Z=0
JPNC nm jump to nm if C=0
JPZ nm jump to nm if Z=1
JPC nm jump to nm if C=1
JP nm jump to nm regardless of flags
As an example, lets say you want to see if the A reg
equals the number 5. You would use the following code:
CMIA 5 # A - n, check if A reg is 5
JPZ PLACE1
# continue as A is not 5
RTN
PLACE1: # A is 5
RTN
JPZ
jumps to PLACE1
if the zero flag was set, which according to the truth table means A equals 5.
This will be our memory setup. Program start is 49217.
ADDRESS ASM VAR COMMENT
49200 RESULT Result (1 equal | 0 not equal)
49201 - 49207 SRC1 String 1
49208 SRCLEN1 Length of string 1
49209 - 49215 SRC2 String 2
49216 SRCLEN2 Length of string 2
49217 Program start
Our assembly program will compare the 2 strings SRC1
and SRC2
, making note of the string lengths SRCLEN1
& SRCLEN2
, and store the result in address RESULT
(49200).
Compile and load at address 49200 (&C030). bin2wav.exe --type=bin --pc=1360 --addr=0xC030 output.bin
and CLOAD M
on your pocket computer.
##############################################################################
# Compare the strings SRC1 and SRC2 to see if they
# are equal. Store 0 in RESULT if no, 1 if they are.
##############################################################################
$JR
org &C030
I_REG EQU 0 # Internal Registers
J_REG EQU 1
A_REG EQU 2
B_REG EQU 3
XL_REG EQU 4
XH_REG EQU 5
YL_REG EQU 6
YH_REG EQU 7
K_REG EQU 8
L_REG EQU 9
M_REG EQU 10
N_REG EQU 11
PORTC EQU 95
# define data and put some dummy data in place
RESULT: DB 0
SRC1: DB 48 49 50 51 52 53 54
SRCLEN1: DB 1
SRC2: DB 65 66 67 68 69 70 71
SRCLEN2: DB 1
START:
# Point the X register to SRC1
LP XH_REG # P [P]
LP XL_REG # P [P] => X now contains SRC1
DX # prep for ++X inside check1
# Point the Y register to SRC2
LP YH_REG # P [P]
LP YL_REG # P [P] => Y now contains SRC2
DY # prep for ++Y inside check1
# put srclen1 into A and srclen2 into B
LIDP SRCLEN2
LDD # [DP] -> A - srclen -> A
EXAB # A B - B contains srclen2
LIDP SRCLEN1
LDD # A contains srclen1
# check if strings are the same length
LP B_REG # P points to B reg
CPMA # [P] - A -> C,Z # compare A and B
JPNZ NOT_EQUAL
# check byte by byte to see if the strings are the same length
lp K_REG
exam # K now contains srclen1
check1:
# put src1 bytes into A, src2 bytes into B, then compare A & B
# load B from Y
iy # ++Y -> DP
ldd # [Y] -> A
exab # B contains [Y]
# load A from X
ixl # ++X -> DP, [DP] -> A
lp B_REG
cpma # compare A and B
jpnz not_equal
# decrement K reg
deck
jpnz check1 # keep checking
# fall through into equal
equal:
lidp result
lia 1
std
rtn
not_equal:
lidp result
ra # 0 -> A
std
rtn
You can type RUN
to start this program once loaded.
100 "S" WAIT 0
110 A=49201:R=49200
120 INPUT "String 1:";X$
130 INPUT "String 2:";Y$
135 PRINT "POKING"
140 K = LEN X$
150 L = LEN Y$
200 FOR I=1 TO K
205 V = ASC(MID$(X$,I,1))
210 POKE A,V
220 A=A+1
230 NEXT I
240 A=49209
250 FOR I=1 TO L
265 V = ASC(MID$(Y$,I,1))
270 POKE A,V
280 A=A+1
290 NEXT I
295 POKE 49208,K : POKE 49216,L
300 PRINT "CALLING ML"
310 CALL 49217
320 IF PEEK 49200 = 0 PRINT "NOT EQUAL"
330 IF PEEK 49200 = 1 PRINT "EQUAL"
Feel free to drop me a line at eightbit at axorion dot com. You can also start a thread on Simons Pocket Computer Forum. Best to let me know you did though, in case I don’t see your forum entry right away.
Copyright © 2025, Lee Patterson