Initial commit (a clone of the jsmachines project as of v1.15.3)

This commit is contained in:
jeffpar 2014-09-27 14:52:57 -07:00
commit a5e3e6a59d
714 changed files with 130602 additions and 0 deletions

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1 @@
.0000/A9 07 85 FF A9 00 85 FE A8 A2 19 91 FE C8 D0 FB E6 FF CA D0 F6 A9 20 A2 00 9D 00 D0 9D 00 D1 9D 00 D2 9D 00 D3 E8 D0 F1 A9 85 85 FE A9 D0 85 FF A9 25 85 FC A9 D3 85 FD A0 14 A9 80 91 FE A9 87 91 FC 88 D0 F5 A2 14 A0 00 A5 FE 18 69 20 85 FE 90 02 E6 FF A9 8F 91 FE A0 15 A9 88 91 FE CA D0 E6 A9 07 85 FF 4C 71 05 EA 85 FD 85 FC 85 F9 85 F8 85 F7 85 F6 85 F0 A9 A6 85 A5 A9 D0 85 A6 A5 FF 85 9A A5 FE 85 99 A5 FD 10 03 18 69 50 85 FB A9 14 85 FA A2 00 A4 FB B9 40 0D 4A 90 04 A9 F0 B0 02 A9 2E 9D 26 D3 C8 C0 50 D0 02 A0 00 E8 A5 F0 4A 90 11 E0 14 F0 11 84 F5 8A A8 A9 AB 91 A5 A4 F5 20 69 03 E0 14 D0 CF A5 99 18 69 50 85 99 90 02 E6 9A A9 20 C5 9A D0 04 A9 07 85 9A A5 A5 18 69 20 85 A5 90 02 E6 A6 C6 FA D0 A7 4C 5F 02 82 .0222/00 01 00 0A 00 64 03 E8 27 10 00 00 00 00 A4 FA 91 F1 E6 FA 60 A0 00 38 A5 F3 FD 21 02 85 F5 CA A5 F4 FD 21 02 90 0A E8 C8 85 F4 A5 F5 85 F3 B0 E7 E8 98 09 30 20 30 02 CA CA D0 D9 60 A9 46 85 F1 A9 D3 85 F2 A2 08 A5 F8 85 F3 A5 F9 85 F4 A9 00 85 FA 20 37 02 A9 20 20 30 02 A9 28 20 30 02 4C A1 02 48 30 04 A9 2B 10 02 A9 2D 20 30 02 68 10 05 18 49 FF 69 01 85 F3 A2 04 20 37 02 60 A9 00 85 F4 A5 FD 20 85 02 A9 2C 20 30 02 A5 FC 20 85 02 EA A9 29 20 30 02 A9 20 20 30 02 A5 F6 85 F3 A5 F7 85 F4 A2 0A 20 37 02 4C EC 02 C9 50 D0 05 EA A9 00 F0 04 C9 B0 F0 F8 A0 10 CA D0 FD 88 D0 FA 60 8D 00 DF AD 00 DF 60 A9 7F 4C 57 05 C9 7F D0 0C E6 FD A5 FD 20 CF 02 85 FD 4C 60 03 A9 7F 20 E5 02 C9 BF D0 05 C6 FD 4C F7 02 A9 7F 20 E5 02 C9 DF D0 21 E6 FC A5 FC 20 CF 02 85 FC 38 A5 FE E9 50 85 FE B0 02 C6 FF A9 06 C5 FF D0 04 A9 1F 85 FF 4C 60 03 A9 7F 20 E5 02 C9 EF D0 33 C6 FC A5 FC 20 CF 02 85 FC 18 A5 FE 69 50 85 FE 90 02 E6 FF A9 20 C5 FF D0 04 A9 07 85 FF A9 7E 25 F0 85 F0 4C 77 00 A9 15 C6 F1 D0 FC 18 69 FF D0 F7 60 A5 F0 0A 90 03 4C 8F 03 E0 C0 F0 04 A2 C0 86 F2 20 69 03 E6 F2 F0 EE 4C EC 02 A5 F0 4A 4A B0 09 A5 F0 09 02 85 F0 4C AF 03 A9 FE 20 E5 02 C9 DE F0 08 4C 9B 04 A5 FB 91 F1 60 A9 00 85 FA A9 A6 85 F1 A9 D0 85 F2 A0 00 B1 F1 85 FB A9 AB 91 F1 20 00 FD C9 0A D0 0C A5 F0 49 01 85 F0 20 AA 03 4C A7 03 C9 32 D0 0A C0 13 F0 E5 20 AA 03 C8 D0 D7 C9 31 D0 0A C0 00 F0 F0 20 AA 03 88 10 C9 C9 33 D0 18 A9 13 C5 FA F0 EE E6 FA 20 AA 03 18 A9 20 65 F1 85 F1 90 02 E6 F2 D0 D4 C9 34 D0 19 A9 00 C5 FA F0 E2 C6 FA 20 AA 03 38 A5 F1 E9 20 85 F1 B0 02 C6 F2 4C BD 03 C9 0D D0 03 4C D2 03 C9 50 D0 5C A5 FE 85 F3 A5 FF 85 F4 A5 FA 85 F5 A9 00 C5 F5 F0 19 18 A5 F3 69 50 85 F3 90 02 E6 F4 A9 20 C5 F4 D0 04 A9 07 85 F4 C6 F5 D0 E7 A5 FD 10 03 18 69 50 84 FB 18 65 FB C9 50 90 02 E9 50 8C 11 02 A8 AD 13 02 C9 50 D0 06 A9 03 A2 F0 D0 04 A9 00 A2 2E 91 F3 86 FB AC 11 02 4C C5 03 C9 4F F0 A0 4C C5 03 A9 07 85 F2 A9 00 85 F1 85 FA A9 4E 85 F3 A9 4E 85 F4 A9 00 85 F5 A2 08 BC 68 05 B1 F1 4A 90 02 E6 F5 CA D0 F3 A9 03 A0 51 D1 F1 D0 2C A2 02 E4 F5 F0 0B E8 E4 F5 F0 06 A9 01 91 F1 85 FA E6 F1 D0 02 E6 F2 C6 F4 D0 CA 18 A5 F1 69 02 85 F1 90 02 E6 F2 C6 F3 D0 B7 F0 0A A2 03 E4 F5 D0 DF A9 02 D0 D7 A9 00 85 F9 85 F8 A9 06 85 F2 A9 FF 85 F1 A2 50 A0 50 B1 F1 C9 02 D0 06 A9 03 91 F1 D0 08 C9 01 D0 04 A9 00 91 F1 C9 03 D0 06 E6 F8 D0 02 E6 F9 88 D0 DF 18 A5 F1 69 50 85 F1 90 02 E6 F2 CA D0 CF A5 FA C9 00 D0 03 4C AF 03 E6 F6 D0 02 E6 F7 A5 F0 09 80 85 F0 4C 77 00 A0 FD 8C 00 DF AC 00 DF C0 EF F0 F4 20 E5 02 4C F1 02 00 01 02 50 52 A0 A1 A2 A9 4C 85 FE A9 00 4C 69 00 EA 00 00 00 00 00 00 00 .0000G

18
apps/c1p/6502/sim.inc Normal file
View file

@ -0,0 +1,18 @@
.code
.org $200
;
; These must be kept in sync with the "opSim operation codes" in c1p.js
;
.define OP_SIM $02
.define SIMOP_HLT $00
.define SIMOP_MSG $01
.macro SIM_MSG msg
.local addr
.byte OP_SIM,SIMOP_MSG
addr: .ASCIIZ msg
.endmacro
.macro SIM_HLT
.byte OP_SIM,SIMOP_HLT
.endmacro

View file

@ -0,0 +1,476 @@
.0200/A0
01
8C
CE
03
A9
00
8D
D1
03
8D
D4
03
AD
D4
03
02
01
54
65
73
74
69
6E
67
20
25
41
00
29
0F
8D
D5
03
AD
D4
03
29
F0
8D
D9
03
09
0F
8D
DA
03
AD
D1
03
29
0F
8D
D3
03
AD
D1
03
29
F0
8D
D2
03
20
79
02
20
62
03
20
33
03
D0
26
20
CC
02
20
6F
03
20
33
03
D0
1B
EE
D1
03
D0
D5
EE
D4
03
D0
AE
88
10
AB
A9
00
8D
CE
03
02
01
50
41
53
53
00
F0
07
02
01
46
41
49
4C
00
02
00
F8
C0
01
AD
D1
03
6D
D4
03
8D
CC
03
08
68
8D
CD
03
D8
C0
01
AD
D1
03
6D
D4
03
8D
CF
03
08
68
8D
D0
03
C0
01
AD
D3
03
6D
D5
03
C9
0A
A2
00
90
06
E8
69
05
29
0F
38
0D
D2
03
7D
D9
03
08
B0
04
C9
A0
90
03
69
5F
38
8D
CA
03
08
68
8D
CB
03
68
8D
D7
03
60
F8
C0
01
AD
D1
03
ED
D4
03
8D
CC
03
08
68
8D
CD
03
D8
C0
01
AD
D1
03
ED
D4
03
8D
CF
03
08
68
8D
D0
03
60
C0
01
AD
D3
03
ED
D5
03
A2
00
B0
06
E8
E9
05
29
0F
18
0D
D2
03
FD
D9
03
B0
02
E9
5F
8D
CA
03
60
C0
01
AD
D3
03
ED
D5
03
A2
00
B0
04
E8
29
0F
18
0D
D2
03
FD
D9
03
B0
02
E9
5F
E0
00
F0
02
E9
06
8D
CA
03
60
AD
CC
03
CD
CA
03
D0
26
AD
CD
03
4D
D6
03
29
80
D0
1C
AD
CD
03
4D
D7
03
29
40
D0
12
AD
CD
03
4D
D8
03
29
02
D0
08
AD
CD
03
4D
CB
03
29
01
60
AD
D7
03
8D
D6
03
AD
D0
03
8D
D8
03
60
20
EF
02
AD
D0
03
8D
D6
03
8D
D7
03
8D
D8
03
8D
CB
03
60
AD
CA
03
08
68
8D
D6
03
8D
D8
03
60
20
0F
03
AD
CA
03
08
68
8D
D6
03
8D
D8
03
AD
D0
03
8D
D7
03
8D
CB
03
60
AD
CA
03
08
68
8D
D6
03
8D
D8
03
60
20
EF
02
AD
CA
03
08
68
8D
D6
03
8D
D8
03
AD
D0
03
8D
D7
03
8D
CB
03
60
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
.0200G

View file

@ -0,0 +1,332 @@
;
; The following code comes from:
;
; http://www.6502.org/tutorials/decimal_mode.html
;
; and is built with:
;
; ca65 bcd.asm -I ../.. -l -o bcd.obj
; ld65 bcd.obj -o bcd.bin --target none
;
; An ASCII hex file which the OSI machine-language monitor can load
; is produced with the following commands:
;
; echo -n ".0200/" > bcd.txt
; hexdump -e '1/1 "%02X\n"' -v bcd.bin >> bcd.txt
; echo -n ".0200" >> bcd.txt
;
.include "sim.inc"
VALID_BCD_ONLY = 0
VALID_FLAGS_ONLY = 0
;
; Verify decimal mode behavior
;
; Returns:
; ERROR = 0 if the test passed
; ERROR = 1 if the test failed
;
; This routine requires 17 bytes of RAM -- 1 byte each for:
; AR, CF, DA, DNVZC, ERROR, HA, HNVZC, N1, N1H, N1L, N2, N2L, NF, VF, and ZF
; and 2 bytes for N2H
;
; Variables:
; N1 and N2 are the two numbers to be added or subtracted
; N1H, N1L, N2H, and N2L are the upper 4 bits and lower 4 bits of N1 and N2
; DA and DNVZC are the actual accumulator and flag results in decimal mode
; HA and HNVZC are the accumulator and flag results when N1 and N2 are
; added or subtracted using binary arithmetic
; AR, NF, VF, ZF, and CF are the predicted decimal mode accumulator and
; flag results, calculated using binary arithmetic
;
; This program takes approximately 1 minute at 1 MHz (a few seconds more on
; a 65C02 than a 6502 or 65816)
;
TEST: LDY #1 ; initialize Y (used to loop through carry flag values)
STY ERROR ; store 1 in ERROR until the test passes
LDA #0 ; initialize N1 and N2
STA N1
STA N2
LOOP1: LDA N2 ; N2L = N2 & $0F
SIM_MSG "Testing %A"
AND #$0F ; [1] see text
.if VALID_BCD_ONLY <> 0
CMP #$0A
BCS NEXT2
.endif
STA N2L
LDA N2 ; N2H = N2 & $F0
AND #$F0 ; [2] see text
.if VALID_BCD_ONLY <> 0
CMP #$A0
BCS NEXT2
.endif
STA N2H
ORA #$0F ; N2H+1 = (N2 & $F0) + $0F
STA N2H+1
LOOP2: LDA N1 ; N1L = N1 & $0F
;; SIM_MSG " with %A"
AND #$0F ; [3] see text
.if VALID_BCD_ONLY <> 0
CMP #$0A
BCS NEXT1
.endif
STA N1L
LDA N1 ; N1H = N1 & $F0
AND #$F0 ; [4] see text
.if VALID_BCD_ONLY <> 0
CMP #$A0
BCS NEXT1
.endif
STA N1H
JSR ADD
JSR A6502
JSR COMPARE
BNE ERR
JSR SUB
JSR S6502
JSR COMPARE
BNE ERR
NEXT1: INC N1 ; [5] see text
BNE LOOP2 ; loop through all 256 values of N1
NEXT2: INC N2 ; [6] see text
BNE LOOP1 ; loop through all 256 values of N2
DEY
BPL LOOP1 ; loop through both values of the carry flag
LDA #0 ; test passed, so store 0 in ERROR
STA ERROR
SIM_MSG "PASS"
BEQ DONE
ERR: SIM_MSG "FAIL"
DONE: SIM_HLT
; Calculate the actual decimal mode accumulator and flags, the accumulator
; and flag results when N1 is added to N2 using binary arithmetic, the
; predicted accumulator result, the predicted carry flag, and the predicted
; V flag
;
ADD: SED ; decimal mode
CPY #1 ; set carry if Y = 1, clear carry if Y = 0
LDA N1
ADC N2
STA DA ; actual accumulator result in decimal mode
PHP
PLA
STA DNVZC ; actual flags result in decimal mode
CLD ; binary mode
CPY #1 ; set carry if Y = 1, clear carry if Y = 0
LDA N1
ADC N2
STA HA ; accumulator result of N1+N2 using binary arithmetic
PHP
PLA
STA HNVZC ; flags result of N1+N2 using binary arithmetic
CPY #1
LDA N1L
ADC N2L
CMP #$0A
LDX #0
BCC A1
INX
ADC #5 ; add 6 (carry is set)
AND #$0F
SEC
A1: ORA N1H
;
; if N1L + N2L < $0A, then add N2 & $F0
; if N1L + N2L >= $0A, then add (N2 & $F0) + $0F + 1 (carry is set)
;
ADC N2H,X
PHP
BCS A2
CMP #$A0
BCC A3
A2: ADC #$5F ; add $60 (carry is set)
SEC
A3: STA AR ; predicted accumulator result
PHP
PLA
STA CF ; predicted carry result
PLA
;
; note that all 8 bits of the P register are stored in VF
;
STA VF ; predicted V flags
RTS
; Calculate the actual decimal mode accumulator and flags, and the
; accumulator and flag results when N2 is subtracted from N1 using binary
; arithmetic
;
SUB: SED ; decimal mode
CPY #1 ; set carry if Y = 1, clear carry if Y = 0
LDA N1
SBC N2
STA DA ; actual accumulator result in decimal mode
PHP
PLA
STA DNVZC ; actual flags result in decimal mode
CLD ; binary mode
CPY #1 ; set carry if Y = 1, clear carry if Y = 0
LDA N1
SBC N2
STA HA ; accumulator result of N1-N2 using binary arithmetic
PHP
PLA
STA HNVZC ; flags result of N1-N2 using binary arithmetic
RTS
; Calculate the predicted SBC accumulator result for the 6502 and 65816
;
SUB1: CPY #1 ; set carry if Y = 1, clear carry if Y = 0
LDA N1L
SBC N2L
LDX #0
BCS S11
INX
SBC #5 ; subtract 6 (carry is clear)
AND #$0F
CLC
S11: ORA N1H
;
; if N1L - N2L >= 0, then subtract N2 & $F0
; if N1L - N2L < 0, then subtract (N2 & $F0) + $0F + 1 (carry is clear)
;
SBC N2H,X
BCS S12
SBC #$5F ; subtract $60 (carry is clear)
S12: STA AR
RTS
; Calculate the predicted SBC accumulator result for the 6502 and 65C02
;
SUB2: CPY #1 ; set carry if Y = 1, clear carry if Y = 0
LDA N1L
SBC N2L
LDX #0
BCS S21
INX
AND #$0F
CLC
S21: ORA N1H
;
; if N1L - N2L >= 0, then subtract N2 & $F0
; if N1L - N2L < 0, then subtract (N2 & $F0) + $0F + 1 (carry is clear)
;
SBC N2H,X
BCS S22
SBC #$5F ; subtract $60 (carry is clear)
S22: CPX #0
BEQ S23
SBC #6
S23: STA AR ; predicted accumulator result
RTS
; Compare accumulator actual results to predicted results
;
; Return:
; Z flag = 1 (BEQ branch) if same
; Z flag = 0 (BNE branch) if different
;
COMPARE:LDA DA
CMP AR
BNE C1
.if VALID_FLAGS_ONLY = 0
LDA DNVZC ; [7] see text
EOR NF
AND #$80 ; mask off N flag
BNE C1
LDA DNVZC ; [8] see text
EOR VF
AND #$40 ; mask off V flag
BNE C1 ; [9] see text
LDA DNVZC
EOR ZF ; mask off Z flag
AND #2
BNE C1 ; [10] see text
.endif
LDA DNVZC
EOR CF
AND #1 ; mask off C flag
C1: RTS
; These routines store the predicted values for ADC and SBC for the 6502,
; 65C02, and 65816 in AR, CF, NF, VF, and ZF
A6502: LDA VF
;
; since all 8 bits of the P register were stored in VF, bit 7 of VF contains
; the N flag for NF
;
STA NF
LDA HNVZC
STA ZF
RTS
S6502: JSR SUB1
LDA HNVZC
STA NF
STA VF
STA ZF
STA CF
RTS
A65C02: LDA AR
PHP
PLA
STA NF
STA ZF
RTS
S65C02: JSR SUB2
LDA AR
PHP
PLA
STA NF
STA ZF
LDA HNVZC
STA VF
STA CF
RTS
A65816: LDA AR
PHP
PLA
STA NF
STA ZF
RTS
S65816: JSR SUB1
LDA AR
PHP
PLA
STA NF
STA ZF
LDA HNVZC
STA VF
STA CF
RTS
.data
AR: .byte 0
CF: .byte 0 ; predicted carry result
DA: .byte 0
DNVZC: .byte 0
ERROR: .byte 0
HA: .byte 0
HNVZC: .byte 0
N1: .byte 0
N1H: .byte 0
N1L: .byte 0
N2: .byte 0
N2L: .byte 0
NF: .byte 0
VF: .byte 0
ZF: .byte 0
N2H: .word 0

View file

@ -0,0 +1,19 @@
CA65 = ca65
LD65 = ld65
ECHO = @/bin/echo
CA65_OPTS =
LD65_OPTS = --target none
all: bcd.65v
bcd.obj: bcd.asm
$(CA65) bcd.asm -I ../.. -l -o bcd.obj
bcd.bin: bcd.obj
$(LD65) $(LD65_OPTS) $+ -o $@
bcd.65v: bcd.bin
$(ECHO) -n ".0200/" > bcd.65v
hexdump -e '1/1 "%02X\n"' -v bcd.bin >> bcd.65v
$(ECHO) -n ".0200G" >> bcd.65v

View file

@ -0,0 +1,19 @@
CA65 = ca65
LD65 = ld65
ECHO = @/bin/echo
CA65_OPTS =
LD65_OPTS = --target none
all: vflag.65v
vflag.obj: vflag.asm
$(CA65) vflag.asm -I ../.. -l -o vflag.obj
vflag.bin: vflag.obj
$(LD65) $(LD65_OPTS) $+ -o $@
vflag.65v: vflag.bin
$(ECHO) -n ".0200/" > vflag.65v
hexdump -e '1/1 "%02X\n"' -v vflag.bin >> vflag.65v
$(ECHO) -n ".0200G" >> vflag.65v

View file

@ -0,0 +1,159 @@
.0200/D8
A9
01
8D
99
02
A9
80
8D
9A
02
8D
9B
02
A9
00
8D
9C
02
8D
9D
02
A0
01
20
50
02
E0
01
F0
28
20
6F
02
E0
01
F0
21
EE
9A
02
EE
9C
02
D0
EA
EE
9B
02
EE
9D
02
D0
E2
88
10
DF
A9
00
8D
99
02
02
01
50
41
53
53
00
F0
07
02
01
46
41
49
4C
00
02
00
C0
01
AD
9A
02
6D
9B
02
A2
00
50
01
E8
C0
01
AD
9C
02
6D
9D
02
B0
04
30
01
E8
60
10
01
E8
60
C0
01
AD
9A
02
ED
9B
02
A2
00
50
01
E8
C0
01
AD
9C
02
ED
9D
02
48
A9
FF
E9
00
C9
FE
D0
05
68
30
01
E8
60
68
90
FB
10
01
E8
60
00
00
00
00
00
.0200G

View file

@ -0,0 +1,124 @@
;
; The following code comes from:
;
; http://www.6502.org/tutorials/vflag.html
;
; and is built with:
;
; ca65 vflag.asm -I ../.. -l -o vflag.obj
; ld65 vflag.obj -o vflag.bin --target none
;
; An ASCII hex file which the OSI machine-language monitor can load
; is produced with the following commands:
;
; echo -n ".0200/" > vflag.txt
; hexdump -e '1/1 "%02X\n"' -v vflag.bin >> vflag.txt
; echo -n ".0200" >> vflag.txt
;
.include "sim.inc"
; Demonstrate that the V flag works as described
;
; Returns with ERROR = 0 if the test passes, ERROR = 1 if the test fails
;
; Five (additional) memory locations are used: ERROR, S1, S2, U1, and U2
; which can be located anywhere convenient in RAM
;
; The program below takes about 16 seconds to complete at 1 MHz.
;
TEST: CLD ; Clear decimal mode (just in case) for test
LDA #1
STA ERROR ; Store 1 in ERROR until test passes
LDA #$80
STA S1 ; Initalize S1 and S2 to -128 ($80)
STA S2
LDA #0
STA U1 ; Initialize U1 and U2 to 0
STA U2
LDY #1 ; Initialize Y (used to set and clear the carry flag) to 1
LOOP: JSR ADD ; Test ADC
CPX #1
BEQ ERR ; End if V and unsigned result do not agree (X = 1)
JSR SUB ; Test SBC
CPX #1
BEQ ERR ; End if V and unsigned result do not agree (X = 1)
INC S1
INC U1
BNE LOOP ; Loop until all 256 possibilities of S1 and U1 are tested
INC S2
INC U2
BNE LOOP ; Loop until all 256 possibilities of S2 and U2 are tested
DEY
BPL LOOP ; Loop until both possiblities of the carry flag are tested
LDA #0
STA ERROR ; All tests pass, so store 0 in ERROR
SIM_MSG "PASS"
BEQ DONE
ERR: SIM_MSG "FAIL"
DONE: SIM_HLT
;
; Test ADC
;
; X is initialized to 0
; X is incremented when V = 1
; X is incremented when the unsigned result predicts an overflow
; Therefore, if the V flag and the unsigned result agree, X will be
; incremented zero or two times (returning X = 0 or X = 2), and if they do
; not agree X will be incremented once (returning X = 1)
;
ADD: CPY #1 ; Set carry when Y = 1, clear carry when Y = 0
LDA S1 ; Test twos complement addition
ADC S2
LDX #0 ; Initialize X to 0
BVC ADD1
INX ; Increment X if V = 1
ADD1: CPY #1 ; Set carry when Y = 1, clear carry when Y = 0
LDA U1 ; Test unsigned addition
ADC U2
BCS ADD3 ; Carry is set if U1 + U2 >= 256
BMI ADD2 ; U1 + U2 < 256, A >= 128 if U1 + U2 >= 128
INX ; Increment X if U1 + U2 < 128
ADD2: RTS
ADD3: BPL ADD4 ; U1 + U2 >= 256, A <= 127 if U1 + U2 <= 383 ($17F)
INX ; Increment X if U1 + U2 > 383
ADD4: RTS
;
; Test SBC
;
; X is initialized to 0
; X is incremented when V = 1
; X is incremented when the unsigned result predicts an overflow
; Therefore, if the V flag and the unsigned result agree, X will be
; incremented zero or two times (returning X = 0 or X = 2), and if they do
; not agree X will be incremented once (returning X = 1)
;
SUB: CPY #1 ; Set carry when Y = 1, clear carry when Y = 0
LDA S1 ; Test twos complement subtraction
SBC S2
LDX #0 ; Initialize X to 0
BVC SUB1
INX ; Increment X if V = 1
SUB1: CPY #1 ; Set carry when Y = 1, clear carry when Y = 0
LDA U1 ; Test unsigned subtraction
SBC U2
PHA ; Save the low byte of result on the stack
LDA #$FF
SBC #$00 ; result = (65280 + U1) - U2, 65280 = $FF00
CMP #$FE
BNE SUB4 ; Branch if result >= 65280 ($FF00) or result < 65024 ($FE00)
PLA ; Get the low byte of result
BMI SUB3 ; result < 65280 ($FF00), A >= 128 if result >= 65152 ($FE80)
SUB2: INX ; Increment X if result < 65152 ($FE80)
SUB3: RTS
SUB4: PLA ; Get the low byte of result (does not affect the carry flag)
BCC SUB2 ; The carry flag is clear if result < 65024 ($FE00)
BPL SUB5 ; result >= 65280 ($FF00), A <= 127 if result <= 65407 ($FF7F)
INX ; Increment X if result > 65407 ($FF7F)
SUB5: RTS
.data
ERROR: .byte 0
S1: .byte 0
S2: .byte 0
U1: .byte 0
U2: .byte 0