Registers
{
a | Accumulator | 8-bit | Main working register
x/y | Index registers | 8-bit | Generally used for array access
ya | y << 8 OR a | 16-bit | Concatenation of y and a
sp | Stack pointer | 8-bit | Index added to $0100. Gives the location of the first free byte on the stack. Decrements when pushed to, increments when pulled from
pc | Program counter | 16-bit | The address of the next instruction to execute
psw | Processor status word | 8-bit | Contains some flags concerning the CPU state:
{
1 | c: Carry flag | See adc/sbc/cmp/asl/lsr/rol/ror/daa/das and *1 instructions
2 | z: Zero flag | Set if the result of an operation is zero
8 | h: Half-carry flag | See adc/sbc/daa/das/div
20h | p: Direct page location | p * 100h used as direct page base address
40h | v: Overflow flag | See adc/sbc/div
80h | n: Negative flag | Set if the result of an operation is negative (most significant bit is set)
}
}
Let DP = psw.p * 100h be the direct page base address.
mov
{
Move a value to/from a register
Loads set PSR.Z and PSR.N according to the value loaded (except mov sp,x)
Stores don't affect PSR
7D | mov a,x | a = x
5D | mov x,a | x = a
DD | mov a,y | a = y
FD | mov y,a | y = a
9D | mov x,sp | x = sp
BD | mov sp,x | sp = x
FA ss dd | mov (dd),(ss) | dd + DP = [ss + DP]
E8 nn | mov a,#nn | a = nn
CD nn | mov x,#nn | x = nn
8D nn | mov y,#nn | y = nn
8F nn dd | mov dd,#nn | dd + DP = nn
E5 ssss | mov a,ssss | a = [ssss]
E9 ssss | mov x,ssss | x = [ssss]
EC ssss | mov y,ssss | y = [ssss]
E4 ss | mov a,ss | a = [ss + DP]
F8 ss | mov x,ss | x = [ss + DP]
EB ss | mov y,ss | y = [ss + DP]
C5 dddd | mov dddd,a | dddd = a
C9 dddd | mov dddd,x | dddd = x
CC dddd | mov dddd,y | dddd = y
C4 dd | mov dd,a | dd + DP = a
D8 dd | mov dd,x | dd + DP = x
CB dd | mov dd,y | dd + DP = y
F5 ssss | mov a,ssss+x | a = [ssss + x]
F6 ssss | mov a,ssss+y | a = [ssss + y]
F4 ss | mov a,ss+x | a = [ss + DP + x]
F9 ss | mov x,ss+y | x = [ss + DP + y]
FB ss | mov y,ss+x | y = [ss + DP + x]
D5 dddd | mov dddd+x,a | dddd + x = a
D6 dddd | mov dddd+y,a | dddd + y = a
D4 dd | mov dd+x,a | dd + DP + x = a
DB dd | mov dd+x,y | dd + DP + x = y
D9 dd | mov dd+y,x | dd + DP + y = x
E6 | mov a,(x) | a = [ss + DP] where ss = [x + DP]
BF | mov a,(x)+ | a = [ss + DP] where ss = [x + DP], x += 1
C6 | mov (x),a | ss + DP = a where ss = [x + DP]
AF | mov (x)+,a | ss + DP = a where ss = [x + DP], x += 1
F7 ss | mov a,(ss)+y | a = [tttt + y] where tttt = [ss + DP]
D7 dd | mov (dd)+y,a | tttt + y = a where tttt = [dd + DP]
E7 ss | mov a,(ss+x) | a = [tttt] where tttt = [ss + DP + x]
C7 dd | mov (dd+x),a | tttt = a where tttt = [dd + DP + x]
}
cmp
{
Compare with memory
Sets psw.z/psw.n/psw.c flags according to the result of subtraction
Unlike sbc, this operation isn't affected by psw.c and doesn't set psw.v
Let lhs and rhs be the left and right side operands:
psw.z is set if lhs - rhs = 0
psw.n is set if 80h <= lhs - rhs <= FFh
psw.c is set if subtraction doesn't exceed the range of unsigned numbers,
i.e. unsigned(lhs) - unsigned(rhs) >= 0 (like ARM and unlike x86/z80)
Thus:
If lhs = rhs, then psw.z = 1
If unsigned(lhs) >= unsigned(rhs), then psw.c = 1
If signed(lhs) >= signed(rhs), then psw.n = 0 (assuming no overflow)
69 dd ss | cmp (dd),(ss) | [dd + DP] - [ss + DP]
68 nn | cmp a,#nn | a - nn
C8 nn | cmp x,#nn | x - nn
AD nn | cmp y,#nn | y - nn
78 nn dd | cmp dd,#nn | [dd + DP] - nn
65 ssss | cmp a,ssss | a - [ssss]
1E ssss | cmp x,ssss | x - [ssss]
5E ssss | cmp y,ssss | y - [ssss]
64 ss | cmp a,ss | a - [ss + DP]
3E ss | cmp x,ss | x - [ss + DP]
7E ss | cmp y,ss | y - [ss + DP]
75 ssss | cmp a,ssss+x | a - [ssss + x]
76 ssss | cmp a,ssss+y | a - [ssss + y]
74 ss | cmp a,ss+x | a - [ss + DP + x]
66 | cmp a,(x) | a - [ss + DP] where ss = [x + DP]
79 | cmp (x),(y) | [dd + DP] - [ss + DP] where dd = [x + DP], ss = [y + DP]
77 ss | cmp a,(ss)+y | a - [tttt + y] where tttt = [ss + DP]
67 ss | cmp a,(ss+x) | a - [tttt] where tttt = [ss + DP + x]
}
adc/sbc/and/or/eor
{
adc: Add with carry
sbc: Subtract with carry
and: Bitwise AND
or: Bitwise OR
eor: Bitwise XOR
adc/sbc notes
{
Let lhs and rhs be the left and right side operands:
sbc sets the carry/overflow flags as:
psw.c is set if subtraction doesn't exceed the range of unsigned numbers (like 65816/ARM and unlike x86/z80),
i.e. unsigned(lhs) - unsigned(rhs) + psw.c - 1 >= 0
psw.v is set if subtraction exceeds the range of signed numbers,
i.e. not 80h <= signed(lhs) - signed(rhs) + psw.c - 1 <= 7Fh
adc sets the carry/overflow flags as:
psw.c is set if addition exceeds the range of unsigned numbers,
i.e. unsigned(lhs) + unsigned(rhs) + psw.c > FFh
psw.v is set if addition exceeds the range of signed numbers,
i.e. not 80h <= signed(lhs) + signed(rhs) + psw.c <= 7Fh
psw.h set whenever adc/sbc causes a carry to be propagated from the low nybble to the high nybble, i.e.
for adc: (lhs & Fh) + (rhs & Fh) + psw.c > Fh
for sbc: (lhs & Fh) - (rhs & Fh) + psw.c - 1 < 0
The reason adc/sbc involves the carry is for multiprecision variables. E.g.:
Suppose:
$01 contains an 8-bit position
$00 contains an 8-bit subpixel position (where there are 100h subpixels per pixel)
$11 contains an 8-bit speed
$10 contains an 8-bit subpixel speed
Then to add the speed to the position, one could do:
clrc ; Clear the carry so that the first addition is correct
adc $00,$10 ; Add the subpixel values, the carry is propagated to the next ADC
adc $01,$11 ; Add the pixel values along with the carry
To subtract the speed, one could do:
setc
sbc $00,$10
sbc $01,$11
}
89 dd ss | adc (dd),(ss) | dd + DP = [dd + DP] + [ss + DP] + psw.c
A9 dd ss | sbc (dd),(ss) | dd + DP = [dd + DP] - [ss + DP] + psw.c - 1
29 dd ss | and (dd),(ss) | dd + DP = [dd + DP] AND [ss + DP]
09 dd ss | or (dd),(ss) | dd + DP = [dd + DP] OR [ss + DP]
49 dd ss | eor (dd),(ss) | dd + DP = [dd + DP] XOR [ss + DP]
88 nn | adc a,#nn | a = a + nn + psw.c
A8 nn | sbc a,#nn | a = a - nn + psw.c - 1
28 nn | and a,#nn | a = a AND nn
08 nn | or a,#nn | a = a OR nn
48 nn | eor a,#nn | a = a XOR nn
98 nn dd | adc dd,#nn | dd + DP = [dd + DP] + nn + psw.c
B8 nn dd | sbc dd,#nn | dd + DP = [dd + DP] - nn + psw.c - 1
38 nn dd | and dd,#nn | dd + DP = [dd + DP] AND nn
18 nn dd | or dd,#nn | dd + DP = [dd + DP] OR nn
58 nn dd | eor dd,#nn | dd + DP = [dd + DP] XOR nn
85 ssss | adc a,ssss | a = a + [ssss] + psw.c
A5 ssss | sbc a,ssss | a = a - [ssss] + psw.c - 1
25 ssss | and a,ssss | a = a AND [ssss]
05 ssss | or a,ssss | a = a OR [ssss]
45 ssss | eor a,ssss | a = a XOR [ssss]
84 ss | adc a,ss | a = a + [ss + DP] + psw.c
A4 ss | sbc a,ss | a = a - [ss + DP] + psw.c - 1
24 ss | and a,ss | a = a AND [ss + DP]
04 ss | or a,ss | a = a OR [ss + DP]
44 ss | eor a,ss | a = a XOR [ss + DP]
95 ssss | adc a,ssss+x | a = a + [ssss + x] + psw.c
B5 ssss | sbc a,ssss+x | a = a - [ssss + x] + psw.c - 1
35 ssss | and a,ssss+x | a = a AND [ssss + x]
15 ssss | or a,ssss+x | a = a OR [ssss + x]
55 ssss | eor a,ssss+x | a = a XOR [ssss + x]
96 ssss | adc a,ssss+y | a = a + [ssss + y] + psw.c
B6 ssss | sbc a,ssss+y | a = a - [ssss + y] + psw.c - 1
36 ssss | and a,ssss+y | a = a AND [ssss + y]
16 ssss | or a,ssss+y | a = a OR [ssss + y]
56 ssss | eor a,ssss+y | a = a XOR [ssss + y]
94 ss | adc a,ss+x | a = a + [ss + DP + x] + psw.c
B4 ss | sbc a,ss+x | a = a - [ss + DP + x] + psw.c - 1
34 ss | and a,ss+x | a = a AND [ss + DP + x]
14 ss | or a,ss+x | a = a OR [ss + DP + x]
54 ss | eor a,ss+x | a = a XOR [ss + DP + x]
86 | adc a,(x) | a = a + [ss + DP] + psw.c where ss = [x + DP]
A6 | sbc a,(x) | a = a - [ss + DP] + psw.c - 1 where ss = [x + DP]
26 | and a,(x) | a = a AND [ss + DP] where ss = [x + DP]
06 | or a,(x) | a = a OR [ss + DP] where ss = [x + DP]
46 | eor a,(x) | a = a XOR [ss + DP] where ss = [x + DP]
99 | adc (x),(y) | dd + DP = [dd + DP] + [ss + DP] + psw.c where dd = [x + DP], ss = [y + DP]
B9 | sbc (x),(y) | dd + DP = [dd + DP] - [ss + DP] + psw.c - 1 where dd = [x + DP], ss = [y + DP]
39 | and (x),(y) | dd + DP = [dd + DP] AND [ss + DP] where dd = [x + DP], ss = [y + DP]
19 | or (x),(y) | dd + DP = [dd + DP] OR [ss + DP] where dd = [x + DP], ss = [y + DP]
59 | eor (x),(y) | dd + DP = [dd + DP] XOR [ss + DP] where dd = [x + DP], ss = [y + DP]
97 ss | adc a,(ss)+y | a = a + [tttt + y] + psw.c where tttt = [ss + DP]
B7 ss | sbc a,(ss)+y | a = a - [tttt + y] + psw.c - 1 where tttt = [ss + DP]
37 ss | and a,(ss)+y | a = a AND [tttt + y] where tttt = [ss + DP]
17 ss | or a,(ss)+y | a = a OR [tttt + y] where tttt = [ss + DP]
57 ss | eor a,(ss)+y | a = a XOR [tttt + y] where tttt = [ss + DP]
87 ss | adc a,(ss+x) | a = a + [tttt] + psw.c where tttt = [ss + DP + x]
A7 ss | sbc a,(ss+x) | a = a - [tttt] + psw.c - 1 where tttt = [ss + DP + x]
27 ss | and a,(ss+x) | a = a AND [tttt] where tttt = [ss + DP + x]
07 ss | or a,(ss+x) | a = a OR [tttt] where tttt = [ss + DP + x]
47 ss | eor a,(ss+x) | a = a XOR [tttt] where tttt = [ss + DP + x]
}
inc/dec / asl/lsr / rol/ror
{
inc: Increment
dec: Decrement
asl: (Arithmetic) shift left
lsr: Logical shift right
rol: Rotate left with carry
ror: Rotate right with carry
rol/ror are like asl/lsr instructions that operate on the 9-bit concatenation of a with psw.c,
that is, the bit shifted out of a by rol/ror is shifted into psw.c, the old psw.c bit being shifted in to a
The reason rol/ror exists is for multiprecision variables. E.g.:
Suppose:
$01 contains an 8-bit speed
$00 contains an 8-bit subpixel speed (where there are 100h subpixels per pixel)
Then to multiply the speed by 2, one would do asl $00 : rol $01
Or if dividing the speed by 2, one would do lsr $01 : ror $00
BC | inc a | a = a + 1
3D | inc x | x = x + 1
FC | inc y | y = y + 1
9C | dec a | a = a - 1
1D | dec x | x = x - 1
DC | dec y | y = y - 1
1C | asl a | a = a << 1
5C | lsr a | a = a >> 1
3C | rol a | a = a << 1, a.LSb = psw.c
7C | ror a | a = a >> 1, a.MSb = psw.c
AC dddd | inc dddd | dddd = [dddd] + 1
8C dddd | dec dddd | dddd = [dddd] - 1
0C dddd | asl dddd | dddd = [dddd] << 1
4C dddd | lsr dddd | dddd = [dddd] >> 1
2C dddd | rol dddd | dddd = [dddd] << 1, a.LSb = psw.c
6C dddd | ror dddd | dddd = [dddd] >> 1, a.MSb = psw.c
AB dd | inc dd | dd + DP = [dd + DP] + 1
8B dd | dec dd | dd + DP = [dd + DP] - 1
0B dd | asl dd | dd + DP = [dd + DP] << 1
4B dd | lsr dd | dd + DP = [dd + DP] >> 1
2B dd | rol dd | dd + DP = [dd + DP] << 1, a.LSb = psw.c
6B dd | ror dd | dd + DP = [dd + DP] >> 1, a.MSb = psw.c
BB dd | inc dd+x | dd + DP + x = [dd + DP + x] + 1
9B dd | dec dd+x | dd + DP + x = [dd + DP + x] - 1
1B dd | asl dd+x | dd + DP + x = [dd + DP + x] << 1
5B dd | lsr dd+x | dd + DP + x = [dd + DP + x] >> 1
3B dd | rol dd+x | dd + DP + x = [dd + DP + x] << 1, a.LSb = psw.c
7B dd | ror dd+x | dd + DP + x = [dd + DP + x] >> 1, a.MSb = psw.c
}
movw / addw/subw/cmpw / incw/decw / mul/div
{
movw: Move word
addw: Add word
subw: Subtract word
cmpw: Compare word
incw: Increment word
decw: Decrement word
mul: Multiply (unsigned)
div: Divide (unsigned)
{
movw/cmpw/incw/decw are straight-forward 16-bit extensions and set the psw flags in the same way
Unlike adc/sbc, addw/subw aren't affected by psw.c (but still set psw.z/psw.n/psw.c/psw.v as expected)
addw/subw set psw.h according to adc/sbc on the upper bytes of the operands (with the carry of the operation on the lower bytes)
mul sets psw.z depending on y only (and sets psw.n as expected)
div sets psw.v if ya / x >= 100h and sets psw.h if y & Fh >= x & Fh
div sets psw.n and psw.z from the resulting quotient a
div gives the expected results provided ya / x < 200h, equivalently y < x*2. Otherwise results are given by:
a = FFh - (ya - x * 200h) / (100h - x)
y = x + (ya - x * 200h) % (100h - x)
}
DA dd | movw dd,ya | dd + DP = ya
BA ss | movw ya,ss | ya = [ss + DP]
7A ss | addw ya,ss | ya = ya + [ss + DP]
9A ss | subw ya,ss | ya = ya - [ss + DP]
5A ss | cmpw ya,ss | ya - [ss + DP]
3A dd | incw dd | dd + DP = [dd + DP] + 1
1A dd | decw dd | dd + DP = [dd + DP] - 1
CF | mul ya | ya = y * a
9E | div ya,x | a = ya / x, y = ya % x
}
clr*/set*/not1 / clrc/setc/notc / clrv / mov1 / and1/or1/eor1
{
clr*: Clear bit
set*: Set bit
not1: Bitwise NOT 1 bit
clrc: Clear carry
setc: Set carry
notc: Bitwise NOT carry
clrv: Clear overflow (and half carry)
mov1: Move 1 bit
and1: Bitwise AND 1 bit
or1: Bitwise OR 1 bit
eor1: Bitwise XOR 1 bit
No other psw flags are set than those explicitly described below
The address range of not1/mov1/or1/and1/eor1 is 13 bits ($0000..1FFF)
12 dd | clr0 dd | dd + DP = [dd + DP] AND NOT 1
32 dd | clr1 dd | dd + DP = [dd + DP] AND NOT 2
52 dd | clr2 dd | dd + DP = [dd + DP] AND NOT 4
72 dd | clr3 dd | dd + DP = [dd + DP] AND NOT 8
92 dd | clr4 dd | dd + DP = [dd + DP] AND NOT 10h
B2 dd | clr5 dd | dd + DP = [dd + DP] AND NOT 20h
D2 dd | clr6 dd | dd + DP = [dd + DP] AND NOT 40h
F2 dd | clr7 dd | dd + DP = [dd + DP] AND NOT 80h
02 dd | set0 dd | dd + DP = [dd + DP] OR 1
22 dd | set1 dd | dd + DP = [dd + DP] OR 2
42 dd | set2 dd | dd + DP = [dd + DP] OR 4
62 dd | set3 dd | dd + DP = [dd + DP] OR 8
82 dd | set4 dd | dd + DP = [dd + DP] OR 10h
A2 dd | set5 dd | dd + DP = [dd + DP] OR 20h
C2 dd | set6 dd | dd + DP = [dd + DP] OR 40h
E2 dd | set7 dd | dd + DP = [dd + DP] OR 80h
60 | clrc | psw.c = 0
80 | setc | psw.c = 1
ED | notc | psw.c = psw.c ^ 1
E0 | clrv | psw.v = psw.h = 0
; ssss/dddd = xxxx & 0x1FFF, b = xxxx >> Dh
AA xxxx | mov1 c,ssss,b | psw.c = [ssss] >> b AND 1
0A xxxx | or1 c,ssss,b | psw.c = psw.c OR [ssss] >> b AND 1
2A xxxx | or1 c,!(ssss,b) | psw.c = psw.c OR NOT [ssss] >> b AND 1
4A xxxx | and1 c,ssss,b | psw.c = psw.c AND [ssss] >> b
6A xxxx | and1 c,!(ssss,b) | psw.c = psw.c AND NOT [ssss] >> b
8A xxxx | eor1 c,ssss,b | psw.c = psw.c XOR [ssss] >> b AND 1
EA bddd | not1 dddd,b | dddd = [dddd] XOR (1 << b)
CA bddd | mov1 dddd,b,c | dddd = [dddd] AND NOT (1 << b) OR (psw.c << b)
}
xcn / tclr1/tset1 / daa/das
{
xcn: Exchange nybbles
tclr1: Test and clear bits (not limited to one bit)
tset1: Test and set bits (not limited to one bit)
daa: Decimal adjust addition
das: Decimal adjust subtraction
xcn sets psw.n and psw.z according to result (as one would expect)
tclr1/tset1 set psw.n and psw.z according to [dddd] - a (as if by cmp) before dddd is modified
daa/das set psw.c as adc/sbc do, i.e.
daa sets psw.c if BCD conversion propagates a carry
das clears psw.c if BCD conversion requires a borrow
daa/das notes
{
daa and das are instructions that correct the result of adc/sbc on two BCD values respectively.
They cannot be used in any way to convert an arbitrary hexadecimal number to BCD.
For daa:
If psw.h is set, then the sum of the low nybbles that were added together by adc exceeded 10h,
in this case, daa adds 6 to a to skip over the hexadecimal digits A-F,
e.g. 19h + 19h sets a = 32h and psw.h = 1, daa then adds 6 to get 38h as expected
If l >= Ah, then daa adds 6 to a (again, to skip over the hexadecimal digits A..F),
e.g. 19h + 16h sets a = 2Fh and psw.h = 0, daa then adds 6 to get 35h as expected
If psw.c is set, then the sum of the values that were added together by adc exceeded 100h
in this case, daa adds 60h to a (to skip over the hexadecimal values A0h..FFh),
e.g. 90h + 90h sets a = 20h and psw.c = 1, daa then adds 60h to get 80h (and psw.c = 1) as expected
If a >= A0h, then daa adds 60h to a (to skip over the hexadecimal values A0h..FFh) and sets psw.c = 1 accordingly,
e.g. 90h + 60h sets a = F0h and psw.c = 0, daa then adds 60h to get 50h and psw.c = 1 as expected
Final example:
99h + 99h sets a = 32h, psw.h = psw.c = 1
daa adds 66h because both psw.h and psw.c are set
Result is a = 98h with psw.c = 1
Usage for adding multiprecision variables:
Suppose there is a 6 digit score that needs updating:
$00..02 contains the 6-digit score in little endian (in BCD)
$10..11 contains the 4-digit number of points to add (in BCD)
Then to add the points to the score, one would do:
clrc ; Clear the carry so that the first addition is correct
mov a,$00 : adc a,$10 : daa : mov $00,a ; Add the least significant 2 digits, carry is propagated to next adc irrespective of whether it came from adc or daa
mov a,$01 : adc a,$11 : daa : mov $01,a ; Add the middle 2 digits, ""
mov a,$02 : adc a,#0 : daa : mov $02,a ; Propagate carry to most significant 2 digits
das works the same way, except that the psw.c/psw.h have the inverted meanings and 6/60h is subtracted rather than added
}
9F | xcn a | a = (a AND Fh) << 4 OR (a >> 4)
4E dddd | tclr1 dddd | dddd = [dddd] AND NOT a
0E dddd | tset1 dddd | dddd = [dddd] OR a
DF | daa a | Converts the result of an adc of two BCD values to BCD
BE | das a | Converts the result of an sbc of two BCD values to BCD
}
bra/bcc/bcs/bne/beq/bpl/bmi/bvc/bvs / bbs*/bbc* / cbne / dbnz
{
bra: Branch
bcc: Branch if carry clear
bcs: Branch if carry set
bne: Branch if not equal
beq: Branch if equal
bpl: Branch if plus
bmi: Branch if minus
bvc: Branch if overflow clear
bvs: Branch if overflow set
bbc*: Branch if bit clear
bbs*: Branch if bit set
cbne: Compare and branch if not equal
dbnz: Decrement and branch if not zero
No psw flags are set (even cbne/dbnz)
Note that bne/beq can be misleading names, especially after AND. In practice, they're more like bzc/bzs
2F oo | bra oo | pc = pc + signed(oo)
90 oo | bcc oo | pc = pc + signed(oo) if psw.c = 0
B0 oo | bcs oo | pc = pc + signed(oo) if psw.c = 1
D0 oo | bne oo | pc = pc + signed(oo) if psw.z = 0
F0 oo | beq oo | pc = pc + signed(oo) if psw.z = 1
10 oo | bpl oo | pc = pc + signed(oo) if psw.n = 0
30 oo | bmi oo | pc = pc + signed(oo) if psw.n = 1
50 oo | bvc oo | pc = pc + signed(oo) if psw.v = 0
70 oo | bvs oo | pc = pc + signed(oo) if psw.v = 1
13 ss oo | bbc0 ss,oo | pc = pc + signed(oo) if [ss + DP] AND 1 = 0
33 ss oo | bbc1 ss,oo | pc = pc + signed(oo) if [ss + DP] AND 2 = 0
53 ss oo | bbc2 ss,oo | pc = pc + signed(oo) if [ss + DP] AND 4 = 0
73 ss oo | bbc3 ss,oo | pc = pc + signed(oo) if [ss + DP] AND 8 = 0
93 ss oo | bbc4 ss,oo | pc = pc + signed(oo) if [ss + DP] AND 10h = 0
B3 ss oo | bbc5 ss,oo | pc = pc + signed(oo) if [ss + DP] AND 20h = 0
D3 ss oo | bbc6 ss,oo | pc = pc + signed(oo) if [ss + DP] AND 40h = 0
F3 ss oo | bbc7 ss,oo | pc = pc + signed(oo) if [ss + DP] AND 80h = 0
03 ss oo | bbs0 ss,oo | pc = pc + signed(oo) if [ss + DP] AND 1 != 0
23 ss oo | bbs1 ss,oo | pc = pc + signed(oo) if [ss + DP] AND 2 != 0
43 ss oo | bbs2 ss,oo | pc = pc + signed(oo) if [ss + DP] AND 4 != 0
63 ss oo | bbs3 ss,oo | pc = pc + signed(oo) if [ss + DP] AND 8 != 0
83 ss oo | bbs4 ss,oo | pc = pc + signed(oo) if [ss + DP] AND 10h != 0
A3 ss oo | bbs5 ss,oo | pc = pc + signed(oo) if [ss + DP] AND 20h != 0
C3 ss oo | bbs6 ss,oo | pc = pc + signed(oo) if [ss + DP] AND 40h != 0
E3 ss oo | bbs7 ss,oo | pc = pc + signed(oo) if [ss + DP] AND 80h != 0
2E ss oo | cbne ss,oo | pc = pc + signed(oo) if a != [ss + DP]
DE ss oo | cbne ss+x,oo | pc = pc + signed(oo) if a != [ss + DP + x]
FE oo | dbnz y,oo | y = y - 1, pc = pc + signed(oo) if y != 0
6E dd oo | dbnz dd,oo | dd + DP = [dd + DP] - 1, pc = pc + signed(oo) if y != 0
}
jmp/call / tcall/pcall/brk / ret/reti
{
jmp: Jump
call: Call
tcall: Table call
pcall: Uppermost page call
brk: Breakpoint interrupt
ret: Return
reti: Return from interrupt
No psw flags are set (except reti)
5F dddd | jmp dddd | pc = dddd
1F dddd | jmp (dddd+x) | pc = [dddd + x]
3F dddd | call dddd | Push pc, pc = dddd
n1 | tcall n | Push pc, pc = [$FFDE - n * 2]
4F dd | pcall dd | Push pc, pc = $FF00 + dd
0F | brk | Push pc, push psw, pc = [$FFDE]
6F | ret | Pull to pc
7F | reti | Pull to psw, pull to pc
}
push/pop
{
Push to stack / pop to registers
No psw flags are set (except pop psw)
Pushing register r onto the stack means:
[sp] = r
sp -= 1
Conversely, pulling to r from the stack means:
sp += 1
[sp] = r
2D | push a | Push a
AE | pop a | Pop to a
4D | push x | Push x
CE | pop x | Pop to x
6D | push y | Push y
EE | pop y | Pop to y
0D | push psw | Push psw
8E | pop psw | Pop to psw
}
sleep/stop / clrp/setp / di/ei / nop
{
EF | sleep | Sleep until interrupt occurs (interrupts cannot occur)
FF | stop | Kill CPU
20 | clrp | psw.p = 0
40 | setp | psw.p = 1
C0 | di | psw.i = 0 (interrupt flag not doc'd here)
A0 | ei | psw.i = 1 (interrupt flag not doc'd here)
00 | nop | Nothing
}