diff --git a/.clang-format b/.clang-format
index 55f3d06..778a50f 100644
--- a/.clang-format
+++ b/.clang-format
@@ -1,6 +1,6 @@
----
-BasedOnStyle: LLVM
-ColumnLimit: 130
-IndentCaseLabels: true
-AllowShortIfStatementsOnASingleLine: Always
+---
+BasedOnStyle: LLVM
+ColumnLimit: 130
+IndentCaseLabels: true
+AllowShortIfStatementsOnASingleLine: Always
AllowShortLoopsOnASingleLine: true
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 654b23c..01199e5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,3 @@
-.DS_Store
-
+.DS_Store
+
build
\ No newline at end of file
diff --git a/.vscode/launch.json b/.vscode/launch.json
index 4a74027..6dd4e16 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -1,47 +1,47 @@
-{
- "configurations": [
- {
- "name": "(gdb) Launch",
- "type": "cppdbg",
- "request": "launch",
- "program": "${workspaceFolder}/build/6502PC",
- "args": [],
- "stopAtEntry": false,
- "cwd": "${workspaceFolder}/build",
- "environment": [],
- "externalConsole": false,
- "MIMode": "gdb",
- "setupCommands": [
- {
- "description": "Enable pretty-printing for gdb",
- "text": "-enable-pretty-printing",
- "ignoreFailures": true
- },
- {
- "description": "Set Disassembly Flavor to Intel",
- "text": "-gdb-set disassembly-flavor intel",
- "ignoreFailures": true
- }
- ]
- },
- {
- "name": "(lldb) Launch",
- "type": "cppdbg",
- "request": "launch",
- "program": "${workspaceFolder}/build/6502PC",
- "args": [],
- "stopAtEntry": false,
- "cwd": "${workspaceFolder}/build",
- "environment": [],
- "externalConsole": false,
- "MIMode": "lldb",
- "setupCommands": [
- {
- "description": "Set Disassembly Flavor to Intel",
- "text": "settings set target.x86-disassembly-flavor intel",
- "ignoreFailures": true
- }
- ]
- }
- ]
-}
+{
+ "configurations": [
+ {
+ "name": "(gdb) Launch",
+ "type": "cppdbg",
+ "request": "launch",
+ "program": "${workspaceFolder}/build/6502PC",
+ "args": [],
+ "stopAtEntry": false,
+ "cwd": "${workspaceFolder}/build",
+ "environment": [],
+ "externalConsole": false,
+ "MIMode": "gdb",
+ "setupCommands": [
+ {
+ "description": "Enable pretty-printing for gdb",
+ "text": "-enable-pretty-printing",
+ "ignoreFailures": true
+ },
+ {
+ "description": "Set Disassembly Flavor to Intel",
+ "text": "-gdb-set disassembly-flavor intel",
+ "ignoreFailures": true
+ }
+ ]
+ },
+ {
+ "name": "(lldb) Launch",
+ "type": "cppdbg",
+ "request": "launch",
+ "program": "${workspaceFolder}/build/6502PC",
+ "args": [],
+ "stopAtEntry": false,
+ "cwd": "${workspaceFolder}/build",
+ "environment": [],
+ "externalConsole": false,
+ "MIMode": "lldb",
+ "setupCommands": [
+ {
+ "description": "Set Disassembly Flavor to Intel",
+ "text": "settings set target.x86-disassembly-flavor intel",
+ "ignoreFailures": true
+ }
+ ]
+ }
+ ]
+}
diff --git a/6502_65C02_functional_tests/.gitignore b/6502_65C02_functional_tests/.gitignore
index 9e8ac6d..b7a34cc 100644
--- a/6502_65C02_functional_tests/.gitignore
+++ b/6502_65C02_functional_tests/.gitignore
@@ -1,4 +1,4 @@
-as65_142
-
-*.bin
+as65_142
+
+*.bin
*.lst
\ No newline at end of file
diff --git a/6502_65C02_functional_tests/6502_decimal_test.a65 b/6502_65C02_functional_tests/6502_decimal_test.a65
index 539ca51..8e389ef 100644
--- a/6502_65C02_functional_tests/6502_decimal_test.a65
+++ b/6502_65C02_functional_tests/6502_decimal_test.a65
@@ -1,375 +1,375 @@
-; Verify decimal mode behavior
-; Written by Bruce Clark. This code is public domain.
-; see http://www.6502.org/tutorials/decimal_mode.html
-;
-; Returns:
-; ERROR = 0 if the test passed
-; ERROR = 1 if the test failed
-; modify the code at the DONE label for desired program end
-;
-; 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)
-;
-
-; Configuration:
-cputype = 0 ; 0 = 6502, 1 = 65C02, 2 = 65C816
-vld_bcd = 0 ; 0 = allow invalid bcd, 1 = valid bcd only
-chk_a = 1 ; check accumulator
-chk_n = 0 ; check sign (negative) flag
-chk_v = 0 ; check overflow flag
-chk_z = 0 ; check zero flag
-chk_c = 1 ; check carry flag
-
-end_of_test macro
- db $db ;execute 65C02 stop instruction
- endm
-
- bss
- org 0
-; operands - register Y = carry in
-N1 ds 1
-N2 ds 1
-; binary result
-HA ds 1
-HNVZC ds 1
- ;04
-; decimal result
-DA ds 1
-DNVZC ds 1
-; predicted results
-AR ds 1
-NF ds 1
- ;08
-VF ds 1
-ZF ds 1
-CF ds 1
-ERROR ds 1
- ;0C
-; workspace
-N1L ds 1
-N1H ds 1
-N2L ds 1
-N2H ds 2
-
- code
- org $200
- lda #1
- sta $dc02
-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
- and #$0F ; [1] see text
- if vld_bcd = 1
- cmp #$0a
- bcs NEXT2
- endif
- sta N2L
- lda N2 ; N2H = N2 & $F0
- and #$F0 ; [2] see text
- if vld_bcd = 1
- cmp #$a0
- bcs NEXT2
- endif
- sta N2H
- ora #$0F ; N2H+1 = (N2 & $F0) + $0F
- sta N2H+1
-LOOP2 lda N1 ; N1L = N1 & $0F
- and #$0F ; [3] see text
- if vld_bcd = 1
- cmp #$0a
- bcs NEXT1
- endif
- sta N1L
- lda N1 ; N1H = N1 & $F0
- and #$F0 ; [4] see text
- if vld_bcd = 1
- cmp #$a0
- bcs NEXT1
- endif
- sta N1H
- jsr ADD
- jsr A6502
- jsr COMPARE
- bne DONE
- jsr SUB
- jsr S6502
- jsr COMPARE
- bne DONE
-NEXT1 inc N1 ; [5] see text
- bne LOOP2 ; loop through all 256 values of N1
-NEXT2 lda #'*'
- sta $dc00
- 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
-DONE
- lda #0
- jsr RCHAR
- lda #1
- cmp ERROR
- beq _E
- lda #'P'
- jmp _E2
-_E lda #'F'
-_E2 jsr RCHAR
- end_of_test
-
-RCHAR sta $dc00
- lda #'\r'
- sta $dc00
- lda #'\n'
- sta $dc00
- rts
-
-; 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
-
- if cputype != 1
-; 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
- endif
-
- if cputype = 1
-; 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
- endif
-
-; Compare accumulator actual results to predicted results
-;
-; Return:
-; Z flag = 1 (BEQ branch) if same
-; Z flag = 0 (BNE branch) if different
-;
-COMPARE
- if chk_a = 1
- lda DA
- cmp AR
- bne C1
- endif
- if chk_n = 1
- lda DNVZC ; [7] see text
- eor NF
- and #$80 ; mask off N flag
- bne C1
- endif
- if chk_v = 1
- lda DNVZC ; [8] see text
- eor VF
- and #$40 ; mask off V flag
- bne C1 ; [9] see text
- endif
- if chk_z = 1
- lda DNVZC
- eor ZF ; mask off Z flag
- and #2
- bne C1 ; [10] see text
- endif
- if chk_c = 1
- lda DNVZC
- eor CF
- and #1 ; mask off C flag
- endif
-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
-
- if cputype = 0
-
-A6502 lda VF ; 6502
-;
-; 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
-
- endif
- if cputype = 1
-
-A6502 lda AR ; 65C02
- php
- pla
- sta NF
- sta ZF
- rts
-
-S6502 jsr SUB2
- lda AR
- php
- pla
- sta NF
- sta ZF
- lda HNVZC
- sta VF
- sta CF
- rts
-
- endif
- if cputype = 2
-
-A6502 lda AR ; 65C816
- php
- pla
- sta NF
- sta ZF
- rts
-
-S6502 jsr SUB1
- lda AR
- php
- pla
- sta NF
- sta ZF
- lda HNVZC
- sta VF
- sta CF
- rts
-
- endif
-
- end TEST
+; Verify decimal mode behavior
+; Written by Bruce Clark. This code is public domain.
+; see http://www.6502.org/tutorials/decimal_mode.html
+;
+; Returns:
+; ERROR = 0 if the test passed
+; ERROR = 1 if the test failed
+; modify the code at the DONE label for desired program end
+;
+; 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)
+;
+
+; Configuration:
+cputype = 0 ; 0 = 6502, 1 = 65C02, 2 = 65C816
+vld_bcd = 0 ; 0 = allow invalid bcd, 1 = valid bcd only
+chk_a = 1 ; check accumulator
+chk_n = 0 ; check sign (negative) flag
+chk_v = 0 ; check overflow flag
+chk_z = 0 ; check zero flag
+chk_c = 1 ; check carry flag
+
+end_of_test macro
+ db $db ;execute 65C02 stop instruction
+ endm
+
+ bss
+ org 0
+; operands - register Y = carry in
+N1 ds 1
+N2 ds 1
+; binary result
+HA ds 1
+HNVZC ds 1
+ ;04
+; decimal result
+DA ds 1
+DNVZC ds 1
+; predicted results
+AR ds 1
+NF ds 1
+ ;08
+VF ds 1
+ZF ds 1
+CF ds 1
+ERROR ds 1
+ ;0C
+; workspace
+N1L ds 1
+N1H ds 1
+N2L ds 1
+N2H ds 2
+
+ code
+ org $200
+ lda #1
+ sta $bc02
+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
+ and #$0F ; [1] see text
+ if vld_bcd = 1
+ cmp #$0a
+ bcs NEXT2
+ endif
+ sta N2L
+ lda N2 ; N2H = N2 & $F0
+ and #$F0 ; [2] see text
+ if vld_bcd = 1
+ cmp #$a0
+ bcs NEXT2
+ endif
+ sta N2H
+ ora #$0F ; N2H+1 = (N2 & $F0) + $0F
+ sta N2H+1
+LOOP2 lda N1 ; N1L = N1 & $0F
+ and #$0F ; [3] see text
+ if vld_bcd = 1
+ cmp #$0a
+ bcs NEXT1
+ endif
+ sta N1L
+ lda N1 ; N1H = N1 & $F0
+ and #$F0 ; [4] see text
+ if vld_bcd = 1
+ cmp #$a0
+ bcs NEXT1
+ endif
+ sta N1H
+ jsr ADD
+ jsr A6502
+ jsr COMPARE
+ bne DONE
+ jsr SUB
+ jsr S6502
+ jsr COMPARE
+ bne DONE
+NEXT1 inc N1 ; [5] see text
+ bne LOOP2 ; loop through all 256 values of N1
+NEXT2 lda #'*'
+ sta $bc00
+ 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
+DONE
+ lda #0
+ jsr RCHAR
+ lda #1
+ cmp ERROR
+ beq _E
+ lda #'P'
+ jmp _E2
+_E lda #'F'
+_E2 jsr RCHAR
+ end_of_test
+
+RCHAR sta $bc00
+ lda #'\r'
+ sta $bc00
+ lda #'\n'
+ sta $bc00
+ rts
+
+; 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
+
+ if cputype != 1
+; 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
+ endif
+
+ if cputype = 1
+; 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
+ endif
+
+; Compare accumulator actual results to predicted results
+;
+; Return:
+; Z flag = 1 (BEQ branch) if same
+; Z flag = 0 (BNE branch) if different
+;
+COMPARE
+ if chk_a = 1
+ lda DA
+ cmp AR
+ bne C1
+ endif
+ if chk_n = 1
+ lda DNVZC ; [7] see text
+ eor NF
+ and #$80 ; mask off N flag
+ bne C1
+ endif
+ if chk_v = 1
+ lda DNVZC ; [8] see text
+ eor VF
+ and #$40 ; mask off V flag
+ bne C1 ; [9] see text
+ endif
+ if chk_z = 1
+ lda DNVZC
+ eor ZF ; mask off Z flag
+ and #2
+ bne C1 ; [10] see text
+ endif
+ if chk_c = 1
+ lda DNVZC
+ eor CF
+ and #1 ; mask off C flag
+ endif
+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
+
+ if cputype = 0
+
+A6502 lda VF ; 6502
+;
+; 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
+
+ endif
+ if cputype = 1
+
+A6502 lda AR ; 65C02
+ php
+ pla
+ sta NF
+ sta ZF
+ rts
+
+S6502 jsr SUB2
+ lda AR
+ php
+ pla
+ sta NF
+ sta ZF
+ lda HNVZC
+ sta VF
+ sta CF
+ rts
+
+ endif
+ if cputype = 2
+
+A6502 lda AR ; 65C816
+ php
+ pla
+ sta NF
+ sta ZF
+ rts
+
+S6502 jsr SUB1
+ lda AR
+ php
+ pla
+ sta NF
+ sta ZF
+ lda HNVZC
+ sta VF
+ sta CF
+ rts
+
+ endif
+
+ end TEST
diff --git a/6502_65C02_functional_tests/6502_functional_test.a65 b/6502_65C02_functional_tests/6502_functional_test.a65
index dbbe74f..335f1e8 100644
--- a/6502_65C02_functional_tests/6502_functional_test.a65
+++ b/6502_65C02_functional_tests/6502_functional_test.a65
@@ -1,6111 +1,6111 @@
-;
-; 6 5 0 2 F U N C T I O N A L T E S T
-;
-; Copyright (C) 2012-2020 Klaus Dormann
-;
-; This program is free software: you can redistribute it and/or modify
-; it under the terms of the GNU General Public License as published by
-; the Free Software Foundation, either version 3 of the License, or
-; (at your option) any later version.
-;
-; This program is distributed in the hope that it will be useful,
-; but WITHOUT ANY WARRANTY; without even the implied warranty of
-; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-; GNU General Public License for more details.
-;
-; You should have received a copy of the GNU General Public License
-; along with this program. If not, see .
-
-
-; This program is designed to test all opcodes of a 6502 emulator using all
-; addressing modes with focus on propper setting of the processor status
-; register bits.
-;
-; version 05-jan-2020
-; contact info at http://2m5.de or email K@2m5.de
-;
-; assembled with AS65 written by Frank A. Kingswood
-; The assembler as65_142.zip can be obtained from my GitHub repository
-; command line switches: -l -m -s2 -w -h0
-; | | | | no page headers in listing
-; | | | wide listing (133 char/col)
-; | | write intel hex file instead of binary
-; | expand macros in listing
-; generate pass2 listing
-;
-; No IO - should be run from a monitor with access to registers.
-; To run load intel hex image with a load command, than alter PC to 400 hex
-; (code_segment) and enter a go command.
-; Loop on program counter determines error or successful completion of test.
-; Check listing for relevant traps (jump/branch *).
-; Please note that in early tests some instructions will have to be used before
-; they are actually tested!
-;
-; RESET, NMI or IRQ should not occur and will be trapped if vectors are enabled.
-; Tests documented behavior of the original NMOS 6502 only! No unofficial
-; opcodes. Additional opcodes of newer versions of the CPU (65C02, 65816) will
-; not be tested. Decimal ops will only be tested with valid BCD operands and
-; N V Z flags will be ignored.
-;
-; Debugging hints:
-; Most of the code is written sequentially. if you hit a trap, check the
-; immediately preceeding code for the instruction to be tested. Results are
-; tested first, flags are checked second by pushing them onto the stack and
-; pulling them to the accumulator after the result was checked. The "real"
-; flags are no longer valid for the tested instruction at this time!
-; If the tested instruction was indexed, the relevant index (X or Y) must
-; also be checked. Opposed to the flags, X and Y registers are still valid.
-;
-; versions:
-; 28-jul-2012 1st version distributed for testing
-; 29-jul-2012 fixed references to location 0, now #0
-; added license - GPLv3
-; 30-jul-2012 added configuration options
-; 01-aug-2012 added trap macro to allow user to change error handling
-; 01-dec-2012 fixed trap in branch field must be a branch
-; 02-mar-2013 fixed PLA flags not tested
-; 19-jul-2013 allowed ROM vectors to be loaded when load_data_direct = 0
-; added test sequence check to detect if tests jump their fence
-; 23-jul-2013 added RAM integrity check option
-; 16-aug-2013 added error report to standard output option
-; 13-dec-2014 added binary/decimal opcode table switch test
-; 14-dec-2014 improved relative address test
-; 23-aug-2015 added option to disable self modifying tests
-; 24-aug-2015 all self modifying immediate opcodes now execute in data RAM
-; added small branch offset pretest
-; 21-oct-2015 added option to disable decimal mode ADC & SBC tests
-; 04-dec-2017 fixed BRK only tested with interrupts enabled
-; added option to skip the remainder of a failing test
-; in report.i65
-; 05-jan-2020 fixed shifts not testing zero result and flag when last 1-bit
-; is shifted out
-
-; C O N F I G U R A T I O N
-
-;ROM_vectors writable (0=no, 1=yes)
-;if ROM vectors can not be used interrupts will not be trapped
-;as a consequence BRK can not be tested but will be emulated to test RTI
-ROM_vectors = 1
-
-;load_data_direct (0=move from code segment, 1=load directly)
-;loading directly is preferred but may not be supported by your platform
-;0 produces only consecutive object code, 1 is not suitable for a binary image
-load_data_direct = 1
-
-;I_flag behavior (0=force enabled, 1=force disabled, 2=prohibit change, 3=allow
-;change) 2 requires extra code and is not recommended. SEI & CLI can only be
-;tested if you allow changing the interrupt status (I_flag = 3)
-I_flag = 3
-
-;configure memory - try to stay away from memory used by the system
-;zero_page memory start address, $52 (82) consecutive Bytes required
-; add 2 if I_flag = 2
-zero_page = $0
-
-;data_segment memory start address, $7B (123) consecutive Bytes required
-data_segment = $200
- if (data_segment & $ff) != 0
- ERROR ERROR ERROR low byte of data_segment MUST be $00 !!
- endif
-
-;code_segment memory start address, 13.1kB of consecutive space required
-; add 2.5 kB if I_flag = 2
-code_segment = $400
-
-;self modifying code may be disabled to allow running in ROM
-;0=part of the code is self modifying and must reside in RAM
-;1=tests disabled: branch range
-disable_selfmod = 0
-
-;report errors through I/O channel (0=use standard self trap loops, 1=include
-;report.i65 as I/O channel, add 3.5 kB)
-report = 1
-
-;RAM integrity test option. Checks for undesired RAM writes.
-;set lowest non RAM or RAM mirror address page (-1=disable, 0=64k, $40=16k)
-;leave disabled if a monitor, OS or background interrupt is allowed to alter RAM
-ram_top = -1
-
-;disable test decimal mode ADC & SBC, 0=enable, 1=disable,
-;2=disable including decimal flag in processor status
-disable_decimal = 0
-
- noopt ;do not take shortcuts
-
-;macros for error & success traps to allow user modification
-;example:
-;trap macro
-; jsr my_error_handler
-; endm
-;trap_eq macro
-; bne skip\?
-; trap ;failed equal (zero)
-;skip\?
-; endm
-;
-; my_error_handler should pop the calling address from the stack and report it.
-; putting larger portions of code (more than 3 bytes) inside the trap macro
-; may lead to branch range problems for some tests.
- if report = 0
-trap macro
- jmp * ;failed anyway
- endm
-trap_eq macro
- beq * ;failed equal (zero)
- endm
-trap_ne macro
- bne * ;failed not equal (non zero)
- endm
-trap_cs macro
- bcs * ;failed carry set
- endm
-trap_cc macro
- bcc * ;failed carry clear
- endm
-trap_mi macro
- bmi * ;failed minus (bit 7 set)
- endm
-trap_pl macro
- bpl * ;failed plus (bit 7 clear)
- endm
-trap_vs macro
- bvs * ;failed overflow set
- endm
-trap_vc macro
- bvc * ;failed overflow clear
- endm
-; please observe that during the test the stack gets invalidated
-; therefore a RTS inside the success macro is not possible
-success macro
- jmp * ;test passed, no errors
- endm
- endif
- if report = 1
-trap macro
- jsr report_error
- endm
-trap_eq macro
- bne skip\?
- trap ;failed equal (zero)
-skip\?
- endm
-trap_ne macro
- beq skip\?
- trap ;failed not equal (non zero)
-skip\?
- endm
-trap_cs macro
- bcc skip\?
- trap ;failed carry set
-skip\?
- endm
-trap_cc macro
- bcs skip\?
- trap ;failed carry clear
-skip\?
- endm
-trap_mi macro
- bpl skip\?
- trap ;failed minus (bit 7 set)
-skip\?
- endm
-trap_pl macro
- bmi skip\?
- trap ;failed plus (bit 7 clear)
-skip\?
- endm
-trap_vs macro
- bvc skip\?
- trap ;failed overflow set
-skip\?
- endm
-trap_vc macro
- bvs skip\?
- trap ;failed overflow clear
-skip\?
- endm
-; please observe that during the test the stack gets invalidated
-; therefore a RTS inside the success macro is not possible
-success macro
- jsr report_success
- endm
- endif
-
-
-carry equ %00000001 ;flag bits in status
-zero equ %00000010
-intdis equ %00000100
-decmode equ %00001000
-break equ %00010000
-reserv equ %00100000
-overfl equ %01000000
-minus equ %10000000
-
-fc equ carry
-fz equ zero
-fzc equ carry+zero
-fv equ overfl
-fvz equ overfl+zero
-fn equ minus
-fnc equ minus+carry
-fnz equ minus+zero
-fnzc equ minus+zero+carry
-fnv equ minus+overfl
-
-fao equ break+reserv ;bits always on after PHP, BRK
-fai equ fao+intdis ;+ forced interrupt disable
-faod equ fao+decmode ;+ ignore decimal
-faid equ fai+decmode ;+ ignore decimal
-m8 equ $ff ;8 bit mask
-m8i equ $ff&~intdis ;8 bit mask - interrupt disable
-
-;macros to allow masking of status bits.
-;masking test of decimal bit
-;masking of interrupt enable/disable on load and compare
-;masking of always on bits after PHP or BRK (unused & break) on compare
- if disable_decimal < 2
- if I_flag = 0
-load_flag macro
- lda #\1&m8i ;force enable interrupts (mask I)
- endm
-cmp_flag macro
- cmp #(\1|fao)&m8i ;I_flag is always enabled + always on bits
- endm
-eor_flag macro
- eor #(\1&m8i|fao) ;mask I, invert expected flags + always on bits
- endm
- endif
- if I_flag = 1
-load_flag macro
- lda #\1|intdis ;force disable interrupts
- endm
-cmp_flag macro
- cmp #(\1|fai)&m8 ;I_flag is always disabled + always on bits
- endm
-eor_flag macro
- eor #(\1|fai) ;invert expected flags + always on bits + I
- endm
- endif
- if I_flag = 2
-load_flag macro
- lda #\1
- ora flag_I_on ;restore I-flag
- and flag_I_off
- endm
-cmp_flag macro
- eor flag_I_on ;I_flag is never changed
- cmp #(\1|fao)&m8i ;expected flags + always on bits, mask I
- endm
-eor_flag macro
- eor flag_I_on ;I_flag is never changed
- eor #(\1&m8i|fao) ;mask I, invert expected flags + always on bits
- endm
- endif
- if I_flag = 3
-load_flag macro
- lda #\1 ;allow test to change I-flag (no mask)
- endm
-cmp_flag macro
- cmp #(\1|fao)&m8 ;expected flags + always on bits
- endm
-eor_flag macro
- eor #\1|fao ;invert expected flags + always on bits
- endm
- endif
- else
- if I_flag = 0
-load_flag macro
- lda #\1&m8i ;force enable interrupts (mask I)
- endm
-cmp_flag macro
- ora #decmode ;ignore decimal mode bit
- cmp #(\1|faod)&m8i ;I_flag is always enabled + always on bits
- endm
-eor_flag macro
- ora #decmode ;ignore decimal mode bit
- eor #(\1&m8i|faod) ;mask I, invert expected flags + always on bits
- endm
- endif
- if I_flag = 1
-load_flag macro
- lda #\1|intdis ;force disable interrupts
- endm
-cmp_flag macro
- ora #decmode ;ignore decimal mode bit
- cmp #(\1|faid)&m8 ;I_flag is always disabled + always on bits
- endm
-eor_flag macro
- ora #decmode ;ignore decimal mode bit
- eor #(\1|faid) ;invert expected flags + always on bits + I
- endm
- endif
- if I_flag = 2
-load_flag macro
- lda #\1
- ora flag_I_on ;restore I-flag
- and flag_I_off
- endm
-cmp_flag macro
- eor flag_I_on ;I_flag is never changed
- ora #decmode ;ignore decimal mode bit
- cmp #(\1|faod)&m8i ;expected flags + always on bits, mask I
- endm
-eor_flag macro
- eor flag_I_on ;I_flag is never changed
- ora #decmode ;ignore decimal mode bit
- eor #(\1&m8i|faod) ;mask I, invert expected flags + always on bits
- endm
- endif
- if I_flag = 3
-load_flag macro
- lda #\1 ;allow test to change I-flag (no mask)
- endm
-cmp_flag macro
- ora #decmode ;ignore decimal mode bit
- cmp #(\1|faod)&m8 ;expected flags + always on bits
- endm
-eor_flag macro
- ora #decmode ;ignore decimal mode bit
- eor #\1|faod ;invert expected flags + always on bits
- endm
- endif
- endif
-
-;macros to set (register|memory|zeropage) & status
-set_stat macro ;setting flags in the processor status register
- load_flag \1
- pha ;use stack to load status
- plp
- endm
-
-set_a macro ;precharging accu & status
- load_flag \2
- pha ;use stack to load status
- lda #\1 ;precharge accu
- plp
- endm
-
-set_x macro ;precharging index & status
- load_flag \2
- pha ;use stack to load status
- ldx #\1 ;precharge index x
- plp
- endm
-
-set_y macro ;precharging index & status
- load_flag \2
- pha ;use stack to load status
- ldy #\1 ;precharge index y
- plp
- endm
-
-set_ax macro ;precharging indexed accu & immediate status
- load_flag \2
- pha ;use stack to load status
- lda \1,x ;precharge accu
- plp
- endm
-
-set_ay macro ;precharging indexed accu & immediate status
- load_flag \2
- pha ;use stack to load status
- lda \1,y ;precharge accu
- plp
- endm
-
-set_z macro ;precharging indexed zp & immediate status
- load_flag \2
- pha ;use stack to load status
- lda \1,x ;load to zeropage
- sta zpt
- plp
- endm
-
-set_zx macro ;precharging zp,x & immediate status
- load_flag \2
- pha ;use stack to load status
- lda \1,x ;load to indexed zeropage
- sta zpt,x
- plp
- endm
-
-set_abs macro ;precharging indexed memory & immediate status
- load_flag \2
- pha ;use stack to load status
- lda \1,x ;load to memory
- sta abst
- plp
- endm
-
-set_absx macro ;precharging abs,x & immediate status
- load_flag \2
- pha ;use stack to load status
- lda \1,x ;load to indexed memory
- sta abst,x
- plp
- endm
-
-;macros to test (register|memory|zeropage) & status & (mask)
-tst_stat macro ;testing flags in the processor status register
- php ;save status
- pla ;use stack to retrieve status
- pha
- cmp_flag \1
- trap_ne
- plp ;restore status
- endm
-
-tst_a macro ;testing result in accu & flags
- php ;save flags
- cmp #\1 ;test result
- trap_ne
- pla ;load status
- pha
- cmp_flag \2
- trap_ne
- plp ;restore status
- endm
-
-tst_x macro ;testing result in x index & flags
- php ;save flags
- cpx #\1 ;test result
- trap_ne
- pla ;load status
- pha
- cmp_flag \2
- trap_ne
- plp ;restore status
- endm
-
-tst_y macro ;testing result in y index & flags
- php ;save flags
- cpy #\1 ;test result
- trap_ne
- pla ;load status
- pha
- cmp_flag \2
- trap_ne
- plp ;restore status
- endm
-
-tst_ax macro ;indexed testing result in accu & flags
- php ;save flags
- cmp \1,x ;test result
- trap_ne
- pla ;load status
- eor_flag \3
- cmp \2,x ;test flags
- trap_ne ;
- endm
-
-tst_ay macro ;indexed testing result in accu & flags
- php ;save flags
- cmp \1,y ;test result
- trap_ne ;
- pla ;load status
- eor_flag \3
- cmp \2,y ;test flags
- trap_ne
- endm
-
-tst_z macro ;indexed testing result in zp & flags
- php ;save flags
- lda zpt
- cmp \1,x ;test result
- trap_ne
- pla ;load status
- eor_flag \3
- cmp \2,x ;test flags
- trap_ne
- endm
-
-tst_zx macro ;testing result in zp,x & flags
- php ;save flags
- lda zpt,x
- cmp \1,x ;test result
- trap_ne
- pla ;load status
- eor_flag \3
- cmp \2,x ;test flags
- trap_ne
- endm
-
-tst_abs macro ;indexed testing result in memory & flags
- php ;save flags
- lda abst
- cmp \1,x ;test result
- trap_ne
- pla ;load status
- eor_flag \3
- cmp \2,x ;test flags
- trap_ne
- endm
-
-tst_absx macro ;testing result in abs,x & flags
- php ;save flags
- lda abst,x
- cmp \1,x ;test result
- trap_ne
- pla ;load status
- eor_flag \3
- cmp \2,x ;test flags
- trap_ne
- endm
-
-; RAM integrity test
-; verifies that none of the previous tests has altered RAM outside of the
-; designated write areas.
-; uses zpt word as indirect pointer, zpt+2 word as checksum
- if ram_top > -1
-check_ram macro
- cld
- lda #0
- sta zpt ;set low byte of indirect pointer
- sta zpt+3 ;checksum high byte
- if disable_selfmod = 0
- sta range_adr ;reset self modifying code
- endif
- clc
- ldx #zp_bss-zero_page ;zeropage - write test area
-ccs3\? adc zero_page,x
- bcc ccs2\?
- inc zpt+3 ;carry to high byte
- clc
-ccs2\? inx
- bne ccs3\?
- ldx #hi(abs1) ;set high byte of indirect pointer
- stx zpt+1
- ldy #lo(abs1) ;data after write & execute test area
-ccs5\? adc (zpt),y
- bcc ccs4\?
- inc zpt+3 ;carry to high byte
- clc
-ccs4\? iny
- bne ccs5\?
- inx ;advance RAM high address
- stx zpt+1
- cpx #ram_top
- bne ccs5\?
- sta zpt+2 ;checksum low is
- cmp ram_chksm ;checksum low expected
- trap_ne ;checksum mismatch
- lda zpt+3 ;checksum high is
- cmp ram_chksm+1 ;checksum high expected
- trap_ne ;checksum mismatch
- endm
- else
-check_ram macro
- ;RAM check disabled - RAM size not set
- endm
- endif
-
-next_test macro ;make sure, tests don't jump the fence
- lda test_case ;previous test
- cmp #test_num
- trap_ne ;test is out of sequence
-test_num = test_num + 1
- lda #test_num ;*** next tests' number
- sta test_case
- ;check_ram ;uncomment to find altered RAM after each test
- endm
-
- if load_data_direct = 1
- data
- else
- bss ;uninitialized segment, copy of data at end of code!
- endif
- org zero_page
-;break test interrupt save
-irq_a ds 1 ;a register
-irq_x ds 1 ;x register
- if I_flag = 2
-;masking for I bit in status
-flag_I_on ds 1 ;or mask to load flags
-flag_I_off ds 1 ;and mask to load flags
- endif
-zpt ;6 bytes store/modify test area
-;add/subtract operand generation and result/flag prediction
-adfc ds 1 ;carry flag before op
-ad1 ds 1 ;operand 1 - accumulator
-ad2 ds 1 ;operand 2 - memory / immediate
-adrl ds 1 ;expected result bits 0-7
-adrh ds 1 ;expected result bit 8 (carry)
-adrf ds 1 ;expected flags NV0000ZC (only binary mode)
-sb2 ds 1 ;operand 2 complemented for subtract
-zp_bss
-zps db $80,1 ;additional shift pattern to test zero result & flag
-zp1 db $c3,$82,$41,0 ;test patterns for LDx BIT ROL ROR ASL LSR
-zp7f db $7f ;test pattern for compare
-;logical zeropage operands
-zpOR db 0,$1f,$71,$80 ;test pattern for OR
-zpAN db $0f,$ff,$7f,$80 ;test pattern for AND
-zpEO db $ff,$0f,$8f,$8f ;test pattern for EOR
-;indirect addressing pointers
-ind1 dw abs1 ;indirect pointer to pattern in absolute memory
- dw abs1+1
- dw abs1+2
- dw abs1+3
- dw abs7f
-inw1 dw abs1-$f8 ;indirect pointer for wrap-test pattern
-indt dw abst ;indirect pointer to store area in absolute memory
- dw abst+1
- dw abst+2
- dw abst+3
-inwt dw abst-$f8 ;indirect pointer for wrap-test store
-indAN dw absAN ;indirect pointer to AND pattern in absolute memory
- dw absAN+1
- dw absAN+2
- dw absAN+3
-indEO dw absEO ;indirect pointer to EOR pattern in absolute memory
- dw absEO+1
- dw absEO+2
- dw absEO+3
-indOR dw absOR ;indirect pointer to OR pattern in absolute memory
- dw absOR+1
- dw absOR+2
- dw absOR+3
-;add/subtract indirect pointers
-adi2 dw ada2 ;indirect pointer to operand 2 in absolute memory
-sbi2 dw sba2 ;indirect pointer to complemented operand 2 (SBC)
-adiy2 dw ada2-$ff ;with offset for indirect indexed
-sbiy2 dw sba2-$ff
-zp_bss_end
-
- org data_segment
-test_case ds 1 ;current test number
-ram_chksm ds 2 ;checksum for RAM integrity test
-;add/subtract operand copy - abs tests write area
-abst ;6 bytes store/modify test area
-ada2 ds 1 ;operand 2
-sba2 ds 1 ;operand 2 complemented for subtract
- ds 4 ;fill remaining bytes
-data_bss
- if load_data_direct = 1
-ex_andi and #0 ;execute immediate opcodes
- rts
-ex_eori eor #0 ;execute immediate opcodes
- rts
-ex_orai ora #0 ;execute immediate opcodes
- rts
-ex_adci adc #0 ;execute immediate opcodes
- rts
-ex_sbci sbc #0 ;execute immediate opcodes
- rts
- else
-ex_andi ds 3
-ex_eori ds 3
-ex_orai ds 3
-ex_adci ds 3
-ex_sbci ds 3
- endif
-;zps db $80,1 ;additional shift patterns test zero result & flag
-abs1 db $c3,$82,$41,0 ;test patterns for LDx BIT ROL ROR ASL LSR
-abs7f db $7f ;test pattern for compare
-;loads
-fLDx db fn,fn,0,fz ;expected flags for load
-;shifts
-rASL ;expected result ASL & ROL -carry
-rROL db 0,2,$86,$04,$82,0
-rROLc db 1,3,$87,$05,$83,1 ;expected result ROL +carry
-rLSR ;expected result LSR & ROR -carry
-rROR db $40,0,$61,$41,$20,0
-rRORc db $c0,$80,$e1,$c1,$a0,$80 ;expected result ROR +carry
-fASL ;expected flags for shifts
-fROL db fzc,0,fnc,fc,fn,fz ;no carry in
-fROLc db fc,0,fnc,fc,fn,0 ;carry in
-fLSR
-fROR db 0,fzc,fc,0,fc,fz ;no carry in
-fRORc db fn,fnc,fnc,fn,fnc,fn ;carry in
-;increments (decrements)
-rINC db $7f,$80,$ff,0,1 ;expected result for INC/DEC
-fINC db 0,fn,fn,fz,0 ;expected flags for INC/DEC
-;logical memory operand
-absOR db 0,$1f,$71,$80 ;test pattern for OR
-absAN db $0f,$ff,$7f,$80 ;test pattern for AND
-absEO db $ff,$0f,$8f,$8f ;test pattern for EOR
-;logical accu operand
-absORa db 0,$f1,$1f,0 ;test pattern for OR
-absANa db $f0,$ff,$ff,$ff ;test pattern for AND
-absEOa db $ff,$f0,$f0,$0f ;test pattern for EOR
-;logical results
-absrlo db 0,$ff,$7f,$80
-absflo db fz,fn,0,fn
-data_bss_end
-
-
- code
- org code_segment
-start lda #1
- sta $dc02
- cld
- ldx #$ff
- txs
- lda #0 ;*** test 0 = initialize
- sta test_case
-test_num = 0
-
-;stop interrupts before initializing BSS
- if I_flag = 1
- sei
- endif
-
-;initialize I/O for report channel
- if report = 1
- jsr report_init
- endif
-
-;pretest small branch offset
- ldx #5
- jmp psb_test
-psb_bwok
- ldy #5
- bne psb_forw
- trap ;branch should be taken
- dey ;forward landing zone
- dey
- dey
- dey
- dey
-psb_forw
- dey
- dey
- dey
- dey
- dey
- beq psb_fwok
- trap ;forward offset
-
- dex ;backward landing zone
- dex
- dex
- dex
- dex
-psb_back
- dex
- dex
- dex
- dex
- dex
- beq psb_bwok
- trap ;backward offset
-psb_test
- bne psb_back
- trap ;branch should be taken
-psb_fwok
-
-;initialize BSS segment
- if load_data_direct != 1
- ldx #zp_end-zp_init-1
-ld_zp lda zp_init,x
- sta zp_bss,x
- dex
- bpl ld_zp
- ldx #data_end-data_init-1
-ld_data lda data_init,x
- sta data_bss,x
- dex
- bpl ld_data
- if ROM_vectors = 1
- ldx #5
-ld_vect lda vec_init,x
- sta vec_bss,x
- dex
- bpl ld_vect
- endif
- endif
-
-;retain status of interrupt flag
- if I_flag = 2
- php
- pla
- and #4 ;isolate flag
- sta flag_I_on ;or mask
- eor #lo(~4) ;reverse
- sta flag_I_off ;and mask
- endif
-
-;generate checksum for RAM integrity test
- if ram_top > -1
- lda #0
- sta zpt ;set low byte of indirect pointer
- sta ram_chksm+1 ;checksum high byte
- if disable_selfmod = 0
- sta range_adr ;reset self modifying code
- endif
- clc
- ldx #zp_bss-zero_page ;zeropage - write test area
-gcs3 adc zero_page,x
- bcc gcs2
- inc ram_chksm+1 ;carry to high byte
- clc
-gcs2 inx
- bne gcs3
- ldx #hi(abs1) ;set high byte of indirect pointer
- stx zpt+1
- ldy #lo(abs1) ;data after write & execute test area
-gcs5 adc (zpt),y
- bcc gcs4
- inc ram_chksm+1 ;carry to high byte
- clc
-gcs4 iny
- bne gcs5
- inx ;advance RAM high address
- stx zpt+1
- cpx #ram_top
- bne gcs5
- sta ram_chksm ;checksum complete
- endif
- next_test
-
- if disable_selfmod = 0
-;testing relative addressing with BEQ
- ldy #$fe ;testing maximum range, not -1/-2 (invalid/self adr)
-range_loop
- dey ;next relative address
- tya
- tax ;precharge count to end of loop
- bpl range_fw ;calculate relative address
- clc ;avoid branch self or to relative address of branch
- adc #2
- nop ;offset landing zone - tolerate +/-5 offset to branch
- nop
- nop
- nop
- nop
-range_fw
- nop
- nop
- nop
- nop
- nop
- eor #$7f ;complement except sign
- sta range_adr ;load into test target
- lda #0 ;should set zero flag in status register
- jmp range_op
-
- dex ; offset landing zone - backward branch too far
- dex
- dex
- dex
- dex
- ;relative address target field with branch under test in the middle
- dex ;-128 - max backward
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex ;-120
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex ;-110
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex ;-100
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex ;-90
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex ;-80
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex ;-70
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex ;-60
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex ;-50
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex ;-40
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex ;-30
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex ;-20
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex ;-10
- dex
- dex
- dex
- dex
- dex
- dex
- dex ;-3
-range_op ;test target with zero flag=0, z=1 if previous dex
-range_adr = *+1 ;modifiable relative address
- beq *+64 ;+64 if called without modification
- dex ;+0
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex ;+10
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex ;+20
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex ;+30
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex ;+40
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex ;+50
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex ;+60
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex ;+70
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex ;+80
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex ;+90
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex ;+100
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex ;+110
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex
- dex ;+120
- dex
- dex
- dex
- dex
- dex
- dex
- nop ;offset landing zone - forward branch too far
- nop
- nop
- nop
- nop
- beq range_ok ;+127 - max forward
- trap ; bad range
- nop ;offset landing zone - tolerate +/-5 offset to branch
- nop
- nop
- nop
- nop
-range_ok
- nop
- nop
- nop
- nop
- nop
- cpy #0
- beq range_end
- jmp range_loop
-range_end ;range test successful
- endif
- next_test
-
-;partial test BNE & CMP, CPX, CPY immediate
- cpy #1 ;testing BNE true
- bne test_bne
- trap
-test_bne
- lda #0
- cmp #0 ;test compare immediate
- trap_ne
- trap_cc
- trap_mi
- cmp #1
- trap_eq
- trap_cs
- trap_pl
- tax
- cpx #0 ;test compare x immediate
- trap_ne
- trap_cc
- trap_mi
- cpx #1
- trap_eq
- trap_cs
- trap_pl
- tay
- cpy #0 ;test compare y immediate
- trap_ne
- trap_cc
- trap_mi
- cpy #1
- trap_eq
- trap_cs
- trap_pl
- next_test
-;testing stack operations PHA PHP PLA PLP
-
- ldx #$ff ;initialize stack
- txs
- lda #$55
- pha
- lda #$aa
- pha
- cmp $1fe ;on stack ?
- trap_ne
- tsx
- txa ;overwrite accu
- cmp #$fd ;sp decremented?
- trap_ne
- pla
- cmp #$aa ;successful retreived from stack?
- trap_ne
- pla
- cmp #$55
- trap_ne
- cmp $1ff ;remains on stack?
- trap_ne
- tsx
- cpx #$ff ;sp incremented?
- trap_ne
- next_test
-
-;testing branch decisions BPL BMI BVC BVS BCC BCS BNE BEQ
- set_stat $ff ;all on
- bpl nbr1 ;branches should not be taken
- bvc nbr2
- bcc nbr3
- bne nbr4
- bmi br1 ;branches should be taken
- trap
-br1 bvs br2
- trap
-br2 bcs br3
- trap
-br3 beq br4
- trap
-nbr1
- trap ;previous bpl taken
-nbr2
- trap ;previous bvc taken
-nbr3
- trap ;previous bcc taken
-nbr4
- trap ;previous bne taken
-br4 php
- tsx
- cpx #$fe ;sp after php?
- trap_ne
- pla
- cmp_flag $ff ;returned all flags on?
- trap_ne
- tsx
- cpx #$ff ;sp after php?
- trap_ne
- set_stat 0 ;all off
- bmi nbr11 ;branches should not be taken
- bvs nbr12
- bcs nbr13
- beq nbr14
- bpl br11 ;branches should be taken
- trap
-br11 bvc br12
- trap
-br12 bcc br13
- trap
-br13 bne br14
- trap
-nbr11
- trap ;previous bmi taken
-nbr12
- trap ;previous bvs taken
-nbr13
- trap ;previous bcs taken
-nbr14
- trap ;previous beq taken
-br14 php
- pla
- cmp_flag 0 ;flags off except break (pushed by sw) + reserved?
- trap_ne
- ;crosscheck flags
- set_stat zero
- bne brzs1
- beq brzs2
-brzs1
- trap ;branch zero/non zero
-brzs2 bcs brzs3
- bcc brzs4
-brzs3
- trap ;branch carry/no carry
-brzs4 bmi brzs5
- bpl brzs6
-brzs5
- trap ;branch minus/plus
-brzs6 bvs brzs7
- bvc brzs8
-brzs7
- trap ;branch overflow/no overflow
-brzs8
- set_stat carry
- beq brcs1
- bne brcs2
-brcs1
- trap ;branch zero/non zero
-brcs2 bcc brcs3
- bcs brcs4
-brcs3
- trap ;branch carry/no carry
-brcs4 bmi brcs5
- bpl brcs6
-brcs5
- trap ;branch minus/plus
-brcs6 bvs brcs7
- bvc brcs8
-brcs7
- trap ;branch overflow/no overflow
-
-brcs8
- set_stat minus
- beq brmi1
- bne brmi2
-brmi1
- trap ;branch zero/non zero
-brmi2 bcs brmi3
- bcc brmi4
-brmi3
- trap ;branch carry/no carry
-brmi4 bpl brmi5
- bmi brmi6
-brmi5
- trap ;branch minus/plus
-brmi6 bvs brmi7
- bvc brmi8
-brmi7
- trap ;branch overflow/no overflow
-brmi8
- set_stat overfl
- beq brvs1
- bne brvs2
-brvs1
- trap ;branch zero/non zero
-brvs2 bcs brvs3
- bcc brvs4
-brvs3
- trap ;branch carry/no carry
-brvs4 bmi brvs5
- bpl brvs6
-brvs5
- trap ;branch minus/plus
-brvs6 bvc brvs7
- bvs brvs8
-brvs7
- trap ;branch overflow/no overflow
-brvs8
- set_stat $ff-zero
- beq brzc1
- bne brzc2
-brzc1
- trap ;branch zero/non zero
-brzc2 bcc brzc3
- bcs brzc4
-brzc3
- trap ;branch carry/no carry
-brzc4 bpl brzc5
- bmi brzc6
-brzc5
- trap ;branch minus/plus
-brzc6 bvc brzc7
- bvs brzc8
-brzc7
- trap ;branch overflow/no overflow
-brzc8
- set_stat $ff-carry
- bne brcc1
- beq brcc2
-brcc1
- trap ;branch zero/non zero
-brcc2 bcs brcc3
- bcc brcc4
-brcc3
- trap ;branch carry/no carry
-brcc4 bpl brcc5
- bmi brcc6
-brcc5
- trap ;branch minus/plus
-brcc6 bvc brcc7
- bvs brcc8
-brcc7
- trap ;branch overflow/no overflow
-brcc8
- set_stat $ff-minus
- bne brpl1
- beq brpl2
-brpl1
- trap ;branch zero/non zero
-brpl2 bcc brpl3
- bcs brpl4
-brpl3
- trap ;branch carry/no carry
-brpl4 bmi brpl5
- bpl brpl6
-brpl5
- trap ;branch minus/plus
-brpl6 bvc brpl7
- bvs brpl8
-brpl7
- trap ;branch overflow/no overflow
-brpl8
- set_stat $ff-overfl
- bne brvc1
- beq brvc2
-brvc1
- trap ;branch zero/non zero
-brvc2 bcc brvc3
- bcs brvc4
-brvc3
- trap ;branch carry/no carry
-brvc4 bpl brvc5
- bmi brvc6
-brvc5
- trap ;branch minus/plus
-brvc6 bvs brvc7
- bvc brvc8
-brvc7
- trap ;branch overflow/no overflow
-brvc8
- next_test
-
-; test PHA does not alter flags or accumulator but PLA does
- ldx #$55 ;x & y protected
- ldy #$aa
- set_a 1,$ff ;push
- pha
- tst_a 1,$ff
- set_a 0,0
- pha
- tst_a 0,0
- set_a $ff,$ff
- pha
- tst_a $ff,$ff
- set_a 1,0
- pha
- tst_a 1,0
- set_a 0,$ff
- pha
- tst_a 0,$ff
- set_a $ff,0
- pha
- tst_a $ff,0
- set_a 0,$ff ;pull
- pla
- tst_a $ff,$ff-zero
- set_a $ff,0
- pla
- tst_a 0,zero
- set_a $fe,$ff
- pla
- tst_a 1,$ff-zero-minus
- set_a 0,0
- pla
- tst_a $ff,minus
- set_a $ff,$ff
- pla
- tst_a 0,$ff-minus
- set_a $fe,0
- pla
- tst_a 1,0
- cpx #$55 ;x & y unchanged?
- trap_ne
- cpy #$aa
- trap_ne
- next_test
-
-; partial pretest EOR #
- set_a $3c,0
- eor #$c3
- tst_a $ff,fn
- set_a $c3,0
- eor #$c3
- tst_a 0,fz
- next_test
-
-; PC modifying instructions except branches (NOP, JMP, JSR, RTS, BRK, RTI)
-; testing NOP
- ldx #$24
- ldy #$42
- set_a $18,0
- nop
- tst_a $18,0
- cpx #$24
- trap_ne
- cpy #$42
- trap_ne
- ldx #$db
- ldy #$bd
- set_a $e7,$ff
- nop
- tst_a $e7,$ff
- cpx #$db
- trap_ne
- cpy #$bd
- trap_ne
- next_test
-
-; jump absolute
- set_stat $0
- lda #'F'
- ldx #'A'
- ldy #'R' ;N=0, V=0, Z=0, C=0
- jmp test_far
- nop
- nop
- trap_ne ;runover protection
- inx
- inx
-far_ret
- trap_eq ;returned flags OK?
- trap_pl
- trap_cc
- trap_vc
- cmp #('F'^$aa) ;returned registers OK?
- trap_ne
- cpx #('A'+1)
- trap_ne
- cpy #('R'-3)
- trap_ne
- dex
- iny
- iny
- iny
- eor #$aa ;N=0, V=1, Z=0, C=1
- jmp test_near
- nop
- nop
- trap_ne ;runover protection
- inx
- inx
-test_near
- trap_eq ;passed flags OK?
- trap_mi
- trap_cc
- trap_vc
- cmp #'F' ;passed registers OK?
- trap_ne
- cpx #'A'
- trap_ne
- cpy #'R'
- trap_ne
- next_test
-
-; jump indirect
- set_stat 0
- lda #'I'
- ldx #'N'
- ldy #'D' ;N=0, V=0, Z=0, C=0
- jmp (ptr_tst_ind)
- nop
- trap_ne ;runover protection
- dey
- dey
-ind_ret
- php ;either SP or Y count will fail, if we do not hit
- dey
- dey
- dey
- plp
- trap_eq ;returned flags OK?
- trap_pl
- trap_cc
- trap_vc
- cmp #('I'^$aa) ;returned registers OK?
- trap_ne
- cpx #('N'+1)
- trap_ne
- cpy #('D'-6)
- trap_ne
- tsx ;SP check
- cpx #$ff
- trap_ne
- next_test
-
-; jump subroutine & return from subroutine
- set_stat 0
- lda #'J'
- ldx #'S'
- ldy #'R' ;N=0, V=0, Z=0, C=0
- jsr test_jsr
-jsr_ret = *-1 ;last address of jsr = return address
- php ;either SP or Y count will fail, if we do not hit
- dey
- dey
- dey
- plp
- trap_eq ;returned flags OK?
- trap_pl
- trap_cc
- trap_vc
- cmp #('J'^$aa) ;returned registers OK?
- trap_ne
- cpx #('S'+1)
- trap_ne
- cpy #('R'-6)
- trap_ne
- tsx ;sp?
- cpx #$ff
- trap_ne
- next_test
-
-; break & return from interrupt
- if ROM_vectors = 1
- load_flag 0 ;with interrupts enabled if allowed!
- pha
- lda #'B'
- ldx #'R'
- ldy #'K'
- plp ;N=0, V=0, Z=0, C=0
- brk
- else
- lda #hi brk_ret0 ;emulated break
- pha
- lda #lo brk_ret0
- pha
- load_flag fao ;set break & unused on stack
- pha
- load_flag intdis ;during interrupt
- pha
- lda #'B'
- ldx #'R'
- ldy #'K'
- plp ;N=0, V=0, Z=0, C=0
- jmp irq_trap
- endif
- dey ;should not be executed
-brk_ret0 ;address of break return
- php ;either SP or Y count will fail, if we do not hit
- dey
- dey
- dey
- cmp #'B'^$aa ;returned registers OK?
- ;the IRQ vector was never executed if A & X stay unmodified
- trap_ne
- cpx #'R'+1
- trap_ne
- cpy #'K'-6
- trap_ne
- pla ;returned flags OK (unchanged)?
- cmp_flag 0
- trap_ne
- tsx ;sp?
- cpx #$ff
- trap_ne
- if ROM_vectors = 1
- load_flag $ff ;with interrupts disabled if allowed!
- pha
- lda #$ff-'B'
- ldx #$ff-'R'
- ldy #$ff-'K'
- plp ;N=1, V=1, Z=1, C=1
- brk
- else
- lda #hi brk_ret1 ;emulated break
- pha
- lda #lo brk_ret1
- pha
- load_flag $ff
- pha ;set break & unused on stack
- pha ;actual flags
- lda #$ff-'B'
- ldx #$ff-'R'
- ldy #$ff-'K'
- plp ;N=1, V=1, Z=1, C=1
- jmp irq_trap
- endif
- dey ;should not be executed
-brk_ret1 ;address of break return
- php ;either SP or Y count will fail, if we do not hit
- dey
- dey
- dey
- cmp #($ff-'B')^$aa ;returned registers OK?
- ;the IRQ vector was never executed if A & X stay unmodified
- trap_ne
- cpx #$ff-'R'+1
- trap_ne
- cpy #$ff-'K'-6
- trap_ne
- pla ;returned flags OK (unchanged)?
- cmp_flag $ff
- trap_ne
- tsx ;sp?
- cpx #$ff
- trap_ne
- next_test
-
-; test set and clear flags CLC CLI CLD CLV SEC SEI SED
- set_stat $ff
- clc
- tst_stat $ff-carry
- sec
- tst_stat $ff
- if I_flag = 3
- cli
- tst_stat $ff-intdis
- sei
- tst_stat $ff
- endif
- cld
- tst_stat $ff-decmode
- sed
- tst_stat $ff
- clv
- tst_stat $ff-overfl
- set_stat 0
- tst_stat 0
- sec
- tst_stat carry
- clc
- tst_stat 0
- if I_flag = 3
- sei
- tst_stat intdis
- cli
- tst_stat 0
- endif
- sed
- tst_stat decmode
- cld
- tst_stat 0
- set_stat overfl
- tst_stat overfl
- clv
- tst_stat 0
- next_test
-; testing index register increment/decrement and transfer
-; INX INY DEX DEY TAX TXA TAY TYA
- ldx #$fe
- set_stat $ff
- inx ;ff
- tst_x $ff,$ff-zero
- inx ;00
- tst_x 0,$ff-minus
- inx ;01
- tst_x 1,$ff-minus-zero
- dex ;00
- tst_x 0,$ff-minus
- dex ;ff
- tst_x $ff,$ff-zero
- dex ;fe
- set_stat 0
- inx ;ff
- tst_x $ff,minus
- inx ;00
- tst_x 0,zero
- inx ;01
- tst_x 1,0
- dex ;00
- tst_x 0,zero
- dex ;ff
- tst_x $ff,minus
-
- ldy #$fe
- set_stat $ff
- iny ;ff
- tst_y $ff,$ff-zero
- iny ;00
- tst_y 0,$ff-minus
- iny ;01
- tst_y 1,$ff-minus-zero
- dey ;00
- tst_y 0,$ff-minus
- dey ;ff
- tst_y $ff,$ff-zero
- dey ;fe
- set_stat 0
- iny ;ff
- tst_y $ff,0+minus
- iny ;00
- tst_y 0,zero
- iny ;01
- tst_y 1,0
- dey ;00
- tst_y 0,zero
- dey ;ff
- tst_y $ff,minus
-
- ldx #$ff
- set_stat $ff
- txa
- tst_a $ff,$ff-zero
- php
- inx ;00
- plp
- txa
- tst_a 0,$ff-minus
- php
- inx ;01
- plp
- txa
- tst_a 1,$ff-minus-zero
- set_stat 0
- txa
- tst_a 1,0
- php
- dex ;00
- plp
- txa
- tst_a 0,zero
- php
- dex ;ff
- plp
- txa
- tst_a $ff,minus
-
- ldy #$ff
- set_stat $ff
- tya
- tst_a $ff,$ff-zero
- php
- iny ;00
- plp
- tya
- tst_a 0,$ff-minus
- php
- iny ;01
- plp
- tya
- tst_a 1,$ff-minus-zero
- set_stat 0
- tya
- tst_a 1,0
- php
- dey ;00
- plp
- tya
- tst_a 0,zero
- php
- dey ;ff
- plp
- tya
- tst_a $ff,minus
-
- load_flag $ff
- pha
- ldx #$ff ;ff
- txa
- plp
- tay
- tst_y $ff,$ff-zero
- php
- inx ;00
- txa
- plp
- tay
- tst_y 0,$ff-minus
- php
- inx ;01
- txa
- plp
- tay
- tst_y 1,$ff-minus-zero
- load_flag 0
- pha
- lda #0
- txa
- plp
- tay
- tst_y 1,0
- php
- dex ;00
- txa
- plp
- tay
- tst_y 0,zero
- php
- dex ;ff
- txa
- plp
- tay
- tst_y $ff,minus
-
-
- load_flag $ff
- pha
- ldy #$ff ;ff
- tya
- plp
- tax
- tst_x $ff,$ff-zero
- php
- iny ;00
- tya
- plp
- tax
- tst_x 0,$ff-minus
- php
- iny ;01
- tya
- plp
- tax
- tst_x 1,$ff-minus-zero
- load_flag 0
- pha
- lda #0 ;preset status
- tya
- plp
- tax
- tst_x 1,0
- php
- dey ;00
- tya
- plp
- tax
- tst_x 0,zero
- php
- dey ;ff
- tya
- plp
- tax
- tst_x $ff,minus
- next_test
-
-;TSX sets NZ - TXS does not
-; This section also tests for proper stack wrap around.
- ldx #1 ;01
- set_stat $ff
- txs
- php
- lda $101
- cmp_flag $ff
- trap_ne
- set_stat 0
- txs
- php
- lda $101
- cmp_flag 0
- trap_ne
- dex ;00
- set_stat $ff
- txs
- php
- lda $100
- cmp_flag $ff
- trap_ne
- set_stat 0
- txs
- php
- lda $100
- cmp_flag 0
- trap_ne
- dex ;ff
- set_stat $ff
- txs
- php
- lda $1ff
- cmp_flag $ff
- trap_ne
- set_stat 0
- txs
- php
- lda $1ff
- cmp_flag 0
-
- ldx #1
- txs ;sp=01
- set_stat $ff
- tsx ;clears Z, N
- php ;sp=00
- cpx #1
- trap_ne
- lda $101
- cmp_flag $ff-minus-zero
- trap_ne
- set_stat $ff
- tsx ;clears N, sets Z
- php ;sp=ff
- cpx #0
- trap_ne
- lda $100
- cmp_flag $ff-minus
- trap_ne
- set_stat $ff
- tsx ;clears N, sets Z
- php ;sp=fe
- cpx #$ff
- trap_ne
- lda $1ff
- cmp_flag $ff-zero
- trap_ne
-
- ldx #1
- txs ;sp=01
- set_stat 0
- tsx ;clears Z, N
- php ;sp=00
- cpx #1
- trap_ne
- lda $101
- cmp_flag 0
- trap_ne
- set_stat 0
- tsx ;clears N, sets Z
- php ;sp=ff
- cpx #0
- trap_ne
- lda $100
- cmp_flag zero
- trap_ne
- set_stat 0
- tsx ;clears N, sets Z
- php ;sp=fe
- cpx #$ff
- trap_ne
- lda $1ff
- cmp_flag minus
- trap_ne
- pla ;sp=ff
- next_test
-
-; testing index register load & store LDY LDX STY STX all addressing modes
-; LDX / STX - zp,y / abs,y
- ldy #3
-tldx
- set_stat 0
- ldx zp1,y
- php ;test stores do not alter flags
- txa
- eor #$c3
- plp
- sta abst,y
- php ;flags after load/store sequence
- eor #$c3
- cmp abs1,y ;test result
- trap_ne
- pla ;load status
- eor_flag 0
- cmp fLDx,y ;test flags
- trap_ne
- dey
- bpl tldx
-
- ldy #3
-tldx1
- set_stat $ff
- ldx zp1,y
- php ;test stores do not alter flags
- txa
- eor #$c3
- plp
- sta abst,y
- php ;flags after load/store sequence
- eor #$c3
- cmp abs1,y ;test result
- trap_ne
- pla ;load status
- eor_flag lo~fnz ;mask bits not altered
- cmp fLDx,y ;test flags
- trap_ne
- dey
- bpl tldx1
-
- ldy #3
-tldx2
- set_stat 0
- ldx abs1,y
- php ;test stores do not alter flags
- txa
- eor #$c3
- tax
- plp
- stx zpt,y
- php ;flags after load/store sequence
- eor #$c3
- cmp zp1,y ;test result
- trap_ne
- pla ;load status
- eor_flag 0
- cmp fLDx,y ;test flags
- trap_ne
- dey
- bpl tldx2
-
- ldy #3
-tldx3
- set_stat $ff
- ldx abs1,y
- php ;test stores do not alter flags
- txa
- eor #$c3
- tax
- plp
- stx zpt,y
- php ;flags after load/store sequence
- eor #$c3
- cmp zp1,y ;test result
- trap_ne
- pla ;load status
- eor_flag lo~fnz ;mask bits not altered
- cmp fLDx,y ;test flags
- trap_ne
- dey
- bpl tldx3
-
- ldy #3 ;testing store result
- ldx #0
-tstx lda zpt,y
- eor #$c3
- cmp zp1,y
- trap_ne ;store to zp data
- stx zpt,y ;clear
- lda abst,y
- eor #$c3
- cmp abs1,y
- trap_ne ;store to abs data
- txa
- sta abst,y ;clear
- dey
- bpl tstx
- next_test
-
-; indexed wraparound test (only zp should wrap)
- ldy #3+$fa
-tldx4 ldx zp1-$fa&$ff,y ;wrap on indexed zp
- txa
- sta abst-$fa,y ;no STX abs,y!
- dey
- cpy #$fa
- bcs tldx4
- ldy #3+$fa
-tldx5 ldx abs1-$fa,y ;no wrap on indexed abs
- stx zpt-$fa&$ff,y
- dey
- cpy #$fa
- bcs tldx5
- ldy #3 ;testing wraparound result
- ldx #0
-tstx1 lda zpt,y
- cmp zp1,y
- trap_ne ;store to zp data
- stx zpt,y ;clear
- lda abst,y
- cmp abs1,y
- trap_ne ;store to abs data
- txa
- sta abst,y ;clear
- dey
- bpl tstx1
- next_test
-
-; LDY / STY - zp,x / abs,x
- ldx #3
-tldy
- set_stat 0
- ldy zp1,x
- php ;test stores do not alter flags
- tya
- eor #$c3
- plp
- sta abst,x
- php ;flags after load/store sequence
- eor #$c3
- cmp abs1,x ;test result
- trap_ne
- pla ;load status
- eor_flag 0
- cmp fLDx,x ;test flags
- trap_ne
- dex
- bpl tldy
-
- ldx #3
-tldy1
- set_stat $ff
- ldy zp1,x
- php ;test stores do not alter flags
- tya
- eor #$c3
- plp
- sta abst,x
- php ;flags after load/store sequence
- eor #$c3
- cmp abs1,x ;test result
- trap_ne
- pla ;load status
- eor_flag lo~fnz ;mask bits not altered
- cmp fLDx,x ;test flags
- trap_ne
- dex
- bpl tldy1
-
- ldx #3
-tldy2
- set_stat 0
- ldy abs1,x
- php ;test stores do not alter flags
- tya
- eor #$c3
- tay
- plp
- sty zpt,x
- php ;flags after load/store sequence
- eor #$c3
- cmp zp1,x ;test result
- trap_ne
- pla ;load status
- eor_flag 0
- cmp fLDx,x ;test flags
- trap_ne
- dex
- bpl tldy2
-
- ldx #3
-tldy3
- set_stat $ff
- ldy abs1,x
- php ;test stores do not alter flags
- tya
- eor #$c3
- tay
- plp
- sty zpt,x
- php ;flags after load/store sequence
- eor #$c3
- cmp zp1,x ;test result
- trap_ne
- pla ;load status
- eor_flag lo~fnz ;mask bits not altered
- cmp fLDx,x ;test flags
- trap_ne
- dex
- bpl tldy3
-
- ldx #3 ;testing store result
- ldy #0
-tsty lda zpt,x
- eor #$c3
- cmp zp1,x
- trap_ne ;store to zp,x data
- sty zpt,x ;clear
- lda abst,x
- eor #$c3
- cmp abs1,x
- trap_ne ;store to abs,x data
- txa
- sta abst,x ;clear
- dex
- bpl tsty
- next_test
-
-; indexed wraparound test (only zp should wrap)
- ldx #3+$fa
-tldy4 ldy zp1-$fa&$ff,x ;wrap on indexed zp
- tya
- sta abst-$fa,x ;no STX abs,x!
- dex
- cpx #$fa
- bcs tldy4
- ldx #3+$fa
-tldy5 ldy abs1-$fa,x ;no wrap on indexed abs
- sty zpt-$fa&$ff,x
- dex
- cpx #$fa
- bcs tldy5
- ldx #3 ;testing wraparound result
- ldy #0
-tsty1 lda zpt,x
- cmp zp1,x
- trap_ne ;store to zp,x data
- sty zpt,x ;clear
- lda abst,x
- cmp abs1,x
- trap_ne ;store to abs,x data
- txa
- sta abst,x ;clear
- dex
- bpl tsty1
- next_test
-
-; LDX / STX - zp / abs / #
- set_stat 0
- ldx zp1
- php ;test stores do not alter flags
- txa
- eor #$c3
- tax
- plp
- stx abst
- php ;flags after load/store sequence
- eor #$c3
- tax
- cpx #$c3 ;test result
- trap_ne
- pla ;load status
- eor_flag 0
- cmp fLDx ;test flags
- trap_ne
- set_stat 0
- ldx zp1+1
- php ;test stores do not alter flags
- txa
- eor #$c3
- tax
- plp
- stx abst+1
- php ;flags after load/store sequence
- eor #$c3
- tax
- cpx #$82 ;test result
- trap_ne
- pla ;load status
- eor_flag 0
- cmp fLDx+1 ;test flags
- trap_ne
- set_stat 0
- ldx zp1+2
- php ;test stores do not alter flags
- txa
- eor #$c3
- tax
- plp
- stx abst+2
- php ;flags after load/store sequence
- eor #$c3
- tax
- cpx #$41 ;test result
- trap_ne
- pla ;load status
- eor_flag 0
- cmp fLDx+2 ;test flags
- trap_ne
- set_stat 0
- ldx zp1+3
- php ;test stores do not alter flags
- txa
- eor #$c3
- tax
- plp
- stx abst+3
- php ;flags after load/store sequence
- eor #$c3
- tax
- cpx #0 ;test result
- trap_ne
- pla ;load status
- eor_flag 0
- cmp fLDx+3 ;test flags
- trap_ne
-
- set_stat $ff
- ldx zp1
- php ;test stores do not alter flags
- txa
- eor #$c3
- tax
- plp
- stx abst
- php ;flags after load/store sequence
- eor #$c3
- tax
- cpx #$c3 ;test result
- trap_ne ;
- pla ;load status
- eor_flag lo~fnz ;mask bits not altered
- cmp fLDx ;test flags
- trap_ne
- set_stat $ff
- ldx zp1+1
- php ;test stores do not alter flags
- txa
- eor #$c3
- tax
- plp
- stx abst+1
- php ;flags after load/store sequence
- eor #$c3
- tax
- cpx #$82 ;test result
- trap_ne
- pla ;load status
- eor_flag lo~fnz ;mask bits not altered
- cmp fLDx+1 ;test flags
- trap_ne
- set_stat $ff
- ldx zp1+2
- php ;test stores do not alter flags
- txa
- eor #$c3
- tax
- plp
- stx abst+2
- php ;flags after load/store sequence
- eor #$c3
- tax
- cpx #$41 ;test result
- trap_ne ;
- pla ;load status
- eor_flag lo~fnz ;mask bits not altered
- cmp fLDx+2 ;test flags
- trap_ne
- set_stat $ff
- ldx zp1+3
- php ;test stores do not alter flags
- txa
- eor #$c3
- tax
- plp
- stx abst+3
- php ;flags after load/store sequence
- eor #$c3
- tax
- cpx #0 ;test result
- trap_ne
- pla ;load status
- eor_flag lo~fnz ;mask bits not altered
- cmp fLDx+3 ;test flags
- trap_ne
-
- set_stat 0
- ldx abs1
- php ;test stores do not alter flags
- txa
- eor #$c3
- tax
- plp
- stx zpt
- php ;flags after load/store sequence
- eor #$c3
- cmp zp1 ;test result
- trap_ne
- pla ;load status
- eor_flag 0
- cmp fLDx ;test flags
- trap_ne
- set_stat 0
- ldx abs1+1
- php ;test stores do not alter flags
- txa
- eor #$c3
- tax
- plp
- stx zpt+1
- php ;flags after load/store sequence
- eor #$c3
- cmp zp1+1 ;test result
- trap_ne
- pla ;load status
- eor_flag 0
- cmp fLDx+1 ;test flags
- trap_ne
- set_stat 0
- ldx abs1+2
- php ;test stores do not alter flags
- txa
- eor #$c3
- tax
- plp
- stx zpt+2
- php ;flags after load/store sequence
- eor #$c3
- cmp zp1+2 ;test result
- trap_ne
- pla ;load status
- eor_flag 0
- cmp fLDx+2 ;test flags
- trap_ne
- set_stat 0
- ldx abs1+3
- php ;test stores do not alter flags
- txa
- eor #$c3
- tax
- plp
- stx zpt+3
- php ;flags after load/store sequence
- eor #$c3
- cmp zp1+3 ;test result
- trap_ne
- pla ;load status
- eor_flag 0
- cmp fLDx+3 ;test flags
- trap_ne
-
- set_stat $ff
- ldx abs1
- php ;test stores do not alter flags
- txa
- eor #$c3
- tax
- plp
- stx zpt
- php ;flags after load/store sequence
- eor #$c3
- tax
- cpx zp1 ;test result
- trap_ne
- pla ;load status
- eor_flag lo~fnz ;mask bits not altered
- cmp fLDx ;test flags
- trap_ne
- set_stat $ff
- ldx abs1+1
- php ;test stores do not alter flags
- txa
- eor #$c3
- tax
- plp
- stx zpt+1
- php ;flags after load/store sequence
- eor #$c3
- tax
- cpx zp1+1 ;test result
- trap_ne
- pla ;load status
- eor_flag lo~fnz ;mask bits not altered
- cmp fLDx+1 ;test flags
- trap_ne
- set_stat $ff
- ldx abs1+2
- php ;test stores do not alter flags
- txa
- eor #$c3
- tax
- plp
- stx zpt+2
- php ;flags after load/store sequence
- eor #$c3
- tax
- cpx zp1+2 ;test result
- trap_ne
- pla ;load status
- eor_flag lo~fnz ;mask bits not altered
- cmp fLDx+2 ;test flags
- trap_ne
- set_stat $ff
- ldx abs1+3
- php ;test stores do not alter flags
- txa
- eor #$c3
- tax
- plp
- stx zpt+3
- php ;flags after load/store sequence
- eor #$c3
- tax
- cpx zp1+3 ;test result
- trap_ne
- pla ;load status
- eor_flag lo~fnz ;mask bits not altered
- cmp fLDx+3 ;test flags
- trap_ne
-
- set_stat 0
- ldx #$c3
- php
- cpx abs1 ;test result
- trap_ne
- pla ;load status
- eor_flag 0
- cmp fLDx ;test flags
- trap_ne
- set_stat 0
- ldx #$82
- php
- cpx abs1+1 ;test result
- trap_ne
- pla ;load status
- eor_flag 0
- cmp fLDx+1 ;test flags
- trap_ne
- set_stat 0
- ldx #$41
- php
- cpx abs1+2 ;test result
- trap_ne
- pla ;load status
- eor_flag 0
- cmp fLDx+2 ;test flags
- trap_ne
- set_stat 0
- ldx #0
- php
- cpx abs1+3 ;test result
- trap_ne
- pla ;load status
- eor_flag 0
- cmp fLDx+3 ;test flags
- trap_ne
-
- set_stat $ff
- ldx #$c3
- php
- cpx abs1 ;test result
- trap_ne
- pla ;load status
- eor_flag lo~fnz ;mask bits not altered
- cmp fLDx ;test flags
- trap_ne
- set_stat $ff
- ldx #$82
- php
- cpx abs1+1 ;test result
- trap_ne
- pla ;load status
- eor_flag lo~fnz ;mask bits not altered
- cmp fLDx+1 ;test flags
- trap_ne
- set_stat $ff
- ldx #$41
- php
- cpx abs1+2 ;test result
- trap_ne
- pla ;load status
- eor_flag lo~fnz ;mask bits not altered
- cmp fLDx+2 ;test flags
- trap_ne
- set_stat $ff
- ldx #0
- php
- cpx abs1+3 ;test result
- trap_ne
- pla ;load status
- eor_flag lo~fnz ;mask bits not altered
- cmp fLDx+3 ;test flags
- trap_ne
-
- ldx #0
- lda zpt
- eor #$c3
- cmp zp1
- trap_ne ;store to zp data
- stx zpt ;clear
- lda abst
- eor #$c3
- cmp abs1
- trap_ne ;store to abs data
- stx abst ;clear
- lda zpt+1
- eor #$c3
- cmp zp1+1
- trap_ne ;store to zp data
- stx zpt+1 ;clear
- lda abst+1
- eor #$c3
- cmp abs1+1
- trap_ne ;store to abs data
- stx abst+1 ;clear
- lda zpt+2
- eor #$c3
- cmp zp1+2
- trap_ne ;store to zp data
- stx zpt+2 ;clear
- lda abst+2
- eor #$c3
- cmp abs1+2
- trap_ne ;store to abs data
- stx abst+2 ;clear
- lda zpt+3
- eor #$c3
- cmp zp1+3
- trap_ne ;store to zp data
- stx zpt+3 ;clear
- lda abst+3
- eor #$c3
- cmp abs1+3
- trap_ne ;store to abs data
- stx abst+3 ;clear
- next_test
-
-; LDY / STY - zp / abs / #
- set_stat 0
- ldy zp1
- php ;test stores do not alter flags
- tya
- eor #$c3
- tay
- plp
- sty abst
- php ;flags after load/store sequence
- eor #$c3
- tay
- cpy #$c3 ;test result
- trap_ne
- pla ;load status
- eor_flag 0
- cmp fLDx ;test flags
- trap_ne
- set_stat 0
- ldy zp1+1
- php ;test stores do not alter flags
- tya
- eor #$c3
- tay
- plp
- sty abst+1
- php ;flags after load/store sequence
- eor #$c3
- tay
- cpy #$82 ;test result
- trap_ne
- pla ;load status
- eor_flag 0
- cmp fLDx+1 ;test flags
- trap_ne
- set_stat 0
- ldy zp1+2
- php ;test stores do not alter flags
- tya
- eor #$c3
- tay
- plp
- sty abst+2
- php ;flags after load/store sequence
- eor #$c3
- tay
- cpy #$41 ;test result
- trap_ne
- pla ;load status
- eor_flag 0
- cmp fLDx+2 ;test flags
- trap_ne
- set_stat 0
- ldy zp1+3
- php ;test stores do not alter flags
- tya
- eor #$c3
- tay
- plp
- sty abst+3
- php ;flags after load/store sequence
- eor #$c3
- tay
- cpy #0 ;test result
- trap_ne
- pla ;load status
- eor_flag 0
- cmp fLDx+3 ;test flags
- trap_ne
-
- set_stat $ff
- ldy zp1
- php ;test stores do not alter flags
- tya
- eor #$c3
- tay
- plp
- sty abst
- php ;flags after load/store sequence
- eor #$c3
- tay
- cpy #$c3 ;test result
- trap_ne
- pla ;load status
- eor_flag lo~fnz ;mask bits not altered
- cmp fLDx ;test flags
- trap_ne
- set_stat $ff
- ldy zp1+1
- php ;test stores do not alter flags
- tya
- eor #$c3
- tay
- plp
- sty abst+1
- php ;flags after load/store sequence
- eor #$c3
- tay
- cpy #$82 ;test result
- trap_ne
- pla ;load status
- eor_flag lo~fnz ;mask bits not altered
- cmp fLDx+1 ;test flags
- trap_ne
- set_stat $ff
- ldy zp1+2
- php ;test stores do not alter flags
- tya
- eor #$c3
- tay
- plp
- sty abst+2
- php ;flags after load/store sequence
- eor #$c3
- tay
- cpy #$41 ;test result
- trap_ne
- pla ;load status
- eor_flag lo~fnz ;mask bits not altered
- cmp fLDx+2 ;test flags
- trap_ne
- set_stat $ff
- ldy zp1+3
- php ;test stores do not alter flags
- tya
- eor #$c3
- tay
- plp
- sty abst+3
- php ;flags after load/store sequence
- eor #$c3
- tay
- cpy #0 ;test result
- trap_ne
- pla ;load status
- eor_flag lo~fnz ;mask bits not altered
- cmp fLDx+3 ;test flags
- trap_ne
-
- set_stat 0
- ldy abs1
- php ;test stores do not alter flags
- tya
- eor #$c3
- tay
- plp
- sty zpt
- php ;flags after load/store sequence
- eor #$c3
- tay
- cpy zp1 ;test result
- trap_ne
- pla ;load status
- eor_flag 0
- cmp fLDx ;test flags
- trap_ne
- set_stat 0
- ldy abs1+1
- php ;test stores do not alter flags
- tya
- eor #$c3
- tay
- plp
- sty zpt+1
- php ;flags after load/store sequence
- eor #$c3
- tay
- cpy zp1+1 ;test result
- trap_ne
- pla ;load status
- eor_flag 0
- cmp fLDx+1 ;test flags
- trap_ne
- set_stat 0
- ldy abs1+2
- php ;test stores do not alter flags
- tya
- eor #$c3
- tay
- plp
- sty zpt+2
- php ;flags after load/store sequence
- eor #$c3
- tay
- cpy zp1+2 ;test result
- trap_ne
- pla ;load status
- eor_flag 0
- cmp fLDx+2 ;test flags
- trap_ne
- set_stat 0
- ldy abs1+3
- php ;test stores do not alter flags
- tya
- eor #$c3
- tay
- plp
- sty zpt+3
- php ;flags after load/store sequence
- eor #$c3
- tay
- cpy zp1+3 ;test result
- trap_ne
- pla ;load status
- eor_flag 0
- cmp fLDx+3 ;test flags
- trap_ne
-
- set_stat $ff
- ldy abs1
- php ;test stores do not alter flags
- tya
- eor #$c3
- tay
- plp
- sty zpt
- php ;flags after load/store sequence
- eor #$c3
- tay
- cmp zp1 ;test result
- trap_ne
- pla ;load status
- eor_flag lo~fnz ;mask bits not altered
- cmp fLDx ;test flags
- trap_ne
- set_stat $ff
- ldy abs1+1
- php ;test stores do not alter flags
- tya
- eor #$c3
- tay
- plp
- sty zpt+1
- php ;flags after load/store sequence
- eor #$c3
- tay
- cmp zp1+1 ;test result
- trap_ne
- pla ;load status
- eor_flag lo~fnz ;mask bits not altered
- cmp fLDx+1 ;test flags
- trap_ne
- set_stat $ff
- ldy abs1+2
- php ;test stores do not alter flags
- tya
- eor #$c3
- tay
- plp
- sty zpt+2
- php ;flags after load/store sequence
- eor #$c3
- tay
- cmp zp1+2 ;test result
- trap_ne
- pla ;load status
- eor_flag lo~fnz ;mask bits not altered
- cmp fLDx+2 ;test flags
- trap_ne
- set_stat $ff
- ldy abs1+3
- php ;test stores do not alter flags
- tya
- eor #$c3
- tay
- plp
- sty zpt+3
- php ;flags after load/store sequence
- eor #$c3
- tay
- cmp zp1+3 ;test result
- trap_ne
- pla ;load status
- eor_flag lo~fnz ;mask bits not altered
- cmp fLDx+3 ;test flags
- trap_ne
-
-
- set_stat 0
- ldy #$c3
- php
- cpy abs1 ;test result
- trap_ne
- pla ;load status
- eor_flag 0
- cmp fLDx ;test flags
- trap_ne
- set_stat 0
- ldy #$82
- php
- cpy abs1+1 ;test result
- trap_ne
- pla ;load status
- eor_flag 0
- cmp fLDx+1 ;test flags
- trap_ne
- set_stat 0
- ldy #$41
- php
- cpy abs1+2 ;test result
- trap_ne
- pla ;load status
- eor_flag 0
- cmp fLDx+2 ;test flags
- trap_ne
- set_stat 0
- ldy #0
- php
- cpy abs1+3 ;test result
- trap_ne
- pla ;load status
- eor_flag 0
- cmp fLDx+3 ;test flags
- trap_ne
-
- set_stat $ff
- ldy #$c3
- php
- cpy abs1 ;test result
- trap_ne
- pla ;load status
- eor_flag lo~fnz ;mask bits not altered
- cmp fLDx ;test flags
- trap_ne
- set_stat $ff
- ldy #$82
- php
- cpy abs1+1 ;test result
- trap_ne
- pla ;load status
- eor_flag lo~fnz ;mask bits not altered
- cmp fLDx+1 ;test flags
- trap_ne
- set_stat $ff
- ldy #$41
- php
- cpy abs1+2 ;test result
- trap_ne
- pla ;load status
- eor_flag lo~fnz ;mask bits not altered
- cmp fLDx+2 ;test flags
- trap_ne
- set_stat $ff
- ldy #0
- php
- cpy abs1+3 ;test result
- trap_ne
- pla ;load status
- eor_flag lo~fnz ;mask bits not altered
- cmp fLDx+3 ;test flags
- trap_ne
-
- ldy #0
- lda zpt
- eor #$c3
- cmp zp1
- trap_ne ;store to zp data
- sty zpt ;clear
- lda abst
- eor #$c3
- cmp abs1
- trap_ne ;store to abs data
- sty abst ;clear
- lda zpt+1
- eor #$c3
- cmp zp1+1
- trap_ne ;store to zp+1 data
- sty zpt+1 ;clear
- lda abst+1
- eor #$c3
- cmp abs1+1
- trap_ne ;store to abs+1 data
- sty abst+1 ;clear
- lda zpt+2
- eor #$c3
- cmp zp1+2
- trap_ne ;store to zp+2 data
- sty zpt+2 ;clear
- lda abst+2
- eor #$c3
- cmp abs1+2
- trap_ne ;store to abs+2 data
- sty abst+2 ;clear
- lda zpt+3
- eor #$c3
- cmp zp1+3
- trap_ne ;store to zp+3 data
- sty zpt+3 ;clear
- lda abst+3
- eor #$c3
- cmp abs1+3
- trap_ne ;store to abs+3 data
- sty abst+3 ;clear
- next_test
-
-; testing load / store accumulator LDA / STA all addressing modes
-; LDA / STA - zp,x / abs,x
- ldx #3
-tldax
- set_stat 0
- lda zp1,x
- php ;test stores do not alter flags
- eor #$c3
- plp
- sta abst,x
- php ;flags after load/store sequence
- eor #$c3
- cmp abs1,x ;test result
- trap_ne
- pla ;load status
- eor_flag 0
- cmp fLDx,x ;test flags
- trap_ne
- dex
- bpl tldax
-
- ldx #3
-tldax1
- set_stat $ff
- lda zp1,x
- php ;test stores do not alter flags
- eor #$c3
- plp
- sta abst,x
- php ;flags after load/store sequence
- eor #$c3
- cmp abs1,x ;test result
- trap_ne
- pla ;load status
- eor_flag lo~fnz ;mask bits not altered
- cmp fLDx,x ;test flags
- trap_ne
- dex
- bpl tldax1
-
- ldx #3
-tldax2
- set_stat 0
- lda abs1,x
- php ;test stores do not alter flags
- eor #$c3
- plp
- sta zpt,x
- php ;flags after load/store sequence
- eor #$c3
- cmp zp1,x ;test result
- trap_ne
- pla ;load status
- eor_flag 0
- cmp fLDx,x ;test flags
- trap_ne
- dex
- bpl tldax2
-
- ldx #3
-tldax3
- set_stat $ff
- lda abs1,x
- php ;test stores do not alter flags
- eor #$c3
- plp
- sta zpt,x
- php ;flags after load/store sequence
- eor #$c3
- cmp zp1,x ;test result
- trap_ne
- pla ;load status
- eor_flag lo~fnz ;mask bits not altered
- cmp fLDx,x ;test flags
- trap_ne
- dex
- bpl tldax3
-
- ldx #3 ;testing store result
- ldy #0
-tstax lda zpt,x
- eor #$c3
- cmp zp1,x
- trap_ne ;store to zp,x data
- sty zpt,x ;clear
- lda abst,x
- eor #$c3
- cmp abs1,x
- trap_ne ;store to abs,x data
- txa
- sta abst,x ;clear
- dex
- bpl tstax
- next_test
-
-; LDA / STA - (zp),y / abs,y / (zp,x)
- ldy #3
-tlday
- set_stat 0
- lda (ind1),y
- php ;test stores do not alter flags
- eor #$c3
- plp
- sta abst,y
- php ;flags after load/store sequence
- eor #$c3
- cmp abs1,y ;test result
- trap_ne
- pla ;load status
- eor_flag 0
- cmp fLDx,y ;test flags
- trap_ne
- dey
- bpl tlday
-
- ldy #3
-tlday1
- set_stat $ff
- lda (ind1),y
- php ;test stores do not alter flags
- eor #$c3
- plp
- sta abst,y
- php ;flags after load/store sequence
- eor #$c3
- cmp abs1,y ;test result
- trap_ne
- pla ;load status
- eor_flag lo~fnz ;mask bits not altered
- cmp fLDx,y ;test flags
- trap_ne
- dey
- bpl tlday1
-
- ldy #3 ;testing store result
- ldx #0
-tstay lda abst,y
- eor #$c3
- cmp abs1,y
- trap_ne ;store to abs data
- txa
- sta abst,y ;clear
- dey
- bpl tstay
-
- ldy #3
-tlday2
- set_stat 0
- lda abs1,y
- php ;test stores do not alter flags
- eor #$c3
- plp
- sta (indt),y
- php ;flags after load/store sequence
- eor #$c3
- cmp (ind1),y ;test result
- trap_ne
- pla ;load status
- eor_flag 0
- cmp fLDx,y ;test flags
- trap_ne
- dey
- bpl tlday2
-
- ldy #3
-tlday3
- set_stat $ff
- lda abs1,y
- php ;test stores do not alter flags
- eor #$c3
- plp
- sta (indt),y
- php ;flags after load/store sequence
- eor #$c3
- cmp (ind1),y ;test result
- trap_ne
- pla ;load status
- eor_flag lo~fnz ;mask bits not altered
- cmp fLDx,y ;test flags
- trap_ne
- dey
- bpl tlday3
-
- ldy #3 ;testing store result
- ldx #0
-tstay1 lda abst,y
- eor #$c3
- cmp abs1,y
- trap_ne ;store to abs data
- txa
- sta abst,y ;clear
- dey
- bpl tstay1
-
- ldx #6
- ldy #3
-tldax4
- set_stat 0
- lda (ind1,x)
- php ;test stores do not alter flags
- eor #$c3
- plp
- sta (indt,x)
- php ;flags after load/store sequence
- eor #$c3
- cmp abs1,y ;test result
- trap_ne
- pla ;load status
- eor_flag 0
- cmp fLDx,y ;test flags
- trap_ne
- dex
- dex
- dey
- bpl tldax4
-
- ldx #6
- ldy #3
-tldax5
- set_stat $ff
- lda (ind1,x)
- php ;test stores do not alter flags
- eor #$c3
- plp
- sta (indt,x)
- php ;flags after load/store sequence
- eor #$c3
- cmp abs1,y ;test result
- trap_ne
- pla ;load status
- eor_flag lo~fnz ;mask bits not altered
- cmp fLDx,y ;test flags
- trap_ne
- dex
- dex
- dey
- bpl tldax5
-
- ldy #3 ;testing store result
- ldx #0
-tstay2 lda abst,y
- eor #$c3
- cmp abs1,y
- trap_ne ;store to abs data
- txa
- sta abst,y ;clear
- dey
- bpl tstay2
- next_test
-
-; indexed wraparound test (only zp should wrap)
- ldx #3+$fa
-tldax6 lda zp1-$fa&$ff,x ;wrap on indexed zp
- sta abst-$fa,x ;no STX abs,x!
- dex
- cpx #$fa
- bcs tldax6
- ldx #3+$fa
-tldax7 lda abs1-$fa,x ;no wrap on indexed abs
- sta zpt-$fa&$ff,x
- dex
- cpx #$fa
- bcs tldax7
-
- ldx #3 ;testing wraparound result
- ldy #0
-tstax1 lda zpt,x
- cmp zp1,x
- trap_ne ;store to zp,x data
- sty zpt,x ;clear
- lda abst,x
- cmp abs1,x
- trap_ne ;store to abs,x data
- txa
- sta abst,x ;clear
- dex
- bpl tstax1
-
- ldy #3+$f8
- ldx #6+$f8
-tlday4 lda (ind1-$f8&$ff,x) ;wrap on indexed zp indirect
- sta abst-$f8,y
- dex
- dex
- dey
- cpy #$f8
- bcs tlday4
- ldy #3 ;testing wraparound result
- ldx #0
-tstay4 lda abst,y
- cmp abs1,y
- trap_ne ;store to abs data
- txa
- sta abst,y ;clear
- dey
- bpl tstay4
-
- ldy #3+$f8
-tlday5 lda abs1-$f8,y ;no wrap on indexed abs
- sta (inwt),y
- dey
- cpy #$f8
- bcs tlday5
- ldy #3 ;testing wraparound result
- ldx #0
-tstay5 lda abst,y
- cmp abs1,y
- trap_ne ;store to abs data
- txa
- sta abst,y ;clear
- dey
- bpl tstay5
-
- ldy #3+$f8
- ldx #6+$f8
-tlday6 lda (inw1),y ;no wrap on zp indirect indexed
- sta (indt-$f8&$ff,x)
- dex
- dex
- dey
- cpy #$f8
- bcs tlday6
- ldy #3 ;testing wraparound result
- ldx #0
-tstay6 lda abst,y
- cmp abs1,y
- trap_ne ;store to abs data
- txa
- sta abst,y ;clear
- dey
- bpl tstay6
- next_test
-
-; LDA / STA - zp / abs / #
- set_stat 0
- lda zp1
- php ;test stores do not alter flags
- eor #$c3
- plp
- sta abst
- php ;flags after load/store sequence
- eor #$c3
- cmp #$c3 ;test result
- trap_ne
- pla ;load status
- eor_flag 0
- cmp fLDx ;test flags
- trap_ne
- set_stat 0
- lda zp1+1
- php ;test stores do not alter flags
- eor #$c3
- plp
- sta abst+1
- php ;flags after load/store sequence
- eor #$c3
- cmp #$82 ;test result
- trap_ne
- pla ;load status
- eor_flag 0
- cmp fLDx+1 ;test flags
- trap_ne
- set_stat 0
- lda zp1+2
- php ;test stores do not alter flags
- eor #$c3
- plp
- sta abst+2
- php ;flags after load/store sequence
- eor #$c3
- cmp #$41 ;test result
- trap_ne
- pla ;load status
- eor_flag 0
- cmp fLDx+2 ;test flags
- trap_ne
- set_stat 0
- lda zp1+3
- php ;test stores do not alter flags
- eor #$c3
- plp
- sta abst+3
- php ;flags after load/store sequence
- eor #$c3
- cmp #0 ;test result
- trap_ne
- pla ;load status
- eor_flag 0
- cmp fLDx+3 ;test flags
- trap_ne
- set_stat $ff
- lda zp1
- php ;test stores do not alter flags
- eor #$c3
- plp
- sta abst
- php ;flags after load/store sequence
- eor #$c3
- cmp #$c3 ;test result
- trap_ne
- pla ;load status
- eor_flag lo~fnz ;mask bits not altered
- cmp fLDx ;test flags
- trap_ne
- set_stat $ff
- lda zp1+1
- php ;test stores do not alter flags
- eor #$c3
- plp
- sta abst+1
- php ;flags after load/store sequence
- eor #$c3
- cmp #$82 ;test result
- trap_ne
- pla ;load status
- eor_flag lo~fnz ;mask bits not altered
- cmp fLDx+1 ;test flags
- trap_ne
- set_stat $ff
- lda zp1+2
- php ;test stores do not alter flags
- eor #$c3
- plp
- sta abst+2
- php ;flags after load/store sequence
- eor #$c3
- cmp #$41 ;test result
- trap_ne
- pla ;load status
- eor_flag lo~fnz ;mask bits not altered
- cmp fLDx+2 ;test flags
- trap_ne
- set_stat $ff
- lda zp1+3
- php ;test stores do not alter flags
- eor #$c3
- plp
- sta abst+3
- php ;flags after load/store sequence
- eor #$c3
- cmp #0 ;test result
- trap_ne
- pla ;load status
- eor_flag lo~fnz ;mask bits not altered
- cmp fLDx+3 ;test flags
- trap_ne
- set_stat 0
- lda abs1
- php ;test stores do not alter flags
- eor #$c3
- plp
- sta zpt
- php ;flags after load/store sequence
- eor #$c3
- cmp zp1 ;test result
- trap_ne
- pla ;load status
- eor_flag 0
- cmp fLDx ;test flags
- trap_ne
- set_stat 0
- lda abs1+1
- php ;test stores do not alter flags
- eor #$c3
- plp
- sta zpt+1
- php ;flags after load/store sequence
- eor #$c3
- cmp zp1+1 ;test result
- trap_ne
- pla ;load status
- eor_flag 0
- cmp fLDx+1 ;test flags
- trap_ne
- set_stat 0
- lda abs1+2
- php ;test stores do not alter flags
- eor #$c3
- plp
- sta zpt+2
- php ;flags after load/store sequence
- eor #$c3
- cmp zp1+2 ;test result
- trap_ne
- pla ;load status
- eor_flag 0
- cmp fLDx+2 ;test flags
- trap_ne
- set_stat 0
- lda abs1+3
- php ;test stores do not alter flags
- eor #$c3
- plp
- sta zpt+3
- php ;flags after load/store sequence
- eor #$c3
- cmp zp1+3 ;test result
- trap_ne
- pla ;load status
- eor_flag 0
- cmp fLDx+3 ;test flags
- trap_ne
- set_stat $ff
- lda abs1
- php ;test stores do not alter flags
- eor #$c3
- plp
- sta zpt
- php ;flags after load/store sequence
- eor #$c3
- cmp zp1 ;test result
- trap_ne
- pla ;load status
- eor_flag lo~fnz ;mask bits not altered
- cmp fLDx ;test flags
- trap_ne
- set_stat $ff
- lda abs1+1
- php ;test stores do not alter flags
- eor #$c3
- plp
- sta zpt+1
- php ;flags after load/store sequence
- eor #$c3
- cmp zp1+1 ;test result
- trap_ne
- pla ;load status
- eor_flag lo~fnz ;mask bits not altered
- cmp fLDx+1 ;test flags
- trap_ne
- set_stat $ff
- lda abs1+2
- php ;test stores do not alter flags
- eor #$c3
- plp
- sta zpt+2
- php ;flags after load/store sequence
- eor #$c3
- cmp zp1+2 ;test result
- trap_ne
- pla ;load status
- eor_flag lo~fnz ;mask bits not altered
- cmp fLDx+2 ;test flags
- trap_ne
- set_stat $ff
- lda abs1+3
- php ;test stores do not alter flags
- eor #$c3
- plp
- sta zpt+3
- php ;flags after load/store sequence
- eor #$c3
- cmp zp1+3 ;test result
- trap_ne
- pla ;load status
- eor_flag lo~fnz ;mask bits not altered
- cmp fLDx+3 ;test flags
- trap_ne
- set_stat 0
- lda #$c3
- php
- cmp abs1 ;test result
- trap_ne
- pla ;load status
- eor_flag 0
- cmp fLDx ;test flags
- trap_ne
- set_stat 0
- lda #$82
- php
- cmp abs1+1 ;test result
- trap_ne
- pla ;load status
- eor_flag 0
- cmp fLDx+1 ;test flags
- trap_ne
- set_stat 0
- lda #$41
- php
- cmp abs1+2 ;test result
- trap_ne
- pla ;load status
- eor_flag 0
- cmp fLDx+2 ;test flags
- trap_ne
- set_stat 0
- lda #0
- php
- cmp abs1+3 ;test result
- trap_ne
- pla ;load status
- eor_flag 0
- cmp fLDx+3 ;test flags
- trap_ne
-
- set_stat $ff
- lda #$c3
- php
- cmp abs1 ;test result
- trap_ne
- pla ;load status
- eor_flag lo~fnz ;mask bits not altered
- cmp fLDx ;test flags
- trap_ne
- set_stat $ff
- lda #$82
- php
- cmp abs1+1 ;test result
- trap_ne
- pla ;load status
- eor_flag lo~fnz ;mask bits not altered
- cmp fLDx+1 ;test flags
- trap_ne
- set_stat $ff
- lda #$41
- php
- cmp abs1+2 ;test result
- trap_ne
- pla ;load status
- eor_flag lo~fnz ;mask bits not altered
- cmp fLDx+2 ;test flags
- trap_ne
- set_stat $ff
- lda #0
- php
- cmp abs1+3 ;test result
- trap_ne
- pla ;load status
- eor_flag lo~fnz ;mask bits not altered
- cmp fLDx+3 ;test flags
- trap_ne
-
- ldx #0
- lda zpt
- eor #$c3
- cmp zp1
- trap_ne ;store to zp data
- stx zpt ;clear
- lda abst
- eor #$c3
- cmp abs1
- trap_ne ;store to abs data
- stx abst ;clear
- lda zpt+1
- eor #$c3
- cmp zp1+1
- trap_ne ;store to zp data
- stx zpt+1 ;clear
- lda abst+1
- eor #$c3
- cmp abs1+1
- trap_ne ;store to abs data
- stx abst+1 ;clear
- lda zpt+2
- eor #$c3
- cmp zp1+2
- trap_ne ;store to zp data
- stx zpt+2 ;clear
- lda abst+2
- eor #$c3
- cmp abs1+2
- trap_ne ;store to abs data
- stx abst+2 ;clear
- lda zpt+3
- eor #$c3
- cmp zp1+3
- trap_ne ;store to zp data
- stx zpt+3 ;clear
- lda abst+3
- eor #$c3
- cmp abs1+3
- trap_ne ;store to abs data
- stx abst+3 ;clear
- next_test
-
-; testing bit test & compares BIT CPX CPY CMP all addressing modes
-; BIT - zp / abs
- set_a $ff,0
- bit zp1+3 ;00 - should set Z / clear NV
- tst_a $ff,fz
- set_a 1,0
- bit zp1+2 ;41 - should set V (M6) / clear NZ
- tst_a 1,fv
- set_a 1,0
- bit zp1+1 ;82 - should set N (M7) & Z / clear V
- tst_a 1,fnz
- set_a 1,0
- bit zp1 ;c3 - should set N (M7) & V (M6) / clear Z
- tst_a 1,fnv
-
- set_a $ff,$ff
- bit zp1+3 ;00 - should set Z / clear NV
- tst_a $ff,~fnv
- set_a 1,$ff
- bit zp1+2 ;41 - should set V (M6) / clear NZ
- tst_a 1,~fnz
- set_a 1,$ff
- bit zp1+1 ;82 - should set N (M7) & Z / clear V
- tst_a 1,~fv
- set_a 1,$ff
- bit zp1 ;c3 - should set N (M7) & V (M6) / clear Z
- tst_a 1,~fz
-
- set_a $ff,0
- bit abs1+3 ;00 - should set Z / clear NV
- tst_a $ff,fz
- set_a 1,0
- bit abs1+2 ;41 - should set V (M6) / clear NZ
- tst_a 1,fv
- set_a 1,0
- bit abs1+1 ;82 - should set N (M7) & Z / clear V
- tst_a 1,fnz
- set_a 1,0
- bit abs1 ;c3 - should set N (M7) & V (M6) / clear Z
- tst_a 1,fnv
-
- set_a $ff,$ff
- bit abs1+3 ;00 - should set Z / clear NV
- tst_a $ff,~fnv
- set_a 1,$ff
- bit abs1+2 ;41 - should set V (M6) / clear NZ
- tst_a 1,~fnz
- set_a 1,$ff
- bit abs1+1 ;82 - should set N (M7) & Z / clear V
- tst_a 1,~fv
- set_a 1,$ff
- bit abs1 ;c3 - should set N (M7) & V (M6) / clear Z
- tst_a 1,~fz
- next_test
-
-; CPX - zp / abs / #
- set_x $80,0
- cpx zp7f
- tst_stat fc
- dex
- cpx zp7f
- tst_stat fzc
- dex
- cpx zp7f
- tst_x $7e,fn
- set_x $80,$ff
- cpx zp7f
- tst_stat ~fnz
- dex
- cpx zp7f
- tst_stat ~fn
- dex
- cpx zp7f
- tst_x $7e,~fzc
-
- set_x $80,0
- cpx abs7f
- tst_stat fc
- dex
- cpx abs7f
- tst_stat fzc
- dex
- cpx abs7f
- tst_x $7e,fn
- set_x $80,$ff
- cpx abs7f
- tst_stat ~fnz
- dex
- cpx abs7f
- tst_stat ~fn
- dex
- cpx abs7f
- tst_x $7e,~fzc
-
- set_x $80,0
- cpx #$7f
- tst_stat fc
- dex
- cpx #$7f
- tst_stat fzc
- dex
- cpx #$7f
- tst_x $7e,fn
- set_x $80,$ff
- cpx #$7f
- tst_stat ~fnz
- dex
- cpx #$7f
- tst_stat ~fn
- dex
- cpx #$7f
- tst_x $7e,~fzc
- next_test
-
-; CPY - zp / abs / #
- set_y $80,0
- cpy zp7f
- tst_stat fc
- dey
- cpy zp7f
- tst_stat fzc
- dey
- cpy zp7f
- tst_y $7e,fn
- set_y $80,$ff
- cpy zp7f
- tst_stat ~fnz
- dey
- cpy zp7f
- tst_stat ~fn
- dey
- cpy zp7f
- tst_y $7e,~fzc
-
- set_y $80,0
- cpy abs7f
- tst_stat fc
- dey
- cpy abs7f
- tst_stat fzc
- dey
- cpy abs7f
- tst_y $7e,fn
- set_y $80,$ff
- cpy abs7f
- tst_stat ~fnz
- dey
- cpy abs7f
- tst_stat ~fn
- dey
- cpy abs7f
- tst_y $7e,~fzc
-
- set_y $80,0
- cpy #$7f
- tst_stat fc
- dey
- cpy #$7f
- tst_stat fzc
- dey
- cpy #$7f
- tst_y $7e,fn
- set_y $80,$ff
- cpy #$7f
- tst_stat ~fnz
- dey
- cpy #$7f
- tst_stat ~fn
- dey
- cpy #$7f
- tst_y $7e,~fzc
- next_test
-
-; CMP - zp / abs / #
- set_a $80,0
- cmp zp7f
- tst_a $80,fc
- set_a $7f,0
- cmp zp7f
- tst_a $7f,fzc
- set_a $7e,0
- cmp zp7f
- tst_a $7e,fn
- set_a $80,$ff
- cmp zp7f
- tst_a $80,~fnz
- set_a $7f,$ff
- cmp zp7f
- tst_a $7f,~fn
- set_a $7e,$ff
- cmp zp7f
- tst_a $7e,~fzc
-
- set_a $80,0
- cmp abs7f
- tst_a $80,fc
- set_a $7f,0
- cmp abs7f
- tst_a $7f,fzc
- set_a $7e,0
- cmp abs7f
- tst_a $7e,fn
- set_a $80,$ff
- cmp abs7f
- tst_a $80,~fnz
- set_a $7f,$ff
- cmp abs7f
- tst_a $7f,~fn
- set_a $7e,$ff
- cmp abs7f
- tst_a $7e,~fzc
-
- set_a $80,0
- cmp #$7f
- tst_a $80,fc
- set_a $7f,0
- cmp #$7f
- tst_a $7f,fzc
- set_a $7e,0
- cmp #$7f
- tst_a $7e,fn
- set_a $80,$ff
- cmp #$7f
- tst_a $80,~fnz
- set_a $7f,$ff
- cmp #$7f
- tst_a $7f,~fn
- set_a $7e,$ff
- cmp #$7f
- tst_a $7e,~fzc
-
- ldx #4 ;with indexing by X
- set_a $80,0
- cmp zp1,x
- tst_a $80,fc
- set_a $7f,0
- cmp zp1,x
- tst_a $7f,fzc
- set_a $7e,0
- cmp zp1,x
- tst_a $7e,fn
- set_a $80,$ff
- cmp zp1,x
- tst_a $80,~fnz
- set_a $7f,$ff
- cmp zp1,x
- tst_a $7f,~fn
- set_a $7e,$ff
- cmp zp1,x
- tst_a $7e,~fzc
-
- set_a $80,0
- cmp abs1,x
- tst_a $80,fc
- set_a $7f,0
- cmp abs1,x
- tst_a $7f,fzc
- set_a $7e,0
- cmp abs1,x
- tst_a $7e,fn
- set_a $80,$ff
- cmp abs1,x
- tst_a $80,~fnz
- set_a $7f,$ff
- cmp abs1,x
- tst_a $7f,~fn
- set_a $7e,$ff
- cmp abs1,x
- tst_a $7e,~fzc
-
- ldy #4 ;with indexing by Y
- ldx #8 ;with indexed indirect
- set_a $80,0
- cmp abs1,y
- tst_a $80,fc
- set_a $7f,0
- cmp abs1,y
- tst_a $7f,fzc
- set_a $7e,0
- cmp abs1,y
- tst_a $7e,fn
- set_a $80,$ff
- cmp abs1,y
- tst_a $80,~fnz
- set_a $7f,$ff
- cmp abs1,y
- tst_a $7f,~fn
- set_a $7e,$ff
- cmp abs1,y
- tst_a $7e,~fzc
-
- set_a $80,0
- cmp (ind1,x)
- tst_a $80,fc
- set_a $7f,0
- cmp (ind1,x)
- tst_a $7f,fzc
- set_a $7e,0
- cmp (ind1,x)
- tst_a $7e,fn
- set_a $80,$ff
- cmp (ind1,x)
- tst_a $80,~fnz
- set_a $7f,$ff
- cmp (ind1,x)
- tst_a $7f,~fn
- set_a $7e,$ff
- cmp (ind1,x)
- tst_a $7e,~fzc
-
- set_a $80,0
- cmp (ind1),y
- tst_a $80,fc
- set_a $7f,0
- cmp (ind1),y
- tst_a $7f,fzc
- set_a $7e,0
- cmp (ind1),y
- tst_a $7e,fn
- set_a $80,$ff
- cmp (ind1),y
- tst_a $80,~fnz
- set_a $7f,$ff
- cmp (ind1),y
- tst_a $7f,~fn
- set_a $7e,$ff
- cmp (ind1),y
- tst_a $7e,~fzc
- next_test
-
-; testing shifts - ASL LSR ROL ROR all addressing modes
-; shifts - accumulator
- ldx #5
-tasl
- set_ax zps,0
- asl a
- tst_ax rASL,fASL,0
- dex
- bpl tasl
- ldx #5
-tasl1
- set_ax zps,$ff
- asl a
- tst_ax rASL,fASL,$ff-fnzc
- dex
- bpl tasl1
-
- ldx #5
-tlsr
- set_ax zps,0
- lsr a
- tst_ax rLSR,fLSR,0
- dex
- bpl tlsr
- ldx #5
-tlsr1
- set_ax zps,$ff
- lsr a
- tst_ax rLSR,fLSR,$ff-fnzc
- dex
- bpl tlsr1
-
- ldx #5
-trol
- set_ax zps,0
- rol a
- tst_ax rROL,fROL,0
- dex
- bpl trol
- ldx #5
-trol1
- set_ax zps,$ff-fc
- rol a
- tst_ax rROL,fROL,$ff-fnzc
- dex
- bpl trol1
-
- ldx #5
-trolc
- set_ax zps,fc
- rol a
- tst_ax rROLc,fROLc,0
- dex
- bpl trolc
- ldx #5
-trolc1
- set_ax zps,$ff
- rol a
- tst_ax rROLc,fROLc,$ff-fnzc
- dex
- bpl trolc1
-
- ldx #5
-tror
- set_ax zps,0
- ror a
- tst_ax rROR,fROR,0
- dex
- bpl tror
- ldx #5
-tror1
- set_ax zps,$ff-fc
- ror a
- tst_ax rROR,fROR,$ff-fnzc
- dex
- bpl tror1
-
- ldx #5
-trorc
- set_ax zps,fc
- ror a
- tst_ax rRORc,fRORc,0
- dex
- bpl trorc
- ldx #5
-trorc1
- set_ax zps,$ff
- ror a
- tst_ax rRORc,fRORc,$ff-fnzc
- dex
- bpl trorc1
- next_test
-
-; shifts - zeropage
- ldx #5
-tasl2
- set_z zps,0
- asl zpt
- tst_z rASL,fASL,0
- dex
- bpl tasl2
- ldx #5
-tasl3
- set_z zps,$ff
- asl zpt
- tst_z rASL,fASL,$ff-fnzc
- dex
- bpl tasl3
-
- ldx #5
-tlsr2
- set_z zps,0
- lsr zpt
- tst_z rLSR,fLSR,0
- dex
- bpl tlsr2
- ldx #5
-tlsr3
- set_z zps,$ff
- lsr zpt
- tst_z rLSR,fLSR,$ff-fnzc
- dex
- bpl tlsr3
-
- ldx #5
-trol2
- set_z zps,0
- rol zpt
- tst_z rROL,fROL,0
- dex
- bpl trol2
- ldx #5
-trol3
- set_z zps,$ff-fc
- rol zpt
- tst_z rROL,fROL,$ff-fnzc
- dex
- bpl trol3
-
- ldx #5
-trolc2
- set_z zps,fc
- rol zpt
- tst_z rROLc,fROLc,0
- dex
- bpl trolc2
- ldx #5
-trolc3
- set_z zps,$ff
- rol zpt
- tst_z rROLc,fROLc,$ff-fnzc
- dex
- bpl trolc3
-
- ldx #5
-tror2
- set_z zps,0
- ror zpt
- tst_z rROR,fROR,0
- dex
- bpl tror2
- ldx #5
-tror3
- set_z zps,$ff-fc
- ror zpt
- tst_z rROR,fROR,$ff-fnzc
- dex
- bpl tror3
-
- ldx #5
-trorc2
- set_z zps,fc
- ror zpt
- tst_z rRORc,fRORc,0
- dex
- bpl trorc2
- ldx #5
-trorc3
- set_z zps,$ff
- ror zpt
- tst_z rRORc,fRORc,$ff-fnzc
- dex
- bpl trorc3
- next_test
-
-; shifts - absolute
- ldx #5
-tasl4
- set_abs zps,0
- asl abst
- tst_abs rASL,fASL,0
- dex
- bpl tasl4
- ldx #5
-tasl5
- set_abs zps,$ff
- asl abst
- tst_abs rASL,fASL,$ff-fnzc
- dex
- bpl tasl5
-
- ldx #5
-tlsr4
- set_abs zps,0
- lsr abst
- tst_abs rLSR,fLSR,0
- dex
- bpl tlsr4
- ldx #5
-tlsr5
- set_abs zps,$ff
- lsr abst
- tst_abs rLSR,fLSR,$ff-fnzc
- dex
- bpl tlsr5
-
- ldx #5
-trol4
- set_abs zps,0
- rol abst
- tst_abs rROL,fROL,0
- dex
- bpl trol4
- ldx #5
-trol5
- set_abs zps,$ff-fc
- rol abst
- tst_abs rROL,fROL,$ff-fnzc
- dex
- bpl trol5
-
- ldx #5
-trolc4
- set_abs zps,fc
- rol abst
- tst_abs rROLc,fROLc,0
- dex
- bpl trolc4
- ldx #5
-trolc5
- set_abs zps,$ff
- rol abst
- tst_abs rROLc,fROLc,$ff-fnzc
- dex
- bpl trolc5
-
- ldx #5
-tror4
- set_abs zps,0
- ror abst
- tst_abs rROR,fROR,0
- dex
- bpl tror4
- ldx #5
-tror5
- set_abs zps,$ff-fc
- ror abst
- tst_abs rROR,fROR,$ff-fnzc
- dex
- bpl tror5
-
- ldx #5
-trorc4
- set_abs zps,fc
- ror abst
- tst_abs rRORc,fRORc,0
- dex
- bpl trorc4
- ldx #5
-trorc5
- set_abs zps,$ff
- ror abst
- tst_abs rRORc,fRORc,$ff-fnzc
- dex
- bpl trorc5
- next_test
-
-; shifts - zp indexed
- ldx #5
-tasl6
- set_zx zps,0
- asl zpt,x
- tst_zx rASL,fASL,0
- dex
- bpl tasl6
- ldx #5
-tasl7
- set_zx zps,$ff
- asl zpt,x
- tst_zx rASL,fASL,$ff-fnzc
- dex
- bpl tasl7
-
- ldx #5
-tlsr6
- set_zx zps,0
- lsr zpt,x
- tst_zx rLSR,fLSR,0
- dex
- bpl tlsr6
- ldx #5
-tlsr7
- set_zx zps,$ff
- lsr zpt,x
- tst_zx rLSR,fLSR,$ff-fnzc
- dex
- bpl tlsr7
-
- ldx #5
-trol6
- set_zx zps,0
- rol zpt,x
- tst_zx rROL,fROL,0
- dex
- bpl trol6
- ldx #5
-trol7
- set_zx zps,$ff-fc
- rol zpt,x
- tst_zx rROL,fROL,$ff-fnzc
- dex
- bpl trol7
-
- ldx #5
-trolc6
- set_zx zps,fc
- rol zpt,x
- tst_zx rROLc,fROLc,0
- dex
- bpl trolc6
- ldx #5
-trolc7
- set_zx zps,$ff
- rol zpt,x
- tst_zx rROLc,fROLc,$ff-fnzc
- dex
- bpl trolc7
-
- ldx #5
-tror6
- set_zx zps,0
- ror zpt,x
- tst_zx rROR,fROR,0
- dex
- bpl tror6
- ldx #5
-tror7
- set_zx zps,$ff-fc
- ror zpt,x
- tst_zx rROR,fROR,$ff-fnzc
- dex
- bpl tror7
-
- ldx #5
-trorc6
- set_zx zps,fc
- ror zpt,x
- tst_zx rRORc,fRORc,0
- dex
- bpl trorc6
- ldx #5
-trorc7
- set_zx zps,$ff
- ror zpt,x
- tst_zx rRORc,fRORc,$ff-fnzc
- dex
- bpl trorc7
- next_test
-
-; shifts - abs indexed
- ldx #5
-tasl8
- set_absx zps,0
- asl abst,x
- tst_absx rASL,fASL,0
- dex
- bpl tasl8
- ldx #5
-tasl9
- set_absx zps,$ff
- asl abst,x
- tst_absx rASL,fASL,$ff-fnzc
- dex
- bpl tasl9
-
- ldx #5
-tlsr8
- set_absx zps,0
- lsr abst,x
- tst_absx rLSR,fLSR,0
- dex
- bpl tlsr8
- ldx #5
-tlsr9
- set_absx zps,$ff
- lsr abst,x
- tst_absx rLSR,fLSR,$ff-fnzc
- dex
- bpl tlsr9
-
- ldx #5
-trol8
- set_absx zps,0
- rol abst,x
- tst_absx rROL,fROL,0
- dex
- bpl trol8
- ldx #5
-trol9
- set_absx zps,$ff-fc
- rol abst,x
- tst_absx rROL,fROL,$ff-fnzc
- dex
- bpl trol9
-
- ldx #5
-trolc8
- set_absx zps,fc
- rol abst,x
- tst_absx rROLc,fROLc,0
- dex
- bpl trolc8
- ldx #5
-trolc9
- set_absx zps,$ff
- rol abst,x
- tst_absx rROLc,fROLc,$ff-fnzc
- dex
- bpl trolc9
-
- ldx #5
-tror8
- set_absx zps,0
- ror abst,x
- tst_absx rROR,fROR,0
- dex
- bpl tror8
- ldx #5
-tror9
- set_absx zps,$ff-fc
- ror abst,x
- tst_absx rROR,fROR,$ff-fnzc
- dex
- bpl tror9
-
- ldx #5
-trorc8
- set_absx zps,fc
- ror abst,x
- tst_absx rRORc,fRORc,0
- dex
- bpl trorc8
- ldx #5
-trorc9
- set_absx zps,$ff
- ror abst,x
- tst_absx rRORc,fRORc,$ff-fnzc
- dex
- bpl trorc9
- next_test
-
-; testing memory increment/decrement - INC DEC all addressing modes
-; zeropage
- ldx #0
- lda #$7e
- sta zpt
-tinc
- set_stat 0
- inc zpt
- tst_z rINC,fINC,0
- inx
- cpx #2
- bne tinc1
- lda #$fe
- sta zpt
-tinc1 cpx #5
- bne tinc
- dex
- inc zpt
-tdec
- set_stat 0
- dec zpt
- tst_z rINC,fINC,0
- dex
- bmi tdec1
- cpx #1
- bne tdec
- lda #$81
- sta zpt
- bne tdec
-tdec1
- ldx #0
- lda #$7e
- sta zpt
-tinc10
- set_stat $ff
- inc zpt
- tst_z rINC,fINC,$ff-fnz
- inx
- cpx #2
- bne tinc11
- lda #$fe
- sta zpt
-tinc11 cpx #5
- bne tinc10
- dex
- inc zpt
-tdec10
- set_stat $ff
- dec zpt
- tst_z rINC,fINC,$ff-fnz
- dex
- bmi tdec11
- cpx #1
- bne tdec10
- lda #$81
- sta zpt
- bne tdec10
-tdec11
- next_test
-
-; absolute memory
- ldx #0
- lda #$7e
- sta abst
-tinc2
- set_stat 0
- inc abst
- tst_abs rINC,fINC,0
- inx
- cpx #2
- bne tinc3
- lda #$fe
- sta abst
-tinc3 cpx #5
- bne tinc2
- dex
- inc abst
-tdec2
- set_stat 0
- dec abst
- tst_abs rINC,fINC,0
- dex
- bmi tdec3
- cpx #1
- bne tdec2
- lda #$81
- sta abst
- bne tdec2
-tdec3
- ldx #0
- lda #$7e
- sta abst
-tinc12
- set_stat $ff
- inc abst
- tst_abs rINC,fINC,$ff-fnz
- inx
- cpx #2
- bne tinc13
- lda #$fe
- sta abst
-tinc13 cpx #5
- bne tinc12
- dex
- inc abst
-tdec12
- set_stat $ff
- dec abst
- tst_abs rINC,fINC,$ff-fnz
- dex
- bmi tdec13
- cpx #1
- bne tdec12
- lda #$81
- sta abst
- bne tdec12
-tdec13
- next_test
-
-; zeropage indexed
- ldx #0
- lda #$7e
-tinc4 sta zpt,x
- set_stat 0
- inc zpt,x
- tst_zx rINC,fINC,0
- lda zpt,x
- inx
- cpx #2
- bne tinc5
- lda #$fe
-tinc5 cpx #5
- bne tinc4
- dex
- lda #2
-tdec4 sta zpt,x
- set_stat 0
- dec zpt,x
- tst_zx rINC,fINC,0
- lda zpt,x
- dex
- bmi tdec5
- cpx #1
- bne tdec4
- lda #$81
- bne tdec4
-tdec5
- ldx #0
- lda #$7e
-tinc14 sta zpt,x
- set_stat $ff
- inc zpt,x
- tst_zx rINC,fINC,$ff-fnz
- lda zpt,x
- inx
- cpx #2
- bne tinc15
- lda #$fe
-tinc15 cpx #5
- bne tinc14
- dex
- lda #2
-tdec14 sta zpt,x
- set_stat $ff
- dec zpt,x
- tst_zx rINC,fINC,$ff-fnz
- lda zpt,x
- dex
- bmi tdec15
- cpx #1
- bne tdec14
- lda #$81
- bne tdec14
-tdec15
- next_test
-
-; memory indexed
- ldx #0
- lda #$7e
-tinc6 sta abst,x
- set_stat 0
- inc abst,x
- tst_absx rINC,fINC,0
- lda abst,x
- inx
- cpx #2
- bne tinc7
- lda #$fe
-tinc7 cpx #5
- bne tinc6
- dex
- lda #2
-tdec6 sta abst,x
- set_stat 0
- dec abst,x
- tst_absx rINC,fINC,0
- lda abst,x
- dex
- bmi tdec7
- cpx #1
- bne tdec6
- lda #$81
- bne tdec6
-tdec7
- ldx #0
- lda #$7e
-tinc16 sta abst,x
- set_stat $ff
- inc abst,x
- tst_absx rINC,fINC,$ff-fnz
- lda abst,x
- inx
- cpx #2
- bne tinc17
- lda #$fe
-tinc17 cpx #5
- bne tinc16
- dex
- lda #2
-tdec16 sta abst,x
- set_stat $ff
- dec abst,x
- tst_absx rINC,fINC,$ff-fnz
- lda abst,x
- dex
- bmi tdec17
- cpx #1
- bne tdec16
- lda #$81
- bne tdec16
-tdec17
- next_test
-
-; testing logical instructions - AND EOR ORA all addressing modes
-; AND
- ldx #3 ;immediate
-tand lda zpAN,x
- sta ex_andi+1 ;set AND # operand
- set_ax absANa,0
- jsr ex_andi ;execute AND # in RAM
- tst_ax absrlo,absflo,0
- dex
- bpl tand
- ldx #3
-tand1 lda zpAN,x
- sta ex_andi+1 ;set AND # operand
- set_ax absANa,$ff
- jsr ex_andi ;execute AND # in RAM
- tst_ax absrlo,absflo,$ff-fnz
- dex
- bpl tand1
-
- ldx #3 ;zp
-tand2 lda zpAN,x
- sta zpt
- set_ax absANa,0
- and zpt
- tst_ax absrlo,absflo,0
- dex
- bpl tand2
- ldx #3
-tand3 lda zpAN,x
- sta zpt
- set_ax absANa,$ff
- and zpt
- tst_ax absrlo,absflo,$ff-fnz
- dex
- bpl tand3
-
- ldx #3 ;abs
-tand4 lda zpAN,x
- sta abst
- set_ax absANa,0
- and abst
- tst_ax absrlo,absflo,0
- dex
- bpl tand4
- ldx #3
-tand5 lda zpAN,x
- sta abst
- set_ax absANa,$ff
- and abst
- tst_ax absrlo,absflo,$ff-fnz
- dex
- bpl tand6
-
- ldx #3 ;zp,x
-tand6
- set_ax absANa,0
- and zpAN,x
- tst_ax absrlo,absflo,0
- dex
- bpl tand6
- ldx #3
-tand7
- set_ax absANa,$ff
- and zpAN,x
- tst_ax absrlo,absflo,$ff-fnz
- dex
- bpl tand7
-
- ldx #3 ;abs,x
-tand8
- set_ax absANa,0
- and absAN,x
- tst_ax absrlo,absflo,0
- dex
- bpl tand8
- ldx #3
-tand9
- set_ax absANa,$ff
- and absAN,x
- tst_ax absrlo,absflo,$ff-fnz
- dex
- bpl tand9
-
- ldy #3 ;abs,y
-tand10
- set_ay absANa,0
- and absAN,y
- tst_ay absrlo,absflo,0
- dey
- bpl tand10
- ldy #3
-tand11
- set_ay absANa,$ff
- and absAN,y
- tst_ay absrlo,absflo,$ff-fnz
- dey
- bpl tand11
-
- ldx #6 ;(zp,x)
- ldy #3
-tand12
- set_ay absANa,0
- and (indAN,x)
- tst_ay absrlo,absflo,0
- dex
- dex
- dey
- bpl tand12
- ldx #6
- ldy #3
-tand13
- set_ay absANa,$ff
- and (indAN,x)
- tst_ay absrlo,absflo,$ff-fnz
- dex
- dex
- dey
- bpl tand13
-
- ldy #3 ;(zp),y
-tand14
- set_ay absANa,0
- and (indAN),y
- tst_ay absrlo,absflo,0
- dey
- bpl tand14
- ldy #3
-tand15
- set_ay absANa,$ff
- and (indAN),y
- tst_ay absrlo,absflo,$ff-fnz
- dey
- bpl tand15
- next_test
-
-; EOR
- ldx #3 ;immediate - self modifying code
-teor lda zpEO,x
- sta ex_eori+1 ;set EOR # operand
- set_ax absEOa,0
- jsr ex_eori ;execute EOR # in RAM
- tst_ax absrlo,absflo,0
- dex
- bpl teor
- ldx #3
-teor1 lda zpEO,x
- sta ex_eori+1 ;set EOR # operand
- set_ax absEOa,$ff
- jsr ex_eori ;execute EOR # in RAM
- tst_ax absrlo,absflo,$ff-fnz
- dex
- bpl teor1
-
- ldx #3 ;zp
-teor2 lda zpEO,x
- sta zpt
- set_ax absEOa,0
- eor zpt
- tst_ax absrlo,absflo,0
- dex
- bpl teor2
- ldx #3
-teor3 lda zpEO,x
- sta zpt
- set_ax absEOa,$ff
- eor zpt
- tst_ax absrlo,absflo,$ff-fnz
- dex
- bpl teor3
-
- ldx #3 ;abs
-teor4 lda zpEO,x
- sta abst
- set_ax absEOa,0
- eor abst
- tst_ax absrlo,absflo,0
- dex
- bpl teor4
- ldx #3
-teor5 lda zpEO,x
- sta abst
- set_ax absEOa,$ff
- eor abst
- tst_ax absrlo,absflo,$ff-fnz
- dex
- bpl teor6
-
- ldx #3 ;zp,x
-teor6
- set_ax absEOa,0
- eor zpEO,x
- tst_ax absrlo,absflo,0
- dex
- bpl teor6
- ldx #3
-teor7
- set_ax absEOa,$ff
- eor zpEO,x
- tst_ax absrlo,absflo,$ff-fnz
- dex
- bpl teor7
-
- ldx #3 ;abs,x
-teor8
- set_ax absEOa,0
- eor absEO,x
- tst_ax absrlo,absflo,0
- dex
- bpl teor8
- ldx #3
-teor9
- set_ax absEOa,$ff
- eor absEO,x
- tst_ax absrlo,absflo,$ff-fnz
- dex
- bpl teor9
-
- ldy #3 ;abs,y
-teor10
- set_ay absEOa,0
- eor absEO,y
- tst_ay absrlo,absflo,0
- dey
- bpl teor10
- ldy #3
-teor11
- set_ay absEOa,$ff
- eor absEO,y
- tst_ay absrlo,absflo,$ff-fnz
- dey
- bpl teor11
-
- ldx #6 ;(zp,x)
- ldy #3
-teor12
- set_ay absEOa,0
- eor (indEO,x)
- tst_ay absrlo,absflo,0
- dex
- dex
- dey
- bpl teor12
- ldx #6
- ldy #3
-teor13
- set_ay absEOa,$ff
- eor (indEO,x)
- tst_ay absrlo,absflo,$ff-fnz
- dex
- dex
- dey
- bpl teor13
-
- ldy #3 ;(zp),y
-teor14
- set_ay absEOa,0
- eor (indEO),y
- tst_ay absrlo,absflo,0
- dey
- bpl teor14
- ldy #3
-teor15
- set_ay absEOa,$ff
- eor (indEO),y
- tst_ay absrlo,absflo,$ff-fnz
- dey
- bpl teor15
- next_test
-
-; OR
- ldx #3 ;immediate - self modifying code
-tora lda zpOR,x
- sta ex_orai+1 ;set ORA # operand
- set_ax absORa,0
- jsr ex_orai ;execute ORA # in RAM
- tst_ax absrlo,absflo,0
- dex
- bpl tora
- ldx #3
-tora1 lda zpOR,x
- sta ex_orai+1 ;set ORA # operand
- set_ax absORa,$ff
- jsr ex_orai ;execute ORA # in RAM
- tst_ax absrlo,absflo,$ff-fnz
- dex
- bpl tora1
-
- ldx #3 ;zp
-tora2 lda zpOR,x
- sta zpt
- set_ax absORa,0
- ora zpt
- tst_ax absrlo,absflo,0
- dex
- bpl tora2
- ldx #3
-tora3 lda zpOR,x
- sta zpt
- set_ax absORa,$ff
- ora zpt
- tst_ax absrlo,absflo,$ff-fnz
- dex
- bpl tora3
-
- ldx #3 ;abs
-tora4 lda zpOR,x
- sta abst
- set_ax absORa,0
- ora abst
- tst_ax absrlo,absflo,0
- dex
- bpl tora4
- ldx #3
-tora5 lda zpOR,x
- sta abst
- set_ax absORa,$ff
- ora abst
- tst_ax absrlo,absflo,$ff-fnz
- dex
- bpl tora6
-
- ldx #3 ;zp,x
-tora6
- set_ax absORa,0
- ora zpOR,x
- tst_ax absrlo,absflo,0
- dex
- bpl tora6
- ldx #3
-tora7
- set_ax absORa,$ff
- ora zpOR,x
- tst_ax absrlo,absflo,$ff-fnz
- dex
- bpl tora7
-
- ldx #3 ;abs,x
-tora8
- set_ax absORa,0
- ora absOR,x
- tst_ax absrlo,absflo,0
- dex
- bpl tora8
- ldx #3
-tora9
- set_ax absORa,$ff
- ora absOR,x
- tst_ax absrlo,absflo,$ff-fnz
- dex
- bpl tora9
-
- ldy #3 ;abs,y
-tora10
- set_ay absORa,0
- ora absOR,y
- tst_ay absrlo,absflo,0
- dey
- bpl tora10
- ldy #3
-tora11
- set_ay absORa,$ff
- ora absOR,y
- tst_ay absrlo,absflo,$ff-fnz
- dey
- bpl tora11
-
- ldx #6 ;(zp,x)
- ldy #3
-tora12
- set_ay absORa,0
- ora (indOR,x)
- tst_ay absrlo,absflo,0
- dex
- dex
- dey
- bpl tora12
- ldx #6
- ldy #3
-tora13
- set_ay absORa,$ff
- ora (indOR,x)
- tst_ay absrlo,absflo,$ff-fnz
- dex
- dex
- dey
- bpl tora13
-
- ldy #3 ;(zp),y
-tora14
- set_ay absORa,0
- ora (indOR),y
- tst_ay absrlo,absflo,0
- dey
- bpl tora14
- ldy #3
-tora15
- set_ay absORa,$ff
- ora (indOR),y
- tst_ay absrlo,absflo,$ff-fnz
- dey
- bpl tora15
- if I_flag = 3
- cli
- endif
- next_test
-
-; full binary add/subtract test
-; iterates through all combinations of operands and carry input
-; uses increments/decrements to predict result & result flags
- cld
- ldx #ad2 ;for indexed test
- ldy #$ff ;max range
- lda #0 ;start with adding zeroes & no carry
- sta adfc ;carry in - for diag
- sta ad1 ;operand 1 - accumulator
- sta ad2 ;operand 2 - memory or immediate
- sta ada2 ;non zp
- sta adrl ;expected result bits 0-7
- sta adrh ;expected result bit 8 (carry out)
- lda #$ff ;complemented operand 2 for subtract
- sta sb2
- sta sba2 ;non zp
- lda #2 ;expected Z-flag
- sta adrf
-tadd clc ;test with carry clear
- jsr chkadd
- inc adfc ;now with carry
- inc adrl ;result +1
- php ;save N & Z from low result
- php
- pla ;accu holds expected flags
- and #$82 ;mask N & Z
- plp
- bne tadd1
- inc adrh ;result bit 8 - carry
-tadd1 ora adrh ;merge C to expected flags
- sta adrf ;save expected flags except overflow
- sec ;test with carry set
- jsr chkadd
- dec adfc ;same for operand +1 but no carry
- inc ad1
- bne tadd ;iterate op1
- lda #0 ;preset result to op2 when op1 = 0
- sta adrh
- inc ada2
- inc ad2
- php ;save NZ as operand 2 becomes the new result
- pla
- and #$82 ;mask N00000Z0
- sta adrf ;no need to check carry as we are adding to 0
- dec sb2 ;complement subtract operand 2
- dec sba2
- lda ad2
- sta adrl
- bne tadd ;iterate op2
- if disable_decimal < 1
- next_test
-
-; decimal add/subtract test
-; *** WARNING - tests documented behavior only! ***
-; only valid BCD operands are tested, N V Z flags are ignored
-; iterates through all valid combinations of operands and carry input
-; uses increments/decrements to predict result & carry flag
- sed
- ldx #ad2 ;for indexed test
- ldy #$ff ;max range
- lda #$99 ;start with adding 99 to 99 with carry
- sta ad1 ;operand 1 - accumulator
- sta ad2 ;operand 2 - memory or immediate
- sta ada2 ;non zp
- sta adrl ;expected result bits 0-7
- lda #1 ;set carry in & out
- sta adfc ;carry in - for diag
- sta adrh ;expected result bit 8 (carry out)
- lda #0 ;complemented operand 2 for subtract
- sta sb2
- sta sba2 ;non zp
-tdad sec ;test with carry set
- jsr chkdad
- dec adfc ;now with carry clear
- lda adrl ;decimal adjust result
- bne tdad1 ;skip clear carry & preset result 99 (9A-1)
- dec adrh
- lda #$99
- sta adrl
- bne tdad3
-tdad1 and #$f ;lower nibble mask
- bne tdad2 ;no decimal adjust needed
- dec adrl ;decimal adjust (?0-6)
- dec adrl
- dec adrl
- dec adrl
- dec adrl
- dec adrl
-tdad2 dec adrl ;result -1
-tdad3 clc ;test with carry clear
- jsr chkdad
- inc adfc ;same for operand -1 but with carry
- lda ad1 ;decimal adjust operand 1
- beq tdad5 ;iterate operand 2
- and #$f ;lower nibble mask
- bne tdad4 ;skip decimal adjust
- dec ad1 ;decimal adjust (?0-6)
- dec ad1
- dec ad1
- dec ad1
- dec ad1
- dec ad1
-tdad4 dec ad1 ;operand 1 -1
- jmp tdad ;iterate op1
-
-tdad5 lda #$99 ;precharge op1 max
- sta ad1
- lda ad2 ;decimal adjust operand 2
- beq tdad7 ;end of iteration
- and #$f ;lower nibble mask
- bne tdad6 ;skip decimal adjust
- dec ad2 ;decimal adjust (?0-6)
- dec ad2
- dec ad2
- dec ad2
- dec ad2
- dec ad2
- inc sb2 ;complemented decimal adjust for subtract (?9+6)
- inc sb2
- inc sb2
- inc sb2
- inc sb2
- inc sb2
-tdad6 dec ad2 ;operand 2 -1
- inc sb2 ;complemented operand for subtract
- lda sb2
- sta sba2 ;copy as non zp operand
- lda ad2
- sta ada2 ;copy as non zp operand
- sta adrl ;new result since op1+carry=00+carry +op2=op2
- inc adrh ;result carry
- bne tdad ;iterate op2
-tdad7
- next_test
-
-; decimal/binary switch test
-; tests CLD, SED, PLP, RTI to properly switch between decimal & binary opcode
-; tables
- clc
- cld
- php
- lda #$55
- adc #$55
- cmp #$aa
- trap_ne ;expected binary result after cld
- clc
- sed
- php
- lda #$55
- adc #$55
- cmp #$10
- trap_ne ;expected decimal result after sed
- cld
- plp
- lda #$55
- adc #$55
- cmp #$10
- trap_ne ;expected decimal result after plp D=1
- plp
- lda #$55
- adc #$55
- cmp #$aa
- trap_ne ;expected binary result after plp D=0
- clc
- lda #hi bin_rti_ret ;emulated interrupt for rti
- pha
- lda #lo bin_rti_ret
- pha
- php
- sed
- lda #hi dec_rti_ret ;emulated interrupt for rti
- pha
- lda #lo dec_rti_ret
- pha
- php
- cld
- rti
-dec_rti_ret
- lda #$55
- adc #$55
- cmp #$10
- trap_ne ;expected decimal result after rti D=1
- rti
-bin_rti_ret
- lda #$55
- adc #$55
- cmp #$aa
- trap_ne ;expected binary result after rti D=0
- endif
-
- lda test_case
- cmp #test_num
- trap_ne ;previous test is out of sequence
- lda #$f0 ;mark opcode testing complete
- sta test_case
-
-; final RAM integrity test
-; verifies that none of the previous tests has altered RAM outside of the
-; designated write areas.
- check_ram
-; *** DEBUG INFO ***
-; to debug checksum errors uncomment check_ram in the next_test macro to
-; narrow down the responsible opcode.
-; may give false errors when monitor, OS or other background activity is
-; allowed during previous tests.
-
-
-; S U C C E S S ************************************************
-; -------------
- success ;if you get here everything went well
-; -------------
-; S U C C E S S ************************************************
- jmp start ;run again
-
- if disable_decimal < 1
-; core subroutine of the decimal add/subtract test
-; *** WARNING - tests documented behavior only! ***
-; only valid BCD operands are tested, N V Z flags are ignored
-; iterates through all valid combinations of operands and carry input
-; uses increments/decrements to predict result & carry flag
-chkdad
-; decimal ADC / SBC zp
- php ;save carry for subtract
- lda ad1
- adc ad2 ;perform add
- php
- cmp adrl ;check result
- trap_ne ;bad result
- pla ;check flags
- and #1 ;mask carry
- cmp adrh
- trap_ne ;bad carry
- plp
- php ;save carry for next add
- lda ad1
- sbc sb2 ;perform subtract
- php
- cmp adrl ;check result
- trap_ne ;bad result
- pla ;check flags
- and #1 ;mask carry
- cmp adrh
- trap_ne ;bad flags
- plp
-; decimal ADC / SBC abs
- php ;save carry for subtract
- lda ad1
- adc ada2 ;perform add
- php
- cmp adrl ;check result
- trap_ne ;bad result
- pla ;check flags
- and #1 ;mask carry
- cmp adrh
- trap_ne ;bad carry
- plp
- php ;save carry for next add
- lda ad1
- sbc sba2 ;perform subtract
- php
- cmp adrl ;check result
- trap_ne ;bad result
- pla ;check flags
- and #1 ;mask carry
- cmp adrh
- trap_ne ;bad carry
- plp
-; decimal ADC / SBC #
- php ;save carry for subtract
- lda ad2
- sta ex_adci+1 ;set ADC # operand
- lda ad1
- jsr ex_adci ;execute ADC # in RAM
- php
- cmp adrl ;check result
- trap_ne ;bad result
- pla ;check flags
- and #1 ;mask carry
- cmp adrh
- trap_ne ;bad carry
- plp
- php ;save carry for next add
- lda sb2
- sta ex_sbci+1 ;set SBC # operand
- lda ad1
- jsr ex_sbci ;execute SBC # in RAM
- php
- cmp adrl ;check result
- trap_ne ;bad result
- pla ;check flags
- and #1 ;mask carry
- cmp adrh
- trap_ne ;bad carry
- plp
-; decimal ADC / SBC zp,x
- php ;save carry for subtract
- lda ad1
- adc 0,x ;perform add
- php
- cmp adrl ;check result
- trap_ne ;bad result
- pla ;check flags
- and #1 ;mask carry
- cmp adrh
- trap_ne ;bad carry
- plp
- php ;save carry for next add
- lda ad1
- sbc sb2-ad2,x ;perform subtract
- php
- cmp adrl ;check result
- trap_ne ;bad result
- pla ;check flags
- and #1 ;mask carry
- cmp adrh
- trap_ne ;bad carry
- plp
-; decimal ADC / SBC abs,x
- php ;save carry for subtract
- lda ad1
- adc ada2-ad2,x ;perform add
- php
- cmp adrl ;check result
- trap_ne ;bad result
- pla ;check flags
- and #1 ;mask carry
- cmp adrh
- trap_ne ;bad carry
- plp
- php ;save carry for next add
- lda ad1
- sbc sba2-ad2,x ;perform subtract
- php
- cmp adrl ;check result
- trap_ne ;bad result
- pla ;check flags
- and #1 ;mask carry
- cmp adrh
- trap_ne ;bad carry
- plp
-; decimal ADC / SBC abs,y
- php ;save carry for subtract
- lda ad1
- adc ada2-$ff,y ;perform add
- php
- cmp adrl ;check result
- trap_ne ;bad result
- pla ;check flags
- and #1 ;mask carry
- cmp adrh
- trap_ne ;bad carry
- plp
- php ;save carry for next add
- lda ad1
- sbc sba2-$ff,y ;perform subtract
- php
- cmp adrl ;check result
- trap_ne ;bad result
- pla ;check flags
- and #1 ;mask carry
- cmp adrh
- trap_ne ;bad carry
- plp
-; decimal ADC / SBC (zp,x)
- php ;save carry for subtract
- lda ad1
- adc (lo adi2-ad2,x) ;perform add
- php
- cmp adrl ;check result
- trap_ne ;bad result
- pla ;check flags
- and #1 ;mask carry
- cmp adrh
- trap_ne ;bad carry
- plp
- php ;save carry for next add
- lda ad1
- sbc (lo sbi2-ad2,x) ;perform subtract
- php
- cmp adrl ;check result
- trap_ne ;bad result
- pla ;check flags
- and #1 ;mask carry
- cmp adrh
- trap_ne ;bad carry
- plp
-; decimal ADC / SBC (abs),y
- php ;save carry for subtract
- lda ad1
- adc (adiy2),y ;perform add
- php
- cmp adrl ;check result
- trap_ne ;bad result
- pla ;check flags
- and #1 ;mask carry
- cmp adrh
- trap_ne ;bad carry
- plp
- php ;save carry for next add
- lda ad1
- sbc (sbiy2),y ;perform subtract
- php
- cmp adrl ;check result
- trap_ne ;bad result
- pla ;check flags
- and #1 ;mask carry
- cmp adrh
- trap_ne ;bad carry
- plp
- rts
- endif
-
-; core subroutine of the full binary add/subtract test
-; iterates through all combinations of operands and carry input
-; uses increments/decrements to predict result & result flags
-chkadd lda adrf ;add V-flag if overflow
- and #$83 ;keep N-----ZC / clear V
- pha
- lda ad1 ;test sign unequal between operands
- eor ad2
- bmi ckad1 ;no overflow possible - operands have different sign
- lda ad1 ;test sign equal between operands and result
- eor adrl
- bpl ckad1 ;no overflow occured - operand and result have same sign
- pla
- ora #$40 ;set V
- pha
-ckad1 pla
- sta adrf ;save expected flags
-; binary ADC / SBC zp
- php ;save carry for subtract
- lda ad1
- adc ad2 ;perform add
- php
- cmp adrl ;check result
- trap_ne ;bad result
- pla ;check flags
- and #$c3 ;mask NV----ZC
- cmp adrf
- trap_ne ;bad flags
- plp
- php ;save carry for next add
- lda ad1
- sbc sb2 ;perform subtract
- php
- cmp adrl ;check result
- trap_ne ;bad result
- pla ;check flags
- and #$c3 ;mask NV----ZC
- cmp adrf
- trap_ne ;bad flags
- plp
-; binary ADC / SBC abs
- php ;save carry for subtract
- lda ad1
- adc ada2 ;perform add
- php
- cmp adrl ;check result
- trap_ne ;bad result
- pla ;check flags
- and #$c3 ;mask NV----ZC
- cmp adrf
- trap_ne ;bad flags
- plp
- php ;save carry for next add
- lda ad1
- sbc sba2 ;perform subtract
- php
- cmp adrl ;check result
- trap_ne ;bad result
- pla ;check flags
- and #$c3 ;mask NV----ZC
- cmp adrf
- trap_ne ;bad flags
- plp
-; binary ADC / SBC #
- php ;save carry for subtract
- lda ad2
- sta ex_adci+1 ;set ADC # operand
- lda ad1
- jsr ex_adci ;execute ADC # in RAM
- php
- cmp adrl ;check result
- trap_ne ;bad result
- pla ;check flags
- and #$c3 ;mask NV----ZC
- cmp adrf
- trap_ne ;bad flags
- plp
- php ;save carry for next add
- lda sb2
- sta ex_sbci+1 ;set SBC # operand
- lda ad1
- jsr ex_sbci ;execute SBC # in RAM
- php
- cmp adrl ;check result
- trap_ne ;bad result
- pla ;check flags
- and #$c3 ;mask NV----ZC
- cmp adrf
- trap_ne ;bad flags
- plp
-; binary ADC / SBC zp,x
- php ;save carry for subtract
- lda ad1
- adc 0,x ;perform add
- php
- cmp adrl ;check result
- trap_ne ;bad result
- pla ;check flags
- and #$c3 ;mask NV----ZC
- cmp adrf
- trap_ne ;bad flags
- plp
- php ;save carry for next add
- lda ad1
- sbc sb2-ad2,x ;perform subtract
- php
- cmp adrl ;check result
- trap_ne ;bad result
- pla ;check flags
- and #$c3 ;mask NV----ZC
- cmp adrf
- trap_ne ;bad flags
- plp
-; binary ADC / SBC abs,x
- php ;save carry for subtract
- lda ad1
- adc ada2-ad2,x ;perform add
- php
- cmp adrl ;check result
- trap_ne ;bad result
- pla ;check flags
- and #$c3 ;mask NV----ZC
- cmp adrf
- trap_ne ;bad flags
- plp
- php ;save carry for next add
- lda ad1
- sbc sba2-ad2,x ;perform subtract
- php
- cmp adrl ;check result
- trap_ne ;bad result
- pla ;check flags
- and #$c3 ;mask NV----ZC
- cmp adrf
- trap_ne ;bad flags
- plp
-; binary ADC / SBC abs,y
- php ;save carry for subtract
- lda ad1
- adc ada2-$ff,y ;perform add
- php
- cmp adrl ;check result
- trap_ne ;bad result
- pla ;check flags
- and #$c3 ;mask NV----ZC
- cmp adrf
- trap_ne ;bad flags
- plp
- php ;save carry for next add
- lda ad1
- sbc sba2-$ff,y ;perform subtract
- php
- cmp adrl ;check result
- trap_ne ;bad result
- pla ;check flags
- and #$c3 ;mask NV----ZC
- cmp adrf
- trap_ne ;bad flags
- plp
-; binary ADC / SBC (zp,x)
- php ;save carry for subtract
- lda ad1
- adc (lo adi2-ad2,x) ;perform add
- php
- cmp adrl ;check result
- trap_ne ;bad result
- pla ;check flags
- and #$c3 ;mask NV----ZC
- cmp adrf
- trap_ne ;bad flags
- plp
- php ;save carry for next add
- lda ad1
- sbc (lo sbi2-ad2,x) ;perform subtract
- php
- cmp adrl ;check result
- trap_ne ;bad result
- pla ;check flags
- and #$c3 ;mask NV----ZC
- cmp adrf
- trap_ne ;bad flags
- plp
-; binary ADC / SBC (abs),y
- php ;save carry for subtract
- lda ad1
- adc (adiy2),y ;perform add
- php
- cmp adrl ;check result
- trap_ne ;bad result
- pla ;check flags
- and #$c3 ;mask NV----ZC
- cmp adrf
- trap_ne ;bad flags
- plp
- php ;save carry for next add
- lda ad1
- sbc (sbiy2),y ;perform subtract
- php
- cmp adrl ;check result
- trap_ne ;bad result
- pla ;check flags
- and #$c3 ;mask NV----ZC
- cmp adrf
- trap_ne ;bad flags
- plp
- rts
-
-; target for the jump absolute test
- dey
- dey
-test_far
- php ;either SP or Y count will fail, if we do not hit
- dey
- dey
- dey
- plp
- trap_cs ;flags loaded?
- trap_vs
- trap_mi
- trap_eq
- cmp #'F' ;registers loaded?
- trap_ne
- cpx #'A'
- trap_ne
- cpy #('R'-3)
- trap_ne
- pha ;save a,x
- txa
- pha
- tsx
- cpx #$fd ;check SP
- trap_ne
- pla ;restore x
- tax
- set_stat $ff
- pla ;restore a
- inx ;return registers with modifications
- eor #$aa ;N=1, V=1, Z=0, C=1
- jmp far_ret
-
-; target for the jump indirect test
- align
-ptr_tst_ind dw test_ind
-ptr_ind_ret dw ind_ret
- trap ;runover protection
- dey
- dey
-test_ind
- php ;either SP or Y count will fail, if we do not hit
- dey
- dey
- dey
- plp
- trap_cs ;flags loaded?
- trap_vs
- trap_mi
- trap_eq
- cmp #'I' ;registers loaded?
- trap_ne
- cpx #'N'
- trap_ne
- cpy #('D'-3)
- trap_ne
- pha ;save a,x
- txa
- pha
- tsx
- cpx #$fd ;check SP
- trap_ne
- pla ;restore x
- tax
- set_stat $ff
- pla ;restore a
- inx ;return registers with modifications
- eor #$aa ;N=1, V=1, Z=0, C=1
- jmp (ptr_ind_ret)
- trap ;runover protection
- jmp start ;catastrophic error - cannot continue
-
-; target for the jump subroutine test
- dey
- dey
-test_jsr
- php ;either SP or Y count will fail, if we do not hit
- dey
- dey
- dey
- plp
- trap_cs ;flags loaded?
- trap_vs
- trap_mi
- trap_eq
- cmp #'J' ;registers loaded?
- trap_ne
- cpx #'S'
- trap_ne
- cpy #('R'-3)
- trap_ne
- pha ;save a,x
- txa
- pha
- tsx ;sp -4? (return addr,a,x)
- cpx #$fb
- trap_ne
- lda $1ff ;propper return on stack
- cmp #hi(jsr_ret)
- trap_ne
- lda $1fe
- cmp #lo(jsr_ret)
- trap_ne
- set_stat $ff
- pla ;pull x,a
- tax
- pla
- inx ;return registers with modifications
- eor #$aa ;N=1, V=1, Z=0, C=1
- rts
- trap ;runover protection
- jmp start ;catastrophic error - cannot continue
-
-;trap in case of unexpected IRQ, NMI, BRK, RESET - BRK test target
-nmi_trap
- trap ;check stack for conditions at NMI
- jmp start ;catastrophic error - cannot continue
-res_trap
- trap ;unexpected RESET
- jmp start ;catastrophic error - cannot continue
-
- dey
- dey
-irq_trap ;BRK test or unextpected BRK or IRQ
- php ;either SP or Y count will fail, if we do not hit
- dey
- dey
- dey
- ;next traps could be caused by unexpected BRK or IRQ
- ;check stack for BREAK and originating location
- ;possible jump/branch into weeds (uninitialized space)
- cmp #$ff-'B' ;BRK pass 2 registers loaded?
- beq break2
- cmp #'B' ;BRK pass 1 registers loaded?
- trap_ne
- cpx #'R'
- trap_ne
- cpy #'K'-3
- trap_ne
- sta irq_a ;save registers during break test
- stx irq_x
- tsx ;test break on stack
- lda $102,x
- cmp_flag 0 ;break test should have B=1 & unused=1 on stack
- trap_ne ; - no break flag on stack
- pla
- cmp_flag intdis ;should have added interrupt disable
- trap_ne
- tsx
- cpx #$fc ;sp -3? (return addr, flags)
- trap_ne
- lda $1ff ;propper return on stack
- cmp #hi(brk_ret0)
- trap_ne
- lda $1fe
- cmp #lo(brk_ret0)
- trap_ne
- load_flag $ff
- pha
- ldx irq_x
- inx ;return registers with modifications
- lda irq_a
- eor #$aa
- plp ;N=1, V=1, Z=1, C=1 but original flags should be restored
- rti
- trap ;runover protection
- jmp start ;catastrophic error - cannot continue
-
-break2 ;BRK pass 2
- cpx #$ff-'R'
- trap_ne
- cpy #$ff-'K'-3
- trap_ne
- sta irq_a ;save registers during break test
- stx irq_x
- tsx ;test break on stack
- lda $102,x
- cmp_flag $ff ;break test should have B=1
- trap_ne ; - no break flag on stack
- pla
- ora #decmode ;ignore decmode cleared if 65c02
- cmp_flag $ff ;actual passed flags
- trap_ne
- tsx
- cpx #$fc ;sp -3? (return addr, flags)
- trap_ne
- lda $1ff ;propper return on stack
- cmp #hi(brk_ret1)
- trap_ne
- lda $1fe
- cmp #lo(brk_ret1)
- trap_ne
- load_flag intdis
- pha
- ldx irq_x
- inx ;return registers with modifications
- lda irq_a
- eor #$aa
- plp ;N=0, V=0, Z=0, C=0 but original flags should be restored
- rti
- trap ;runover protection
- jmp start ;catastrophic error - cannot continue
-
- if report = 1
- include "report.i65"
- endif
-
-;copy of data to initialize BSS segment
- if load_data_direct != 1
-zp_init
-zps_ db $80,1 ;additional shift pattern to test zero result & flag
-zp1_ db $c3,$82,$41,0 ;test patterns for LDx BIT ROL ROR ASL LSR
-zp7f_ db $7f ;test pattern for compare
-;logical zeropage operands
-zpOR_ db 0,$1f,$71,$80 ;test pattern for OR
-zpAN_ db $0f,$ff,$7f,$80 ;test pattern for AND
-zpEO_ db $ff,$0f,$8f,$8f ;test pattern for EOR
-;indirect addressing pointers
-ind1_ dw abs1 ;indirect pointer to pattern in absolute memory
- dw abs1+1
- dw abs1+2
- dw abs1+3
- dw abs7f
-inw1_ dw abs1-$f8 ;indirect pointer for wrap-test pattern
-indt_ dw abst ;indirect pointer to store area in absolute memory
- dw abst+1
- dw abst+2
- dw abst+3
-inwt_ dw abst-$f8 ;indirect pointer for wrap-test store
-indAN_ dw absAN ;indirect pointer to AND pattern in absolute memory
- dw absAN+1
- dw absAN+2
- dw absAN+3
-indEO_ dw absEO ;indirect pointer to EOR pattern in absolute memory
- dw absEO+1
- dw absEO+2
- dw absEO+3
-indOR_ dw absOR ;indirect pointer to OR pattern in absolute memory
- dw absOR+1
- dw absOR+2
- dw absOR+3
-;add/subtract indirect pointers
-adi2_ dw ada2 ;indirect pointer to operand 2 in absolute memory
-sbi2_ dw sba2 ;indirect pointer to complemented operand 2 (SBC)
-adiy2_ dw ada2-$ff ;with offset for indirect indexed
-sbiy2_ dw sba2-$ff
-zp_end
- if (zp_end - zp_init) != (zp_bss_end - zp_bss)
- ;force assembler error if size is different
- ERROR ERROR ERROR ;mismatch between bss and zeropage data
- endif
-data_init
-ex_and_ and #0 ;execute immediate opcodes
- rts
-ex_eor_ eor #0 ;execute immediate opcodes
- rts
-ex_ora_ ora #0 ;execute immediate opcodes
- rts
-ex_adc_ adc #0 ;execute immediate opcodes
- rts
-ex_sbc_ sbc #0 ;execute immediate opcodes
- rts
-;zps db $80,1 ;additional shift patterns test zero result & flag
-abs1_ db $c3,$82,$41,0 ;test patterns for LDx BIT ROL ROR ASL LSR
-abs7f_ db $7f ;test pattern for compare
-;loads
-fLDx_ db fn,fn,0,fz ;expected flags for load
-;shifts
-rASL_ ;expected result ASL & ROL -carry
-rROL_ db 0,2,$86,$04,$82,0
-rROLc_ db 1,3,$87,$05,$83,1 ;expected result ROL +carry
-rLSR_ ;expected result LSR & ROR -carry
-rROR_ db $40,0,$61,$41,$20,0
-rRORc_ db $c0,$80,$e1,$c1,$a0,$80 ;expected result ROR +carry
-fASL_ ;expected flags for shifts
-fROL_ db fzc,0,fnc,fc,fn,fz ;no carry in
-fROLc_ db fc,0,fnc,fc,fn,0 ;carry in
-fLSR_
-fROR_ db 0,fzc,fc,0,fc,fz ;no carry in
-fRORc_ db fn,fnc,fnc,fn,fnc,fn ;carry in
-;increments (decrements)
-rINC_ db $7f,$80,$ff,0,1 ;expected result for INC/DEC
-fINC_ db 0,fn,fn,fz,0 ;expected flags for INC/DEC
-;logical memory operand
-absOR_ db 0,$1f,$71,$80 ;test pattern for OR
-absAN_ db $0f,$ff,$7f,$80 ;test pattern for AND
-absEO_ db $ff,$0f,$8f,$8f ;test pattern for EOR
-;logical accu operand
-absORa_ db 0,$f1,$1f,0 ;test pattern for OR
-absANa_ db $f0,$ff,$ff,$ff ;test pattern for AND
-absEOa_ db $ff,$f0,$f0,$0f ;test pattern for EOR
-;logical results
-absrlo_ db 0,$ff,$7f,$80
-absflo_ db fz,fn,0,fn
-data_end
- if (data_end - data_init) != (data_bss_end - data_bss)
- ;force assembler error if size is different
- ERROR ERROR ERROR ;mismatch between bss and data
- endif
-
-vec_init
- dw nmi_trap
- dw res_trap
- dw irq_trap
-vec_bss equ $fffa
- endif ;end of RAM init data
-
- if (load_data_direct = 1) & (ROM_vectors = 1)
- org $fffa ;vectors
- dw nmi_trap
- dw res_trap
- dw irq_trap
- endif
-
- end start
+;
+; 6 5 0 2 F U N C T I O N A L T E S T
+;
+; Copyright (C) 2012-2020 Klaus Dormann
+;
+; This program is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; This program is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with this program. If not, see .
+
+
+; This program is designed to test all opcodes of a 6502 emulator using all
+; addressing modes with focus on propper setting of the processor status
+; register bits.
+;
+; version 05-jan-2020
+; contact info at http://2m5.de or email K@2m5.de
+;
+; assembled with AS65 written by Frank A. Kingswood
+; The assembler as65_142.zip can be obtained from my GitHub repository
+; command line switches: -l -m -s2 -w -h0
+; | | | | no page headers in listing
+; | | | wide listing (133 char/col)
+; | | write intel hex file instead of binary
+; | expand macros in listing
+; generate pass2 listing
+;
+; No IO - should be run from a monitor with access to registers.
+; To run load intel hex image with a load command, than alter PC to 400 hex
+; (code_segment) and enter a go command.
+; Loop on program counter determines error or successful completion of test.
+; Check listing for relevant traps (jump/branch *).
+; Please note that in early tests some instructions will have to be used before
+; they are actually tested!
+;
+; RESET, NMI or IRQ should not occur and will be trapped if vectors are enabled.
+; Tests documented behavior of the original NMOS 6502 only! No unofficial
+; opcodes. Additional opcodes of newer versions of the CPU (65C02, 65816) will
+; not be tested. Decimal ops will only be tested with valid BCD operands and
+; N V Z flags will be ignored.
+;
+; Debugging hints:
+; Most of the code is written sequentially. if you hit a trap, check the
+; immediately preceeding code for the instruction to be tested. Results are
+; tested first, flags are checked second by pushing them onto the stack and
+; pulling them to the accumulator after the result was checked. The "real"
+; flags are no longer valid for the tested instruction at this time!
+; If the tested instruction was indexed, the relevant index (X or Y) must
+; also be checked. Opposed to the flags, X and Y registers are still valid.
+;
+; versions:
+; 28-jul-2012 1st version distributed for testing
+; 29-jul-2012 fixed references to location 0, now #0
+; added license - GPLv3
+; 30-jul-2012 added configuration options
+; 01-aug-2012 added trap macro to allow user to change error handling
+; 01-dec-2012 fixed trap in branch field must be a branch
+; 02-mar-2013 fixed PLA flags not tested
+; 19-jul-2013 allowed ROM vectors to be loaded when load_data_direct = 0
+; added test sequence check to detect if tests jump their fence
+; 23-jul-2013 added RAM integrity check option
+; 16-aug-2013 added error report to standard output option
+; 13-dec-2014 added binary/decimal opcode table switch test
+; 14-dec-2014 improved relative address test
+; 23-aug-2015 added option to disable self modifying tests
+; 24-aug-2015 all self modifying immediate opcodes now execute in data RAM
+; added small branch offset pretest
+; 21-oct-2015 added option to disable decimal mode ADC & SBC tests
+; 04-dec-2017 fixed BRK only tested with interrupts enabled
+; added option to skip the remainder of a failing test
+; in report.i65
+; 05-jan-2020 fixed shifts not testing zero result and flag when last 1-bit
+; is shifted out
+
+; C O N F I G U R A T I O N
+
+;ROM_vectors writable (0=no, 1=yes)
+;if ROM vectors can not be used interrupts will not be trapped
+;as a consequence BRK can not be tested but will be emulated to test RTI
+ROM_vectors = 1
+
+;load_data_direct (0=move from code segment, 1=load directly)
+;loading directly is preferred but may not be supported by your platform
+;0 produces only consecutive object code, 1 is not suitable for a binary image
+load_data_direct = 1
+
+;I_flag behavior (0=force enabled, 1=force disabled, 2=prohibit change, 3=allow
+;change) 2 requires extra code and is not recommended. SEI & CLI can only be
+;tested if you allow changing the interrupt status (I_flag = 3)
+I_flag = 3
+
+;configure memory - try to stay away from memory used by the system
+;zero_page memory start address, $52 (82) consecutive Bytes required
+; add 2 if I_flag = 2
+zero_page = $0
+
+;data_segment memory start address, $7B (123) consecutive Bytes required
+data_segment = $200
+ if (data_segment & $ff) != 0
+ ERROR ERROR ERROR low byte of data_segment MUST be $00 !!
+ endif
+
+;code_segment memory start address, 13.1kB of consecutive space required
+; add 2.5 kB if I_flag = 2
+code_segment = $400
+
+;self modifying code may be disabled to allow running in ROM
+;0=part of the code is self modifying and must reside in RAM
+;1=tests disabled: branch range
+disable_selfmod = 0
+
+;report errors through I/O channel (0=use standard self trap loops, 1=include
+;report.i65 as I/O channel, add 3.5 kB)
+report = 1
+
+;RAM integrity test option. Checks for undesired RAM writes.
+;set lowest non RAM or RAM mirror address page (-1=disable, 0=64k, $40=16k)
+;leave disabled if a monitor, OS or background interrupt is allowed to alter RAM
+ram_top = -1
+
+;disable test decimal mode ADC & SBC, 0=enable, 1=disable,
+;2=disable including decimal flag in processor status
+disable_decimal = 0
+
+ noopt ;do not take shortcuts
+
+;macros for error & success traps to allow user modification
+;example:
+;trap macro
+; jsr my_error_handler
+; endm
+;trap_eq macro
+; bne skip\?
+; trap ;failed equal (zero)
+;skip\?
+; endm
+;
+; my_error_handler should pop the calling address from the stack and report it.
+; putting larger portions of code (more than 3 bytes) inside the trap macro
+; may lead to branch range problems for some tests.
+ if report = 0
+trap macro
+ jmp * ;failed anyway
+ endm
+trap_eq macro
+ beq * ;failed equal (zero)
+ endm
+trap_ne macro
+ bne * ;failed not equal (non zero)
+ endm
+trap_cs macro
+ bcs * ;failed carry set
+ endm
+trap_cc macro
+ bcc * ;failed carry clear
+ endm
+trap_mi macro
+ bmi * ;failed minus (bit 7 set)
+ endm
+trap_pl macro
+ bpl * ;failed plus (bit 7 clear)
+ endm
+trap_vs macro
+ bvs * ;failed overflow set
+ endm
+trap_vc macro
+ bvc * ;failed overflow clear
+ endm
+; please observe that during the test the stack gets invalidated
+; therefore a RTS inside the success macro is not possible
+success macro
+ jmp * ;test passed, no errors
+ endm
+ endif
+ if report = 1
+trap macro
+ jsr report_error
+ endm
+trap_eq macro
+ bne skip\?
+ trap ;failed equal (zero)
+skip\?
+ endm
+trap_ne macro
+ beq skip\?
+ trap ;failed not equal (non zero)
+skip\?
+ endm
+trap_cs macro
+ bcc skip\?
+ trap ;failed carry set
+skip\?
+ endm
+trap_cc macro
+ bcs skip\?
+ trap ;failed carry clear
+skip\?
+ endm
+trap_mi macro
+ bpl skip\?
+ trap ;failed minus (bit 7 set)
+skip\?
+ endm
+trap_pl macro
+ bmi skip\?
+ trap ;failed plus (bit 7 clear)
+skip\?
+ endm
+trap_vs macro
+ bvc skip\?
+ trap ;failed overflow set
+skip\?
+ endm
+trap_vc macro
+ bvs skip\?
+ trap ;failed overflow clear
+skip\?
+ endm
+; please observe that during the test the stack gets invalidated
+; therefore a RTS inside the success macro is not possible
+success macro
+ jsr report_success
+ endm
+ endif
+
+
+carry equ %00000001 ;flag bits in status
+zero equ %00000010
+intdis equ %00000100
+decmode equ %00001000
+break equ %00010000
+reserv equ %00100000
+overfl equ %01000000
+minus equ %10000000
+
+fc equ carry
+fz equ zero
+fzc equ carry+zero
+fv equ overfl
+fvz equ overfl+zero
+fn equ minus
+fnc equ minus+carry
+fnz equ minus+zero
+fnzc equ minus+zero+carry
+fnv equ minus+overfl
+
+fao equ break+reserv ;bits always on after PHP, BRK
+fai equ fao+intdis ;+ forced interrupt disable
+faod equ fao+decmode ;+ ignore decimal
+faid equ fai+decmode ;+ ignore decimal
+m8 equ $ff ;8 bit mask
+m8i equ $ff&~intdis ;8 bit mask - interrupt disable
+
+;macros to allow masking of status bits.
+;masking test of decimal bit
+;masking of interrupt enable/disable on load and compare
+;masking of always on bits after PHP or BRK (unused & break) on compare
+ if disable_decimal < 2
+ if I_flag = 0
+load_flag macro
+ lda #\1&m8i ;force enable interrupts (mask I)
+ endm
+cmp_flag macro
+ cmp #(\1|fao)&m8i ;I_flag is always enabled + always on bits
+ endm
+eor_flag macro
+ eor #(\1&m8i|fao) ;mask I, invert expected flags + always on bits
+ endm
+ endif
+ if I_flag = 1
+load_flag macro
+ lda #\1|intdis ;force disable interrupts
+ endm
+cmp_flag macro
+ cmp #(\1|fai)&m8 ;I_flag is always disabled + always on bits
+ endm
+eor_flag macro
+ eor #(\1|fai) ;invert expected flags + always on bits + I
+ endm
+ endif
+ if I_flag = 2
+load_flag macro
+ lda #\1
+ ora flag_I_on ;restore I-flag
+ and flag_I_off
+ endm
+cmp_flag macro
+ eor flag_I_on ;I_flag is never changed
+ cmp #(\1|fao)&m8i ;expected flags + always on bits, mask I
+ endm
+eor_flag macro
+ eor flag_I_on ;I_flag is never changed
+ eor #(\1&m8i|fao) ;mask I, invert expected flags + always on bits
+ endm
+ endif
+ if I_flag = 3
+load_flag macro
+ lda #\1 ;allow test to change I-flag (no mask)
+ endm
+cmp_flag macro
+ cmp #(\1|fao)&m8 ;expected flags + always on bits
+ endm
+eor_flag macro
+ eor #\1|fao ;invert expected flags + always on bits
+ endm
+ endif
+ else
+ if I_flag = 0
+load_flag macro
+ lda #\1&m8i ;force enable interrupts (mask I)
+ endm
+cmp_flag macro
+ ora #decmode ;ignore decimal mode bit
+ cmp #(\1|faod)&m8i ;I_flag is always enabled + always on bits
+ endm
+eor_flag macro
+ ora #decmode ;ignore decimal mode bit
+ eor #(\1&m8i|faod) ;mask I, invert expected flags + always on bits
+ endm
+ endif
+ if I_flag = 1
+load_flag macro
+ lda #\1|intdis ;force disable interrupts
+ endm
+cmp_flag macro
+ ora #decmode ;ignore decimal mode bit
+ cmp #(\1|faid)&m8 ;I_flag is always disabled + always on bits
+ endm
+eor_flag macro
+ ora #decmode ;ignore decimal mode bit
+ eor #(\1|faid) ;invert expected flags + always on bits + I
+ endm
+ endif
+ if I_flag = 2
+load_flag macro
+ lda #\1
+ ora flag_I_on ;restore I-flag
+ and flag_I_off
+ endm
+cmp_flag macro
+ eor flag_I_on ;I_flag is never changed
+ ora #decmode ;ignore decimal mode bit
+ cmp #(\1|faod)&m8i ;expected flags + always on bits, mask I
+ endm
+eor_flag macro
+ eor flag_I_on ;I_flag is never changed
+ ora #decmode ;ignore decimal mode bit
+ eor #(\1&m8i|faod) ;mask I, invert expected flags + always on bits
+ endm
+ endif
+ if I_flag = 3
+load_flag macro
+ lda #\1 ;allow test to change I-flag (no mask)
+ endm
+cmp_flag macro
+ ora #decmode ;ignore decimal mode bit
+ cmp #(\1|faod)&m8 ;expected flags + always on bits
+ endm
+eor_flag macro
+ ora #decmode ;ignore decimal mode bit
+ eor #\1|faod ;invert expected flags + always on bits
+ endm
+ endif
+ endif
+
+;macros to set (register|memory|zeropage) & status
+set_stat macro ;setting flags in the processor status register
+ load_flag \1
+ pha ;use stack to load status
+ plp
+ endm
+
+set_a macro ;precharging accu & status
+ load_flag \2
+ pha ;use stack to load status
+ lda #\1 ;precharge accu
+ plp
+ endm
+
+set_x macro ;precharging index & status
+ load_flag \2
+ pha ;use stack to load status
+ ldx #\1 ;precharge index x
+ plp
+ endm
+
+set_y macro ;precharging index & status
+ load_flag \2
+ pha ;use stack to load status
+ ldy #\1 ;precharge index y
+ plp
+ endm
+
+set_ax macro ;precharging indexed accu & immediate status
+ load_flag \2
+ pha ;use stack to load status
+ lda \1,x ;precharge accu
+ plp
+ endm
+
+set_ay macro ;precharging indexed accu & immediate status
+ load_flag \2
+ pha ;use stack to load status
+ lda \1,y ;precharge accu
+ plp
+ endm
+
+set_z macro ;precharging indexed zp & immediate status
+ load_flag \2
+ pha ;use stack to load status
+ lda \1,x ;load to zeropage
+ sta zpt
+ plp
+ endm
+
+set_zx macro ;precharging zp,x & immediate status
+ load_flag \2
+ pha ;use stack to load status
+ lda \1,x ;load to indexed zeropage
+ sta zpt,x
+ plp
+ endm
+
+set_abs macro ;precharging indexed memory & immediate status
+ load_flag \2
+ pha ;use stack to load status
+ lda \1,x ;load to memory
+ sta abst
+ plp
+ endm
+
+set_absx macro ;precharging abs,x & immediate status
+ load_flag \2
+ pha ;use stack to load status
+ lda \1,x ;load to indexed memory
+ sta abst,x
+ plp
+ endm
+
+;macros to test (register|memory|zeropage) & status & (mask)
+tst_stat macro ;testing flags in the processor status register
+ php ;save status
+ pla ;use stack to retrieve status
+ pha
+ cmp_flag \1
+ trap_ne
+ plp ;restore status
+ endm
+
+tst_a macro ;testing result in accu & flags
+ php ;save flags
+ cmp #\1 ;test result
+ trap_ne
+ pla ;load status
+ pha
+ cmp_flag \2
+ trap_ne
+ plp ;restore status
+ endm
+
+tst_x macro ;testing result in x index & flags
+ php ;save flags
+ cpx #\1 ;test result
+ trap_ne
+ pla ;load status
+ pha
+ cmp_flag \2
+ trap_ne
+ plp ;restore status
+ endm
+
+tst_y macro ;testing result in y index & flags
+ php ;save flags
+ cpy #\1 ;test result
+ trap_ne
+ pla ;load status
+ pha
+ cmp_flag \2
+ trap_ne
+ plp ;restore status
+ endm
+
+tst_ax macro ;indexed testing result in accu & flags
+ php ;save flags
+ cmp \1,x ;test result
+ trap_ne
+ pla ;load status
+ eor_flag \3
+ cmp \2,x ;test flags
+ trap_ne ;
+ endm
+
+tst_ay macro ;indexed testing result in accu & flags
+ php ;save flags
+ cmp \1,y ;test result
+ trap_ne ;
+ pla ;load status
+ eor_flag \3
+ cmp \2,y ;test flags
+ trap_ne
+ endm
+
+tst_z macro ;indexed testing result in zp & flags
+ php ;save flags
+ lda zpt
+ cmp \1,x ;test result
+ trap_ne
+ pla ;load status
+ eor_flag \3
+ cmp \2,x ;test flags
+ trap_ne
+ endm
+
+tst_zx macro ;testing result in zp,x & flags
+ php ;save flags
+ lda zpt,x
+ cmp \1,x ;test result
+ trap_ne
+ pla ;load status
+ eor_flag \3
+ cmp \2,x ;test flags
+ trap_ne
+ endm
+
+tst_abs macro ;indexed testing result in memory & flags
+ php ;save flags
+ lda abst
+ cmp \1,x ;test result
+ trap_ne
+ pla ;load status
+ eor_flag \3
+ cmp \2,x ;test flags
+ trap_ne
+ endm
+
+tst_absx macro ;testing result in abs,x & flags
+ php ;save flags
+ lda abst,x
+ cmp \1,x ;test result
+ trap_ne
+ pla ;load status
+ eor_flag \3
+ cmp \2,x ;test flags
+ trap_ne
+ endm
+
+; RAM integrity test
+; verifies that none of the previous tests has altered RAM outside of the
+; designated write areas.
+; uses zpt word as indirect pointer, zpt+2 word as checksum
+ if ram_top > -1
+check_ram macro
+ cld
+ lda #0
+ sta zpt ;set low byte of indirect pointer
+ sta zpt+3 ;checksum high byte
+ if disable_selfmod = 0
+ sta range_adr ;reset self modifying code
+ endif
+ clc
+ ldx #zp_bss-zero_page ;zeropage - write test area
+ccs3\? adc zero_page,x
+ bcc ccs2\?
+ inc zpt+3 ;carry to high byte
+ clc
+ccs2\? inx
+ bne ccs3\?
+ ldx #hi(abs1) ;set high byte of indirect pointer
+ stx zpt+1
+ ldy #lo(abs1) ;data after write & execute test area
+ccs5\? adc (zpt),y
+ bcc ccs4\?
+ inc zpt+3 ;carry to high byte
+ clc
+ccs4\? iny
+ bne ccs5\?
+ inx ;advance RAM high address
+ stx zpt+1
+ cpx #ram_top
+ bne ccs5\?
+ sta zpt+2 ;checksum low is
+ cmp ram_chksm ;checksum low expected
+ trap_ne ;checksum mismatch
+ lda zpt+3 ;checksum high is
+ cmp ram_chksm+1 ;checksum high expected
+ trap_ne ;checksum mismatch
+ endm
+ else
+check_ram macro
+ ;RAM check disabled - RAM size not set
+ endm
+ endif
+
+next_test macro ;make sure, tests don't jump the fence
+ lda test_case ;previous test
+ cmp #test_num
+ trap_ne ;test is out of sequence
+test_num = test_num + 1
+ lda #test_num ;*** next tests' number
+ sta test_case
+ ;check_ram ;uncomment to find altered RAM after each test
+ endm
+
+ if load_data_direct = 1
+ data
+ else
+ bss ;uninitialized segment, copy of data at end of code!
+ endif
+ org zero_page
+;break test interrupt save
+irq_a ds 1 ;a register
+irq_x ds 1 ;x register
+ if I_flag = 2
+;masking for I bit in status
+flag_I_on ds 1 ;or mask to load flags
+flag_I_off ds 1 ;and mask to load flags
+ endif
+zpt ;6 bytes store/modify test area
+;add/subtract operand generation and result/flag prediction
+adfc ds 1 ;carry flag before op
+ad1 ds 1 ;operand 1 - accumulator
+ad2 ds 1 ;operand 2 - memory / immediate
+adrl ds 1 ;expected result bits 0-7
+adrh ds 1 ;expected result bit 8 (carry)
+adrf ds 1 ;expected flags NV0000ZC (only binary mode)
+sb2 ds 1 ;operand 2 complemented for subtract
+zp_bss
+zps db $80,1 ;additional shift pattern to test zero result & flag
+zp1 db $c3,$82,$41,0 ;test patterns for LDx BIT ROL ROR ASL LSR
+zp7f db $7f ;test pattern for compare
+;logical zeropage operands
+zpOR db 0,$1f,$71,$80 ;test pattern for OR
+zpAN db $0f,$ff,$7f,$80 ;test pattern for AND
+zpEO db $ff,$0f,$8f,$8f ;test pattern for EOR
+;indirect addressing pointers
+ind1 dw abs1 ;indirect pointer to pattern in absolute memory
+ dw abs1+1
+ dw abs1+2
+ dw abs1+3
+ dw abs7f
+inw1 dw abs1-$f8 ;indirect pointer for wrap-test pattern
+indt dw abst ;indirect pointer to store area in absolute memory
+ dw abst+1
+ dw abst+2
+ dw abst+3
+inwt dw abst-$f8 ;indirect pointer for wrap-test store
+indAN dw absAN ;indirect pointer to AND pattern in absolute memory
+ dw absAN+1
+ dw absAN+2
+ dw absAN+3
+indEO dw absEO ;indirect pointer to EOR pattern in absolute memory
+ dw absEO+1
+ dw absEO+2
+ dw absEO+3
+indOR dw absOR ;indirect pointer to OR pattern in absolute memory
+ dw absOR+1
+ dw absOR+2
+ dw absOR+3
+;add/subtract indirect pointers
+adi2 dw ada2 ;indirect pointer to operand 2 in absolute memory
+sbi2 dw sba2 ;indirect pointer to complemented operand 2 (SBC)
+adiy2 dw ada2-$ff ;with offset for indirect indexed
+sbiy2 dw sba2-$ff
+zp_bss_end
+
+ org data_segment
+test_case ds 1 ;current test number
+ram_chksm ds 2 ;checksum for RAM integrity test
+;add/subtract operand copy - abs tests write area
+abst ;6 bytes store/modify test area
+ada2 ds 1 ;operand 2
+sba2 ds 1 ;operand 2 complemented for subtract
+ ds 4 ;fill remaining bytes
+data_bss
+ if load_data_direct = 1
+ex_andi and #0 ;execute immediate opcodes
+ rts
+ex_eori eor #0 ;execute immediate opcodes
+ rts
+ex_orai ora #0 ;execute immediate opcodes
+ rts
+ex_adci adc #0 ;execute immediate opcodes
+ rts
+ex_sbci sbc #0 ;execute immediate opcodes
+ rts
+ else
+ex_andi ds 3
+ex_eori ds 3
+ex_orai ds 3
+ex_adci ds 3
+ex_sbci ds 3
+ endif
+;zps db $80,1 ;additional shift patterns test zero result & flag
+abs1 db $c3,$82,$41,0 ;test patterns for LDx BIT ROL ROR ASL LSR
+abs7f db $7f ;test pattern for compare
+;loads
+fLDx db fn,fn,0,fz ;expected flags for load
+;shifts
+rASL ;expected result ASL & ROL -carry
+rROL db 0,2,$86,$04,$82,0
+rROLc db 1,3,$87,$05,$83,1 ;expected result ROL +carry
+rLSR ;expected result LSR & ROR -carry
+rROR db $40,0,$61,$41,$20,0
+rRORc db $c0,$80,$e1,$c1,$a0,$80 ;expected result ROR +carry
+fASL ;expected flags for shifts
+fROL db fzc,0,fnc,fc,fn,fz ;no carry in
+fROLc db fc,0,fnc,fc,fn,0 ;carry in
+fLSR
+fROR db 0,fzc,fc,0,fc,fz ;no carry in
+fRORc db fn,fnc,fnc,fn,fnc,fn ;carry in
+;increments (decrements)
+rINC db $7f,$80,$ff,0,1 ;expected result for INC/DEC
+fINC db 0,fn,fn,fz,0 ;expected flags for INC/DEC
+;logical memory operand
+absOR db 0,$1f,$71,$80 ;test pattern for OR
+absAN db $0f,$ff,$7f,$80 ;test pattern for AND
+absEO db $ff,$0f,$8f,$8f ;test pattern for EOR
+;logical accu operand
+absORa db 0,$f1,$1f,0 ;test pattern for OR
+absANa db $f0,$ff,$ff,$ff ;test pattern for AND
+absEOa db $ff,$f0,$f0,$0f ;test pattern for EOR
+;logical results
+absrlo db 0,$ff,$7f,$80
+absflo db fz,fn,0,fn
+data_bss_end
+
+
+ code
+ org code_segment
+start lda #1
+ sta $bc02
+ cld
+ ldx #$ff
+ txs
+ lda #0 ;*** test 0 = initialize
+ sta test_case
+test_num = 0
+
+;stop interrupts before initializing BSS
+ if I_flag = 1
+ sei
+ endif
+
+;initialize I/O for report channel
+ if report = 1
+ jsr report_init
+ endif
+
+;pretest small branch offset
+ ldx #5
+ jmp psb_test
+psb_bwok
+ ldy #5
+ bne psb_forw
+ trap ;branch should be taken
+ dey ;forward landing zone
+ dey
+ dey
+ dey
+ dey
+psb_forw
+ dey
+ dey
+ dey
+ dey
+ dey
+ beq psb_fwok
+ trap ;forward offset
+
+ dex ;backward landing zone
+ dex
+ dex
+ dex
+ dex
+psb_back
+ dex
+ dex
+ dex
+ dex
+ dex
+ beq psb_bwok
+ trap ;backward offset
+psb_test
+ bne psb_back
+ trap ;branch should be taken
+psb_fwok
+
+;initialize BSS segment
+ if load_data_direct != 1
+ ldx #zp_end-zp_init-1
+ld_zp lda zp_init,x
+ sta zp_bss,x
+ dex
+ bpl ld_zp
+ ldx #data_end-data_init-1
+ld_data lda data_init,x
+ sta data_bss,x
+ dex
+ bpl ld_data
+ if ROM_vectors = 1
+ ldx #5
+ld_vect lda vec_init,x
+ sta vec_bss,x
+ dex
+ bpl ld_vect
+ endif
+ endif
+
+;retain status of interrupt flag
+ if I_flag = 2
+ php
+ pla
+ and #4 ;isolate flag
+ sta flag_I_on ;or mask
+ eor #lo(~4) ;reverse
+ sta flag_I_off ;and mask
+ endif
+
+;generate checksum for RAM integrity test
+ if ram_top > -1
+ lda #0
+ sta zpt ;set low byte of indirect pointer
+ sta ram_chksm+1 ;checksum high byte
+ if disable_selfmod = 0
+ sta range_adr ;reset self modifying code
+ endif
+ clc
+ ldx #zp_bss-zero_page ;zeropage - write test area
+gcs3 adc zero_page,x
+ bcc gcs2
+ inc ram_chksm+1 ;carry to high byte
+ clc
+gcs2 inx
+ bne gcs3
+ ldx #hi(abs1) ;set high byte of indirect pointer
+ stx zpt+1
+ ldy #lo(abs1) ;data after write & execute test area
+gcs5 adc (zpt),y
+ bcc gcs4
+ inc ram_chksm+1 ;carry to high byte
+ clc
+gcs4 iny
+ bne gcs5
+ inx ;advance RAM high address
+ stx zpt+1
+ cpx #ram_top
+ bne gcs5
+ sta ram_chksm ;checksum complete
+ endif
+ next_test
+
+ if disable_selfmod = 0
+;testing relative addressing with BEQ
+ ldy #$fe ;testing maximum range, not -1/-2 (invalid/self adr)
+range_loop
+ dey ;next relative address
+ tya
+ tax ;precharge count to end of loop
+ bpl range_fw ;calculate relative address
+ clc ;avoid branch self or to relative address of branch
+ adc #2
+ nop ;offset landing zone - tolerate +/-5 offset to branch
+ nop
+ nop
+ nop
+ nop
+range_fw
+ nop
+ nop
+ nop
+ nop
+ nop
+ eor #$7f ;complement except sign
+ sta range_adr ;load into test target
+ lda #0 ;should set zero flag in status register
+ jmp range_op
+
+ dex ; offset landing zone - backward branch too far
+ dex
+ dex
+ dex
+ dex
+ ;relative address target field with branch under test in the middle
+ dex ;-128 - max backward
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex ;-120
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex ;-110
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex ;-100
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex ;-90
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex ;-80
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex ;-70
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex ;-60
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex ;-50
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex ;-40
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex ;-30
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex ;-20
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex ;-10
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex ;-3
+range_op ;test target with zero flag=0, z=1 if previous dex
+range_adr = *+1 ;modifiable relative address
+ beq *+64 ;+64 if called without modification
+ dex ;+0
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex ;+10
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex ;+20
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex ;+30
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex ;+40
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex ;+50
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex ;+60
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex ;+70
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex ;+80
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex ;+90
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex ;+100
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex ;+110
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex ;+120
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ nop ;offset landing zone - forward branch too far
+ nop
+ nop
+ nop
+ nop
+ beq range_ok ;+127 - max forward
+ trap ; bad range
+ nop ;offset landing zone - tolerate +/-5 offset to branch
+ nop
+ nop
+ nop
+ nop
+range_ok
+ nop
+ nop
+ nop
+ nop
+ nop
+ cpy #0
+ beq range_end
+ jmp range_loop
+range_end ;range test successful
+ endif
+ next_test
+
+;partial test BNE & CMP, CPX, CPY immediate
+ cpy #1 ;testing BNE true
+ bne test_bne
+ trap
+test_bne
+ lda #0
+ cmp #0 ;test compare immediate
+ trap_ne
+ trap_cc
+ trap_mi
+ cmp #1
+ trap_eq
+ trap_cs
+ trap_pl
+ tax
+ cpx #0 ;test compare x immediate
+ trap_ne
+ trap_cc
+ trap_mi
+ cpx #1
+ trap_eq
+ trap_cs
+ trap_pl
+ tay
+ cpy #0 ;test compare y immediate
+ trap_ne
+ trap_cc
+ trap_mi
+ cpy #1
+ trap_eq
+ trap_cs
+ trap_pl
+ next_test
+;testing stack operations PHA PHP PLA PLP
+
+ ldx #$ff ;initialize stack
+ txs
+ lda #$55
+ pha
+ lda #$aa
+ pha
+ cmp $1fe ;on stack ?
+ trap_ne
+ tsx
+ txa ;overwrite accu
+ cmp #$fd ;sp decremented?
+ trap_ne
+ pla
+ cmp #$aa ;successful retreived from stack?
+ trap_ne
+ pla
+ cmp #$55
+ trap_ne
+ cmp $1ff ;remains on stack?
+ trap_ne
+ tsx
+ cpx #$ff ;sp incremented?
+ trap_ne
+ next_test
+
+;testing branch decisions BPL BMI BVC BVS BCC BCS BNE BEQ
+ set_stat $ff ;all on
+ bpl nbr1 ;branches should not be taken
+ bvc nbr2
+ bcc nbr3
+ bne nbr4
+ bmi br1 ;branches should be taken
+ trap
+br1 bvs br2
+ trap
+br2 bcs br3
+ trap
+br3 beq br4
+ trap
+nbr1
+ trap ;previous bpl taken
+nbr2
+ trap ;previous bvc taken
+nbr3
+ trap ;previous bcc taken
+nbr4
+ trap ;previous bne taken
+br4 php
+ tsx
+ cpx #$fe ;sp after php?
+ trap_ne
+ pla
+ cmp_flag $ff ;returned all flags on?
+ trap_ne
+ tsx
+ cpx #$ff ;sp after php?
+ trap_ne
+ set_stat 0 ;all off
+ bmi nbr11 ;branches should not be taken
+ bvs nbr12
+ bcs nbr13
+ beq nbr14
+ bpl br11 ;branches should be taken
+ trap
+br11 bvc br12
+ trap
+br12 bcc br13
+ trap
+br13 bne br14
+ trap
+nbr11
+ trap ;previous bmi taken
+nbr12
+ trap ;previous bvs taken
+nbr13
+ trap ;previous bcs taken
+nbr14
+ trap ;previous beq taken
+br14 php
+ pla
+ cmp_flag 0 ;flags off except break (pushed by sw) + reserved?
+ trap_ne
+ ;crosscheck flags
+ set_stat zero
+ bne brzs1
+ beq brzs2
+brzs1
+ trap ;branch zero/non zero
+brzs2 bcs brzs3
+ bcc brzs4
+brzs3
+ trap ;branch carry/no carry
+brzs4 bmi brzs5
+ bpl brzs6
+brzs5
+ trap ;branch minus/plus
+brzs6 bvs brzs7
+ bvc brzs8
+brzs7
+ trap ;branch overflow/no overflow
+brzs8
+ set_stat carry
+ beq brcs1
+ bne brcs2
+brcs1
+ trap ;branch zero/non zero
+brcs2 bcc brcs3
+ bcs brcs4
+brcs3
+ trap ;branch carry/no carry
+brcs4 bmi brcs5
+ bpl brcs6
+brcs5
+ trap ;branch minus/plus
+brcs6 bvs brcs7
+ bvc brcs8
+brcs7
+ trap ;branch overflow/no overflow
+
+brcs8
+ set_stat minus
+ beq brmi1
+ bne brmi2
+brmi1
+ trap ;branch zero/non zero
+brmi2 bcs brmi3
+ bcc brmi4
+brmi3
+ trap ;branch carry/no carry
+brmi4 bpl brmi5
+ bmi brmi6
+brmi5
+ trap ;branch minus/plus
+brmi6 bvs brmi7
+ bvc brmi8
+brmi7
+ trap ;branch overflow/no overflow
+brmi8
+ set_stat overfl
+ beq brvs1
+ bne brvs2
+brvs1
+ trap ;branch zero/non zero
+brvs2 bcs brvs3
+ bcc brvs4
+brvs3
+ trap ;branch carry/no carry
+brvs4 bmi brvs5
+ bpl brvs6
+brvs5
+ trap ;branch minus/plus
+brvs6 bvc brvs7
+ bvs brvs8
+brvs7
+ trap ;branch overflow/no overflow
+brvs8
+ set_stat $ff-zero
+ beq brzc1
+ bne brzc2
+brzc1
+ trap ;branch zero/non zero
+brzc2 bcc brzc3
+ bcs brzc4
+brzc3
+ trap ;branch carry/no carry
+brzc4 bpl brzc5
+ bmi brzc6
+brzc5
+ trap ;branch minus/plus
+brzc6 bvc brzc7
+ bvs brzc8
+brzc7
+ trap ;branch overflow/no overflow
+brzc8
+ set_stat $ff-carry
+ bne brcc1
+ beq brcc2
+brcc1
+ trap ;branch zero/non zero
+brcc2 bcs brcc3
+ bcc brcc4
+brcc3
+ trap ;branch carry/no carry
+brcc4 bpl brcc5
+ bmi brcc6
+brcc5
+ trap ;branch minus/plus
+brcc6 bvc brcc7
+ bvs brcc8
+brcc7
+ trap ;branch overflow/no overflow
+brcc8
+ set_stat $ff-minus
+ bne brpl1
+ beq brpl2
+brpl1
+ trap ;branch zero/non zero
+brpl2 bcc brpl3
+ bcs brpl4
+brpl3
+ trap ;branch carry/no carry
+brpl4 bmi brpl5
+ bpl brpl6
+brpl5
+ trap ;branch minus/plus
+brpl6 bvc brpl7
+ bvs brpl8
+brpl7
+ trap ;branch overflow/no overflow
+brpl8
+ set_stat $ff-overfl
+ bne brvc1
+ beq brvc2
+brvc1
+ trap ;branch zero/non zero
+brvc2 bcc brvc3
+ bcs brvc4
+brvc3
+ trap ;branch carry/no carry
+brvc4 bpl brvc5
+ bmi brvc6
+brvc5
+ trap ;branch minus/plus
+brvc6 bvs brvc7
+ bvc brvc8
+brvc7
+ trap ;branch overflow/no overflow
+brvc8
+ next_test
+
+; test PHA does not alter flags or accumulator but PLA does
+ ldx #$55 ;x & y protected
+ ldy #$aa
+ set_a 1,$ff ;push
+ pha
+ tst_a 1,$ff
+ set_a 0,0
+ pha
+ tst_a 0,0
+ set_a $ff,$ff
+ pha
+ tst_a $ff,$ff
+ set_a 1,0
+ pha
+ tst_a 1,0
+ set_a 0,$ff
+ pha
+ tst_a 0,$ff
+ set_a $ff,0
+ pha
+ tst_a $ff,0
+ set_a 0,$ff ;pull
+ pla
+ tst_a $ff,$ff-zero
+ set_a $ff,0
+ pla
+ tst_a 0,zero
+ set_a $fe,$ff
+ pla
+ tst_a 1,$ff-zero-minus
+ set_a 0,0
+ pla
+ tst_a $ff,minus
+ set_a $ff,$ff
+ pla
+ tst_a 0,$ff-minus
+ set_a $fe,0
+ pla
+ tst_a 1,0
+ cpx #$55 ;x & y unchanged?
+ trap_ne
+ cpy #$aa
+ trap_ne
+ next_test
+
+; partial pretest EOR #
+ set_a $3c,0
+ eor #$c3
+ tst_a $ff,fn
+ set_a $c3,0
+ eor #$c3
+ tst_a 0,fz
+ next_test
+
+; PC modifying instructions except branches (NOP, JMP, JSR, RTS, BRK, RTI)
+; testing NOP
+ ldx #$24
+ ldy #$42
+ set_a $18,0
+ nop
+ tst_a $18,0
+ cpx #$24
+ trap_ne
+ cpy #$42
+ trap_ne
+ ldx #$db
+ ldy #$bd
+ set_a $e7,$ff
+ nop
+ tst_a $e7,$ff
+ cpx #$db
+ trap_ne
+ cpy #$bd
+ trap_ne
+ next_test
+
+; jump absolute
+ set_stat $0
+ lda #'F'
+ ldx #'A'
+ ldy #'R' ;N=0, V=0, Z=0, C=0
+ jmp test_far
+ nop
+ nop
+ trap_ne ;runover protection
+ inx
+ inx
+far_ret
+ trap_eq ;returned flags OK?
+ trap_pl
+ trap_cc
+ trap_vc
+ cmp #('F'^$aa) ;returned registers OK?
+ trap_ne
+ cpx #('A'+1)
+ trap_ne
+ cpy #('R'-3)
+ trap_ne
+ dex
+ iny
+ iny
+ iny
+ eor #$aa ;N=0, V=1, Z=0, C=1
+ jmp test_near
+ nop
+ nop
+ trap_ne ;runover protection
+ inx
+ inx
+test_near
+ trap_eq ;passed flags OK?
+ trap_mi
+ trap_cc
+ trap_vc
+ cmp #'F' ;passed registers OK?
+ trap_ne
+ cpx #'A'
+ trap_ne
+ cpy #'R'
+ trap_ne
+ next_test
+
+; jump indirect
+ set_stat 0
+ lda #'I'
+ ldx #'N'
+ ldy #'D' ;N=0, V=0, Z=0, C=0
+ jmp (ptr_tst_ind)
+ nop
+ trap_ne ;runover protection
+ dey
+ dey
+ind_ret
+ php ;either SP or Y count will fail, if we do not hit
+ dey
+ dey
+ dey
+ plp
+ trap_eq ;returned flags OK?
+ trap_pl
+ trap_cc
+ trap_vc
+ cmp #('I'^$aa) ;returned registers OK?
+ trap_ne
+ cpx #('N'+1)
+ trap_ne
+ cpy #('D'-6)
+ trap_ne
+ tsx ;SP check
+ cpx #$ff
+ trap_ne
+ next_test
+
+; jump subroutine & return from subroutine
+ set_stat 0
+ lda #'J'
+ ldx #'S'
+ ldy #'R' ;N=0, V=0, Z=0, C=0
+ jsr test_jsr
+jsr_ret = *-1 ;last address of jsr = return address
+ php ;either SP or Y count will fail, if we do not hit
+ dey
+ dey
+ dey
+ plp
+ trap_eq ;returned flags OK?
+ trap_pl
+ trap_cc
+ trap_vc
+ cmp #('J'^$aa) ;returned registers OK?
+ trap_ne
+ cpx #('S'+1)
+ trap_ne
+ cpy #('R'-6)
+ trap_ne
+ tsx ;sp?
+ cpx #$ff
+ trap_ne
+ next_test
+
+; break & return from interrupt
+ if ROM_vectors = 1
+ load_flag 0 ;with interrupts enabled if allowed!
+ pha
+ lda #'B'
+ ldx #'R'
+ ldy #'K'
+ plp ;N=0, V=0, Z=0, C=0
+ brk
+ else
+ lda #hi brk_ret0 ;emulated break
+ pha
+ lda #lo brk_ret0
+ pha
+ load_flag fao ;set break & unused on stack
+ pha
+ load_flag intdis ;during interrupt
+ pha
+ lda #'B'
+ ldx #'R'
+ ldy #'K'
+ plp ;N=0, V=0, Z=0, C=0
+ jmp irq_trap
+ endif
+ dey ;should not be executed
+brk_ret0 ;address of break return
+ php ;either SP or Y count will fail, if we do not hit
+ dey
+ dey
+ dey
+ cmp #'B'^$aa ;returned registers OK?
+ ;the IRQ vector was never executed if A & X stay unmodified
+ trap_ne
+ cpx #'R'+1
+ trap_ne
+ cpy #'K'-6
+ trap_ne
+ pla ;returned flags OK (unchanged)?
+ cmp_flag 0
+ trap_ne
+ tsx ;sp?
+ cpx #$ff
+ trap_ne
+ if ROM_vectors = 1
+ load_flag $ff ;with interrupts disabled if allowed!
+ pha
+ lda #$ff-'B'
+ ldx #$ff-'R'
+ ldy #$ff-'K'
+ plp ;N=1, V=1, Z=1, C=1
+ brk
+ else
+ lda #hi brk_ret1 ;emulated break
+ pha
+ lda #lo brk_ret1
+ pha
+ load_flag $ff
+ pha ;set break & unused on stack
+ pha ;actual flags
+ lda #$ff-'B'
+ ldx #$ff-'R'
+ ldy #$ff-'K'
+ plp ;N=1, V=1, Z=1, C=1
+ jmp irq_trap
+ endif
+ dey ;should not be executed
+brk_ret1 ;address of break return
+ php ;either SP or Y count will fail, if we do not hit
+ dey
+ dey
+ dey
+ cmp #($ff-'B')^$aa ;returned registers OK?
+ ;the IRQ vector was never executed if A & X stay unmodified
+ trap_ne
+ cpx #$ff-'R'+1
+ trap_ne
+ cpy #$ff-'K'-6
+ trap_ne
+ pla ;returned flags OK (unchanged)?
+ cmp_flag $ff
+ trap_ne
+ tsx ;sp?
+ cpx #$ff
+ trap_ne
+ next_test
+
+; test set and clear flags CLC CLI CLD CLV SEC SEI SED
+ set_stat $ff
+ clc
+ tst_stat $ff-carry
+ sec
+ tst_stat $ff
+ if I_flag = 3
+ cli
+ tst_stat $ff-intdis
+ sei
+ tst_stat $ff
+ endif
+ cld
+ tst_stat $ff-decmode
+ sed
+ tst_stat $ff
+ clv
+ tst_stat $ff-overfl
+ set_stat 0
+ tst_stat 0
+ sec
+ tst_stat carry
+ clc
+ tst_stat 0
+ if I_flag = 3
+ sei
+ tst_stat intdis
+ cli
+ tst_stat 0
+ endif
+ sed
+ tst_stat decmode
+ cld
+ tst_stat 0
+ set_stat overfl
+ tst_stat overfl
+ clv
+ tst_stat 0
+ next_test
+; testing index register increment/decrement and transfer
+; INX INY DEX DEY TAX TXA TAY TYA
+ ldx #$fe
+ set_stat $ff
+ inx ;ff
+ tst_x $ff,$ff-zero
+ inx ;00
+ tst_x 0,$ff-minus
+ inx ;01
+ tst_x 1,$ff-minus-zero
+ dex ;00
+ tst_x 0,$ff-minus
+ dex ;ff
+ tst_x $ff,$ff-zero
+ dex ;fe
+ set_stat 0
+ inx ;ff
+ tst_x $ff,minus
+ inx ;00
+ tst_x 0,zero
+ inx ;01
+ tst_x 1,0
+ dex ;00
+ tst_x 0,zero
+ dex ;ff
+ tst_x $ff,minus
+
+ ldy #$fe
+ set_stat $ff
+ iny ;ff
+ tst_y $ff,$ff-zero
+ iny ;00
+ tst_y 0,$ff-minus
+ iny ;01
+ tst_y 1,$ff-minus-zero
+ dey ;00
+ tst_y 0,$ff-minus
+ dey ;ff
+ tst_y $ff,$ff-zero
+ dey ;fe
+ set_stat 0
+ iny ;ff
+ tst_y $ff,0+minus
+ iny ;00
+ tst_y 0,zero
+ iny ;01
+ tst_y 1,0
+ dey ;00
+ tst_y 0,zero
+ dey ;ff
+ tst_y $ff,minus
+
+ ldx #$ff
+ set_stat $ff
+ txa
+ tst_a $ff,$ff-zero
+ php
+ inx ;00
+ plp
+ txa
+ tst_a 0,$ff-minus
+ php
+ inx ;01
+ plp
+ txa
+ tst_a 1,$ff-minus-zero
+ set_stat 0
+ txa
+ tst_a 1,0
+ php
+ dex ;00
+ plp
+ txa
+ tst_a 0,zero
+ php
+ dex ;ff
+ plp
+ txa
+ tst_a $ff,minus
+
+ ldy #$ff
+ set_stat $ff
+ tya
+ tst_a $ff,$ff-zero
+ php
+ iny ;00
+ plp
+ tya
+ tst_a 0,$ff-minus
+ php
+ iny ;01
+ plp
+ tya
+ tst_a 1,$ff-minus-zero
+ set_stat 0
+ tya
+ tst_a 1,0
+ php
+ dey ;00
+ plp
+ tya
+ tst_a 0,zero
+ php
+ dey ;ff
+ plp
+ tya
+ tst_a $ff,minus
+
+ load_flag $ff
+ pha
+ ldx #$ff ;ff
+ txa
+ plp
+ tay
+ tst_y $ff,$ff-zero
+ php
+ inx ;00
+ txa
+ plp
+ tay
+ tst_y 0,$ff-minus
+ php
+ inx ;01
+ txa
+ plp
+ tay
+ tst_y 1,$ff-minus-zero
+ load_flag 0
+ pha
+ lda #0
+ txa
+ plp
+ tay
+ tst_y 1,0
+ php
+ dex ;00
+ txa
+ plp
+ tay
+ tst_y 0,zero
+ php
+ dex ;ff
+ txa
+ plp
+ tay
+ tst_y $ff,minus
+
+
+ load_flag $ff
+ pha
+ ldy #$ff ;ff
+ tya
+ plp
+ tax
+ tst_x $ff,$ff-zero
+ php
+ iny ;00
+ tya
+ plp
+ tax
+ tst_x 0,$ff-minus
+ php
+ iny ;01
+ tya
+ plp
+ tax
+ tst_x 1,$ff-minus-zero
+ load_flag 0
+ pha
+ lda #0 ;preset status
+ tya
+ plp
+ tax
+ tst_x 1,0
+ php
+ dey ;00
+ tya
+ plp
+ tax
+ tst_x 0,zero
+ php
+ dey ;ff
+ tya
+ plp
+ tax
+ tst_x $ff,minus
+ next_test
+
+;TSX sets NZ - TXS does not
+; This section also tests for proper stack wrap around.
+ ldx #1 ;01
+ set_stat $ff
+ txs
+ php
+ lda $101
+ cmp_flag $ff
+ trap_ne
+ set_stat 0
+ txs
+ php
+ lda $101
+ cmp_flag 0
+ trap_ne
+ dex ;00
+ set_stat $ff
+ txs
+ php
+ lda $100
+ cmp_flag $ff
+ trap_ne
+ set_stat 0
+ txs
+ php
+ lda $100
+ cmp_flag 0
+ trap_ne
+ dex ;ff
+ set_stat $ff
+ txs
+ php
+ lda $1ff
+ cmp_flag $ff
+ trap_ne
+ set_stat 0
+ txs
+ php
+ lda $1ff
+ cmp_flag 0
+
+ ldx #1
+ txs ;sp=01
+ set_stat $ff
+ tsx ;clears Z, N
+ php ;sp=00
+ cpx #1
+ trap_ne
+ lda $101
+ cmp_flag $ff-minus-zero
+ trap_ne
+ set_stat $ff
+ tsx ;clears N, sets Z
+ php ;sp=ff
+ cpx #0
+ trap_ne
+ lda $100
+ cmp_flag $ff-minus
+ trap_ne
+ set_stat $ff
+ tsx ;clears N, sets Z
+ php ;sp=fe
+ cpx #$ff
+ trap_ne
+ lda $1ff
+ cmp_flag $ff-zero
+ trap_ne
+
+ ldx #1
+ txs ;sp=01
+ set_stat 0
+ tsx ;clears Z, N
+ php ;sp=00
+ cpx #1
+ trap_ne
+ lda $101
+ cmp_flag 0
+ trap_ne
+ set_stat 0
+ tsx ;clears N, sets Z
+ php ;sp=ff
+ cpx #0
+ trap_ne
+ lda $100
+ cmp_flag zero
+ trap_ne
+ set_stat 0
+ tsx ;clears N, sets Z
+ php ;sp=fe
+ cpx #$ff
+ trap_ne
+ lda $1ff
+ cmp_flag minus
+ trap_ne
+ pla ;sp=ff
+ next_test
+
+; testing index register load & store LDY LDX STY STX all addressing modes
+; LDX / STX - zp,y / abs,y
+ ldy #3
+tldx
+ set_stat 0
+ ldx zp1,y
+ php ;test stores do not alter flags
+ txa
+ eor #$c3
+ plp
+ sta abst,y
+ php ;flags after load/store sequence
+ eor #$c3
+ cmp abs1,y ;test result
+ trap_ne
+ pla ;load status
+ eor_flag 0
+ cmp fLDx,y ;test flags
+ trap_ne
+ dey
+ bpl tldx
+
+ ldy #3
+tldx1
+ set_stat $ff
+ ldx zp1,y
+ php ;test stores do not alter flags
+ txa
+ eor #$c3
+ plp
+ sta abst,y
+ php ;flags after load/store sequence
+ eor #$c3
+ cmp abs1,y ;test result
+ trap_ne
+ pla ;load status
+ eor_flag lo~fnz ;mask bits not altered
+ cmp fLDx,y ;test flags
+ trap_ne
+ dey
+ bpl tldx1
+
+ ldy #3
+tldx2
+ set_stat 0
+ ldx abs1,y
+ php ;test stores do not alter flags
+ txa
+ eor #$c3
+ tax
+ plp
+ stx zpt,y
+ php ;flags after load/store sequence
+ eor #$c3
+ cmp zp1,y ;test result
+ trap_ne
+ pla ;load status
+ eor_flag 0
+ cmp fLDx,y ;test flags
+ trap_ne
+ dey
+ bpl tldx2
+
+ ldy #3
+tldx3
+ set_stat $ff
+ ldx abs1,y
+ php ;test stores do not alter flags
+ txa
+ eor #$c3
+ tax
+ plp
+ stx zpt,y
+ php ;flags after load/store sequence
+ eor #$c3
+ cmp zp1,y ;test result
+ trap_ne
+ pla ;load status
+ eor_flag lo~fnz ;mask bits not altered
+ cmp fLDx,y ;test flags
+ trap_ne
+ dey
+ bpl tldx3
+
+ ldy #3 ;testing store result
+ ldx #0
+tstx lda zpt,y
+ eor #$c3
+ cmp zp1,y
+ trap_ne ;store to zp data
+ stx zpt,y ;clear
+ lda abst,y
+ eor #$c3
+ cmp abs1,y
+ trap_ne ;store to abs data
+ txa
+ sta abst,y ;clear
+ dey
+ bpl tstx
+ next_test
+
+; indexed wraparound test (only zp should wrap)
+ ldy #3+$fa
+tldx4 ldx zp1-$fa&$ff,y ;wrap on indexed zp
+ txa
+ sta abst-$fa,y ;no STX abs,y!
+ dey
+ cpy #$fa
+ bcs tldx4
+ ldy #3+$fa
+tldx5 ldx abs1-$fa,y ;no wrap on indexed abs
+ stx zpt-$fa&$ff,y
+ dey
+ cpy #$fa
+ bcs tldx5
+ ldy #3 ;testing wraparound result
+ ldx #0
+tstx1 lda zpt,y
+ cmp zp1,y
+ trap_ne ;store to zp data
+ stx zpt,y ;clear
+ lda abst,y
+ cmp abs1,y
+ trap_ne ;store to abs data
+ txa
+ sta abst,y ;clear
+ dey
+ bpl tstx1
+ next_test
+
+; LDY / STY - zp,x / abs,x
+ ldx #3
+tldy
+ set_stat 0
+ ldy zp1,x
+ php ;test stores do not alter flags
+ tya
+ eor #$c3
+ plp
+ sta abst,x
+ php ;flags after load/store sequence
+ eor #$c3
+ cmp abs1,x ;test result
+ trap_ne
+ pla ;load status
+ eor_flag 0
+ cmp fLDx,x ;test flags
+ trap_ne
+ dex
+ bpl tldy
+
+ ldx #3
+tldy1
+ set_stat $ff
+ ldy zp1,x
+ php ;test stores do not alter flags
+ tya
+ eor #$c3
+ plp
+ sta abst,x
+ php ;flags after load/store sequence
+ eor #$c3
+ cmp abs1,x ;test result
+ trap_ne
+ pla ;load status
+ eor_flag lo~fnz ;mask bits not altered
+ cmp fLDx,x ;test flags
+ trap_ne
+ dex
+ bpl tldy1
+
+ ldx #3
+tldy2
+ set_stat 0
+ ldy abs1,x
+ php ;test stores do not alter flags
+ tya
+ eor #$c3
+ tay
+ plp
+ sty zpt,x
+ php ;flags after load/store sequence
+ eor #$c3
+ cmp zp1,x ;test result
+ trap_ne
+ pla ;load status
+ eor_flag 0
+ cmp fLDx,x ;test flags
+ trap_ne
+ dex
+ bpl tldy2
+
+ ldx #3
+tldy3
+ set_stat $ff
+ ldy abs1,x
+ php ;test stores do not alter flags
+ tya
+ eor #$c3
+ tay
+ plp
+ sty zpt,x
+ php ;flags after load/store sequence
+ eor #$c3
+ cmp zp1,x ;test result
+ trap_ne
+ pla ;load status
+ eor_flag lo~fnz ;mask bits not altered
+ cmp fLDx,x ;test flags
+ trap_ne
+ dex
+ bpl tldy3
+
+ ldx #3 ;testing store result
+ ldy #0
+tsty lda zpt,x
+ eor #$c3
+ cmp zp1,x
+ trap_ne ;store to zp,x data
+ sty zpt,x ;clear
+ lda abst,x
+ eor #$c3
+ cmp abs1,x
+ trap_ne ;store to abs,x data
+ txa
+ sta abst,x ;clear
+ dex
+ bpl tsty
+ next_test
+
+; indexed wraparound test (only zp should wrap)
+ ldx #3+$fa
+tldy4 ldy zp1-$fa&$ff,x ;wrap on indexed zp
+ tya
+ sta abst-$fa,x ;no STX abs,x!
+ dex
+ cpx #$fa
+ bcs tldy4
+ ldx #3+$fa
+tldy5 ldy abs1-$fa,x ;no wrap on indexed abs
+ sty zpt-$fa&$ff,x
+ dex
+ cpx #$fa
+ bcs tldy5
+ ldx #3 ;testing wraparound result
+ ldy #0
+tsty1 lda zpt,x
+ cmp zp1,x
+ trap_ne ;store to zp,x data
+ sty zpt,x ;clear
+ lda abst,x
+ cmp abs1,x
+ trap_ne ;store to abs,x data
+ txa
+ sta abst,x ;clear
+ dex
+ bpl tsty1
+ next_test
+
+; LDX / STX - zp / abs / #
+ set_stat 0
+ ldx zp1
+ php ;test stores do not alter flags
+ txa
+ eor #$c3
+ tax
+ plp
+ stx abst
+ php ;flags after load/store sequence
+ eor #$c3
+ tax
+ cpx #$c3 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag 0
+ cmp fLDx ;test flags
+ trap_ne
+ set_stat 0
+ ldx zp1+1
+ php ;test stores do not alter flags
+ txa
+ eor #$c3
+ tax
+ plp
+ stx abst+1
+ php ;flags after load/store sequence
+ eor #$c3
+ tax
+ cpx #$82 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag 0
+ cmp fLDx+1 ;test flags
+ trap_ne
+ set_stat 0
+ ldx zp1+2
+ php ;test stores do not alter flags
+ txa
+ eor #$c3
+ tax
+ plp
+ stx abst+2
+ php ;flags after load/store sequence
+ eor #$c3
+ tax
+ cpx #$41 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag 0
+ cmp fLDx+2 ;test flags
+ trap_ne
+ set_stat 0
+ ldx zp1+3
+ php ;test stores do not alter flags
+ txa
+ eor #$c3
+ tax
+ plp
+ stx abst+3
+ php ;flags after load/store sequence
+ eor #$c3
+ tax
+ cpx #0 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag 0
+ cmp fLDx+3 ;test flags
+ trap_ne
+
+ set_stat $ff
+ ldx zp1
+ php ;test stores do not alter flags
+ txa
+ eor #$c3
+ tax
+ plp
+ stx abst
+ php ;flags after load/store sequence
+ eor #$c3
+ tax
+ cpx #$c3 ;test result
+ trap_ne ;
+ pla ;load status
+ eor_flag lo~fnz ;mask bits not altered
+ cmp fLDx ;test flags
+ trap_ne
+ set_stat $ff
+ ldx zp1+1
+ php ;test stores do not alter flags
+ txa
+ eor #$c3
+ tax
+ plp
+ stx abst+1
+ php ;flags after load/store sequence
+ eor #$c3
+ tax
+ cpx #$82 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag lo~fnz ;mask bits not altered
+ cmp fLDx+1 ;test flags
+ trap_ne
+ set_stat $ff
+ ldx zp1+2
+ php ;test stores do not alter flags
+ txa
+ eor #$c3
+ tax
+ plp
+ stx abst+2
+ php ;flags after load/store sequence
+ eor #$c3
+ tax
+ cpx #$41 ;test result
+ trap_ne ;
+ pla ;load status
+ eor_flag lo~fnz ;mask bits not altered
+ cmp fLDx+2 ;test flags
+ trap_ne
+ set_stat $ff
+ ldx zp1+3
+ php ;test stores do not alter flags
+ txa
+ eor #$c3
+ tax
+ plp
+ stx abst+3
+ php ;flags after load/store sequence
+ eor #$c3
+ tax
+ cpx #0 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag lo~fnz ;mask bits not altered
+ cmp fLDx+3 ;test flags
+ trap_ne
+
+ set_stat 0
+ ldx abs1
+ php ;test stores do not alter flags
+ txa
+ eor #$c3
+ tax
+ plp
+ stx zpt
+ php ;flags after load/store sequence
+ eor #$c3
+ cmp zp1 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag 0
+ cmp fLDx ;test flags
+ trap_ne
+ set_stat 0
+ ldx abs1+1
+ php ;test stores do not alter flags
+ txa
+ eor #$c3
+ tax
+ plp
+ stx zpt+1
+ php ;flags after load/store sequence
+ eor #$c3
+ cmp zp1+1 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag 0
+ cmp fLDx+1 ;test flags
+ trap_ne
+ set_stat 0
+ ldx abs1+2
+ php ;test stores do not alter flags
+ txa
+ eor #$c3
+ tax
+ plp
+ stx zpt+2
+ php ;flags after load/store sequence
+ eor #$c3
+ cmp zp1+2 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag 0
+ cmp fLDx+2 ;test flags
+ trap_ne
+ set_stat 0
+ ldx abs1+3
+ php ;test stores do not alter flags
+ txa
+ eor #$c3
+ tax
+ plp
+ stx zpt+3
+ php ;flags after load/store sequence
+ eor #$c3
+ cmp zp1+3 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag 0
+ cmp fLDx+3 ;test flags
+ trap_ne
+
+ set_stat $ff
+ ldx abs1
+ php ;test stores do not alter flags
+ txa
+ eor #$c3
+ tax
+ plp
+ stx zpt
+ php ;flags after load/store sequence
+ eor #$c3
+ tax
+ cpx zp1 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag lo~fnz ;mask bits not altered
+ cmp fLDx ;test flags
+ trap_ne
+ set_stat $ff
+ ldx abs1+1
+ php ;test stores do not alter flags
+ txa
+ eor #$c3
+ tax
+ plp
+ stx zpt+1
+ php ;flags after load/store sequence
+ eor #$c3
+ tax
+ cpx zp1+1 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag lo~fnz ;mask bits not altered
+ cmp fLDx+1 ;test flags
+ trap_ne
+ set_stat $ff
+ ldx abs1+2
+ php ;test stores do not alter flags
+ txa
+ eor #$c3
+ tax
+ plp
+ stx zpt+2
+ php ;flags after load/store sequence
+ eor #$c3
+ tax
+ cpx zp1+2 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag lo~fnz ;mask bits not altered
+ cmp fLDx+2 ;test flags
+ trap_ne
+ set_stat $ff
+ ldx abs1+3
+ php ;test stores do not alter flags
+ txa
+ eor #$c3
+ tax
+ plp
+ stx zpt+3
+ php ;flags after load/store sequence
+ eor #$c3
+ tax
+ cpx zp1+3 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag lo~fnz ;mask bits not altered
+ cmp fLDx+3 ;test flags
+ trap_ne
+
+ set_stat 0
+ ldx #$c3
+ php
+ cpx abs1 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag 0
+ cmp fLDx ;test flags
+ trap_ne
+ set_stat 0
+ ldx #$82
+ php
+ cpx abs1+1 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag 0
+ cmp fLDx+1 ;test flags
+ trap_ne
+ set_stat 0
+ ldx #$41
+ php
+ cpx abs1+2 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag 0
+ cmp fLDx+2 ;test flags
+ trap_ne
+ set_stat 0
+ ldx #0
+ php
+ cpx abs1+3 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag 0
+ cmp fLDx+3 ;test flags
+ trap_ne
+
+ set_stat $ff
+ ldx #$c3
+ php
+ cpx abs1 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag lo~fnz ;mask bits not altered
+ cmp fLDx ;test flags
+ trap_ne
+ set_stat $ff
+ ldx #$82
+ php
+ cpx abs1+1 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag lo~fnz ;mask bits not altered
+ cmp fLDx+1 ;test flags
+ trap_ne
+ set_stat $ff
+ ldx #$41
+ php
+ cpx abs1+2 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag lo~fnz ;mask bits not altered
+ cmp fLDx+2 ;test flags
+ trap_ne
+ set_stat $ff
+ ldx #0
+ php
+ cpx abs1+3 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag lo~fnz ;mask bits not altered
+ cmp fLDx+3 ;test flags
+ trap_ne
+
+ ldx #0
+ lda zpt
+ eor #$c3
+ cmp zp1
+ trap_ne ;store to zp data
+ stx zpt ;clear
+ lda abst
+ eor #$c3
+ cmp abs1
+ trap_ne ;store to abs data
+ stx abst ;clear
+ lda zpt+1
+ eor #$c3
+ cmp zp1+1
+ trap_ne ;store to zp data
+ stx zpt+1 ;clear
+ lda abst+1
+ eor #$c3
+ cmp abs1+1
+ trap_ne ;store to abs data
+ stx abst+1 ;clear
+ lda zpt+2
+ eor #$c3
+ cmp zp1+2
+ trap_ne ;store to zp data
+ stx zpt+2 ;clear
+ lda abst+2
+ eor #$c3
+ cmp abs1+2
+ trap_ne ;store to abs data
+ stx abst+2 ;clear
+ lda zpt+3
+ eor #$c3
+ cmp zp1+3
+ trap_ne ;store to zp data
+ stx zpt+3 ;clear
+ lda abst+3
+ eor #$c3
+ cmp abs1+3
+ trap_ne ;store to abs data
+ stx abst+3 ;clear
+ next_test
+
+; LDY / STY - zp / abs / #
+ set_stat 0
+ ldy zp1
+ php ;test stores do not alter flags
+ tya
+ eor #$c3
+ tay
+ plp
+ sty abst
+ php ;flags after load/store sequence
+ eor #$c3
+ tay
+ cpy #$c3 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag 0
+ cmp fLDx ;test flags
+ trap_ne
+ set_stat 0
+ ldy zp1+1
+ php ;test stores do not alter flags
+ tya
+ eor #$c3
+ tay
+ plp
+ sty abst+1
+ php ;flags after load/store sequence
+ eor #$c3
+ tay
+ cpy #$82 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag 0
+ cmp fLDx+1 ;test flags
+ trap_ne
+ set_stat 0
+ ldy zp1+2
+ php ;test stores do not alter flags
+ tya
+ eor #$c3
+ tay
+ plp
+ sty abst+2
+ php ;flags after load/store sequence
+ eor #$c3
+ tay
+ cpy #$41 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag 0
+ cmp fLDx+2 ;test flags
+ trap_ne
+ set_stat 0
+ ldy zp1+3
+ php ;test stores do not alter flags
+ tya
+ eor #$c3
+ tay
+ plp
+ sty abst+3
+ php ;flags after load/store sequence
+ eor #$c3
+ tay
+ cpy #0 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag 0
+ cmp fLDx+3 ;test flags
+ trap_ne
+
+ set_stat $ff
+ ldy zp1
+ php ;test stores do not alter flags
+ tya
+ eor #$c3
+ tay
+ plp
+ sty abst
+ php ;flags after load/store sequence
+ eor #$c3
+ tay
+ cpy #$c3 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag lo~fnz ;mask bits not altered
+ cmp fLDx ;test flags
+ trap_ne
+ set_stat $ff
+ ldy zp1+1
+ php ;test stores do not alter flags
+ tya
+ eor #$c3
+ tay
+ plp
+ sty abst+1
+ php ;flags after load/store sequence
+ eor #$c3
+ tay
+ cpy #$82 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag lo~fnz ;mask bits not altered
+ cmp fLDx+1 ;test flags
+ trap_ne
+ set_stat $ff
+ ldy zp1+2
+ php ;test stores do not alter flags
+ tya
+ eor #$c3
+ tay
+ plp
+ sty abst+2
+ php ;flags after load/store sequence
+ eor #$c3
+ tay
+ cpy #$41 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag lo~fnz ;mask bits not altered
+ cmp fLDx+2 ;test flags
+ trap_ne
+ set_stat $ff
+ ldy zp1+3
+ php ;test stores do not alter flags
+ tya
+ eor #$c3
+ tay
+ plp
+ sty abst+3
+ php ;flags after load/store sequence
+ eor #$c3
+ tay
+ cpy #0 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag lo~fnz ;mask bits not altered
+ cmp fLDx+3 ;test flags
+ trap_ne
+
+ set_stat 0
+ ldy abs1
+ php ;test stores do not alter flags
+ tya
+ eor #$c3
+ tay
+ plp
+ sty zpt
+ php ;flags after load/store sequence
+ eor #$c3
+ tay
+ cpy zp1 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag 0
+ cmp fLDx ;test flags
+ trap_ne
+ set_stat 0
+ ldy abs1+1
+ php ;test stores do not alter flags
+ tya
+ eor #$c3
+ tay
+ plp
+ sty zpt+1
+ php ;flags after load/store sequence
+ eor #$c3
+ tay
+ cpy zp1+1 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag 0
+ cmp fLDx+1 ;test flags
+ trap_ne
+ set_stat 0
+ ldy abs1+2
+ php ;test stores do not alter flags
+ tya
+ eor #$c3
+ tay
+ plp
+ sty zpt+2
+ php ;flags after load/store sequence
+ eor #$c3
+ tay
+ cpy zp1+2 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag 0
+ cmp fLDx+2 ;test flags
+ trap_ne
+ set_stat 0
+ ldy abs1+3
+ php ;test stores do not alter flags
+ tya
+ eor #$c3
+ tay
+ plp
+ sty zpt+3
+ php ;flags after load/store sequence
+ eor #$c3
+ tay
+ cpy zp1+3 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag 0
+ cmp fLDx+3 ;test flags
+ trap_ne
+
+ set_stat $ff
+ ldy abs1
+ php ;test stores do not alter flags
+ tya
+ eor #$c3
+ tay
+ plp
+ sty zpt
+ php ;flags after load/store sequence
+ eor #$c3
+ tay
+ cmp zp1 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag lo~fnz ;mask bits not altered
+ cmp fLDx ;test flags
+ trap_ne
+ set_stat $ff
+ ldy abs1+1
+ php ;test stores do not alter flags
+ tya
+ eor #$c3
+ tay
+ plp
+ sty zpt+1
+ php ;flags after load/store sequence
+ eor #$c3
+ tay
+ cmp zp1+1 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag lo~fnz ;mask bits not altered
+ cmp fLDx+1 ;test flags
+ trap_ne
+ set_stat $ff
+ ldy abs1+2
+ php ;test stores do not alter flags
+ tya
+ eor #$c3
+ tay
+ plp
+ sty zpt+2
+ php ;flags after load/store sequence
+ eor #$c3
+ tay
+ cmp zp1+2 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag lo~fnz ;mask bits not altered
+ cmp fLDx+2 ;test flags
+ trap_ne
+ set_stat $ff
+ ldy abs1+3
+ php ;test stores do not alter flags
+ tya
+ eor #$c3
+ tay
+ plp
+ sty zpt+3
+ php ;flags after load/store sequence
+ eor #$c3
+ tay
+ cmp zp1+3 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag lo~fnz ;mask bits not altered
+ cmp fLDx+3 ;test flags
+ trap_ne
+
+
+ set_stat 0
+ ldy #$c3
+ php
+ cpy abs1 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag 0
+ cmp fLDx ;test flags
+ trap_ne
+ set_stat 0
+ ldy #$82
+ php
+ cpy abs1+1 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag 0
+ cmp fLDx+1 ;test flags
+ trap_ne
+ set_stat 0
+ ldy #$41
+ php
+ cpy abs1+2 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag 0
+ cmp fLDx+2 ;test flags
+ trap_ne
+ set_stat 0
+ ldy #0
+ php
+ cpy abs1+3 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag 0
+ cmp fLDx+3 ;test flags
+ trap_ne
+
+ set_stat $ff
+ ldy #$c3
+ php
+ cpy abs1 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag lo~fnz ;mask bits not altered
+ cmp fLDx ;test flags
+ trap_ne
+ set_stat $ff
+ ldy #$82
+ php
+ cpy abs1+1 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag lo~fnz ;mask bits not altered
+ cmp fLDx+1 ;test flags
+ trap_ne
+ set_stat $ff
+ ldy #$41
+ php
+ cpy abs1+2 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag lo~fnz ;mask bits not altered
+ cmp fLDx+2 ;test flags
+ trap_ne
+ set_stat $ff
+ ldy #0
+ php
+ cpy abs1+3 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag lo~fnz ;mask bits not altered
+ cmp fLDx+3 ;test flags
+ trap_ne
+
+ ldy #0
+ lda zpt
+ eor #$c3
+ cmp zp1
+ trap_ne ;store to zp data
+ sty zpt ;clear
+ lda abst
+ eor #$c3
+ cmp abs1
+ trap_ne ;store to abs data
+ sty abst ;clear
+ lda zpt+1
+ eor #$c3
+ cmp zp1+1
+ trap_ne ;store to zp+1 data
+ sty zpt+1 ;clear
+ lda abst+1
+ eor #$c3
+ cmp abs1+1
+ trap_ne ;store to abs+1 data
+ sty abst+1 ;clear
+ lda zpt+2
+ eor #$c3
+ cmp zp1+2
+ trap_ne ;store to zp+2 data
+ sty zpt+2 ;clear
+ lda abst+2
+ eor #$c3
+ cmp abs1+2
+ trap_ne ;store to abs+2 data
+ sty abst+2 ;clear
+ lda zpt+3
+ eor #$c3
+ cmp zp1+3
+ trap_ne ;store to zp+3 data
+ sty zpt+3 ;clear
+ lda abst+3
+ eor #$c3
+ cmp abs1+3
+ trap_ne ;store to abs+3 data
+ sty abst+3 ;clear
+ next_test
+
+; testing load / store accumulator LDA / STA all addressing modes
+; LDA / STA - zp,x / abs,x
+ ldx #3
+tldax
+ set_stat 0
+ lda zp1,x
+ php ;test stores do not alter flags
+ eor #$c3
+ plp
+ sta abst,x
+ php ;flags after load/store sequence
+ eor #$c3
+ cmp abs1,x ;test result
+ trap_ne
+ pla ;load status
+ eor_flag 0
+ cmp fLDx,x ;test flags
+ trap_ne
+ dex
+ bpl tldax
+
+ ldx #3
+tldax1
+ set_stat $ff
+ lda zp1,x
+ php ;test stores do not alter flags
+ eor #$c3
+ plp
+ sta abst,x
+ php ;flags after load/store sequence
+ eor #$c3
+ cmp abs1,x ;test result
+ trap_ne
+ pla ;load status
+ eor_flag lo~fnz ;mask bits not altered
+ cmp fLDx,x ;test flags
+ trap_ne
+ dex
+ bpl tldax1
+
+ ldx #3
+tldax2
+ set_stat 0
+ lda abs1,x
+ php ;test stores do not alter flags
+ eor #$c3
+ plp
+ sta zpt,x
+ php ;flags after load/store sequence
+ eor #$c3
+ cmp zp1,x ;test result
+ trap_ne
+ pla ;load status
+ eor_flag 0
+ cmp fLDx,x ;test flags
+ trap_ne
+ dex
+ bpl tldax2
+
+ ldx #3
+tldax3
+ set_stat $ff
+ lda abs1,x
+ php ;test stores do not alter flags
+ eor #$c3
+ plp
+ sta zpt,x
+ php ;flags after load/store sequence
+ eor #$c3
+ cmp zp1,x ;test result
+ trap_ne
+ pla ;load status
+ eor_flag lo~fnz ;mask bits not altered
+ cmp fLDx,x ;test flags
+ trap_ne
+ dex
+ bpl tldax3
+
+ ldx #3 ;testing store result
+ ldy #0
+tstax lda zpt,x
+ eor #$c3
+ cmp zp1,x
+ trap_ne ;store to zp,x data
+ sty zpt,x ;clear
+ lda abst,x
+ eor #$c3
+ cmp abs1,x
+ trap_ne ;store to abs,x data
+ txa
+ sta abst,x ;clear
+ dex
+ bpl tstax
+ next_test
+
+; LDA / STA - (zp),y / abs,y / (zp,x)
+ ldy #3
+tlday
+ set_stat 0
+ lda (ind1),y
+ php ;test stores do not alter flags
+ eor #$c3
+ plp
+ sta abst,y
+ php ;flags after load/store sequence
+ eor #$c3
+ cmp abs1,y ;test result
+ trap_ne
+ pla ;load status
+ eor_flag 0
+ cmp fLDx,y ;test flags
+ trap_ne
+ dey
+ bpl tlday
+
+ ldy #3
+tlday1
+ set_stat $ff
+ lda (ind1),y
+ php ;test stores do not alter flags
+ eor #$c3
+ plp
+ sta abst,y
+ php ;flags after load/store sequence
+ eor #$c3
+ cmp abs1,y ;test result
+ trap_ne
+ pla ;load status
+ eor_flag lo~fnz ;mask bits not altered
+ cmp fLDx,y ;test flags
+ trap_ne
+ dey
+ bpl tlday1
+
+ ldy #3 ;testing store result
+ ldx #0
+tstay lda abst,y
+ eor #$c3
+ cmp abs1,y
+ trap_ne ;store to abs data
+ txa
+ sta abst,y ;clear
+ dey
+ bpl tstay
+
+ ldy #3
+tlday2
+ set_stat 0
+ lda abs1,y
+ php ;test stores do not alter flags
+ eor #$c3
+ plp
+ sta (indt),y
+ php ;flags after load/store sequence
+ eor #$c3
+ cmp (ind1),y ;test result
+ trap_ne
+ pla ;load status
+ eor_flag 0
+ cmp fLDx,y ;test flags
+ trap_ne
+ dey
+ bpl tlday2
+
+ ldy #3
+tlday3
+ set_stat $ff
+ lda abs1,y
+ php ;test stores do not alter flags
+ eor #$c3
+ plp
+ sta (indt),y
+ php ;flags after load/store sequence
+ eor #$c3
+ cmp (ind1),y ;test result
+ trap_ne
+ pla ;load status
+ eor_flag lo~fnz ;mask bits not altered
+ cmp fLDx,y ;test flags
+ trap_ne
+ dey
+ bpl tlday3
+
+ ldy #3 ;testing store result
+ ldx #0
+tstay1 lda abst,y
+ eor #$c3
+ cmp abs1,y
+ trap_ne ;store to abs data
+ txa
+ sta abst,y ;clear
+ dey
+ bpl tstay1
+
+ ldx #6
+ ldy #3
+tldax4
+ set_stat 0
+ lda (ind1,x)
+ php ;test stores do not alter flags
+ eor #$c3
+ plp
+ sta (indt,x)
+ php ;flags after load/store sequence
+ eor #$c3
+ cmp abs1,y ;test result
+ trap_ne
+ pla ;load status
+ eor_flag 0
+ cmp fLDx,y ;test flags
+ trap_ne
+ dex
+ dex
+ dey
+ bpl tldax4
+
+ ldx #6
+ ldy #3
+tldax5
+ set_stat $ff
+ lda (ind1,x)
+ php ;test stores do not alter flags
+ eor #$c3
+ plp
+ sta (indt,x)
+ php ;flags after load/store sequence
+ eor #$c3
+ cmp abs1,y ;test result
+ trap_ne
+ pla ;load status
+ eor_flag lo~fnz ;mask bits not altered
+ cmp fLDx,y ;test flags
+ trap_ne
+ dex
+ dex
+ dey
+ bpl tldax5
+
+ ldy #3 ;testing store result
+ ldx #0
+tstay2 lda abst,y
+ eor #$c3
+ cmp abs1,y
+ trap_ne ;store to abs data
+ txa
+ sta abst,y ;clear
+ dey
+ bpl tstay2
+ next_test
+
+; indexed wraparound test (only zp should wrap)
+ ldx #3+$fa
+tldax6 lda zp1-$fa&$ff,x ;wrap on indexed zp
+ sta abst-$fa,x ;no STX abs,x!
+ dex
+ cpx #$fa
+ bcs tldax6
+ ldx #3+$fa
+tldax7 lda abs1-$fa,x ;no wrap on indexed abs
+ sta zpt-$fa&$ff,x
+ dex
+ cpx #$fa
+ bcs tldax7
+
+ ldx #3 ;testing wraparound result
+ ldy #0
+tstax1 lda zpt,x
+ cmp zp1,x
+ trap_ne ;store to zp,x data
+ sty zpt,x ;clear
+ lda abst,x
+ cmp abs1,x
+ trap_ne ;store to abs,x data
+ txa
+ sta abst,x ;clear
+ dex
+ bpl tstax1
+
+ ldy #3+$f8
+ ldx #6+$f8
+tlday4 lda (ind1-$f8&$ff,x) ;wrap on indexed zp indirect
+ sta abst-$f8,y
+ dex
+ dex
+ dey
+ cpy #$f8
+ bcs tlday4
+ ldy #3 ;testing wraparound result
+ ldx #0
+tstay4 lda abst,y
+ cmp abs1,y
+ trap_ne ;store to abs data
+ txa
+ sta abst,y ;clear
+ dey
+ bpl tstay4
+
+ ldy #3+$f8
+tlday5 lda abs1-$f8,y ;no wrap on indexed abs
+ sta (inwt),y
+ dey
+ cpy #$f8
+ bcs tlday5
+ ldy #3 ;testing wraparound result
+ ldx #0
+tstay5 lda abst,y
+ cmp abs1,y
+ trap_ne ;store to abs data
+ txa
+ sta abst,y ;clear
+ dey
+ bpl tstay5
+
+ ldy #3+$f8
+ ldx #6+$f8
+tlday6 lda (inw1),y ;no wrap on zp indirect indexed
+ sta (indt-$f8&$ff,x)
+ dex
+ dex
+ dey
+ cpy #$f8
+ bcs tlday6
+ ldy #3 ;testing wraparound result
+ ldx #0
+tstay6 lda abst,y
+ cmp abs1,y
+ trap_ne ;store to abs data
+ txa
+ sta abst,y ;clear
+ dey
+ bpl tstay6
+ next_test
+
+; LDA / STA - zp / abs / #
+ set_stat 0
+ lda zp1
+ php ;test stores do not alter flags
+ eor #$c3
+ plp
+ sta abst
+ php ;flags after load/store sequence
+ eor #$c3
+ cmp #$c3 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag 0
+ cmp fLDx ;test flags
+ trap_ne
+ set_stat 0
+ lda zp1+1
+ php ;test stores do not alter flags
+ eor #$c3
+ plp
+ sta abst+1
+ php ;flags after load/store sequence
+ eor #$c3
+ cmp #$82 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag 0
+ cmp fLDx+1 ;test flags
+ trap_ne
+ set_stat 0
+ lda zp1+2
+ php ;test stores do not alter flags
+ eor #$c3
+ plp
+ sta abst+2
+ php ;flags after load/store sequence
+ eor #$c3
+ cmp #$41 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag 0
+ cmp fLDx+2 ;test flags
+ trap_ne
+ set_stat 0
+ lda zp1+3
+ php ;test stores do not alter flags
+ eor #$c3
+ plp
+ sta abst+3
+ php ;flags after load/store sequence
+ eor #$c3
+ cmp #0 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag 0
+ cmp fLDx+3 ;test flags
+ trap_ne
+ set_stat $ff
+ lda zp1
+ php ;test stores do not alter flags
+ eor #$c3
+ plp
+ sta abst
+ php ;flags after load/store sequence
+ eor #$c3
+ cmp #$c3 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag lo~fnz ;mask bits not altered
+ cmp fLDx ;test flags
+ trap_ne
+ set_stat $ff
+ lda zp1+1
+ php ;test stores do not alter flags
+ eor #$c3
+ plp
+ sta abst+1
+ php ;flags after load/store sequence
+ eor #$c3
+ cmp #$82 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag lo~fnz ;mask bits not altered
+ cmp fLDx+1 ;test flags
+ trap_ne
+ set_stat $ff
+ lda zp1+2
+ php ;test stores do not alter flags
+ eor #$c3
+ plp
+ sta abst+2
+ php ;flags after load/store sequence
+ eor #$c3
+ cmp #$41 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag lo~fnz ;mask bits not altered
+ cmp fLDx+2 ;test flags
+ trap_ne
+ set_stat $ff
+ lda zp1+3
+ php ;test stores do not alter flags
+ eor #$c3
+ plp
+ sta abst+3
+ php ;flags after load/store sequence
+ eor #$c3
+ cmp #0 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag lo~fnz ;mask bits not altered
+ cmp fLDx+3 ;test flags
+ trap_ne
+ set_stat 0
+ lda abs1
+ php ;test stores do not alter flags
+ eor #$c3
+ plp
+ sta zpt
+ php ;flags after load/store sequence
+ eor #$c3
+ cmp zp1 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag 0
+ cmp fLDx ;test flags
+ trap_ne
+ set_stat 0
+ lda abs1+1
+ php ;test stores do not alter flags
+ eor #$c3
+ plp
+ sta zpt+1
+ php ;flags after load/store sequence
+ eor #$c3
+ cmp zp1+1 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag 0
+ cmp fLDx+1 ;test flags
+ trap_ne
+ set_stat 0
+ lda abs1+2
+ php ;test stores do not alter flags
+ eor #$c3
+ plp
+ sta zpt+2
+ php ;flags after load/store sequence
+ eor #$c3
+ cmp zp1+2 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag 0
+ cmp fLDx+2 ;test flags
+ trap_ne
+ set_stat 0
+ lda abs1+3
+ php ;test stores do not alter flags
+ eor #$c3
+ plp
+ sta zpt+3
+ php ;flags after load/store sequence
+ eor #$c3
+ cmp zp1+3 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag 0
+ cmp fLDx+3 ;test flags
+ trap_ne
+ set_stat $ff
+ lda abs1
+ php ;test stores do not alter flags
+ eor #$c3
+ plp
+ sta zpt
+ php ;flags after load/store sequence
+ eor #$c3
+ cmp zp1 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag lo~fnz ;mask bits not altered
+ cmp fLDx ;test flags
+ trap_ne
+ set_stat $ff
+ lda abs1+1
+ php ;test stores do not alter flags
+ eor #$c3
+ plp
+ sta zpt+1
+ php ;flags after load/store sequence
+ eor #$c3
+ cmp zp1+1 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag lo~fnz ;mask bits not altered
+ cmp fLDx+1 ;test flags
+ trap_ne
+ set_stat $ff
+ lda abs1+2
+ php ;test stores do not alter flags
+ eor #$c3
+ plp
+ sta zpt+2
+ php ;flags after load/store sequence
+ eor #$c3
+ cmp zp1+2 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag lo~fnz ;mask bits not altered
+ cmp fLDx+2 ;test flags
+ trap_ne
+ set_stat $ff
+ lda abs1+3
+ php ;test stores do not alter flags
+ eor #$c3
+ plp
+ sta zpt+3
+ php ;flags after load/store sequence
+ eor #$c3
+ cmp zp1+3 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag lo~fnz ;mask bits not altered
+ cmp fLDx+3 ;test flags
+ trap_ne
+ set_stat 0
+ lda #$c3
+ php
+ cmp abs1 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag 0
+ cmp fLDx ;test flags
+ trap_ne
+ set_stat 0
+ lda #$82
+ php
+ cmp abs1+1 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag 0
+ cmp fLDx+1 ;test flags
+ trap_ne
+ set_stat 0
+ lda #$41
+ php
+ cmp abs1+2 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag 0
+ cmp fLDx+2 ;test flags
+ trap_ne
+ set_stat 0
+ lda #0
+ php
+ cmp abs1+3 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag 0
+ cmp fLDx+3 ;test flags
+ trap_ne
+
+ set_stat $ff
+ lda #$c3
+ php
+ cmp abs1 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag lo~fnz ;mask bits not altered
+ cmp fLDx ;test flags
+ trap_ne
+ set_stat $ff
+ lda #$82
+ php
+ cmp abs1+1 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag lo~fnz ;mask bits not altered
+ cmp fLDx+1 ;test flags
+ trap_ne
+ set_stat $ff
+ lda #$41
+ php
+ cmp abs1+2 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag lo~fnz ;mask bits not altered
+ cmp fLDx+2 ;test flags
+ trap_ne
+ set_stat $ff
+ lda #0
+ php
+ cmp abs1+3 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag lo~fnz ;mask bits not altered
+ cmp fLDx+3 ;test flags
+ trap_ne
+
+ ldx #0
+ lda zpt
+ eor #$c3
+ cmp zp1
+ trap_ne ;store to zp data
+ stx zpt ;clear
+ lda abst
+ eor #$c3
+ cmp abs1
+ trap_ne ;store to abs data
+ stx abst ;clear
+ lda zpt+1
+ eor #$c3
+ cmp zp1+1
+ trap_ne ;store to zp data
+ stx zpt+1 ;clear
+ lda abst+1
+ eor #$c3
+ cmp abs1+1
+ trap_ne ;store to abs data
+ stx abst+1 ;clear
+ lda zpt+2
+ eor #$c3
+ cmp zp1+2
+ trap_ne ;store to zp data
+ stx zpt+2 ;clear
+ lda abst+2
+ eor #$c3
+ cmp abs1+2
+ trap_ne ;store to abs data
+ stx abst+2 ;clear
+ lda zpt+3
+ eor #$c3
+ cmp zp1+3
+ trap_ne ;store to zp data
+ stx zpt+3 ;clear
+ lda abst+3
+ eor #$c3
+ cmp abs1+3
+ trap_ne ;store to abs data
+ stx abst+3 ;clear
+ next_test
+
+; testing bit test & compares BIT CPX CPY CMP all addressing modes
+; BIT - zp / abs
+ set_a $ff,0
+ bit zp1+3 ;00 - should set Z / clear NV
+ tst_a $ff,fz
+ set_a 1,0
+ bit zp1+2 ;41 - should set V (M6) / clear NZ
+ tst_a 1,fv
+ set_a 1,0
+ bit zp1+1 ;82 - should set N (M7) & Z / clear V
+ tst_a 1,fnz
+ set_a 1,0
+ bit zp1 ;c3 - should set N (M7) & V (M6) / clear Z
+ tst_a 1,fnv
+
+ set_a $ff,$ff
+ bit zp1+3 ;00 - should set Z / clear NV
+ tst_a $ff,~fnv
+ set_a 1,$ff
+ bit zp1+2 ;41 - should set V (M6) / clear NZ
+ tst_a 1,~fnz
+ set_a 1,$ff
+ bit zp1+1 ;82 - should set N (M7) & Z / clear V
+ tst_a 1,~fv
+ set_a 1,$ff
+ bit zp1 ;c3 - should set N (M7) & V (M6) / clear Z
+ tst_a 1,~fz
+
+ set_a $ff,0
+ bit abs1+3 ;00 - should set Z / clear NV
+ tst_a $ff,fz
+ set_a 1,0
+ bit abs1+2 ;41 - should set V (M6) / clear NZ
+ tst_a 1,fv
+ set_a 1,0
+ bit abs1+1 ;82 - should set N (M7) & Z / clear V
+ tst_a 1,fnz
+ set_a 1,0
+ bit abs1 ;c3 - should set N (M7) & V (M6) / clear Z
+ tst_a 1,fnv
+
+ set_a $ff,$ff
+ bit abs1+3 ;00 - should set Z / clear NV
+ tst_a $ff,~fnv
+ set_a 1,$ff
+ bit abs1+2 ;41 - should set V (M6) / clear NZ
+ tst_a 1,~fnz
+ set_a 1,$ff
+ bit abs1+1 ;82 - should set N (M7) & Z / clear V
+ tst_a 1,~fv
+ set_a 1,$ff
+ bit abs1 ;c3 - should set N (M7) & V (M6) / clear Z
+ tst_a 1,~fz
+ next_test
+
+; CPX - zp / abs / #
+ set_x $80,0
+ cpx zp7f
+ tst_stat fc
+ dex
+ cpx zp7f
+ tst_stat fzc
+ dex
+ cpx zp7f
+ tst_x $7e,fn
+ set_x $80,$ff
+ cpx zp7f
+ tst_stat ~fnz
+ dex
+ cpx zp7f
+ tst_stat ~fn
+ dex
+ cpx zp7f
+ tst_x $7e,~fzc
+
+ set_x $80,0
+ cpx abs7f
+ tst_stat fc
+ dex
+ cpx abs7f
+ tst_stat fzc
+ dex
+ cpx abs7f
+ tst_x $7e,fn
+ set_x $80,$ff
+ cpx abs7f
+ tst_stat ~fnz
+ dex
+ cpx abs7f
+ tst_stat ~fn
+ dex
+ cpx abs7f
+ tst_x $7e,~fzc
+
+ set_x $80,0
+ cpx #$7f
+ tst_stat fc
+ dex
+ cpx #$7f
+ tst_stat fzc
+ dex
+ cpx #$7f
+ tst_x $7e,fn
+ set_x $80,$ff
+ cpx #$7f
+ tst_stat ~fnz
+ dex
+ cpx #$7f
+ tst_stat ~fn
+ dex
+ cpx #$7f
+ tst_x $7e,~fzc
+ next_test
+
+; CPY - zp / abs / #
+ set_y $80,0
+ cpy zp7f
+ tst_stat fc
+ dey
+ cpy zp7f
+ tst_stat fzc
+ dey
+ cpy zp7f
+ tst_y $7e,fn
+ set_y $80,$ff
+ cpy zp7f
+ tst_stat ~fnz
+ dey
+ cpy zp7f
+ tst_stat ~fn
+ dey
+ cpy zp7f
+ tst_y $7e,~fzc
+
+ set_y $80,0
+ cpy abs7f
+ tst_stat fc
+ dey
+ cpy abs7f
+ tst_stat fzc
+ dey
+ cpy abs7f
+ tst_y $7e,fn
+ set_y $80,$ff
+ cpy abs7f
+ tst_stat ~fnz
+ dey
+ cpy abs7f
+ tst_stat ~fn
+ dey
+ cpy abs7f
+ tst_y $7e,~fzc
+
+ set_y $80,0
+ cpy #$7f
+ tst_stat fc
+ dey
+ cpy #$7f
+ tst_stat fzc
+ dey
+ cpy #$7f
+ tst_y $7e,fn
+ set_y $80,$ff
+ cpy #$7f
+ tst_stat ~fnz
+ dey
+ cpy #$7f
+ tst_stat ~fn
+ dey
+ cpy #$7f
+ tst_y $7e,~fzc
+ next_test
+
+; CMP - zp / abs / #
+ set_a $80,0
+ cmp zp7f
+ tst_a $80,fc
+ set_a $7f,0
+ cmp zp7f
+ tst_a $7f,fzc
+ set_a $7e,0
+ cmp zp7f
+ tst_a $7e,fn
+ set_a $80,$ff
+ cmp zp7f
+ tst_a $80,~fnz
+ set_a $7f,$ff
+ cmp zp7f
+ tst_a $7f,~fn
+ set_a $7e,$ff
+ cmp zp7f
+ tst_a $7e,~fzc
+
+ set_a $80,0
+ cmp abs7f
+ tst_a $80,fc
+ set_a $7f,0
+ cmp abs7f
+ tst_a $7f,fzc
+ set_a $7e,0
+ cmp abs7f
+ tst_a $7e,fn
+ set_a $80,$ff
+ cmp abs7f
+ tst_a $80,~fnz
+ set_a $7f,$ff
+ cmp abs7f
+ tst_a $7f,~fn
+ set_a $7e,$ff
+ cmp abs7f
+ tst_a $7e,~fzc
+
+ set_a $80,0
+ cmp #$7f
+ tst_a $80,fc
+ set_a $7f,0
+ cmp #$7f
+ tst_a $7f,fzc
+ set_a $7e,0
+ cmp #$7f
+ tst_a $7e,fn
+ set_a $80,$ff
+ cmp #$7f
+ tst_a $80,~fnz
+ set_a $7f,$ff
+ cmp #$7f
+ tst_a $7f,~fn
+ set_a $7e,$ff
+ cmp #$7f
+ tst_a $7e,~fzc
+
+ ldx #4 ;with indexing by X
+ set_a $80,0
+ cmp zp1,x
+ tst_a $80,fc
+ set_a $7f,0
+ cmp zp1,x
+ tst_a $7f,fzc
+ set_a $7e,0
+ cmp zp1,x
+ tst_a $7e,fn
+ set_a $80,$ff
+ cmp zp1,x
+ tst_a $80,~fnz
+ set_a $7f,$ff
+ cmp zp1,x
+ tst_a $7f,~fn
+ set_a $7e,$ff
+ cmp zp1,x
+ tst_a $7e,~fzc
+
+ set_a $80,0
+ cmp abs1,x
+ tst_a $80,fc
+ set_a $7f,0
+ cmp abs1,x
+ tst_a $7f,fzc
+ set_a $7e,0
+ cmp abs1,x
+ tst_a $7e,fn
+ set_a $80,$ff
+ cmp abs1,x
+ tst_a $80,~fnz
+ set_a $7f,$ff
+ cmp abs1,x
+ tst_a $7f,~fn
+ set_a $7e,$ff
+ cmp abs1,x
+ tst_a $7e,~fzc
+
+ ldy #4 ;with indexing by Y
+ ldx #8 ;with indexed indirect
+ set_a $80,0
+ cmp abs1,y
+ tst_a $80,fc
+ set_a $7f,0
+ cmp abs1,y
+ tst_a $7f,fzc
+ set_a $7e,0
+ cmp abs1,y
+ tst_a $7e,fn
+ set_a $80,$ff
+ cmp abs1,y
+ tst_a $80,~fnz
+ set_a $7f,$ff
+ cmp abs1,y
+ tst_a $7f,~fn
+ set_a $7e,$ff
+ cmp abs1,y
+ tst_a $7e,~fzc
+
+ set_a $80,0
+ cmp (ind1,x)
+ tst_a $80,fc
+ set_a $7f,0
+ cmp (ind1,x)
+ tst_a $7f,fzc
+ set_a $7e,0
+ cmp (ind1,x)
+ tst_a $7e,fn
+ set_a $80,$ff
+ cmp (ind1,x)
+ tst_a $80,~fnz
+ set_a $7f,$ff
+ cmp (ind1,x)
+ tst_a $7f,~fn
+ set_a $7e,$ff
+ cmp (ind1,x)
+ tst_a $7e,~fzc
+
+ set_a $80,0
+ cmp (ind1),y
+ tst_a $80,fc
+ set_a $7f,0
+ cmp (ind1),y
+ tst_a $7f,fzc
+ set_a $7e,0
+ cmp (ind1),y
+ tst_a $7e,fn
+ set_a $80,$ff
+ cmp (ind1),y
+ tst_a $80,~fnz
+ set_a $7f,$ff
+ cmp (ind1),y
+ tst_a $7f,~fn
+ set_a $7e,$ff
+ cmp (ind1),y
+ tst_a $7e,~fzc
+ next_test
+
+; testing shifts - ASL LSR ROL ROR all addressing modes
+; shifts - accumulator
+ ldx #5
+tasl
+ set_ax zps,0
+ asl a
+ tst_ax rASL,fASL,0
+ dex
+ bpl tasl
+ ldx #5
+tasl1
+ set_ax zps,$ff
+ asl a
+ tst_ax rASL,fASL,$ff-fnzc
+ dex
+ bpl tasl1
+
+ ldx #5
+tlsr
+ set_ax zps,0
+ lsr a
+ tst_ax rLSR,fLSR,0
+ dex
+ bpl tlsr
+ ldx #5
+tlsr1
+ set_ax zps,$ff
+ lsr a
+ tst_ax rLSR,fLSR,$ff-fnzc
+ dex
+ bpl tlsr1
+
+ ldx #5
+trol
+ set_ax zps,0
+ rol a
+ tst_ax rROL,fROL,0
+ dex
+ bpl trol
+ ldx #5
+trol1
+ set_ax zps,$ff-fc
+ rol a
+ tst_ax rROL,fROL,$ff-fnzc
+ dex
+ bpl trol1
+
+ ldx #5
+trolc
+ set_ax zps,fc
+ rol a
+ tst_ax rROLc,fROLc,0
+ dex
+ bpl trolc
+ ldx #5
+trolc1
+ set_ax zps,$ff
+ rol a
+ tst_ax rROLc,fROLc,$ff-fnzc
+ dex
+ bpl trolc1
+
+ ldx #5
+tror
+ set_ax zps,0
+ ror a
+ tst_ax rROR,fROR,0
+ dex
+ bpl tror
+ ldx #5
+tror1
+ set_ax zps,$ff-fc
+ ror a
+ tst_ax rROR,fROR,$ff-fnzc
+ dex
+ bpl tror1
+
+ ldx #5
+trorc
+ set_ax zps,fc
+ ror a
+ tst_ax rRORc,fRORc,0
+ dex
+ bpl trorc
+ ldx #5
+trorc1
+ set_ax zps,$ff
+ ror a
+ tst_ax rRORc,fRORc,$ff-fnzc
+ dex
+ bpl trorc1
+ next_test
+
+; shifts - zeropage
+ ldx #5
+tasl2
+ set_z zps,0
+ asl zpt
+ tst_z rASL,fASL,0
+ dex
+ bpl tasl2
+ ldx #5
+tasl3
+ set_z zps,$ff
+ asl zpt
+ tst_z rASL,fASL,$ff-fnzc
+ dex
+ bpl tasl3
+
+ ldx #5
+tlsr2
+ set_z zps,0
+ lsr zpt
+ tst_z rLSR,fLSR,0
+ dex
+ bpl tlsr2
+ ldx #5
+tlsr3
+ set_z zps,$ff
+ lsr zpt
+ tst_z rLSR,fLSR,$ff-fnzc
+ dex
+ bpl tlsr3
+
+ ldx #5
+trol2
+ set_z zps,0
+ rol zpt
+ tst_z rROL,fROL,0
+ dex
+ bpl trol2
+ ldx #5
+trol3
+ set_z zps,$ff-fc
+ rol zpt
+ tst_z rROL,fROL,$ff-fnzc
+ dex
+ bpl trol3
+
+ ldx #5
+trolc2
+ set_z zps,fc
+ rol zpt
+ tst_z rROLc,fROLc,0
+ dex
+ bpl trolc2
+ ldx #5
+trolc3
+ set_z zps,$ff
+ rol zpt
+ tst_z rROLc,fROLc,$ff-fnzc
+ dex
+ bpl trolc3
+
+ ldx #5
+tror2
+ set_z zps,0
+ ror zpt
+ tst_z rROR,fROR,0
+ dex
+ bpl tror2
+ ldx #5
+tror3
+ set_z zps,$ff-fc
+ ror zpt
+ tst_z rROR,fROR,$ff-fnzc
+ dex
+ bpl tror3
+
+ ldx #5
+trorc2
+ set_z zps,fc
+ ror zpt
+ tst_z rRORc,fRORc,0
+ dex
+ bpl trorc2
+ ldx #5
+trorc3
+ set_z zps,$ff
+ ror zpt
+ tst_z rRORc,fRORc,$ff-fnzc
+ dex
+ bpl trorc3
+ next_test
+
+; shifts - absolute
+ ldx #5
+tasl4
+ set_abs zps,0
+ asl abst
+ tst_abs rASL,fASL,0
+ dex
+ bpl tasl4
+ ldx #5
+tasl5
+ set_abs zps,$ff
+ asl abst
+ tst_abs rASL,fASL,$ff-fnzc
+ dex
+ bpl tasl5
+
+ ldx #5
+tlsr4
+ set_abs zps,0
+ lsr abst
+ tst_abs rLSR,fLSR,0
+ dex
+ bpl tlsr4
+ ldx #5
+tlsr5
+ set_abs zps,$ff
+ lsr abst
+ tst_abs rLSR,fLSR,$ff-fnzc
+ dex
+ bpl tlsr5
+
+ ldx #5
+trol4
+ set_abs zps,0
+ rol abst
+ tst_abs rROL,fROL,0
+ dex
+ bpl trol4
+ ldx #5
+trol5
+ set_abs zps,$ff-fc
+ rol abst
+ tst_abs rROL,fROL,$ff-fnzc
+ dex
+ bpl trol5
+
+ ldx #5
+trolc4
+ set_abs zps,fc
+ rol abst
+ tst_abs rROLc,fROLc,0
+ dex
+ bpl trolc4
+ ldx #5
+trolc5
+ set_abs zps,$ff
+ rol abst
+ tst_abs rROLc,fROLc,$ff-fnzc
+ dex
+ bpl trolc5
+
+ ldx #5
+tror4
+ set_abs zps,0
+ ror abst
+ tst_abs rROR,fROR,0
+ dex
+ bpl tror4
+ ldx #5
+tror5
+ set_abs zps,$ff-fc
+ ror abst
+ tst_abs rROR,fROR,$ff-fnzc
+ dex
+ bpl tror5
+
+ ldx #5
+trorc4
+ set_abs zps,fc
+ ror abst
+ tst_abs rRORc,fRORc,0
+ dex
+ bpl trorc4
+ ldx #5
+trorc5
+ set_abs zps,$ff
+ ror abst
+ tst_abs rRORc,fRORc,$ff-fnzc
+ dex
+ bpl trorc5
+ next_test
+
+; shifts - zp indexed
+ ldx #5
+tasl6
+ set_zx zps,0
+ asl zpt,x
+ tst_zx rASL,fASL,0
+ dex
+ bpl tasl6
+ ldx #5
+tasl7
+ set_zx zps,$ff
+ asl zpt,x
+ tst_zx rASL,fASL,$ff-fnzc
+ dex
+ bpl tasl7
+
+ ldx #5
+tlsr6
+ set_zx zps,0
+ lsr zpt,x
+ tst_zx rLSR,fLSR,0
+ dex
+ bpl tlsr6
+ ldx #5
+tlsr7
+ set_zx zps,$ff
+ lsr zpt,x
+ tst_zx rLSR,fLSR,$ff-fnzc
+ dex
+ bpl tlsr7
+
+ ldx #5
+trol6
+ set_zx zps,0
+ rol zpt,x
+ tst_zx rROL,fROL,0
+ dex
+ bpl trol6
+ ldx #5
+trol7
+ set_zx zps,$ff-fc
+ rol zpt,x
+ tst_zx rROL,fROL,$ff-fnzc
+ dex
+ bpl trol7
+
+ ldx #5
+trolc6
+ set_zx zps,fc
+ rol zpt,x
+ tst_zx rROLc,fROLc,0
+ dex
+ bpl trolc6
+ ldx #5
+trolc7
+ set_zx zps,$ff
+ rol zpt,x
+ tst_zx rROLc,fROLc,$ff-fnzc
+ dex
+ bpl trolc7
+
+ ldx #5
+tror6
+ set_zx zps,0
+ ror zpt,x
+ tst_zx rROR,fROR,0
+ dex
+ bpl tror6
+ ldx #5
+tror7
+ set_zx zps,$ff-fc
+ ror zpt,x
+ tst_zx rROR,fROR,$ff-fnzc
+ dex
+ bpl tror7
+
+ ldx #5
+trorc6
+ set_zx zps,fc
+ ror zpt,x
+ tst_zx rRORc,fRORc,0
+ dex
+ bpl trorc6
+ ldx #5
+trorc7
+ set_zx zps,$ff
+ ror zpt,x
+ tst_zx rRORc,fRORc,$ff-fnzc
+ dex
+ bpl trorc7
+ next_test
+
+; shifts - abs indexed
+ ldx #5
+tasl8
+ set_absx zps,0
+ asl abst,x
+ tst_absx rASL,fASL,0
+ dex
+ bpl tasl8
+ ldx #5
+tasl9
+ set_absx zps,$ff
+ asl abst,x
+ tst_absx rASL,fASL,$ff-fnzc
+ dex
+ bpl tasl9
+
+ ldx #5
+tlsr8
+ set_absx zps,0
+ lsr abst,x
+ tst_absx rLSR,fLSR,0
+ dex
+ bpl tlsr8
+ ldx #5
+tlsr9
+ set_absx zps,$ff
+ lsr abst,x
+ tst_absx rLSR,fLSR,$ff-fnzc
+ dex
+ bpl tlsr9
+
+ ldx #5
+trol8
+ set_absx zps,0
+ rol abst,x
+ tst_absx rROL,fROL,0
+ dex
+ bpl trol8
+ ldx #5
+trol9
+ set_absx zps,$ff-fc
+ rol abst,x
+ tst_absx rROL,fROL,$ff-fnzc
+ dex
+ bpl trol9
+
+ ldx #5
+trolc8
+ set_absx zps,fc
+ rol abst,x
+ tst_absx rROLc,fROLc,0
+ dex
+ bpl trolc8
+ ldx #5
+trolc9
+ set_absx zps,$ff
+ rol abst,x
+ tst_absx rROLc,fROLc,$ff-fnzc
+ dex
+ bpl trolc9
+
+ ldx #5
+tror8
+ set_absx zps,0
+ ror abst,x
+ tst_absx rROR,fROR,0
+ dex
+ bpl tror8
+ ldx #5
+tror9
+ set_absx zps,$ff-fc
+ ror abst,x
+ tst_absx rROR,fROR,$ff-fnzc
+ dex
+ bpl tror9
+
+ ldx #5
+trorc8
+ set_absx zps,fc
+ ror abst,x
+ tst_absx rRORc,fRORc,0
+ dex
+ bpl trorc8
+ ldx #5
+trorc9
+ set_absx zps,$ff
+ ror abst,x
+ tst_absx rRORc,fRORc,$ff-fnzc
+ dex
+ bpl trorc9
+ next_test
+
+; testing memory increment/decrement - INC DEC all addressing modes
+; zeropage
+ ldx #0
+ lda #$7e
+ sta zpt
+tinc
+ set_stat 0
+ inc zpt
+ tst_z rINC,fINC,0
+ inx
+ cpx #2
+ bne tinc1
+ lda #$fe
+ sta zpt
+tinc1 cpx #5
+ bne tinc
+ dex
+ inc zpt
+tdec
+ set_stat 0
+ dec zpt
+ tst_z rINC,fINC,0
+ dex
+ bmi tdec1
+ cpx #1
+ bne tdec
+ lda #$81
+ sta zpt
+ bne tdec
+tdec1
+ ldx #0
+ lda #$7e
+ sta zpt
+tinc10
+ set_stat $ff
+ inc zpt
+ tst_z rINC,fINC,$ff-fnz
+ inx
+ cpx #2
+ bne tinc11
+ lda #$fe
+ sta zpt
+tinc11 cpx #5
+ bne tinc10
+ dex
+ inc zpt
+tdec10
+ set_stat $ff
+ dec zpt
+ tst_z rINC,fINC,$ff-fnz
+ dex
+ bmi tdec11
+ cpx #1
+ bne tdec10
+ lda #$81
+ sta zpt
+ bne tdec10
+tdec11
+ next_test
+
+; absolute memory
+ ldx #0
+ lda #$7e
+ sta abst
+tinc2
+ set_stat 0
+ inc abst
+ tst_abs rINC,fINC,0
+ inx
+ cpx #2
+ bne tinc3
+ lda #$fe
+ sta abst
+tinc3 cpx #5
+ bne tinc2
+ dex
+ inc abst
+tdec2
+ set_stat 0
+ dec abst
+ tst_abs rINC,fINC,0
+ dex
+ bmi tdec3
+ cpx #1
+ bne tdec2
+ lda #$81
+ sta abst
+ bne tdec2
+tdec3
+ ldx #0
+ lda #$7e
+ sta abst
+tinc12
+ set_stat $ff
+ inc abst
+ tst_abs rINC,fINC,$ff-fnz
+ inx
+ cpx #2
+ bne tinc13
+ lda #$fe
+ sta abst
+tinc13 cpx #5
+ bne tinc12
+ dex
+ inc abst
+tdec12
+ set_stat $ff
+ dec abst
+ tst_abs rINC,fINC,$ff-fnz
+ dex
+ bmi tdec13
+ cpx #1
+ bne tdec12
+ lda #$81
+ sta abst
+ bne tdec12
+tdec13
+ next_test
+
+; zeropage indexed
+ ldx #0
+ lda #$7e
+tinc4 sta zpt,x
+ set_stat 0
+ inc zpt,x
+ tst_zx rINC,fINC,0
+ lda zpt,x
+ inx
+ cpx #2
+ bne tinc5
+ lda #$fe
+tinc5 cpx #5
+ bne tinc4
+ dex
+ lda #2
+tdec4 sta zpt,x
+ set_stat 0
+ dec zpt,x
+ tst_zx rINC,fINC,0
+ lda zpt,x
+ dex
+ bmi tdec5
+ cpx #1
+ bne tdec4
+ lda #$81
+ bne tdec4
+tdec5
+ ldx #0
+ lda #$7e
+tinc14 sta zpt,x
+ set_stat $ff
+ inc zpt,x
+ tst_zx rINC,fINC,$ff-fnz
+ lda zpt,x
+ inx
+ cpx #2
+ bne tinc15
+ lda #$fe
+tinc15 cpx #5
+ bne tinc14
+ dex
+ lda #2
+tdec14 sta zpt,x
+ set_stat $ff
+ dec zpt,x
+ tst_zx rINC,fINC,$ff-fnz
+ lda zpt,x
+ dex
+ bmi tdec15
+ cpx #1
+ bne tdec14
+ lda #$81
+ bne tdec14
+tdec15
+ next_test
+
+; memory indexed
+ ldx #0
+ lda #$7e
+tinc6 sta abst,x
+ set_stat 0
+ inc abst,x
+ tst_absx rINC,fINC,0
+ lda abst,x
+ inx
+ cpx #2
+ bne tinc7
+ lda #$fe
+tinc7 cpx #5
+ bne tinc6
+ dex
+ lda #2
+tdec6 sta abst,x
+ set_stat 0
+ dec abst,x
+ tst_absx rINC,fINC,0
+ lda abst,x
+ dex
+ bmi tdec7
+ cpx #1
+ bne tdec6
+ lda #$81
+ bne tdec6
+tdec7
+ ldx #0
+ lda #$7e
+tinc16 sta abst,x
+ set_stat $ff
+ inc abst,x
+ tst_absx rINC,fINC,$ff-fnz
+ lda abst,x
+ inx
+ cpx #2
+ bne tinc17
+ lda #$fe
+tinc17 cpx #5
+ bne tinc16
+ dex
+ lda #2
+tdec16 sta abst,x
+ set_stat $ff
+ dec abst,x
+ tst_absx rINC,fINC,$ff-fnz
+ lda abst,x
+ dex
+ bmi tdec17
+ cpx #1
+ bne tdec16
+ lda #$81
+ bne tdec16
+tdec17
+ next_test
+
+; testing logical instructions - AND EOR ORA all addressing modes
+; AND
+ ldx #3 ;immediate
+tand lda zpAN,x
+ sta ex_andi+1 ;set AND # operand
+ set_ax absANa,0
+ jsr ex_andi ;execute AND # in RAM
+ tst_ax absrlo,absflo,0
+ dex
+ bpl tand
+ ldx #3
+tand1 lda zpAN,x
+ sta ex_andi+1 ;set AND # operand
+ set_ax absANa,$ff
+ jsr ex_andi ;execute AND # in RAM
+ tst_ax absrlo,absflo,$ff-fnz
+ dex
+ bpl tand1
+
+ ldx #3 ;zp
+tand2 lda zpAN,x
+ sta zpt
+ set_ax absANa,0
+ and zpt
+ tst_ax absrlo,absflo,0
+ dex
+ bpl tand2
+ ldx #3
+tand3 lda zpAN,x
+ sta zpt
+ set_ax absANa,$ff
+ and zpt
+ tst_ax absrlo,absflo,$ff-fnz
+ dex
+ bpl tand3
+
+ ldx #3 ;abs
+tand4 lda zpAN,x
+ sta abst
+ set_ax absANa,0
+ and abst
+ tst_ax absrlo,absflo,0
+ dex
+ bpl tand4
+ ldx #3
+tand5 lda zpAN,x
+ sta abst
+ set_ax absANa,$ff
+ and abst
+ tst_ax absrlo,absflo,$ff-fnz
+ dex
+ bpl tand6
+
+ ldx #3 ;zp,x
+tand6
+ set_ax absANa,0
+ and zpAN,x
+ tst_ax absrlo,absflo,0
+ dex
+ bpl tand6
+ ldx #3
+tand7
+ set_ax absANa,$ff
+ and zpAN,x
+ tst_ax absrlo,absflo,$ff-fnz
+ dex
+ bpl tand7
+
+ ldx #3 ;abs,x
+tand8
+ set_ax absANa,0
+ and absAN,x
+ tst_ax absrlo,absflo,0
+ dex
+ bpl tand8
+ ldx #3
+tand9
+ set_ax absANa,$ff
+ and absAN,x
+ tst_ax absrlo,absflo,$ff-fnz
+ dex
+ bpl tand9
+
+ ldy #3 ;abs,y
+tand10
+ set_ay absANa,0
+ and absAN,y
+ tst_ay absrlo,absflo,0
+ dey
+ bpl tand10
+ ldy #3
+tand11
+ set_ay absANa,$ff
+ and absAN,y
+ tst_ay absrlo,absflo,$ff-fnz
+ dey
+ bpl tand11
+
+ ldx #6 ;(zp,x)
+ ldy #3
+tand12
+ set_ay absANa,0
+ and (indAN,x)
+ tst_ay absrlo,absflo,0
+ dex
+ dex
+ dey
+ bpl tand12
+ ldx #6
+ ldy #3
+tand13
+ set_ay absANa,$ff
+ and (indAN,x)
+ tst_ay absrlo,absflo,$ff-fnz
+ dex
+ dex
+ dey
+ bpl tand13
+
+ ldy #3 ;(zp),y
+tand14
+ set_ay absANa,0
+ and (indAN),y
+ tst_ay absrlo,absflo,0
+ dey
+ bpl tand14
+ ldy #3
+tand15
+ set_ay absANa,$ff
+ and (indAN),y
+ tst_ay absrlo,absflo,$ff-fnz
+ dey
+ bpl tand15
+ next_test
+
+; EOR
+ ldx #3 ;immediate - self modifying code
+teor lda zpEO,x
+ sta ex_eori+1 ;set EOR # operand
+ set_ax absEOa,0
+ jsr ex_eori ;execute EOR # in RAM
+ tst_ax absrlo,absflo,0
+ dex
+ bpl teor
+ ldx #3
+teor1 lda zpEO,x
+ sta ex_eori+1 ;set EOR # operand
+ set_ax absEOa,$ff
+ jsr ex_eori ;execute EOR # in RAM
+ tst_ax absrlo,absflo,$ff-fnz
+ dex
+ bpl teor1
+
+ ldx #3 ;zp
+teor2 lda zpEO,x
+ sta zpt
+ set_ax absEOa,0
+ eor zpt
+ tst_ax absrlo,absflo,0
+ dex
+ bpl teor2
+ ldx #3
+teor3 lda zpEO,x
+ sta zpt
+ set_ax absEOa,$ff
+ eor zpt
+ tst_ax absrlo,absflo,$ff-fnz
+ dex
+ bpl teor3
+
+ ldx #3 ;abs
+teor4 lda zpEO,x
+ sta abst
+ set_ax absEOa,0
+ eor abst
+ tst_ax absrlo,absflo,0
+ dex
+ bpl teor4
+ ldx #3
+teor5 lda zpEO,x
+ sta abst
+ set_ax absEOa,$ff
+ eor abst
+ tst_ax absrlo,absflo,$ff-fnz
+ dex
+ bpl teor6
+
+ ldx #3 ;zp,x
+teor6
+ set_ax absEOa,0
+ eor zpEO,x
+ tst_ax absrlo,absflo,0
+ dex
+ bpl teor6
+ ldx #3
+teor7
+ set_ax absEOa,$ff
+ eor zpEO,x
+ tst_ax absrlo,absflo,$ff-fnz
+ dex
+ bpl teor7
+
+ ldx #3 ;abs,x
+teor8
+ set_ax absEOa,0
+ eor absEO,x
+ tst_ax absrlo,absflo,0
+ dex
+ bpl teor8
+ ldx #3
+teor9
+ set_ax absEOa,$ff
+ eor absEO,x
+ tst_ax absrlo,absflo,$ff-fnz
+ dex
+ bpl teor9
+
+ ldy #3 ;abs,y
+teor10
+ set_ay absEOa,0
+ eor absEO,y
+ tst_ay absrlo,absflo,0
+ dey
+ bpl teor10
+ ldy #3
+teor11
+ set_ay absEOa,$ff
+ eor absEO,y
+ tst_ay absrlo,absflo,$ff-fnz
+ dey
+ bpl teor11
+
+ ldx #6 ;(zp,x)
+ ldy #3
+teor12
+ set_ay absEOa,0
+ eor (indEO,x)
+ tst_ay absrlo,absflo,0
+ dex
+ dex
+ dey
+ bpl teor12
+ ldx #6
+ ldy #3
+teor13
+ set_ay absEOa,$ff
+ eor (indEO,x)
+ tst_ay absrlo,absflo,$ff-fnz
+ dex
+ dex
+ dey
+ bpl teor13
+
+ ldy #3 ;(zp),y
+teor14
+ set_ay absEOa,0
+ eor (indEO),y
+ tst_ay absrlo,absflo,0
+ dey
+ bpl teor14
+ ldy #3
+teor15
+ set_ay absEOa,$ff
+ eor (indEO),y
+ tst_ay absrlo,absflo,$ff-fnz
+ dey
+ bpl teor15
+ next_test
+
+; OR
+ ldx #3 ;immediate - self modifying code
+tora lda zpOR,x
+ sta ex_orai+1 ;set ORA # operand
+ set_ax absORa,0
+ jsr ex_orai ;execute ORA # in RAM
+ tst_ax absrlo,absflo,0
+ dex
+ bpl tora
+ ldx #3
+tora1 lda zpOR,x
+ sta ex_orai+1 ;set ORA # operand
+ set_ax absORa,$ff
+ jsr ex_orai ;execute ORA # in RAM
+ tst_ax absrlo,absflo,$ff-fnz
+ dex
+ bpl tora1
+
+ ldx #3 ;zp
+tora2 lda zpOR,x
+ sta zpt
+ set_ax absORa,0
+ ora zpt
+ tst_ax absrlo,absflo,0
+ dex
+ bpl tora2
+ ldx #3
+tora3 lda zpOR,x
+ sta zpt
+ set_ax absORa,$ff
+ ora zpt
+ tst_ax absrlo,absflo,$ff-fnz
+ dex
+ bpl tora3
+
+ ldx #3 ;abs
+tora4 lda zpOR,x
+ sta abst
+ set_ax absORa,0
+ ora abst
+ tst_ax absrlo,absflo,0
+ dex
+ bpl tora4
+ ldx #3
+tora5 lda zpOR,x
+ sta abst
+ set_ax absORa,$ff
+ ora abst
+ tst_ax absrlo,absflo,$ff-fnz
+ dex
+ bpl tora6
+
+ ldx #3 ;zp,x
+tora6
+ set_ax absORa,0
+ ora zpOR,x
+ tst_ax absrlo,absflo,0
+ dex
+ bpl tora6
+ ldx #3
+tora7
+ set_ax absORa,$ff
+ ora zpOR,x
+ tst_ax absrlo,absflo,$ff-fnz
+ dex
+ bpl tora7
+
+ ldx #3 ;abs,x
+tora8
+ set_ax absORa,0
+ ora absOR,x
+ tst_ax absrlo,absflo,0
+ dex
+ bpl tora8
+ ldx #3
+tora9
+ set_ax absORa,$ff
+ ora absOR,x
+ tst_ax absrlo,absflo,$ff-fnz
+ dex
+ bpl tora9
+
+ ldy #3 ;abs,y
+tora10
+ set_ay absORa,0
+ ora absOR,y
+ tst_ay absrlo,absflo,0
+ dey
+ bpl tora10
+ ldy #3
+tora11
+ set_ay absORa,$ff
+ ora absOR,y
+ tst_ay absrlo,absflo,$ff-fnz
+ dey
+ bpl tora11
+
+ ldx #6 ;(zp,x)
+ ldy #3
+tora12
+ set_ay absORa,0
+ ora (indOR,x)
+ tst_ay absrlo,absflo,0
+ dex
+ dex
+ dey
+ bpl tora12
+ ldx #6
+ ldy #3
+tora13
+ set_ay absORa,$ff
+ ora (indOR,x)
+ tst_ay absrlo,absflo,$ff-fnz
+ dex
+ dex
+ dey
+ bpl tora13
+
+ ldy #3 ;(zp),y
+tora14
+ set_ay absORa,0
+ ora (indOR),y
+ tst_ay absrlo,absflo,0
+ dey
+ bpl tora14
+ ldy #3
+tora15
+ set_ay absORa,$ff
+ ora (indOR),y
+ tst_ay absrlo,absflo,$ff-fnz
+ dey
+ bpl tora15
+ if I_flag = 3
+ cli
+ endif
+ next_test
+
+; full binary add/subtract test
+; iterates through all combinations of operands and carry input
+; uses increments/decrements to predict result & result flags
+ cld
+ ldx #ad2 ;for indexed test
+ ldy #$ff ;max range
+ lda #0 ;start with adding zeroes & no carry
+ sta adfc ;carry in - for diag
+ sta ad1 ;operand 1 - accumulator
+ sta ad2 ;operand 2 - memory or immediate
+ sta ada2 ;non zp
+ sta adrl ;expected result bits 0-7
+ sta adrh ;expected result bit 8 (carry out)
+ lda #$ff ;complemented operand 2 for subtract
+ sta sb2
+ sta sba2 ;non zp
+ lda #2 ;expected Z-flag
+ sta adrf
+tadd clc ;test with carry clear
+ jsr chkadd
+ inc adfc ;now with carry
+ inc adrl ;result +1
+ php ;save N & Z from low result
+ php
+ pla ;accu holds expected flags
+ and #$82 ;mask N & Z
+ plp
+ bne tadd1
+ inc adrh ;result bit 8 - carry
+tadd1 ora adrh ;merge C to expected flags
+ sta adrf ;save expected flags except overflow
+ sec ;test with carry set
+ jsr chkadd
+ dec adfc ;same for operand +1 but no carry
+ inc ad1
+ bne tadd ;iterate op1
+ lda #0 ;preset result to op2 when op1 = 0
+ sta adrh
+ inc ada2
+ inc ad2
+ php ;save NZ as operand 2 becomes the new result
+ pla
+ and #$82 ;mask N00000Z0
+ sta adrf ;no need to check carry as we are adding to 0
+ dec sb2 ;complement subtract operand 2
+ dec sba2
+ lda ad2
+ sta adrl
+ bne tadd ;iterate op2
+ if disable_decimal < 1
+ next_test
+
+; decimal add/subtract test
+; *** WARNING - tests documented behavior only! ***
+; only valid BCD operands are tested, N V Z flags are ignored
+; iterates through all valid combinations of operands and carry input
+; uses increments/decrements to predict result & carry flag
+ sed
+ ldx #ad2 ;for indexed test
+ ldy #$ff ;max range
+ lda #$99 ;start with adding 99 to 99 with carry
+ sta ad1 ;operand 1 - accumulator
+ sta ad2 ;operand 2 - memory or immediate
+ sta ada2 ;non zp
+ sta adrl ;expected result bits 0-7
+ lda #1 ;set carry in & out
+ sta adfc ;carry in - for diag
+ sta adrh ;expected result bit 8 (carry out)
+ lda #0 ;complemented operand 2 for subtract
+ sta sb2
+ sta sba2 ;non zp
+tdad sec ;test with carry set
+ jsr chkdad
+ dec adfc ;now with carry clear
+ lda adrl ;decimal adjust result
+ bne tdad1 ;skip clear carry & preset result 99 (9A-1)
+ dec adrh
+ lda #$99
+ sta adrl
+ bne tdad3
+tdad1 and #$f ;lower nibble mask
+ bne tdad2 ;no decimal adjust needed
+ dec adrl ;decimal adjust (?0-6)
+ dec adrl
+ dec adrl
+ dec adrl
+ dec adrl
+ dec adrl
+tdad2 dec adrl ;result -1
+tdad3 clc ;test with carry clear
+ jsr chkdad
+ inc adfc ;same for operand -1 but with carry
+ lda ad1 ;decimal adjust operand 1
+ beq tdad5 ;iterate operand 2
+ and #$f ;lower nibble mask
+ bne tdad4 ;skip decimal adjust
+ dec ad1 ;decimal adjust (?0-6)
+ dec ad1
+ dec ad1
+ dec ad1
+ dec ad1
+ dec ad1
+tdad4 dec ad1 ;operand 1 -1
+ jmp tdad ;iterate op1
+
+tdad5 lda #$99 ;precharge op1 max
+ sta ad1
+ lda ad2 ;decimal adjust operand 2
+ beq tdad7 ;end of iteration
+ and #$f ;lower nibble mask
+ bne tdad6 ;skip decimal adjust
+ dec ad2 ;decimal adjust (?0-6)
+ dec ad2
+ dec ad2
+ dec ad2
+ dec ad2
+ dec ad2
+ inc sb2 ;complemented decimal adjust for subtract (?9+6)
+ inc sb2
+ inc sb2
+ inc sb2
+ inc sb2
+ inc sb2
+tdad6 dec ad2 ;operand 2 -1
+ inc sb2 ;complemented operand for subtract
+ lda sb2
+ sta sba2 ;copy as non zp operand
+ lda ad2
+ sta ada2 ;copy as non zp operand
+ sta adrl ;new result since op1+carry=00+carry +op2=op2
+ inc adrh ;result carry
+ bne tdad ;iterate op2
+tdad7
+ next_test
+
+; decimal/binary switch test
+; tests CLD, SED, PLP, RTI to properly switch between decimal & binary opcode
+; tables
+ clc
+ cld
+ php
+ lda #$55
+ adc #$55
+ cmp #$aa
+ trap_ne ;expected binary result after cld
+ clc
+ sed
+ php
+ lda #$55
+ adc #$55
+ cmp #$10
+ trap_ne ;expected decimal result after sed
+ cld
+ plp
+ lda #$55
+ adc #$55
+ cmp #$10
+ trap_ne ;expected decimal result after plp D=1
+ plp
+ lda #$55
+ adc #$55
+ cmp #$aa
+ trap_ne ;expected binary result after plp D=0
+ clc
+ lda #hi bin_rti_ret ;emulated interrupt for rti
+ pha
+ lda #lo bin_rti_ret
+ pha
+ php
+ sed
+ lda #hi dec_rti_ret ;emulated interrupt for rti
+ pha
+ lda #lo dec_rti_ret
+ pha
+ php
+ cld
+ rti
+dec_rti_ret
+ lda #$55
+ adc #$55
+ cmp #$10
+ trap_ne ;expected decimal result after rti D=1
+ rti
+bin_rti_ret
+ lda #$55
+ adc #$55
+ cmp #$aa
+ trap_ne ;expected binary result after rti D=0
+ endif
+
+ lda test_case
+ cmp #test_num
+ trap_ne ;previous test is out of sequence
+ lda #$f0 ;mark opcode testing complete
+ sta test_case
+
+; final RAM integrity test
+; verifies that none of the previous tests has altered RAM outside of the
+; designated write areas.
+ check_ram
+; *** DEBUG INFO ***
+; to debug checksum errors uncomment check_ram in the next_test macro to
+; narrow down the responsible opcode.
+; may give false errors when monitor, OS or other background activity is
+; allowed during previous tests.
+
+
+; S U C C E S S ************************************************
+; -------------
+ success ;if you get here everything went well
+; -------------
+; S U C C E S S ************************************************
+ jmp start ;run again
+
+ if disable_decimal < 1
+; core subroutine of the decimal add/subtract test
+; *** WARNING - tests documented behavior only! ***
+; only valid BCD operands are tested, N V Z flags are ignored
+; iterates through all valid combinations of operands and carry input
+; uses increments/decrements to predict result & carry flag
+chkdad
+; decimal ADC / SBC zp
+ php ;save carry for subtract
+ lda ad1
+ adc ad2 ;perform add
+ php
+ cmp adrl ;check result
+ trap_ne ;bad result
+ pla ;check flags
+ and #1 ;mask carry
+ cmp adrh
+ trap_ne ;bad carry
+ plp
+ php ;save carry for next add
+ lda ad1
+ sbc sb2 ;perform subtract
+ php
+ cmp adrl ;check result
+ trap_ne ;bad result
+ pla ;check flags
+ and #1 ;mask carry
+ cmp adrh
+ trap_ne ;bad flags
+ plp
+; decimal ADC / SBC abs
+ php ;save carry for subtract
+ lda ad1
+ adc ada2 ;perform add
+ php
+ cmp adrl ;check result
+ trap_ne ;bad result
+ pla ;check flags
+ and #1 ;mask carry
+ cmp adrh
+ trap_ne ;bad carry
+ plp
+ php ;save carry for next add
+ lda ad1
+ sbc sba2 ;perform subtract
+ php
+ cmp adrl ;check result
+ trap_ne ;bad result
+ pla ;check flags
+ and #1 ;mask carry
+ cmp adrh
+ trap_ne ;bad carry
+ plp
+; decimal ADC / SBC #
+ php ;save carry for subtract
+ lda ad2
+ sta ex_adci+1 ;set ADC # operand
+ lda ad1
+ jsr ex_adci ;execute ADC # in RAM
+ php
+ cmp adrl ;check result
+ trap_ne ;bad result
+ pla ;check flags
+ and #1 ;mask carry
+ cmp adrh
+ trap_ne ;bad carry
+ plp
+ php ;save carry for next add
+ lda sb2
+ sta ex_sbci+1 ;set SBC # operand
+ lda ad1
+ jsr ex_sbci ;execute SBC # in RAM
+ php
+ cmp adrl ;check result
+ trap_ne ;bad result
+ pla ;check flags
+ and #1 ;mask carry
+ cmp adrh
+ trap_ne ;bad carry
+ plp
+; decimal ADC / SBC zp,x
+ php ;save carry for subtract
+ lda ad1
+ adc 0,x ;perform add
+ php
+ cmp adrl ;check result
+ trap_ne ;bad result
+ pla ;check flags
+ and #1 ;mask carry
+ cmp adrh
+ trap_ne ;bad carry
+ plp
+ php ;save carry for next add
+ lda ad1
+ sbc sb2-ad2,x ;perform subtract
+ php
+ cmp adrl ;check result
+ trap_ne ;bad result
+ pla ;check flags
+ and #1 ;mask carry
+ cmp adrh
+ trap_ne ;bad carry
+ plp
+; decimal ADC / SBC abs,x
+ php ;save carry for subtract
+ lda ad1
+ adc ada2-ad2,x ;perform add
+ php
+ cmp adrl ;check result
+ trap_ne ;bad result
+ pla ;check flags
+ and #1 ;mask carry
+ cmp adrh
+ trap_ne ;bad carry
+ plp
+ php ;save carry for next add
+ lda ad1
+ sbc sba2-ad2,x ;perform subtract
+ php
+ cmp adrl ;check result
+ trap_ne ;bad result
+ pla ;check flags
+ and #1 ;mask carry
+ cmp adrh
+ trap_ne ;bad carry
+ plp
+; decimal ADC / SBC abs,y
+ php ;save carry for subtract
+ lda ad1
+ adc ada2-$ff,y ;perform add
+ php
+ cmp adrl ;check result
+ trap_ne ;bad result
+ pla ;check flags
+ and #1 ;mask carry
+ cmp adrh
+ trap_ne ;bad carry
+ plp
+ php ;save carry for next add
+ lda ad1
+ sbc sba2-$ff,y ;perform subtract
+ php
+ cmp adrl ;check result
+ trap_ne ;bad result
+ pla ;check flags
+ and #1 ;mask carry
+ cmp adrh
+ trap_ne ;bad carry
+ plp
+; decimal ADC / SBC (zp,x)
+ php ;save carry for subtract
+ lda ad1
+ adc (lo adi2-ad2,x) ;perform add
+ php
+ cmp adrl ;check result
+ trap_ne ;bad result
+ pla ;check flags
+ and #1 ;mask carry
+ cmp adrh
+ trap_ne ;bad carry
+ plp
+ php ;save carry for next add
+ lda ad1
+ sbc (lo sbi2-ad2,x) ;perform subtract
+ php
+ cmp adrl ;check result
+ trap_ne ;bad result
+ pla ;check flags
+ and #1 ;mask carry
+ cmp adrh
+ trap_ne ;bad carry
+ plp
+; decimal ADC / SBC (abs),y
+ php ;save carry for subtract
+ lda ad1
+ adc (adiy2),y ;perform add
+ php
+ cmp adrl ;check result
+ trap_ne ;bad result
+ pla ;check flags
+ and #1 ;mask carry
+ cmp adrh
+ trap_ne ;bad carry
+ plp
+ php ;save carry for next add
+ lda ad1
+ sbc (sbiy2),y ;perform subtract
+ php
+ cmp adrl ;check result
+ trap_ne ;bad result
+ pla ;check flags
+ and #1 ;mask carry
+ cmp adrh
+ trap_ne ;bad carry
+ plp
+ rts
+ endif
+
+; core subroutine of the full binary add/subtract test
+; iterates through all combinations of operands and carry input
+; uses increments/decrements to predict result & result flags
+chkadd lda adrf ;add V-flag if overflow
+ and #$83 ;keep N-----ZC / clear V
+ pha
+ lda ad1 ;test sign unequal between operands
+ eor ad2
+ bmi ckad1 ;no overflow possible - operands have different sign
+ lda ad1 ;test sign equal between operands and result
+ eor adrl
+ bpl ckad1 ;no overflow occured - operand and result have same sign
+ pla
+ ora #$40 ;set V
+ pha
+ckad1 pla
+ sta adrf ;save expected flags
+; binary ADC / SBC zp
+ php ;save carry for subtract
+ lda ad1
+ adc ad2 ;perform add
+ php
+ cmp adrl ;check result
+ trap_ne ;bad result
+ pla ;check flags
+ and #$c3 ;mask NV----ZC
+ cmp adrf
+ trap_ne ;bad flags
+ plp
+ php ;save carry for next add
+ lda ad1
+ sbc sb2 ;perform subtract
+ php
+ cmp adrl ;check result
+ trap_ne ;bad result
+ pla ;check flags
+ and #$c3 ;mask NV----ZC
+ cmp adrf
+ trap_ne ;bad flags
+ plp
+; binary ADC / SBC abs
+ php ;save carry for subtract
+ lda ad1
+ adc ada2 ;perform add
+ php
+ cmp adrl ;check result
+ trap_ne ;bad result
+ pla ;check flags
+ and #$c3 ;mask NV----ZC
+ cmp adrf
+ trap_ne ;bad flags
+ plp
+ php ;save carry for next add
+ lda ad1
+ sbc sba2 ;perform subtract
+ php
+ cmp adrl ;check result
+ trap_ne ;bad result
+ pla ;check flags
+ and #$c3 ;mask NV----ZC
+ cmp adrf
+ trap_ne ;bad flags
+ plp
+; binary ADC / SBC #
+ php ;save carry for subtract
+ lda ad2
+ sta ex_adci+1 ;set ADC # operand
+ lda ad1
+ jsr ex_adci ;execute ADC # in RAM
+ php
+ cmp adrl ;check result
+ trap_ne ;bad result
+ pla ;check flags
+ and #$c3 ;mask NV----ZC
+ cmp adrf
+ trap_ne ;bad flags
+ plp
+ php ;save carry for next add
+ lda sb2
+ sta ex_sbci+1 ;set SBC # operand
+ lda ad1
+ jsr ex_sbci ;execute SBC # in RAM
+ php
+ cmp adrl ;check result
+ trap_ne ;bad result
+ pla ;check flags
+ and #$c3 ;mask NV----ZC
+ cmp adrf
+ trap_ne ;bad flags
+ plp
+; binary ADC / SBC zp,x
+ php ;save carry for subtract
+ lda ad1
+ adc 0,x ;perform add
+ php
+ cmp adrl ;check result
+ trap_ne ;bad result
+ pla ;check flags
+ and #$c3 ;mask NV----ZC
+ cmp adrf
+ trap_ne ;bad flags
+ plp
+ php ;save carry for next add
+ lda ad1
+ sbc sb2-ad2,x ;perform subtract
+ php
+ cmp adrl ;check result
+ trap_ne ;bad result
+ pla ;check flags
+ and #$c3 ;mask NV----ZC
+ cmp adrf
+ trap_ne ;bad flags
+ plp
+; binary ADC / SBC abs,x
+ php ;save carry for subtract
+ lda ad1
+ adc ada2-ad2,x ;perform add
+ php
+ cmp adrl ;check result
+ trap_ne ;bad result
+ pla ;check flags
+ and #$c3 ;mask NV----ZC
+ cmp adrf
+ trap_ne ;bad flags
+ plp
+ php ;save carry for next add
+ lda ad1
+ sbc sba2-ad2,x ;perform subtract
+ php
+ cmp adrl ;check result
+ trap_ne ;bad result
+ pla ;check flags
+ and #$c3 ;mask NV----ZC
+ cmp adrf
+ trap_ne ;bad flags
+ plp
+; binary ADC / SBC abs,y
+ php ;save carry for subtract
+ lda ad1
+ adc ada2-$ff,y ;perform add
+ php
+ cmp adrl ;check result
+ trap_ne ;bad result
+ pla ;check flags
+ and #$c3 ;mask NV----ZC
+ cmp adrf
+ trap_ne ;bad flags
+ plp
+ php ;save carry for next add
+ lda ad1
+ sbc sba2-$ff,y ;perform subtract
+ php
+ cmp adrl ;check result
+ trap_ne ;bad result
+ pla ;check flags
+ and #$c3 ;mask NV----ZC
+ cmp adrf
+ trap_ne ;bad flags
+ plp
+; binary ADC / SBC (zp,x)
+ php ;save carry for subtract
+ lda ad1
+ adc (lo adi2-ad2,x) ;perform add
+ php
+ cmp adrl ;check result
+ trap_ne ;bad result
+ pla ;check flags
+ and #$c3 ;mask NV----ZC
+ cmp adrf
+ trap_ne ;bad flags
+ plp
+ php ;save carry for next add
+ lda ad1
+ sbc (lo sbi2-ad2,x) ;perform subtract
+ php
+ cmp adrl ;check result
+ trap_ne ;bad result
+ pla ;check flags
+ and #$c3 ;mask NV----ZC
+ cmp adrf
+ trap_ne ;bad flags
+ plp
+; binary ADC / SBC (abs),y
+ php ;save carry for subtract
+ lda ad1
+ adc (adiy2),y ;perform add
+ php
+ cmp adrl ;check result
+ trap_ne ;bad result
+ pla ;check flags
+ and #$c3 ;mask NV----ZC
+ cmp adrf
+ trap_ne ;bad flags
+ plp
+ php ;save carry for next add
+ lda ad1
+ sbc (sbiy2),y ;perform subtract
+ php
+ cmp adrl ;check result
+ trap_ne ;bad result
+ pla ;check flags
+ and #$c3 ;mask NV----ZC
+ cmp adrf
+ trap_ne ;bad flags
+ plp
+ rts
+
+; target for the jump absolute test
+ dey
+ dey
+test_far
+ php ;either SP or Y count will fail, if we do not hit
+ dey
+ dey
+ dey
+ plp
+ trap_cs ;flags loaded?
+ trap_vs
+ trap_mi
+ trap_eq
+ cmp #'F' ;registers loaded?
+ trap_ne
+ cpx #'A'
+ trap_ne
+ cpy #('R'-3)
+ trap_ne
+ pha ;save a,x
+ txa
+ pha
+ tsx
+ cpx #$fd ;check SP
+ trap_ne
+ pla ;restore x
+ tax
+ set_stat $ff
+ pla ;restore a
+ inx ;return registers with modifications
+ eor #$aa ;N=1, V=1, Z=0, C=1
+ jmp far_ret
+
+; target for the jump indirect test
+ align
+ptr_tst_ind dw test_ind
+ptr_ind_ret dw ind_ret
+ trap ;runover protection
+ dey
+ dey
+test_ind
+ php ;either SP or Y count will fail, if we do not hit
+ dey
+ dey
+ dey
+ plp
+ trap_cs ;flags loaded?
+ trap_vs
+ trap_mi
+ trap_eq
+ cmp #'I' ;registers loaded?
+ trap_ne
+ cpx #'N'
+ trap_ne
+ cpy #('D'-3)
+ trap_ne
+ pha ;save a,x
+ txa
+ pha
+ tsx
+ cpx #$fd ;check SP
+ trap_ne
+ pla ;restore x
+ tax
+ set_stat $ff
+ pla ;restore a
+ inx ;return registers with modifications
+ eor #$aa ;N=1, V=1, Z=0, C=1
+ jmp (ptr_ind_ret)
+ trap ;runover protection
+ jmp start ;catastrophic error - cannot continue
+
+; target for the jump subroutine test
+ dey
+ dey
+test_jsr
+ php ;either SP or Y count will fail, if we do not hit
+ dey
+ dey
+ dey
+ plp
+ trap_cs ;flags loaded?
+ trap_vs
+ trap_mi
+ trap_eq
+ cmp #'J' ;registers loaded?
+ trap_ne
+ cpx #'S'
+ trap_ne
+ cpy #('R'-3)
+ trap_ne
+ pha ;save a,x
+ txa
+ pha
+ tsx ;sp -4? (return addr,a,x)
+ cpx #$fb
+ trap_ne
+ lda $1ff ;propper return on stack
+ cmp #hi(jsr_ret)
+ trap_ne
+ lda $1fe
+ cmp #lo(jsr_ret)
+ trap_ne
+ set_stat $ff
+ pla ;pull x,a
+ tax
+ pla
+ inx ;return registers with modifications
+ eor #$aa ;N=1, V=1, Z=0, C=1
+ rts
+ trap ;runover protection
+ jmp start ;catastrophic error - cannot continue
+
+;trap in case of unexpected IRQ, NMI, BRK, RESET - BRK test target
+nmi_trap
+ trap ;check stack for conditions at NMI
+ jmp start ;catastrophic error - cannot continue
+res_trap
+ trap ;unexpected RESET
+ jmp start ;catastrophic error - cannot continue
+
+ dey
+ dey
+irq_trap ;BRK test or unextpected BRK or IRQ
+ php ;either SP or Y count will fail, if we do not hit
+ dey
+ dey
+ dey
+ ;next traps could be caused by unexpected BRK or IRQ
+ ;check stack for BREAK and originating location
+ ;possible jump/branch into weeds (uninitialized space)
+ cmp #$ff-'B' ;BRK pass 2 registers loaded?
+ beq break2
+ cmp #'B' ;BRK pass 1 registers loaded?
+ trap_ne
+ cpx #'R'
+ trap_ne
+ cpy #'K'-3
+ trap_ne
+ sta irq_a ;save registers during break test
+ stx irq_x
+ tsx ;test break on stack
+ lda $102,x
+ cmp_flag 0 ;break test should have B=1 & unused=1 on stack
+ trap_ne ; - no break flag on stack
+ pla
+ cmp_flag intdis ;should have added interrupt disable
+ trap_ne
+ tsx
+ cpx #$fc ;sp -3? (return addr, flags)
+ trap_ne
+ lda $1ff ;propper return on stack
+ cmp #hi(brk_ret0)
+ trap_ne
+ lda $1fe
+ cmp #lo(brk_ret0)
+ trap_ne
+ load_flag $ff
+ pha
+ ldx irq_x
+ inx ;return registers with modifications
+ lda irq_a
+ eor #$aa
+ plp ;N=1, V=1, Z=1, C=1 but original flags should be restored
+ rti
+ trap ;runover protection
+ jmp start ;catastrophic error - cannot continue
+
+break2 ;BRK pass 2
+ cpx #$ff-'R'
+ trap_ne
+ cpy #$ff-'K'-3
+ trap_ne
+ sta irq_a ;save registers during break test
+ stx irq_x
+ tsx ;test break on stack
+ lda $102,x
+ cmp_flag $ff ;break test should have B=1
+ trap_ne ; - no break flag on stack
+ pla
+ ora #decmode ;ignore decmode cleared if 65c02
+ cmp_flag $ff ;actual passed flags
+ trap_ne
+ tsx
+ cpx #$fc ;sp -3? (return addr, flags)
+ trap_ne
+ lda $1ff ;propper return on stack
+ cmp #hi(brk_ret1)
+ trap_ne
+ lda $1fe
+ cmp #lo(brk_ret1)
+ trap_ne
+ load_flag intdis
+ pha
+ ldx irq_x
+ inx ;return registers with modifications
+ lda irq_a
+ eor #$aa
+ plp ;N=0, V=0, Z=0, C=0 but original flags should be restored
+ rti
+ trap ;runover protection
+ jmp start ;catastrophic error - cannot continue
+
+ if report = 1
+ include "report.i65"
+ endif
+
+;copy of data to initialize BSS segment
+ if load_data_direct != 1
+zp_init
+zps_ db $80,1 ;additional shift pattern to test zero result & flag
+zp1_ db $c3,$82,$41,0 ;test patterns for LDx BIT ROL ROR ASL LSR
+zp7f_ db $7f ;test pattern for compare
+;logical zeropage operands
+zpOR_ db 0,$1f,$71,$80 ;test pattern for OR
+zpAN_ db $0f,$ff,$7f,$80 ;test pattern for AND
+zpEO_ db $ff,$0f,$8f,$8f ;test pattern for EOR
+;indirect addressing pointers
+ind1_ dw abs1 ;indirect pointer to pattern in absolute memory
+ dw abs1+1
+ dw abs1+2
+ dw abs1+3
+ dw abs7f
+inw1_ dw abs1-$f8 ;indirect pointer for wrap-test pattern
+indt_ dw abst ;indirect pointer to store area in absolute memory
+ dw abst+1
+ dw abst+2
+ dw abst+3
+inwt_ dw abst-$f8 ;indirect pointer for wrap-test store
+indAN_ dw absAN ;indirect pointer to AND pattern in absolute memory
+ dw absAN+1
+ dw absAN+2
+ dw absAN+3
+indEO_ dw absEO ;indirect pointer to EOR pattern in absolute memory
+ dw absEO+1
+ dw absEO+2
+ dw absEO+3
+indOR_ dw absOR ;indirect pointer to OR pattern in absolute memory
+ dw absOR+1
+ dw absOR+2
+ dw absOR+3
+;add/subtract indirect pointers
+adi2_ dw ada2 ;indirect pointer to operand 2 in absolute memory
+sbi2_ dw sba2 ;indirect pointer to complemented operand 2 (SBC)
+adiy2_ dw ada2-$ff ;with offset for indirect indexed
+sbiy2_ dw sba2-$ff
+zp_end
+ if (zp_end - zp_init) != (zp_bss_end - zp_bss)
+ ;force assembler error if size is different
+ ERROR ERROR ERROR ;mismatch between bss and zeropage data
+ endif
+data_init
+ex_and_ and #0 ;execute immediate opcodes
+ rts
+ex_eor_ eor #0 ;execute immediate opcodes
+ rts
+ex_ora_ ora #0 ;execute immediate opcodes
+ rts
+ex_adc_ adc #0 ;execute immediate opcodes
+ rts
+ex_sbc_ sbc #0 ;execute immediate opcodes
+ rts
+;zps db $80,1 ;additional shift patterns test zero result & flag
+abs1_ db $c3,$82,$41,0 ;test patterns for LDx BIT ROL ROR ASL LSR
+abs7f_ db $7f ;test pattern for compare
+;loads
+fLDx_ db fn,fn,0,fz ;expected flags for load
+;shifts
+rASL_ ;expected result ASL & ROL -carry
+rROL_ db 0,2,$86,$04,$82,0
+rROLc_ db 1,3,$87,$05,$83,1 ;expected result ROL +carry
+rLSR_ ;expected result LSR & ROR -carry
+rROR_ db $40,0,$61,$41,$20,0
+rRORc_ db $c0,$80,$e1,$c1,$a0,$80 ;expected result ROR +carry
+fASL_ ;expected flags for shifts
+fROL_ db fzc,0,fnc,fc,fn,fz ;no carry in
+fROLc_ db fc,0,fnc,fc,fn,0 ;carry in
+fLSR_
+fROR_ db 0,fzc,fc,0,fc,fz ;no carry in
+fRORc_ db fn,fnc,fnc,fn,fnc,fn ;carry in
+;increments (decrements)
+rINC_ db $7f,$80,$ff,0,1 ;expected result for INC/DEC
+fINC_ db 0,fn,fn,fz,0 ;expected flags for INC/DEC
+;logical memory operand
+absOR_ db 0,$1f,$71,$80 ;test pattern for OR
+absAN_ db $0f,$ff,$7f,$80 ;test pattern for AND
+absEO_ db $ff,$0f,$8f,$8f ;test pattern for EOR
+;logical accu operand
+absORa_ db 0,$f1,$1f,0 ;test pattern for OR
+absANa_ db $f0,$ff,$ff,$ff ;test pattern for AND
+absEOa_ db $ff,$f0,$f0,$0f ;test pattern for EOR
+;logical results
+absrlo_ db 0,$ff,$7f,$80
+absflo_ db fz,fn,0,fn
+data_end
+ if (data_end - data_init) != (data_bss_end - data_bss)
+ ;force assembler error if size is different
+ ERROR ERROR ERROR ;mismatch between bss and data
+ endif
+
+vec_init
+ dw nmi_trap
+ dw res_trap
+ dw irq_trap
+vec_bss equ $fffa
+ endif ;end of RAM init data
+
+ if (load_data_direct = 1) & (ROM_vectors = 1)
+ org $fffa ;vectors
+ dw nmi_trap
+ dw res_trap
+ dw irq_trap
+ endif
+
+ end start
\ No newline at end of file
diff --git a/6502_65C02_functional_tests/6502_interrupt_test.a65 b/6502_65C02_functional_tests/6502_interrupt_test.a65
index e88d22c..2199617 100644
--- a/6502_65C02_functional_tests/6502_interrupt_test.a65
+++ b/6502_65C02_functional_tests/6502_interrupt_test.a65
@@ -1,1026 +1,1026 @@
-;
-; 6 5 0 2 I N T E R R U P T T E S T
-;
-; Copyright (C) 2013 Klaus Dormann
-;
-; This program is free software: you can redistribute it and/or modify
-; it under the terms of the GNU General Public License as published by
-; the Free Software Foundation, either version 3 of the License, or
-; (at your option) any later version.
-;
-; This program is distributed in the hope that it will be useful,
-; but WITHOUT ANY WARRANTY; without even the implied warranty of
-; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-; GNU General Public License for more details.
-;
-; You should have received a copy of the GNU General Public License
-; along with this program. If not, see .
-
-
-; This program is designed to test IRQ and NMI of a 6502 emulator. It requires
-; an internal or external feedback register to the IRQ & NMI inputs
-;
-; version 15-aug-2014
-; contact info at http://2m5.de or email K@2m5.de
-;
-; assembled with AS65 from http://www.kingswood-consulting.co.uk/assemblers/
-; command line switches: -l -m -s2 -w -h0
-; | | | | no page headers in listing
-; | | | wide listing (133 char/col)
-; | | write intel hex file instead of binary
-; | expand macros in listing
-; generate pass2 listing
-;
-; No IO - should be run from a monitor with access to registers.
-; To run load intel hex image with a load command, than alter PC to 400 hex and
-; enter a go command.
-; Loop on program counter determines error or successful completion of test.
-; Check listing for relevant traps (jump/branch *).
-;
-; Debugging hints:
-; Most of the code is written sequentially. if you hit a trap, check the
-; immediately preceeding code for the instruction to be tested. Results are
-; tested first, flags are checked second by pushing them onto the stack and
-; pulling them to the accumulator after the result was checked. The "real"
-; flags are no longer valid for the tested instruction at this time!
-; If the tested instruction was indexed, the relevant index (X or Y) must
-; also be checked. Opposed to the flags, X and Y registers are still valid.
-;
-; versions:
-; 19-jul-2013 1st version distributed for testing
-; 16-aug-2013 added error report to standard output option
-; 15-aug-2014 added filter to feedback (bit 7 will cause diag stop in emu)
-
-
-; C O N F I G U R A T I O N
-;
-;ROM_vectors MUST be writable & the I_flag MUST be alterable
-
-;load_data_direct (0=move from code segment, 1=load directly)
-;loading directly is preferred but may not be supported by your platform
-;0 produces only consecutive object code, 1 is not suitable for a binary image
-load_data_direct = 1
-
-;NMI & IRQ are tested with a feedback register
-;emulators diag register - set i_drive = 0 for a latch (74HC573)
-I_port = $bffc ;feedback port address
-I_ddr = 0 ;feedback DDR address, 0 = no DDR
-I_drive = 1 ;0 = totem pole, 1 = open collector
-IRQ_bit = 0 ;bit number of feedback to IRQ
-NMI_bit = 1 ;bit number of feedback to NMI, -1 if not available
-I_filter = $7f ;filtering bit 7 = diag stop
-
-;typical IO chip port B - set i_drive = 0 to avoid pullup resistors
-;I_port = $bfb2 ;feedback port address
-;I_ddr = $bfb3 ;feedback DDR address, 0 = no DDR
-;I_drive = 1 ;0 = totem pole, 1 = open collector
-;IRQ_bit = 0 ;bit number of feedback to IRQ
-;NMI_bit = 1 ;bit number of feedback to NMI, -1 if not available
-;I_filter = $ff ;no bits filtered
-
-;decimal mode flag during IRQ, NMI & BRK
-D_clear = 0 ;0 = not cleared (NMOS), 1 = cleared (CMOS)
-
-;configure memory - try to stay away from memory used by the system
-;zero_page memory start address, 6 consecutive Bytes required
-zero_page = $0
-
-;data_segment memory start address, 4 consecutive Bytes required
-data_segment = $200
-
-;code_segment memory start address
-code_segment = $400
-
-;report errors through I/O channel (0=use standard self trap loops, 1=include
-;report.i65 as I/O channel)
-report = 1
-
- noopt ;do not take shortcuts
-
-;macros for error & success traps to allow user modification
-;example:
-;trap macro
-; jsr my_error_handler
-; endm
-;trap_eq macro
-; bne skip\?
-; trap ;failed equal (zero)
-;skip\?
-; endm
-;
-; my_error_handler should pop the calling address from the stack and report it.
-; putting larger portions of code (more than 3 bytes) inside the trap macro
-; may lead to branch range problems for some tests.
- if report = 0
-trap macro
- jmp * ;failed anyway
- endm
-trap_eq macro
- beq * ;failed equal (zero)
- endm
-trap_ne macro
- bne * ;failed not equal (non zero)
- endm
-; please observe that during the test the stack gets invalidated
-; therefore a RTS inside the success macro is not possible
-success macro
- jmp * ;test passed, no errors
- endm
- endif
- if report = 1
-trap macro
- jsr report_error
- endm
-trap_eq macro
- bne skip\?
- trap ;failed equal (zero)
-skip\?
- endm
-trap_ne macro
- beq skip\?
- trap ;failed not equal (non zero)
-skip\?
- endm
-; please observe that during the test the stack gets invalidated
-; therefore a RTS inside the success macro is not possible
-success macro
- jsr report_success
- endm
- endif
-
-
-carry equ %00000001 ;flag bits in status
-zero equ %00000010
-intdis equ %00000100
-decmode equ %00001000
-break equ %00010000
-reserv equ %00100000
-overfl equ %01000000
-minus equ %10000000
-
-fc equ carry
-fz equ zero
-fzc equ carry+zero
-fv equ overfl
-fvz equ overfl+zero
-fn equ minus
-fnc equ minus+carry
-fnz equ minus+zero
-fnzc equ minus+zero+carry
-fnv equ minus+overfl
-
-fao equ break+reserv ;bits always on after PHP, BRK
-fai equ fao+intdis ;+ forced interrupt disable
-m8 equ $ff ;8 bit mask
-m8i equ $ff&~intdis ;8 bit mask - interrupt disable
-
-;macros to set status
-push_stat macro ;setting flags in the processor status register
- lda #\1
- pha ;use stack to load status
- endm
-
-set_stat macro ;setting flags in the processor status register
- lda #\1
- pha ;use stack to load status
- plp
- endm
-
- if load_data_direct = 1
- data
- else
- bss ;uninitialized segment, copy of data at end of code!
- endif
- org zero_page
-;BRK, IRQ, NMI test interrupt save
-zpt
-irq_a ds 1 ;a register
-irq_x ds 1 ;x register
-irq_f ds 1 ;flags
-nmi_a ds 1 ;a register
-nmi_x ds 1 ;x register
-nmi_f ds 1 ;flags
-zp_bss
-
-;fixed stack locations
-lst_f equ $1fe ;last flags before interrupt
-lst_a equ $1ff ;last accumulator before interrupt
-
- org data_segment
-;concurrent NMI, IRQ & BRK test result
-nmi_count ds 1 ;lowest number handled first, $ff = never
-irq_count ds 1 ;separation-1 = instructions between interrupts
-brk_count ds 1
-;expected interrupt mask
-I_src ds 1 ;bit: 0=BRK, 1=IRQ, 2=NMI
-data_bss
-
- code
- org code_segment
-start cld
- lda #0 ;clear expected interrupts for 2nd run
- sta I_src
- ldx #$ff
- txs
-
-;initialize I/O for report channel
- if report = 1
- jsr report_init
- endif
-
-; load system vectors
- if load_data_direct != 1
- ldx #5
-ld_vect lda vec_init,x
- sta vec_bss,x
- dex
- bpl ld_vect
- endif
-
-; IRQ & NMI test - requires a feedback register
- if I_drive > 1
- ERROR ;invalid interrupt drive!
- endif
- if NMI_bit < 0
- if I_drive = 0 ;totem pole (push/pull, 0 -> I_port to force interrupt)
-I_set macro ibit ;ibit = interrupt bit
- lda I_port ;turn on interrupt by bit
- and #I_filter-(1<<\1)
- plp ;set flags
- pha ;save to verify
- php
- sta I_port ;interrupt next instruction plus outbound delay
- endm
-I_clr macro ibit ;ibit = interrupt bit
- lda I_port ;turn off interrupt by bit
- and #I_filter
- ora #(1< I_DDR or I_port to force interrupt
- if I_ddr != 0 ;with DDR
-I_set macro ibit ;ibit = interrupt bit
- lda I_ddr ;turn on interrupt by bit
- and #I_filter
- ora #(1<<\1)
- plp ;set flags
- pha ;save to verify
- php
- sta I_ddr ;interrupt next instruction plus outbound delay
- endm
-I_clr macro ibit ;ibit = interrupt bit
- lda I_ddr ;turn off interrupt by bit
- and #I_filter-(1< I_port to force interrupt)
-I_set macro ibit ;ibit = interrupt bit
- lda I_port ;turn on interrupt by bit
- if ibit > 7 ;set both NMI & IRQ
- and #I_filter-(1< I_DDR or I_port to force interrupt
- if I_ddr != 0 ;with DDR
-I_set macro ibit ;ibit = interrupt bit
- lda I_ddr ;turn on interrupt by bit
- and #I_filter
- if ibit > 7 ;set both NMI & IRQ
- ora #(1< 7 ;set both NMI & IRQ
- ora #(1<.
+
+
+; This program is designed to test IRQ and NMI of a 6502 emulator. It requires
+; an internal or external feedback register to the IRQ & NMI inputs
+;
+; version 15-aug-2014
+; contact info at http://2m5.de or email K@2m5.de
+;
+; assembled with AS65 from http://www.kingswood-consulting.co.uk/assemblers/
+; command line switches: -l -m -s2 -w -h0
+; | | | | no page headers in listing
+; | | | wide listing (133 char/col)
+; | | write intel hex file instead of binary
+; | expand macros in listing
+; generate pass2 listing
+;
+; No IO - should be run from a monitor with access to registers.
+; To run load intel hex image with a load command, than alter PC to 400 hex and
+; enter a go command.
+; Loop on program counter determines error or successful completion of test.
+; Check listing for relevant traps (jump/branch *).
+;
+; Debugging hints:
+; Most of the code is written sequentially. if you hit a trap, check the
+; immediately preceeding code for the instruction to be tested. Results are
+; tested first, flags are checked second by pushing them onto the stack and
+; pulling them to the accumulator after the result was checked. The "real"
+; flags are no longer valid for the tested instruction at this time!
+; If the tested instruction was indexed, the relevant index (X or Y) must
+; also be checked. Opposed to the flags, X and Y registers are still valid.
+;
+; versions:
+; 19-jul-2013 1st version distributed for testing
+; 16-aug-2013 added error report to standard output option
+; 15-aug-2014 added filter to feedback (bit 7 will cause diag stop in emu)
+
+
+; C O N F I G U R A T I O N
+;
+;ROM_vectors MUST be writable & the I_flag MUST be alterable
+
+;load_data_direct (0=move from code segment, 1=load directly)
+;loading directly is preferred but may not be supported by your platform
+;0 produces only consecutive object code, 1 is not suitable for a binary image
+load_data_direct = 1
+
+;NMI & IRQ are tested with a feedback register
+;emulators diag register - set i_drive = 0 for a latch (74HC573)
+I_port = $bffc ;feedback port address
+I_ddr = 0 ;feedback DDR address, 0 = no DDR
+I_drive = 1 ;0 = totem pole, 1 = open collector
+IRQ_bit = 0 ;bit number of feedback to IRQ
+NMI_bit = 1 ;bit number of feedback to NMI, -1 if not available
+I_filter = $7f ;filtering bit 7 = diag stop
+
+;typical IO chip port B - set i_drive = 0 to avoid pullup resistors
+;I_port = $bfb2 ;feedback port address
+;I_ddr = $bfb3 ;feedback DDR address, 0 = no DDR
+;I_drive = 1 ;0 = totem pole, 1 = open collector
+;IRQ_bit = 0 ;bit number of feedback to IRQ
+;NMI_bit = 1 ;bit number of feedback to NMI, -1 if not available
+;I_filter = $ff ;no bits filtered
+
+;decimal mode flag during IRQ, NMI & BRK
+D_clear = 0 ;0 = not cleared (NMOS), 1 = cleared (CMOS)
+
+;configure memory - try to stay away from memory used by the system
+;zero_page memory start address, 6 consecutive Bytes required
+zero_page = $0
+
+;data_segment memory start address, 4 consecutive Bytes required
+data_segment = $200
+
+;code_segment memory start address
+code_segment = $400
+
+;report errors through I/O channel (0=use standard self trap loops, 1=include
+;report.i65 as I/O channel)
+report = 1
+
+ noopt ;do not take shortcuts
+
+;macros for error & success traps to allow user modification
+;example:
+;trap macro
+; jsr my_error_handler
+; endm
+;trap_eq macro
+; bne skip\?
+; trap ;failed equal (zero)
+;skip\?
+; endm
+;
+; my_error_handler should pop the calling address from the stack and report it.
+; putting larger portions of code (more than 3 bytes) inside the trap macro
+; may lead to branch range problems for some tests.
+ if report = 0
+trap macro
+ jmp * ;failed anyway
+ endm
+trap_eq macro
+ beq * ;failed equal (zero)
+ endm
+trap_ne macro
+ bne * ;failed not equal (non zero)
+ endm
+; please observe that during the test the stack gets invalidated
+; therefore a RTS inside the success macro is not possible
+success macro
+ jmp * ;test passed, no errors
+ endm
+ endif
+ if report = 1
+trap macro
+ jsr report_error
+ endm
+trap_eq macro
+ bne skip\?
+ trap ;failed equal (zero)
+skip\?
+ endm
+trap_ne macro
+ beq skip\?
+ trap ;failed not equal (non zero)
+skip\?
+ endm
+; please observe that during the test the stack gets invalidated
+; therefore a RTS inside the success macro is not possible
+success macro
+ jsr report_success
+ endm
+ endif
+
+
+carry equ %00000001 ;flag bits in status
+zero equ %00000010
+intdis equ %00000100
+decmode equ %00001000
+break equ %00010000
+reserv equ %00100000
+overfl equ %01000000
+minus equ %10000000
+
+fc equ carry
+fz equ zero
+fzc equ carry+zero
+fv equ overfl
+fvz equ overfl+zero
+fn equ minus
+fnc equ minus+carry
+fnz equ minus+zero
+fnzc equ minus+zero+carry
+fnv equ minus+overfl
+
+fao equ break+reserv ;bits always on after PHP, BRK
+fai equ fao+intdis ;+ forced interrupt disable
+m8 equ $ff ;8 bit mask
+m8i equ $ff&~intdis ;8 bit mask - interrupt disable
+
+;macros to set status
+push_stat macro ;setting flags in the processor status register
+ lda #\1
+ pha ;use stack to load status
+ endm
+
+set_stat macro ;setting flags in the processor status register
+ lda #\1
+ pha ;use stack to load status
+ plp
+ endm
+
+ if load_data_direct = 1
+ data
+ else
+ bss ;uninitialized segment, copy of data at end of code!
+ endif
+ org zero_page
+;BRK, IRQ, NMI test interrupt save
+zpt
+irq_a ds 1 ;a register
+irq_x ds 1 ;x register
+irq_f ds 1 ;flags
+nmi_a ds 1 ;a register
+nmi_x ds 1 ;x register
+nmi_f ds 1 ;flags
+zp_bss
+
+;fixed stack locations
+lst_f equ $1fe ;last flags before interrupt
+lst_a equ $1ff ;last accumulator before interrupt
+
+ org data_segment
+;concurrent NMI, IRQ & BRK test result
+nmi_count ds 1 ;lowest number handled first, $ff = never
+irq_count ds 1 ;separation-1 = instructions between interrupts
+brk_count ds 1
+;expected interrupt mask
+I_src ds 1 ;bit: 0=BRK, 1=IRQ, 2=NMI
+data_bss
+
+ code
+ org code_segment
+start cld
+ lda #0 ;clear expected interrupts for 2nd run
+ sta I_src
+ ldx #$ff
+ txs
+
+;initialize I/O for report channel
+ if report = 1
+ jsr report_init
+ endif
+
+; load system vectors
+ if load_data_direct != 1
+ ldx #5
+ld_vect lda vec_init,x
+ sta vec_bss,x
+ dex
+ bpl ld_vect
+ endif
+
+; IRQ & NMI test - requires a feedback register
+ if I_drive > 1
+ ERROR ;invalid interrupt drive!
+ endif
+ if NMI_bit < 0
+ if I_drive = 0 ;totem pole (push/pull, 0 -> I_port to force interrupt)
+I_set macro ibit ;ibit = interrupt bit
+ lda I_port ;turn on interrupt by bit
+ and #I_filter-(1<<\1)
+ plp ;set flags
+ pha ;save to verify
+ php
+ sta I_port ;interrupt next instruction plus outbound delay
+ endm
+I_clr macro ibit ;ibit = interrupt bit
+ lda I_port ;turn off interrupt by bit
+ and #I_filter
+ ora #(1< I_DDR or I_port to force interrupt
+ if I_ddr != 0 ;with DDR
+I_set macro ibit ;ibit = interrupt bit
+ lda I_ddr ;turn on interrupt by bit
+ and #I_filter
+ ora #(1<<\1)
+ plp ;set flags
+ pha ;save to verify
+ php
+ sta I_ddr ;interrupt next instruction plus outbound delay
+ endm
+I_clr macro ibit ;ibit = interrupt bit
+ lda I_ddr ;turn off interrupt by bit
+ and #I_filter-(1< I_port to force interrupt)
+I_set macro ibit ;ibit = interrupt bit
+ lda I_port ;turn on interrupt by bit
+ if ibit > 7 ;set both NMI & IRQ
+ and #I_filter-(1< I_DDR or I_port to force interrupt
+ if I_ddr != 0 ;with DDR
+I_set macro ibit ;ibit = interrupt bit
+ lda I_ddr ;turn on interrupt by bit
+ and #I_filter
+ if ibit > 7 ;set both NMI & IRQ
+ ora #(1< 7 ;set both NMI & IRQ
+ ora #(1<.
-
-
-; This program is designed to test all additional 65C02 opcodes, addressing
-; modes and functionality not available in the NMOS version of the 6502.
-; The 6502_functional_test is a prerequisite to this test.
-; NMI, IRQ, STP & WAI are covered in the 6502_interrupt_test.
-;
-; version 04-dec-2017
-; contact info at http://2m5.de or email K@2m5.de
-;
-; assembled with AS65 from http://www.kingswood-consulting.co.uk/assemblers/
-; command line switches: -l -m -s2 -w -x -h0
-; | | | | | no page headers in listing
-; | | | | 65C02 extensions
-; | | | wide listing (133 char/col)
-; | | write intel hex file instead of binary
-; | expand macros in listing
-; generate pass2 listing
-;
-; No IO - should be run from a monitor with access to registers.
-; To run load intel hex image with a load command, than alter PC to 400 hex
-; (code_segment) and enter a go command.
-; Loop on program counter determines error or successful completion of test.
-; Check listing for relevant traps (jump/branch *).
-; Please note that in early tests some instructions will have to be used before
-; they are actually tested!
-;
-; RESET, NMI or IRQ should not occur and will be trapped if vectors are enabled.
-; Tests documented behavior of the original 65C02 only!
-; Decimal ops will only be tested with valid BCD operands and the V flag will
-; be ignored as it is absolutely useless in decimal mode.
-;
-; Debugging hints:
-; Most of the code is written sequentially. if you hit a trap, check the
-; immediately preceeding code for the instruction to be tested. Results are
-; tested first, flags are checked second by pushing them onto the stack and
-; pulling them to the accumulator after the result was checked. The "real"
-; flags are no longer valid for the tested instruction at this time!
-; If the tested instruction was indexed, the relevant index (X or Y) must
-; also be checked. Opposed to the flags, X and Y registers are still valid.
-;
-; versions:
-; 19-jul-2013 1st version distributed for testing
-; 23-jul-2013 fixed BRA out of range due to larger trap macros
-; added RAM integrity check
-; 16-aug-2013 added error report to standard output option
-; 23-aug-2015 change revoked
-; 24-aug-2015 all self modifying immediate opcodes now execute in data RAM
-; 28-aug-2015 fixed decimal adc/sbc immediate only testing carry
-; 09-feb-2017 fixed RMB/SMB tested when they shouldn't be tested
-; 04-dec-2017 fixed BRK not tested for actually going through the IRQ vector
-; added option to skip the remainder of a failing test
-; in report.i65
-; added skip override to undefined opcode as NOP test
-
-
-; C O N F I G U R A T I O N
-
-;ROM_vectors writable (0=no, 1=yes)
-;if ROM vectors can not be used interrupts will not be trapped
-;as a consequence BRK can not be tested but will be emulated to test RTI
-ROM_vectors = 1
-
-;load_data_direct (0=move from code segment, 1=load directly)
-;loading directly is preferred but may not be supported by your platform
-;0 produces only consecutive object code, 1 is not suitable for a binary image
-load_data_direct = 1
-
-;I_flag behavior (0=force enabled, 1=force disabled, 2=prohibit change, 3=allow
-;change) 2 requires extra code and is not recommended.
-I_flag = 3
-
-;configure memory - try to stay away from memory used by the system
-;zero_page memory start address, $4e (78) consecutive Bytes required
-; add 2 if I_flag = 2
-zero_page = $a
-
-;data_segment memory start address, $63 (99) consecutive Bytes required
-; + 12 Bytes at data_segment + $f9 (JMP indirect page cross test)
-data_segment = $200
- if (data_segment & $ff) != 0
- ERROR ERROR ERROR low byte of data_segment MUST be $00 !!
- endif
-
-;code_segment memory start address, 10kB of consecutive space required
-; add 1 kB if I_flag = 2
-code_segment = $400
-
-;added WDC only opcodes WAI & STP (0=test as NOPs, >0=no test)
-wdc_op = 1
-
-;added Rockwell & WDC opcodes BBR, BBS, RMB & SMB
-;(0=test as NOPs, 1=full test, >1=no test)
-rkwl_wdc_op = 1
-
-;skip testing all undefined opcodes override
-;0=test as NOP, >0=skip
-skip_nop = 0
-
-;report errors through I/O channel (0=use standard self trap loops, 1=include
-;report.i65 as I/O channel, add 3 kB)
-report = 0
-
-;RAM integrity test option. Checks for undesired RAM writes.
-;set lowest non RAM or RAM mirror address page (-1=disable, 0=64k, $40=16k)
-;leave disabled if a monitor, OS or background interrupt is allowed to alter RAM
-ram_top = -1
-
- noopt ;do not take shortcuts
-
-;macros for error & success traps to allow user modification
-;example:
-;trap macro
-; jsr my_error_handler
-; endm
-;trap_eq macro
-; bne skip\?
-; trap ;failed equal (zero)
-;skip\?
-; endm
-;
-; my_error_handler should pop the calling address from the stack and report it.
-; putting larger portions of code (more than 3 bytes) inside the trap macro
-; may lead to branch range problems for some tests.
- if report = 0
-trap macro
- jmp * ;failed anyway
- endm
-trap_eq macro
- beq * ;failed equal (zero)
- endm
-trap_ne macro
- bne * ;failed not equal (non zero)
- endm
-trap_cs macro
- bcs * ;failed carry set
- endm
-trap_cc macro
- bcc * ;failed carry clear
- endm
-trap_mi macro
- bmi * ;failed minus (bit 7 set)
- endm
-trap_pl macro
- bpl * ;failed plus (bit 7 clear)
- endm
-trap_vs macro
- bvs * ;failed overflow set
- endm
-trap_vc macro
- bvc * ;failed overflow clear
- endm
-; please observe that during the test the stack gets invalidated
-; therefore a RTS inside the success macro is not possible
-success macro
- jmp * ;test passed, no errors
- endm
- endif
- if report = 1
-trap macro
- jsr report_error
- endm
-trap_eq macro
- bne skip\?
- trap ;failed equal (zero)
-skip\?
- endm
-trap_ne macro
- beq skip\?
- trap ;failed not equal (non zero)
-skip\?
- endm
-trap_cs macro
- bcc skip\?
- trap ;failed carry set
-skip\?
- endm
-trap_cc macro
- bcs skip\?
- trap ;failed carry clear
-skip\?
- endm
-trap_mi macro
- bpl skip\?
- trap ;failed minus (bit 7 set)
-skip\?
- endm
-trap_pl macro
- bmi skip\?
- trap ;failed plus (bit 7 clear)
-skip\?
- endm
-trap_vs macro
- bvc skip\?
- trap ;failed overflow set
-skip\?
- endm
-trap_vc macro
- bvs skip\?
- trap ;failed overflow clear
-skip\?
- endm
-; please observe that during the test the stack gets invalidated
-; therefore a RTS inside the success macro is not possible
-success macro
- jsr report_success
- endm
- endif
-
-
-carry equ %00000001 ;flag bits in status
-zero equ %00000010
-intdis equ %00000100
-decmode equ %00001000
-break equ %00010000
-reserv equ %00100000
-overfl equ %01000000
-minus equ %10000000
-
-fc equ carry
-fz equ zero
-fzc equ carry+zero
-fv equ overfl
-fvz equ overfl+zero
-fn equ minus
-fnc equ minus+carry
-fnz equ minus+zero
-fnzc equ minus+zero+carry
-fnv equ minus+overfl
-
-fao equ break+reserv ;bits always on after PHP, BRK
-fai equ fao+intdis ;+ forced interrupt disable
-m8 equ $ff ;8 bit mask
-m8i equ $ff&~intdis ;8 bit mask - interrupt disable
-
-;macros to allow masking of status bits.
-;masking of interrupt enable/disable on load and compare
-;masking of always on bits after PHP or BRK (unused & break) on compare
- if I_flag = 0
-load_flag macro
- lda #\1&m8i ;force enable interrupts (mask I)
- endm
-cmp_flag macro
- cmp #(\1|fao)&m8i ;I_flag is always enabled + always on bits
- endm
-eor_flag macro
- eor #(\1&m8i|fao) ;mask I, invert expected flags + always on bits
- endm
- endif
- if I_flag = 1
-load_flag macro
- lda #\1|intdis ;force disable interrupts
- endm
-cmp_flag macro
- cmp #(\1|fai)&m8 ;I_flag is always disabled + always on bits
- endm
-eor_flag macro
- eor #(\1|fai) ;invert expected flags + always on bits + I
- endm
- endif
- if I_flag = 2
-load_flag macro
- lda #\1
- ora flag_I_on ;restore I-flag
- and flag_I_off
- endm
-cmp_flag macro
- eor flag_I_on ;I_flag is never changed
- cmp #(\1|fao)&m8i ;expected flags + always on bits, mask I
- endm
-eor_flag macro
- eor flag_I_on ;I_flag is never changed
- eor #(\1&m8i|fao) ;mask I, invert expected flags + always on bits
- endm
- endif
- if I_flag = 3
-load_flag macro
- lda #\1 ;allow test to change I-flag (no mask)
- endm
-cmp_flag macro
- cmp #(\1|fao)&m8 ;expected flags + always on bits
- endm
-eor_flag macro
- eor #\1|fao ;invert expected flags + always on bits
- endm
- endif
-
-;macros to set (register|memory|zeropage) & status
-set_stat macro ;setting flags in the processor status register
- load_flag \1
- pha ;use stack to load status
- plp
- endm
-
-set_a macro ;precharging accu & status
- load_flag \2
- pha ;use stack to load status
- lda #\1 ;precharge accu
- plp
- endm
-
-set_x macro ;precharging index & status
- load_flag \2
- pha ;use stack to load status
- ldx #\1 ;precharge index x
- plp
- endm
-
-set_y macro ;precharging index & status
- load_flag \2
- pha ;use stack to load status
- ldy #\1 ;precharge index y
- plp
- endm
-
-set_ax macro ;precharging indexed accu & immediate status
- load_flag \2
- pha ;use stack to load status
- lda \1,x ;precharge accu
- plp
- endm
-
-set_ay macro ;precharging indexed accu & immediate status
- load_flag \2
- pha ;use stack to load status
- lda \1,y ;precharge accu
- plp
- endm
-
-set_z macro ;precharging indexed zp & immediate status
- load_flag \2
- pha ;use stack to load status
- lda \1,x ;load to zeropage
- sta zpt
- plp
- endm
-
-set_zx macro ;precharging zp,x & immediate status
- load_flag \2
- pha ;use stack to load status
- lda \1,x ;load to indexed zeropage
- sta zpt,x
- plp
- endm
-
-set_abs macro ;precharging indexed memory & immediate status
- load_flag \2
- pha ;use stack to load status
- lda \1,x ;load to memory
- sta abst
- plp
- endm
-
-set_absx macro ;precharging abs,x & immediate status
- load_flag \2
- pha ;use stack to load status
- lda \1,x ;load to indexed memory
- sta abst,x
- plp
- endm
-
-;macros to test (register|memory|zeropage) & status & (mask)
-tst_stat macro ;testing flags in the processor status register
- php ;save status
- pla ;use stack to retrieve status
- pha
- cmp_flag \1
- trap_ne
- plp ;restore status
- endm
-
-tst_a macro ;testing result in accu & flags
- php ;save flags
- cmp #\1 ;test result
- trap_ne
- pla ;load status
- pha
- cmp_flag \2
- trap_ne
- plp ;restore status
- endm
-
-tst_as macro ;testing result in accu & flags, save accu
- pha
- php ;save flags
- cmp #\1 ;test result
- trap_ne
- pla ;load status
- pha
- cmp_flag \2
- trap_ne
- plp ;restore status
- pla
- endm
-
-tst_x macro ;testing result in x index & flags
- php ;save flags
- cpx #\1 ;test result
- trap_ne
- pla ;load status
- pha
- cmp_flag \2
- trap_ne
- plp ;restore status
- endm
-
-tst_y macro ;testing result in y index & flags
- php ;save flags
- cpy #\1 ;test result
- trap_ne
- pla ;load status
- pha
- cmp_flag \2
- trap_ne
- plp ;restore status
- endm
-
-tst_ax macro ;indexed testing result in accu & flags
- php ;save flags
- cmp \1,x ;test result
- trap_ne
- pla ;load status
- eor_flag \3
- cmp \2,x ;test flags
- trap_ne ;
- endm
-
-tst_ay macro ;indexed testing result in accu & flags
- php ;save flags
- cmp \1,y ;test result
- trap_ne ;
- pla ;load status
- eor_flag \3
- cmp \2,y ;test flags
- trap_ne
- endm
-
-tst_z macro ;indexed testing result in zp & flags
- php ;save flags
- lda zpt
- cmp \1,x ;test result
- trap_ne
- pla ;load status
- eor_flag \3
- cmp \2,x ;test flags
- trap_ne
- endm
-
-tst_zx macro ;testing result in zp,x & flags
- php ;save flags
- lda zpt,x
- cmp \1,x ;test result
- trap_ne
- pla ;load status
- eor_flag \3
- cmp \2,x ;test flags
- trap_ne
- endm
-
-tst_abs macro ;indexed testing result in memory & flags
- php ;save flags
- lda abst
- cmp \1,x ;test result
- trap_ne
- pla ;load status
- eor_flag \3
- cmp \2,x ;test flags
- trap_ne
- endm
-
-tst_absx macro ;testing result in abs,x & flags
- php ;save flags
- lda abst,x
- cmp \1,x ;test result
- trap_ne
- pla ;load status
- eor_flag \3
- cmp \2,x ;test flags
- trap_ne
- endm
-
-; RAM integrity test
-; verifies that none of the previous tests has altered RAM outside of the
-; designated write areas.
-; uses zpt word as indirect pointer, zpt+2 word as checksum
- if ram_top > -1
-check_ram macro
- cld
- lda #0
- sta zpt ;set low byte of indirect pointer
- sta zpt+3 ;checksum high byte
- ldx #11 ;reset modifiable RAM
-ccs1\? sta jxi_tab,x ;JMP indirect page cross area
- dex
- bpl ccs1\?
- clc
- ldx #zp_bss-zero_page ;zeropage - write test area
-ccs3\? adc zero_page,x
- bcc ccs2\?
- inc zpt+3 ;carry to high byte
- clc
-ccs2\? inx
- bne ccs3\?
- ldx #hi(abs1) ;set high byte of indirect pointer
- stx zpt+1
- ldy #lo(abs1) ;data after write & execute test area
-ccs5\? adc (zpt),y
- bcc ccs4\?
- inc zpt+3 ;carry to high byte
- clc
-ccs4\? iny
- bne ccs5\?
- inx ;advance RAM high address
- stx zpt+1
- cpx #ram_top
- bne ccs5\?
- sta zpt+2 ;checksum low is
- cmp ram_chksm ;checksum low expected
- trap_ne ;checksum mismatch
- lda zpt+3 ;checksum high is
- cmp ram_chksm+1 ;checksum high expected
- trap_ne ;checksum mismatch
- endm
- else
-check_ram macro
- ;RAM check disabled - RAM size not set
- endm
- endif
-
-next_test macro ;make sure, tests don't jump the fence
- lda test_case ;previous test
- cmp #test_num
- trap_ne ;test is out of sequence
-test_num = test_num + 1
- lda #test_num ;*** next tests' number
- sta test_case
- ;check_ram ;uncomment to find altered RAM after each test
- endm
-
- if load_data_direct = 1
- data
- else
- bss ;uninitialized segment, copy of data at end of code!
- endif
- org zero_page
-;break test interrupt save
-irq_a ds 1 ;a register
-irq_x ds 1 ;x register
- if I_flag = 2
-;masking for I bit in status
-flag_I_on ds 1 ;or mask to load flags
-flag_I_off ds 1 ;and mask to load flags
- endif
-zpt ;5 bytes store/modify test area
-;add/subtract operand generation and result/flag prediction
-adfc ds 1 ;carry flag before op
-ad1 ds 1 ;operand 1 - accumulator
-ad2 ds 1 ;operand 2 - memory / immediate
-adrl ds 1 ;expected result bits 0-7
-adrh ds 1 ;expected result bit 8 (carry)
-adrf ds 1 ;expected flags NV0000ZC (-V in decimal mode)
-sb2 ds 1 ;operand 2 complemented for subtract
-zp_bss
-zp1 db $c3,$82,$41,0 ;test patterns for LDx BIT ROL ROR ASL LSR
-zp7f db $7f ;test pattern for compare
-;logical zeropage operands
-zpOR db 0,$1f,$71,$80 ;test pattern for OR
-zpAN db $0f,$ff,$7f,$80 ;test pattern for AND
-zpEO db $ff,$0f,$8f,$8f ;test pattern for EOR
-;indirect addressing pointers
-ind1 dw abs1 ;indirect pointer to pattern in absolute memory
- dw abs1+1
- dw abs1+2
- dw abs1+3
- dw abs7f
-inw1 dw abs1-$f8 ;indirect pointer for wrap-test pattern
-indt dw abst ;indirect pointer to store area in absolute memory
- dw abst+1
- dw abst+2
- dw abst+3
-inwt dw abst-$f8 ;indirect pointer for wrap-test store
-indAN dw absAN ;indirect pointer to AND pattern in absolute memory
- dw absAN+1
- dw absAN+2
- dw absAN+3
-indEO dw absEO ;indirect pointer to EOR pattern in absolute memory
- dw absEO+1
- dw absEO+2
- dw absEO+3
-indOR dw absOR ;indirect pointer to OR pattern in absolute memory
- dw absOR+1
- dw absOR+2
- dw absOR+3
-;add/subtract indirect pointers
-adi2 dw ada2 ;indirect pointer to operand 2 in absolute memory
-sbi2 dw sba2 ;indirect pointer to complemented operand 2 (SBC)
-adiy2 dw ada2-$ff ;with offset for indirect indexed
-sbiy2 dw sba2-$ff
-zp_bss_end
-
- org data_segment
-pg_x ds 2 ;high JMP indirect address for page cross bug
-test_case ds 1 ;current test number
-ram_chksm ds 2 ;checksum for RAM integrity test
-;add/subtract operand copy - abs tests write area
-abst ;5 bytes store/modify test area
-ada2 ds 1 ;operand 2
-sba2 ds 1 ;operand 2 complemented for subtract
- ds 3 ;fill remaining bytes
-data_bss
- if load_data_direct = 1
-ex_adci adc #0 ;execute immediate opcodes
- rts
-ex_sbci sbc #0 ;execute immediate opcodes
- rts
- else
-ex_adci ds 3
-ex_sbci ds 3
- endif
-abs1 db $c3,$82,$41,0 ;test patterns for LDx BIT ROL ROR ASL LSR
-abs7f db $7f ;test pattern for compare
-;loads
-fLDx db fn,fn,0,fz ;expected flags for load
-;shifts
-rASL ;expected result ASL & ROL -carry
-rROL db $86,$04,$82,0 ; "
-rROLc db $87,$05,$83,1 ;expected result ROL +carry
-rLSR ;expected result LSR & ROR -carry
-rROR db $61,$41,$20,0 ; "
-rRORc db $e1,$c1,$a0,$80 ;expected result ROR +carry
-fASL ;expected flags for shifts
-fROL db fnc,fc,fn,fz ;no carry in
-fROLc db fnc,fc,fn,0 ;carry in
-fLSR
-fROR db fc,0,fc,fz ;no carry in
-fRORc db fnc,fn,fnc,fn ;carry in
-;increments (decrements)
-rINC db $7f,$80,$ff,0,1 ;expected result for INC/DEC
-fINC db 0,fn,fn,fz,0 ;expected flags for INC/DEC
-;logical memory operand
-absOR db 0,$1f,$71,$80 ;test pattern for OR
-absAN db $0f,$ff,$7f,$80 ;test pattern for AND
-absEO db $ff,$0f,$8f,$8f ;test pattern for EOR
-;logical accu operand
-absORa db 0,$f1,$1f,0 ;test pattern for OR
-absANa db $f0,$ff,$ff,$ff ;test pattern for AND
-absEOa db $ff,$f0,$f0,$0f ;test pattern for EOR
-;logical results
-absrlo db 0,$ff,$7f,$80
-absflo db fz,fn,0,fn
-data_bss_end
-;define area for page crossing JMP (abs) & JMP (abs,x) test
-jxi_tab equ data_segment + $100 - 7 ;JMP (jxi_tab,x) x=6
-ji_tab equ data_segment + $100 - 3 ;JMP (ji_tab+2)
-jxp_tab equ data_segment + $100 ;JMP (jxp_tab-255) x=255
-
-
- code
- org code_segment
-start cld
- ldx #$ff
- txs
- lda #0 ;*** test 0 = initialize
- sta test_case
-test_num = 0
-
-;stop interrupts before initializing BSS
- if I_flag = 1
- sei
- endif
-
-;initialize I/O for report channel
- if report = 1
- jsr report_init
- endif
-
-;initialize BSS segment
- if load_data_direct != 1
- ldx #zp_end-zp_init-1
-ld_zp lda zp_init,x
- sta zp_bss,x
- dex
- bpl ld_zp
- ldx #data_end-data_init-1
-ld_data lda data_init,x
- sta data_bss,x
- dex
- bpl ld_data
- if ROM_vectors = 1
- ldx #5
-ld_vect lda vec_init,x
- sta vec_bss,x
- dex
- bpl ld_vect
- endif
- endif
-
-;retain status of interrupt flag
- if I_flag = 2
- php
- pla
- and #4 ;isolate flag
- sta flag_I_on ;or mask
- eor #lo(~4) ;reverse
- sta flag_I_off ;and mask
- endif
-
-;generate checksum for RAM integrity test
- if ram_top > -1
- lda #0
- sta zpt ;set low byte of indirect pointer
- sta ram_chksm+1 ;checksum high byte
- ldx #11 ;reset modifiable RAM
-gcs1 sta jxi_tab,x ;JMP indirect page cross area
- dex
- bpl gcs1
- clc
- ldx #zp_bss-zero_page ;zeropage - write test area
-gcs3 adc zero_page,x
- bcc gcs2
- inc ram_chksm+1 ;carry to high byte
- clc
-gcs2 inx
- bne gcs3
- ldx #hi(abs1) ;set high byte of indirect pointer
- stx zpt+1
- ldy #lo(abs1) ;data after write & execute test area
-gcs5 adc (zpt),y
- bcc gcs4
- inc ram_chksm+1 ;carry to high byte
- clc
-gcs4 iny
- bne gcs5
- inx ;advance RAM high address
- stx zpt+1
- cpx #ram_top
- bne gcs5
- sta ram_chksm ;checksum complete
- endif
- next_test
-
-;testing stack operations PHX PHY PLX PLY
- lda #$99 ;protect a
- ldx #$ff ;initialize stack
- txs
- ldx #$55
- phx
- ldx #$aa
- phx
- cpx $1fe ;on stack ?
- trap_ne
- tsx
- cpx #$fd ;sp decremented?
- trap_ne
- ply
- cpy #$aa ;successful retreived from stack?
- trap_ne
- ply
- cpy #$55
- trap_ne
- cpy $1ff ;remains on stack?
- trap_ne
- tsx
- cpx #$ff ;sp incremented?
- trap_ne
-
- ldy #$a5
- phy
- ldy #$5a
- phy
- cpy $1fe ;on stack ?
- trap_ne
- tsx
- cpx #$fd ;sp decremented?
- trap_ne
- plx
- cpx #$5a ;successful retreived from stack?
- trap_ne
- plx
- cpx #$a5
- trap_ne
- cpx $1ff ;remains on stack?
- trap_ne
- tsx
- cpx #$ff ;sp incremented?
- trap_ne
- cmp #$99 ;unchanged?
- trap_ne
- next_test
-
-; test PHX does not alter flags or X but PLX does
- ldy #$aa ;protect y
- set_x 1,$ff ;push
- phx
- tst_x 1,$ff
- set_x 0,0
- phx
- tst_x 0,0
- set_x $ff,$ff
- phx
- tst_x $ff,$ff
- set_x 1,0
- phx
- tst_x 1,0
- set_x 0,$ff
- phx
- tst_x 0,$ff
- set_x $ff,0
- phx
- tst_x $ff,0
- set_x 0,$ff ;pull
- plx
- tst_x $ff,$ff-zero
- set_x $ff,0
- plx
- tst_x 0,zero
- set_x $fe,$ff
- plx
- tst_x 1,$ff-zero-minus
- set_x 0,0
- plx
- tst_x $ff,minus
- set_x $ff,$ff
- plx
- tst_x 0,$ff-minus
- set_x $fe,0
- plx
- tst_x 1,0
- cpy #$aa ;Y unchanged
- trap_ne
- next_test
-
-; test PHY does not alter flags or Y but PLY does
- ldx #$55 ;x & a protected
- set_y 1,$ff ;push
- phy
- tst_y 1,$ff
- set_y 0,0
- phy
- tst_y 0,0
- set_y $ff,$ff
- phy
- tst_y $ff,$ff
- set_y 1,0
- phy
- tst_y 1,0
- set_y 0,$ff
- phy
- tst_y 0,$ff
- set_y $ff,0
- phy
- tst_y $ff,0
- set_y 0,$ff ;pull
- ply
- tst_y $ff,$ff-zero
- set_y $ff,0
- ply
- tst_y 0,zero
- set_y $fe,$ff
- ply
- tst_y 1,$ff-zero-minus
- set_y 0,0
- ply
- tst_y $ff,minus
- set_y $ff,$ff
- ply
- tst_y 0,$ff-minus
- set_y $fe,0
- ply
- tst_y 1,0
- cpx #$55 ;x unchanged?
- trap_ne
- next_test
-
-; PC modifying instructions (BRA, BBR, BBS, 1, 2, 3 byte NOPs, JMP(abs,x))
-; testing unconditional branch BRA
-
- ldx #$81 ;protect unused registers
- ldy #$7e
- set_a 0,$ff
- bra br1 ;branch should always be taken
- trap
-br1
- tst_a 0,$ff
- set_a $ff,0
- bra br2 ;branch should always be taken
- trap
-br2
- tst_a $ff,0
- cpx #$81
- trap_ne
- cpy #$7e
- trap_ne
- next_test
-
- ldy #0 ;branch range test
- bra bra0
-
-bra1 cpy #1
- trap_ne ;long range backward
- iny
- bra bra2
-
-bra3 cpy #3
- trap_ne ;long range backward
- iny
- bra bra4
-
-bra5 cpy #5
- trap_ne ;long range backward
- iny
- ldy #0
- bra brf0
-
- iny
- iny
- iny
- iny
-brf0 bra brf1
-
- iny
- iny
- iny
-brf1 iny
- bra brf2
-
- iny
- iny
-brf2 iny
- iny
- bra brf3
-
- iny
-brf3 iny
- iny
- iny
- bra brf4
-
-brf4 iny
- iny
- iny
- iny
- cpy #10
- trap_ne ;short range forward
- bra brb0
-
-brb4 dey
- dey
- dey
- dey
- bra brb5
-
-brb3 dey
- dey
- dey
- bra brb4
-
-brb2 dey
- dey
- bra brb3
-
-brb1 dey
- bra brb2
-
-brb0 bra brb1
-
-brb5 cpy #0
- trap_ne ;short range backward
- bra bra6
-
-bra4 cpy #4
- trap_ne ;long range forward
- iny
- bra bra5
-
-bra2 cpy #2
- trap_ne ;long range forward
- iny
- bra bra3
-
-bra0 cpy #0
- trap_ne ;long range forward
- iny
- bra bra1
-
-bra6
- next_test
-
- if rkwl_wdc_op = 1
-; testing BBR & BBS
-
-bbt macro ;\1 = bitnum
- lda #(1<<\1) ;testing 1 bit on
- sta zpt
- set_a $33,0 ;with flags off
- bbr \1,zpt,fail1\?
- bbs \1,zpt,ok1\?
- trap ;bbs branch not taken
-fail1\?
- trap ;bbr branch taken
-ok1\?
- tst_a $33,0
- set_a $cc,$ff ;with flags on
- bbr \1,zpt,fail2\?
- bbs \1,zpt,ok2\?
- trap ;bbs branch not taken
-fail2\?
- trap ;bbr branch taken
-ok2\?
- tst_a $cc,$ff
- lda zpt
- cmp #(1<<\1)
- trap_ne ;zp altered
- lda #$ff-(1<<\1) ;testing 1 bit off
- sta zpt
- set_a $33,0 ;with flags off
- bbs \1,zpt,fail3\?
- bbr \1,zpt,ok3\?
- trap ;bbr branch not taken
-fail3\?
- trap ;bbs branch taken
-ok3\?
- tst_a $33,0
- set_a $cc,$ff ;with flags on
- bbs \1,zpt,fail4\?
- bbr \1,zpt,ok4\?
- trap ;bbr branch not taken
-fail4\?
- trap ;bbs branch taken
-ok4\?
- tst_a $cc,$ff
- lda zpt
- cmp #$ff-(1<<\1)
- trap_ne ;zp altered
- endm
-
- ldx #$11 ;test bbr/bbs integrity
- ldy #$22
- bbt 0
- bbt 1
- bbt 2
- bbt 3
- bbt 4
- bbt 5
- bbt 6
- bbt 7
- cpx #$11
- trap_ne ;x overwritten
- cpy #$22
- trap_ne ;y overwritten
- next_test
-
-bbrc macro ;\1 = bitnum
- bbr \1,zpt,skip\?
- eor #(1<<\1)
-skip\?
- endm
-bbsc macro ;\1 = bitnum
- bbs \1,zpt,skip\?
- eor #(1<<\1)
-skip\?
- endm
-
- lda #0 ;combined bit test
- sta zpt
-bbcl lda #0
- bbrc 0
- bbrc 1
- bbrc 2
- bbrc 3
- bbrc 4
- bbrc 5
- bbrc 6
- bbrc 7
- eor zpt
- trap_ne ;failed bbr bitnum in accu
- lda #$ff
- bbsc 0
- bbsc 1
- bbsc 2
- bbsc 3
- bbsc 4
- bbsc 5
- bbsc 6
- bbsc 7
- eor zpt
- trap_ne ;failed bbs bitnum in accu
- inc zpt
- bne bbcl
- next_test
- endif
-
-; testing NOP
-
-nop_test macro ;\1 = opcode, \2 = # of bytes
- ldy #$42
- ldx #4-\2
- db \1 ;test nop length
- if \2 = 1
- dex
- dex
- endif
- if \2 = 2
- iny
- dex
- endif
- if \2 = 3
- iny
- iny
- endif
- dex
- trap_ne ;wrong number of bytes
- set_a $ff-\1,0
- db \1 ;test nop integrity - flags off
- nop
- nop
- tst_a $ff-\1,0
- set_a $aa-\1,$ff
- db \1 ;test nop integrity - flags on
- nop
- nop
- tst_a $aa-\1,$ff
- cpy #$42
- trap_ne ;y changed
- cpx #0
- trap_ne ;x changed
- endm
-
- if skip_nop = 0
- nop_test $02,2
- nop_test $22,2
- nop_test $42,2
- nop_test $62,2
- nop_test $82,2
- nop_test $c2,2
- nop_test $e2,2
- nop_test $44,2
- nop_test $54,2
- nop_test $d4,2
- nop_test $f4,2
- nop_test $5c,3
- nop_test $dc,3
- nop_test $fc,3
- nop_test $03,1
- nop_test $13,1
- nop_test $23,1
- nop_test $33,1
- nop_test $43,1
- nop_test $53,1
- nop_test $63,1
- nop_test $73,1
- nop_test $83,1
- nop_test $93,1
- nop_test $a3,1
- nop_test $b3,1
- nop_test $c3,1
- nop_test $d3,1
- nop_test $e3,1
- nop_test $f3,1
- nop_test $0b,1
- nop_test $1b,1
- nop_test $2b,1
- nop_test $3b,1
- nop_test $4b,1
- nop_test $5b,1
- nop_test $6b,1
- nop_test $7b,1
- nop_test $8b,1
- nop_test $9b,1
- nop_test $ab,1
- nop_test $bb,1
- nop_test $eb,1
- nop_test $fb,1
- if rkwl_wdc_op = 0 ;NOPs not available on Rockwell & WDC 65C02
- nop_test $07,1
- nop_test $17,1
- nop_test $27,1
- nop_test $37,1
- nop_test $47,1
- nop_test $57,1
- nop_test $67,1
- nop_test $77,1
- nop_test $87,1
- nop_test $97,1
- nop_test $a7,1
- nop_test $b7,1
- nop_test $c7,1
- nop_test $d7,1
- nop_test $e7,1
- nop_test $f7,1
- nop_test $0f,1
- nop_test $1f,1
- nop_test $2f,1
- nop_test $3f,1
- nop_test $4f,1
- nop_test $5f,1
- nop_test $6f,1
- nop_test $7f,1
- nop_test $8f,1
- nop_test $9f,1
- nop_test $af,1
- nop_test $bf,1
- nop_test $cf,1
- nop_test $df,1
- nop_test $ef,1
- nop_test $ff,1
- endif
- if wdc_op = 0 ;NOPs not available on WDC 65C02 (WAI, STP)
- nop_test $cb,1
- nop_test $db,1
- endif
- next_test
- endif
-
-; jump indirect (test page cross bug is fixed)
- ldx #3 ;prepare table
-ji1 lda ji_adr,x
- sta ji_tab,x
- dex
- bpl ji1
- lda #hi(ji_px) ;high address if page cross bug
- sta pg_x
- set_stat 0
- lda #'I'
- ldx #'N'
- ldy #'D' ;N=0, V=0, Z=0, C=0
- jmp (ji_tab)
- nop
- trap_ne ;runover protection
-
- dey
- dey
-ji_ret php ;either SP or Y count will fail, if we do not hit
- dey
- dey
- dey
- plp
- trap_eq ;returned flags OK?
- trap_pl
- trap_cc
- trap_vc
- cmp #('I'^$aa) ;returned registers OK?
- trap_ne
- cpx #('N'+1)
- trap_ne
- cpy #('D'-6)
- trap_ne
- tsx ;SP check
- cpx #$ff
- trap_ne
- next_test
-
-; jump indexed indirect
- ldx #11 ;prepare table
-jxi1 lda jxi_adr,x
- sta jxi_tab,x
- dex
- bpl jxi1
- lda #hi(jxi_px) ;high address if page cross bug
- sta pg_x
- set_stat 0
- lda #'X'
- ldx #4
- ldy #'I' ;N=0, V=0, Z=0, C=0
- jmp (jxi_tab,x)
- nop
- trap_ne ;runover protection
-
- dey
- dey
-jxi_ret php ;either SP or Y count will fail, if we do not hit
- dey
- dey
- dey
- plp
- trap_eq ;returned flags OK?
- trap_pl
- trap_cc
- trap_vc
- cmp #('X'^$aa) ;returned registers OK?
- trap_ne
- cpx #6
- trap_ne
- cpy #('I'-6)
- trap_ne
- tsx ;SP check
- cpx #$ff
- trap_ne
-
- lda #lo(jxp_ok) ;test with index causing a page cross
- sta jxp_tab
- lda #hi(jxp_ok)
- sta jxp_tab+1
- lda #lo(jxp_px)
- sta pg_x
- lda #hi(jxp_px)
- sta pg_x+1
- ldx #$ff
- jmp (jxp_tab-$ff,x)
-
-jxp_px
- trap ;page cross by index to wrong page
-
-jxp_ok
- next_test
-
- if ROM_vectors = 1
-; test BRK clears decimal mode
- load_flag 0 ;with interrupts enabled if allowed!
- pha
- lda #'B'
- ldx #'R'
- ldy #'K'
- plp ;N=0, V=0, Z=0, C=0
- brk
- dey ;should not be executed
-brk_ret0 ;address of break return
- php ;either SP or Y count will fail, if we do not hit
- dey
- dey
- dey
- cmp #'B'^$aa ;returned registers OK?
- ;the IRQ vector was never executed if A & X stay unmodified
- trap_ne
- cpx #'R'+1
- trap_ne
- cpy #'K'-6
- trap_ne
- pla ;returned flags OK (unchanged)?
- cmp_flag 0
- trap_ne
- tsx ;sp?
- cpx #$ff
- trap_ne
-;pass 2
- load_flag $ff ;with interrupts disabled if allowed!
- pha
- lda #$ff-'B'
- ldx #$ff-'R'
- ldy #$ff-'K'
- plp ;N=1, V=1, Z=1, C=1
- brk
- dey ;should not be executed
-brk_ret1 ;address of break return
- php ;either SP or Y count will fail, if we do not hit
- dey
- dey
- dey
- cmp #($ff-'B')^$aa ;returned registers OK?
- ;the IRQ vector was never executed if A & X stay unmodified
- trap_ne
- cpx #$ff-'R'+1
- trap_ne
- cpy #$ff-'K'-6
- trap_ne
- pla ;returned flags OK (unchanged)?
- cmp_flag $ff
- trap_ne
- tsx ;sp?
- cpx #$ff
- trap_ne
- next_test
- endif
-
-; testing accumulator increment/decrement INC A & DEC A
- ldx #$ac ;protect x & y
- ldy #$dc
- set_a $fe,$ff
- inc a ;ff
- tst_as $ff,$ff-zero
- inc a ;00
- tst_as 0,$ff-minus
- inc a ;01
- tst_as 1,$ff-minus-zero
- dec a ;00
- tst_as 0,$ff-minus
- dec a ;ff
- tst_as $ff,$ff-zero
- dec a ;fe
- set_a $fe,0
- inc a ;ff
- tst_as $ff,minus
- inc a ;00
- tst_as 0,zero
- inc a ;01
- tst_as 1,0
- dec a ;00
- tst_as 0,zero
- dec a ;ff
- tst_as $ff,minus
- cpx #$ac
- trap_ne ;x altered during test
- cpy #$dc
- trap_ne ;y altered during test
- tsx
- cpx #$ff
- trap_ne ;sp push/pop mismatch
- next_test
-
-; testing load / store accumulator LDA / STA (zp)
- ldx #$99 ;protect x & y
- ldy #$66
- set_stat 0
- lda (ind1)
- php ;test stores do not alter flags
- eor #$c3
- plp
- sta (indt)
- php ;flags after load/store sequence
- eor #$c3
- cmp #$c3 ;test result
- trap_ne
- pla ;load status
- eor_flag 0
- cmp fLDx ;test flags
- trap_ne
- set_stat 0
- lda (ind1+2)
- php ;test stores do not alter flags
- eor #$c3
- plp
- sta (indt+2)
- php ;flags after load/store sequence
- eor #$c3
- cmp #$82 ;test result
- trap_ne
- pla ;load status
- eor_flag 0
- cmp fLDx+1 ;test flags
- trap_ne
- set_stat 0
- lda (ind1+4)
- php ;test stores do not alter flags
- eor #$c3
- plp
- sta (indt+4)
- php ;flags after load/store sequence
- eor #$c3
- cmp #$41 ;test result
- trap_ne
- pla ;load status
- eor_flag 0
- cmp fLDx+2 ;test flags
- trap_ne
- set_stat 0
- lda (ind1+6)
- php ;test stores do not alter flags
- eor #$c3
- plp
- sta (indt+6)
- php ;flags after load/store sequence
- eor #$c3
- cmp #0 ;test result
- trap_ne
- pla ;load status
- eor_flag 0
- cmp fLDx+3 ;test flags
- trap_ne
- cpx #$99
- trap_ne ;x altered during test
- cpy #$66
- trap_ne ;y altered during test
-
- ldy #3 ;testing store result
- ldx #0
-tstai1 lda abst,y
- eor #$c3
- cmp abs1,y
- trap_ne ;store to indirect data
- txa
- sta abst,y ;clear
- dey
- bpl tstai1
-
- ldx #$99 ;protect x & y
- ldy #$66
- set_stat $ff
- lda (ind1)
- php ;test stores do not alter flags
- eor #$c3
- plp
- sta (indt)
- php ;flags after load/store sequence
- eor #$c3
- cmp #$c3 ;test result
- trap_ne
- pla ;load status
- eor_flag lo~fnz ;mask bits not altered
- cmp fLDx ;test flags
- trap_ne
- set_stat $ff
- lda (ind1+2)
- php ;test stores do not alter flags
- eor #$c3
- plp
- sta (indt+2)
- php ;flags after load/store sequence
- eor #$c3
- cmp #$82 ;test result
- trap_ne
- pla ;load status
- eor_flag lo~fnz ;mask bits not altered
- cmp fLDx+1 ;test flags
- trap_ne
- set_stat $ff
- lda (ind1+4)
- php ;test stores do not alter flags
- eor #$c3
- plp
- sta (indt+4)
- php ;flags after load/store sequence
- eor #$c3
- cmp #$41 ;test result
- trap_ne
- pla ;load status
- eor_flag lo~fnz ;mask bits not altered
- cmp fLDx+2 ;test flags
- trap_ne
- set_stat $ff
- lda (ind1+6)
- php ;test stores do not alter flags
- eor #$c3
- plp
- sta (indt+6)
- php ;flags after load/store sequence
- eor #$c3
- cmp #0 ;test result
- trap_ne
- pla ;load status
- eor_flag lo~fnz ;mask bits not altered
- cmp fLDx+3 ;test flags
- trap_ne
- cpx #$99
- trap_ne ;x altered during test
- cpy #$66
- trap_ne ;y altered during test
-
- ldy #3 ;testing store result
- ldx #0
-tstai2 lda abst,y
- eor #$c3
- cmp abs1,y
- trap_ne ;store to indirect data
- txa
- sta abst,y ;clear
- dey
- bpl tstai2
- tsx
- cpx #$ff
- trap_ne ;sp push/pop mismatch
- next_test
-
-; testing STZ - zp / abs / zp,x / abs,x
- ldy #123 ;protect y
- ldx #4 ;precharge test area
- lda #7
-tstz1 sta zpt,x
- asl a
- dex
- bpl tstz1
- ldx #4
- set_a $55,$ff
- stz zpt
- stz zpt+1
- stz zpt+2
- stz zpt+3
- stz zpt+4
- tst_a $55,$ff
-tstz2 lda zpt,x ;verify zeros stored
- trap_ne ;non zero after STZ zp
- dex
- bpl tstz2
- ldx #4 ;precharge test area
- lda #7
-tstz3 sta zpt,x
- asl a
- dex
- bpl tstz3
- ldx #4
- set_a $aa,0
- stz zpt
- stz zpt+1
- stz zpt+2
- stz zpt+3
- stz zpt+4
- tst_a $aa,0
-tstz4 lda zpt,x ;verify zeros stored
- trap_ne ;non zero after STZ zp
- dex
- bpl tstz4
-
- ldx #4 ;precharge test area
- lda #7
-tstz5 sta abst,x
- asl a
- dex
- bpl tstz5
- ldx #4
- set_a $55,$ff
- stz abst
- stz abst+1
- stz abst+2
- stz abst+3
- stz abst+4
- tst_a $55,$ff
-tstz6 lda abst,x ;verify zeros stored
- trap_ne ;non zero after STZ abs
- dex
- bpl tstz6
- ldx #4 ;precharge test area
- lda #7
-tstz7 sta abst,x
- asl a
- dex
- bpl tstz7
- ldx #4
- set_a $aa,0
- stz abst
- stz abst+1
- stz abst+2
- stz abst+3
- stz abst+4
- tst_a $aa,0
-tstz8 lda abst,x ;verify zeros stored
- trap_ne ;non zero after STZ abs
- dex
- bpl tstz8
-
- ldx #4 ;precharge test area
- lda #7
-tstz11 sta zpt,x
- asl a
- dex
- bpl tstz11
- ldx #4
-tstz15
- set_a $55,$ff
- stz zpt,x
- tst_a $55,$ff
- dex
- bpl tstz15
- ldx #4
-tstz12 lda zpt,x ;verify zeros stored
- trap_ne ;non zero after STZ zp
- dex
- bpl tstz12
- ldx #4 ;precharge test area
- lda #7
-tstz13 sta zpt,x
- asl a
- dex
- bpl tstz13
- ldx #4
-tstz16
- set_a $aa,0
- stz zpt,x
- tst_a $aa,0
- dex
- bpl tstz16
- ldx #4
-tstz14 lda zpt,x ;verify zeros stored
- trap_ne ;non zero after STZ zp
- dex
- bpl tstz14
-
- ldx #4 ;precharge test area
- lda #7
-tstz21 sta abst,x
- asl a
- dex
- bpl tstz21
- ldx #4
-tstz25
- set_a $55,$ff
- stz abst,x
- tst_a $55,$ff
- dex
- bpl tstz25
- ldx #4
-tstz22 lda abst,x ;verify zeros stored
- trap_ne ;non zero after STZ zp
- dex
- bpl tstz22
- ldx #4 ;precharge test area
- lda #7
-tstz23 sta abst,x
- asl a
- dex
- bpl tstz23
- ldx #4
-tstz26
- set_a $aa,0
- stz abst,x
- tst_a $aa,0
- dex
- bpl tstz26
- ldx #4
-tstz24 lda abst,x ;verify zeros stored
- trap_ne ;non zero after STZ zp
- dex
- bpl tstz24
-
- cpy #123
- trap_ne ;y altered during test
- tsx
- cpx #$ff
- trap_ne ;sp push/pop mismatch
- next_test
-
-; testing BIT - zp,x / abs,x / #
- ldy #$42
- ldx #3
- set_a $ff,0
- bit zp1,x ;00 - should set Z / clear NV
- tst_a $ff,fz
- dex
- set_a 1,0
- bit zp1,x ;41 - should set V (M6) / clear NZ
- tst_a 1,fv
- dex
- set_a 1,0
- bit zp1,x ;82 - should set N (M7) & Z / clear V
- tst_a 1,fnz
- dex
- set_a 1,0
- bit zp1,x ;c3 - should set N (M7) & V (M6) / clear Z
- tst_a 1,fnv
-
- set_a 1,$ff
- bit zp1,x ;c3 - should set N (M7) & V (M6) / clear Z
- tst_a 1,~fz
- inx
- set_a 1,$ff
- bit zp1,x ;82 - should set N (M7) & Z / clear V
- tst_a 1,~fv
- inx
- set_a 1,$ff
- bit zp1,x ;41 - should set V (M6) / clear NZ
- tst_a 1,~fnz
- inx
- set_a $ff,$ff
- bit zp1,x ;00 - should set Z / clear NV
- tst_a $ff,~fnv
-
- set_a $ff,0
- bit abs1,x ;00 - should set Z / clear NV
- tst_a $ff,fz
- dex
- set_a 1,0
- bit abs1,x ;41 - should set V (M6) / clear NZ
- tst_a 1,fv
- dex
- set_a 1,0
- bit abs1,x ;82 - should set N (M7) & Z / clear V
- tst_a 1,fnz
- dex
- set_a 1,0
- bit abs1,x ;c3 - should set N (M7) & V (M6) / clear Z
- tst_a 1,fnv
-
- set_a 1,$ff
- bit abs1,x ;c3 - should set N (M7) & V (M6) / clear Z
- tst_a 1,~fz
- inx
- set_a 1,$ff
- bit abs1,x ;82 - should set N (M7) & Z / clear V
- tst_a 1,~fv
- inx
- set_a 1,$ff
- bit abs1,x ;41 - should set V (M6) / clear NZ
- tst_a 1,~fnz
- inx
- set_a $ff,$ff
- bit abs1,x ;00 - should set Z / clear NV
- tst_a $ff,~fnv
-
- set_a $ff,0
- bit #$00 ;00 - should set Z
- tst_a $ff,fz
- dex
- set_a 1,0
- bit #$41 ;41 - should clear Z
- tst_a 1,0
-; *** DEBUG INFO ***
-; if it fails the previous test and your BIT # has set the V flag
-; see http://forum.6502.org/viewtopic.php?f=2&t=2241&p=27243#p27239
-; why it shouldn't alter N or V flags on a BIT #
- dex
- set_a 1,0
- bit #$82 ;82 - should set Z
- tst_a 1,fz
- dex
- set_a 1,0
- bit #$c3 ;c3 - should clear Z
- tst_a 1,0
-
- set_a 1,$ff
- bit #$c3 ;c3 - clear Z
- tst_a 1,~fz
- inx
- set_a 1,$ff
- bit #$82 ;82 - should set Z
- tst_a 1,$ff
- inx
- set_a 1,$ff
- bit #$41 ;41 - should clear Z
- tst_a 1,~fz
- inx
- set_a $ff,$ff
- bit #$00 ;00 - should set Z
- tst_a $ff,$ff
-
- cpx #3
- trap_ne ;x altered during test
- cpy #$42
- trap_ne ;y altered during test
- tsx
- cpx #$ff
- trap_ne ;sp push/pop mismatch
- next_test
-
-; testing TRB, TSB - zp / abs
-
-trbt macro ;\1 = memory, \2 = flags
- sty \1
- load_flag \2
- pha
- lda zpt+1
- plp
- trb \1
- php
- cmp zpt+1
- trap_ne ;accu was changed
- pla
- pha
- ora #fz ;mask Z
- cmp_flag \2|fz
- trap_ne ;flags changed except Z
- pla
- and #fz
- cmp zpt+2
- trap_ne ;Z flag invalid
- lda zpt+3
- cmp zpt
- trap_ne ;altered bits in memory wrong
- endm
-
-tsbt macro ;\1 = memory, \2 = flags
- sty \1
- load_flag \2
- pha
- lda zpt+1
- plp
- tsb \1
- php
- cmp zpt+1
- trap_ne ;accu was changed
- pla
- pha
- ora #fz ;mask Z
- cmp_flag \2|fz
- trap_ne ;flags changed except Z
- pla
- and #fz
- cmp zpt+2
- trap_ne ;Z flag invalid
- lda zpt+4
- cmp zpt
- trap_ne ;altered bits in memory wrong
- endm
-
- ldx #$c0
- ldy #0 ;op1 - memory save
- ; zpt ;op1 - memory modifiable
- stz zpt+1 ;op2 - accu
- ; zpt+2 ;and flags
- ; zpt+3 ;memory after reset
- ; zpt+4 ;memory after set
-
-tbt1 tya
- and zpt+1 ;set Z by anding the 2 operands
- php
- pla
- and #fz ;mask Z
- sta zpt+2
- tya ;reset op1 bits by op2
- eor #$ff
- ora zpt+1
- eor #$ff
- sta zpt+3
- tya ;set op1 bits by op2
- ora zpt+1
- sta zpt+4
-
- trbt zpt,$ff
- trbt abst,$ff
- trbt zpt,0
- trbt abst,0
- tsbt zpt,$ff
- tsbt abst,$ff
- tsbt zpt,0
- tsbt abst,0
-
- iny ;iterate op1
- bne tbt3
- inc zpt+1 ;iterate op2
- beq tbt2
-tbt3 jmp tbt1
-tbt2
- cpx #$c0
- trap_ne ;x altered during test
- tsx
- cpx #$ff
- trap_ne ;sp push/pop mismatch
- next_test
-
- if rkwl_wdc_op = 1
-; testing RMB, SMB - zp
-rmbt macro ;\1 = bitnum
- lda #$ff
- sta zpt
- set_a $a5,0
- rmb \1,zpt
- tst_a $a5,0
- lda zpt
- cmp #$ff-(1<<\1)
- trap_ne ;wrong bits set or cleared
- lda #1<<\1
- sta zpt
- set_a $5a,$ff
- rmb \1,zpt
- tst_a $5a,$ff
- lda zpt
- trap_ne ;wrong bits set or cleared
- endm
-smbt macro ;\1 = bitnum
- lda #$ff-(1<<\1)
- sta zpt
- set_a $a5,0
- smb \1,zpt
- tst_a $a5,0
- lda zpt
- cmp #$ff
- trap_ne ;wrong bits set or cleared
- lda #0
- sta zpt
- set_a $5a,$ff
- smb \1,zpt
- tst_a $5a,$ff
- lda zpt
- cmp #1<<\1
- trap_ne ;wrong bits set or cleared
- endm
-
- ldx #$ba ;protect x & y
- ldy #$d0
- rmbt 0
- rmbt 1
- rmbt 2
- rmbt 3
- rmbt 4
- rmbt 5
- rmbt 6
- rmbt 7
- smbt 0
- smbt 1
- smbt 2
- smbt 3
- smbt 4
- smbt 5
- smbt 6
- smbt 7
- cpx #$ba
- trap_ne ;x altered during test
- cpy #$d0
- trap_ne ;y altered during test
- tsx
- cpx #$ff
- trap_ne ;sp push/pop mismatch
- next_test
- endif
-
-; testing CMP - (zp)
- ldx #$de ;protect x & y
- ldy #$ad
- set_a $80,0
- cmp (ind1+8)
- tst_a $80,fc
- set_a $7f,0
- cmp (ind1+8)
- tst_a $7f,fzc
- set_a $7e,0
- cmp (ind1+8)
- tst_a $7e,fn
- set_a $80,$ff
- cmp (ind1+8)
- tst_a $80,~fnz
- set_a $7f,$ff
- cmp (ind1+8)
- tst_a $7f,~fn
- set_a $7e,$ff
- cmp (ind1+8)
- tst_a $7e,~fzc
- cpx #$de
- trap_ne ;x altered during test
- cpy #$ad
- trap_ne ;y altered during test
- tsx
- cpx #$ff
- trap_ne ;sp push/pop mismatch
- next_test
-
-; testing logical instructions - AND EOR ORA (zp)
- ldx #$42 ;protect x & y
-
- ldy #0 ;AND
- lda indAN ;set indirect address
- sta zpt
- lda indAN+1
- sta zpt+1
-tand1
- set_ay absANa,0
- and (zpt)
- tst_ay absrlo,absflo,0
- inc zpt
- iny
- cpy #4
- bne tand1
- dey
- dec zpt
-tand2
- set_ay absANa,$ff
- and (zpt)
- tst_ay absrlo,absflo,$ff-fnz
- dec zpt
- dey
- bpl tand2
-
- ldy #0 ;EOR
- lda indEO ;set indirect address
- sta zpt
- lda indEO+1
- sta zpt+1
-teor1
- set_ay absEOa,0
- eor (zpt)
- tst_ay absrlo,absflo,0
- inc zpt
- iny
- cpy #4
- bne teor1
- dey
- dec zpt
-teor2
- set_ay absEOa,$ff
- eor (zpt)
- tst_ay absrlo,absflo,$ff-fnz
- dec zpt
- dey
- bpl teor2
-
- ldy #0 ;ORA
- lda indOR ;set indirect address
- sta zpt
- lda indOR+1
- sta zpt+1
-tora1
- set_ay absORa,0
- ora (zpt)
- tst_ay absrlo,absflo,0
- inc zpt
- iny
- cpy #4
- bne tora1
- dey
- dec zpt
-tora2
- set_ay absORa,$ff
- ora (zpt)
- tst_ay absrlo,absflo,$ff-fnz
- dec zpt
- dey
- bpl tora2
-
- cpx #$42
- trap_ne ;x altered during test
- tsx
- cpx #$ff
- trap_ne ;sp push/pop mismatch
- next_test
-
- if I_flag = 3
- cli
- endif
-
-; full binary add/subtract test - (zp) only
-; iterates through all combinations of operands and carry input
-; uses increments/decrements to predict result & result flags
- cld
- ldx #ad2 ;for indexed test
- ldy #$ff ;max range
- lda #0 ;start with adding zeroes & no carry
- sta adfc ;carry in - for diag
- sta ad1 ;operand 1 - accumulator
- sta ad2 ;operand 2 - memory or immediate
- sta ada2 ;non zp
- sta adrl ;expected result bits 0-7
- sta adrh ;expected result bit 8 (carry out)
- lda #$ff ;complemented operand 2 for subtract
- sta sb2
- sta sba2 ;non zp
- lda #2 ;expected Z-flag
- sta adrf
-tadd clc ;test with carry clear
- jsr chkadd
- inc adfc ;now with carry
- inc adrl ;result +1
- php ;save N & Z from low result
- php
- pla ;accu holds expected flags
- and #$82 ;mask N & Z
- plp
- bne tadd1
- inc adrh ;result bit 8 - carry
-tadd1 ora adrh ;merge C to expected flags
- sta adrf ;save expected flags except overflow
- sec ;test with carry set
- jsr chkadd
- dec adfc ;same for operand +1 but no carry
- inc ad1
- bne tadd ;iterate op1
- lda #0 ;preset result to op2 when op1 = 0
- sta adrh
- inc ada2
- inc ad2
- php ;save NZ as operand 2 becomes the new result
- pla
- and #$82 ;mask N00000Z0
- sta adrf ;no need to check carry as we are adding to 0
- dec sb2 ;complement subtract operand 2
- dec sba2
- lda ad2
- sta adrl
- bne tadd ;iterate op2
-
- cpx #ad2
- trap_ne ;x altered during test
- cpy #$ff
- trap_ne ;y altered during test
- tsx
- cpx #$ff
- trap_ne ;sp push/pop mismatch
- next_test
-
-; decimal add/subtract test
-; *** WARNING - tests documented behavior only! ***
-; only valid BCD operands are tested, the V flag is ignored
-; although V is declared as beeing valid on the 65C02 it has absolutely
-; no use in BCD math. No sign = no overflow!
-; iterates through all valid combinations of operands and carry input
-; uses increments/decrements to predict result & carry flag
- sed
- ldx #ad2 ;for indexed test
- ldy #$ff ;max range
- lda #$99 ;start with adding 99 to 99 with carry
- sta ad1 ;operand 1 - accumulator
- sta ad2 ;operand 2 - memory or immediate
- sta ada2 ;non zp
- sta adrl ;expected result bits 0-7
- lda #1 ;set carry in & out
- sta adfc ;carry in - for diag
- sta adrh ;expected result bit 8 (carry out)
- lda #$81 ;set N & C (99 + 99 + C = 99 + C)
- sta adrf
- lda #0 ;complemented operand 2 for subtract
- sta sb2
- sta sba2 ;non zp
-tdad sec ;test with carry set
- jsr chkdad
- dec adfc ;now with carry clear
- lda adrl ;decimal adjust result
- bne tdad1 ;skip clear carry & preset result 99 (9A-1)
- dec adrh
- lda #$99
- sta adrl
- bne tdad3
-tdad1 and #$f ;lower nibble mask
- bne tdad2 ;no decimal adjust needed
- dec adrl ;decimal adjust (?0-6)
- dec adrl
- dec adrl
- dec adrl
- dec adrl
- dec adrl
-tdad2 dec adrl ;result -1
-tdad3 php ;save valid flags
- pla
- and #$82 ;N-----Z-
- ora adrh ;N-----ZC
- sta adrf
- clc ;test with carry clear
- jsr chkdad
- inc adfc ;same for operand -1 but with carry
- lda ad1 ;decimal adjust operand 1
- beq tdad5 ;iterate operand 2
- and #$f ;lower nibble mask
- bne tdad4 ;skip decimal adjust
- dec ad1 ;decimal adjust (?0-6)
- dec ad1
- dec ad1
- dec ad1
- dec ad1
- dec ad1
-tdad4 dec ad1 ;operand 1 -1
- jmp tdad ;iterate op1
-
-tdad5 lda #$99 ;precharge op1 max
- sta ad1
- lda ad2 ;decimal adjust operand 2
- beq tdad7 ;end of iteration
- and #$f ;lower nibble mask
- bne tdad6 ;skip decimal adjust
- dec ad2 ;decimal adjust (?0-6)
- dec ad2
- dec ad2
- dec ad2
- dec ad2
- dec ad2
- inc sb2 ;complemented decimal adjust for subtract (?9+6)
- inc sb2
- inc sb2
- inc sb2
- inc sb2
- inc sb2
-tdad6 dec ad2 ;operand 2 -1
- inc sb2 ;complemented operand for subtract
- lda sb2
- sta sba2 ;copy as non zp operand
- lda ad2
- sta ada2 ;copy as non zp operand
- sta adrl ;new result since op1+carry=00+carry +op2=op2
- php ;save flags
- pla
- and #$82 ;N-----Z-
- ora #1 ;N-----ZC
- sta adrf
- inc adrh ;result carry
- jmp tdad ;iterate op2
-
-tdad7 cpx #ad2
- trap_ne ;x altered during test
- cpy #$ff
- trap_ne ;y altered during test
- tsx
- cpx #$ff
- trap_ne ;sp push/pop mismatch
- cld
-
- lda test_case
- cmp #test_num
- trap_ne ;previous test is out of sequence
- lda #$f0 ;mark opcode testing complete
- sta test_case
-
-; final RAM integrity test
-; verifies that none of the previous tests has altered RAM outside of the
-; designated write areas.
- check_ram
-; *** DEBUG INFO ***
-; to debug checksum errors uncomment check_ram in the next_test macro to
-; narrow down the responsible opcode.
-; may give false errors when monitor, OS or other background activity is
-; allowed during previous tests.
-
-
-; S U C C E S S ************************************************
-; -------------
- success ;if you get here everything went well
-; -------------
-; S U C C E S S ************************************************
- jmp start ;run again
-
-; core subroutine of the decimal add/subtract test
-; *** WARNING - tests documented behavior only! ***
-; only valid BCD operands are tested, V flag is ignored
-; iterates through all valid combinations of operands and carry input
-; uses increments/decrements to predict result & carry flag
-chkdad
-; decimal ADC / SBC zp
- php ;save carry for subtract
- lda ad1
- adc ad2 ;perform add
- php
- cmp adrl ;check result
- trap_ne ;bad result
- pla ;check flags
- and #$83 ;mask N-----ZC
- cmp adrf
- trap_ne ;bad flags
- plp
- php ;save carry for next add
- lda ad1
- sbc sb2 ;perform subtract
- php
- cmp adrl ;check result
- trap_ne ;bad result
- pla ;check flags
- and #$83 ;mask N-----ZC
- cmp adrf
- trap_ne ;bad flags
- plp
-; decimal ADC / SBC abs
- php ;save carry for subtract
- lda ad1
- adc ada2 ;perform add
- php
- cmp adrl ;check result
- trap_ne ;bad result
- pla ;check flags
- and #$83 ;mask N-----ZC
- cmp adrf
- trap_ne ;bad flags
- plp
- php ;save carry for next add
- lda ad1
- sbc sba2 ;perform subtract
- php
- cmp adrl ;check result
- trap_ne ;bad result
- pla ;check flags
- and #$83 ;mask N-----ZC
- cmp adrf
- trap_ne ;bad flags
- plp
-; decimal ADC / SBC #
- php ;save carry for subtract
- lda ad2
- sta ex_adci+1 ;set ADC # operand
- lda ad1
- jsr ex_adci ;execute ADC # in RAM
- php
- cmp adrl ;check result
- trap_ne ;bad result
- pla ;check flags
- and #$83 ;mask N-----ZC
- cmp adrf
- trap_ne ;bad flags
- plp
- php ;save carry for next add
- lda sb2
- sta ex_sbci+1 ;set SBC # operand
- lda ad1
- jsr ex_sbci ;execute SBC # in RAM
- php
- cmp adrl ;check result
- trap_ne ;bad result
- pla ;check flags
- and #$83 ;mask N-----ZC
- cmp adrf
- trap_ne ;bad flags
- plp
-; decimal ADC / SBC zp,x
- php ;save carry for subtract
- lda ad1
- adc 0,x ;perform add
- php
- cmp adrl ;check result
- trap_ne ;bad result
- pla ;check flags
- and #$83 ;mask N-----ZC
- cmp adrf
- trap_ne ;bad flags
- plp
- php ;save carry for next add
- lda ad1
- sbc sb2-ad2,x ;perform subtract
- php
- cmp adrl ;check result
- trap_ne ;bad result
- pla ;check flags
- and #$83 ;mask N-----ZC
- cmp adrf
- trap_ne ;bad flags
- plp
-; decimal ADC / SBC abs,x
- php ;save carry for subtract
- lda ad1
- adc ada2-ad2,x ;perform add
- php
- cmp adrl ;check result
- trap_ne ;bad result
- pla ;check flags
- and #$83 ;mask N-----ZC
- cmp adrf
- trap_ne ;bad flags
- plp
- php ;save carry for next add
- lda ad1
- sbc sba2-ad2,x ;perform subtract
- php
- cmp adrl ;check result
- trap_ne ;bad result
- pla ;check flags
- and #$83 ;mask N-----ZC
- cmp adrf
- trap_ne ;bad flags
- plp
-; decimal ADC / SBC abs,y
- php ;save carry for subtract
- lda ad1
- adc ada2-$ff,y ;perform add
- php
- cmp adrl ;check result
- trap_ne ;bad result
- pla ;check flags
- and #$83 ;mask N-----ZC
- cmp adrf
- trap_ne ;bad flags
- plp
- php ;save carry for next add
- lda ad1
- sbc sba2-$ff,y ;perform subtract
- php
- cmp adrl ;check result
- trap_ne ;bad result
- pla ;check flags
- and #$83 ;mask N-----ZC
- cmp adrf
- trap_ne ;bad flags
- plp
-; decimal ADC / SBC (zp,x)
- php ;save carry for subtract
- lda ad1
- adc (lo adi2-ad2,x) ;perform add
- php
- cmp adrl ;check result
- trap_ne ;bad result
- pla ;check flags
- and #$83 ;mask N-----ZC
- cmp adrf
- trap_ne ;bad flags
- plp
- php ;save carry for next add
- lda ad1
- sbc (lo sbi2-ad2,x) ;perform subtract
- php
- cmp adrl ;check result
- trap_ne ;bad result
- pla ;check flags
- and #$83 ;mask N-----ZC
- cmp adrf
- trap_ne ;bad flags
- plp
-; decimal ADC / SBC (abs),y
- php ;save carry for subtract
- lda ad1
- adc (adiy2),y ;perform add
- php
- cmp adrl ;check result
- trap_ne ;bad result
- pla ;check flags
- and #$83 ;mask N-----ZC
- cmp adrf
- trap_ne ;bad flags
- plp
- php ;save carry for next add
- lda ad1
- sbc (sbiy2),y ;perform subtract
- php
- cmp adrl ;check result
- trap_ne ;bad result
- pla ;check flags
- and #$83 ;mask N-----ZC
- cmp adrf
- trap_ne ;bad flags
- plp
-; decimal ADC / SBC (zp)
- php ;save carry for subtract
- lda ad1
- adc (adi2) ;perform add
- php
- cmp adrl ;check result
- trap_ne ;bad result
- pla ;check flags
- and #$83 ;mask N-----ZC
- cmp adrf
- trap_ne ;bad flags
- plp
- php ;save carry for next add
- lda ad1
- sbc (sbi2) ;perform subtract
- php
- cmp adrl ;check result
- trap_ne ;bad result
- pla ;check flags
- and #$83 ;mask N-----ZC
- cmp adrf
- trap_ne ;bad flags
- plp
- rts
-
-; core subroutine of the full binary add/subtract test
-; iterates through all combinations of operands and carry input
-; uses increments/decrements to predict result & result flags
-chkadd lda adrf ;add V-flag if overflow
- and #$83 ;keep N-----ZC / clear V
- pha
- lda ad1 ;test sign unequal between operands
- eor ad2
- bmi ckad1 ;no overflow possible - operands have different sign
- lda ad1 ;test sign equal between operands and result
- eor adrl
- bpl ckad1 ;no overflow occured - operand and result have same sign
- pla
- ora #$40 ;set V
- pha
-ckad1 pla
- sta adrf ;save expected flags
-; binary ADC / SBC (zp)
- php ;save carry for subtract
- lda ad1
- adc (adi2) ;perform add
- php
- cmp adrl ;check result
- trap_ne ;bad result
- pla ;check flags
- and #$c3 ;mask NV----ZC
- cmp adrf
- trap_ne ;bad flags
- plp
- php ;save carry for next add
- lda ad1
- sbc (sbi2) ;perform subtract
- php
- cmp adrl ;check result
- trap_ne ;bad result
- pla ;check flags
- and #$c3 ;mask NV----ZC
- cmp adrf
- trap_ne ;bad flags
- plp
- rts
-
-; target for the jump indirect test
-ji_adr dw test_ji
- dw ji_ret
-
- dey
- dey
-test_ji
- php ;either SP or Y count will fail, if we do not hit
- dey
- dey
- dey
- plp
- trap_cs ;flags loaded?
- trap_vs
- trap_mi
- trap_eq
- cmp #'I' ;registers loaded?
- trap_ne
- cpx #'N'
- trap_ne
- cpy #('D'-3)
- trap_ne
- pha ;save a,x
- txa
- pha
- tsx
- cpx #$fd ;check SP
- trap_ne
- pla ;restore x
- tax
- set_stat $ff
- pla ;restore a
- inx ;return registers with modifications
- eor #$aa ;N=1, V=1, Z=0, C=1
- jmp (ji_tab+2)
- nop
- nop
- trap ;runover protection
- jmp start ;catastrophic error - cannot continue
-
-; target for the jump indirect test
-jxi_adr dw trap_ind
- dw trap_ind
- dw test_jxi ;+4
- dw jxi_ret ;+6
- dw trap_ind
- dw trap_ind
-
- dey
- dey
-test_jxi
- php ;either SP or Y count will fail, if we do not hit
- dey
- dey
- dey
- plp
- trap_cs ;flags loaded?
- trap_vs
- trap_mi
- trap_eq
- cmp #'X' ;registers loaded?
- trap_ne
- cpx #4
- trap_ne
- cpy #('I'-3)
- trap_ne
- pha ;save a,x
- txa
- pha
- tsx
- cpx #$fd ;check SP
- trap_ne
- pla ;restore x
- tax
- set_stat $ff
- pla ;restore a
- inx ;return registers with modifications
- inx
- eor #$aa ;N=1, V=1, Z=0, C=1
- jmp (jxi_tab,x)
- nop
- nop
- trap ;runover protection
- jmp start ;catastrophic error - cannot continue
-
-; JMP (abs,x) with bad x
- nop
- nop
-trap_ind
- nop
- nop
- trap ;near miss indexed indirect jump
- jmp start ;catastrophic error - cannot continue
-
-;trap in case of unexpected IRQ, NMI, BRK, RESET
-nmi_trap
- trap ;check stack for conditions at NMI
- jmp start ;catastrophic error - cannot continue
-res_trap
- trap ;unexpected RESET
- jmp start ;catastrophic error - cannot continue
-
- dey
- dey
-irq_trap ;BRK test or unextpected BRK or IRQ
- php ;either SP or Y count will fail, if we do not hit
- dey
- dey
- dey
- ;next traps could be caused by unexpected BRK or IRQ
- ;check stack for BREAK and originating location
- ;possible jump/branch into weeds (uninitialized space)
- cmp #$ff-'B' ;BRK pass 2 registers loaded?
- beq break2
- cmp #'B' ;BRK pass 1 registers loaded?
- trap_ne
- cpx #'R'
- trap_ne
- cpy #'K'-3
- trap_ne
- sta irq_a ;save registers during break test
- stx irq_x
- tsx ;test break on stack
- lda $102,x
- cmp_flag 0 ;break test should have B=1 & unused=1 on stack
- trap_ne ;possible no break flag on stack
- pla
- cmp_flag intdis ;should have added interrupt disable
- trap_ne
- tsx
- cpx #$fc ;sp -3? (return addr, flags)
- trap_ne
- lda $1ff ;propper return on stack
- cmp #hi(brk_ret0)
- trap_ne
- lda $1fe
- cmp #lo(brk_ret0)
- trap_ne
- load_flag $ff
- pha
- ldx irq_x
- inx ;return registers with modifications
- lda irq_a
- eor #$aa
- plp ;N=1, V=1, Z=1, C=1 but original flags should be restored
- rti
- trap ;runover protection
- jmp start ;catastrophic error - cannot continue
-
-break2 ;BRK pass 2
- cpx #$ff-'R'
- trap_ne
- cpy #$ff-'K'-3
- trap_ne
- sta irq_a ;save registers during break test
- stx irq_x
- tsx ;test break on stack
- lda $102,x
- cmp_flag $ff ;break test should have B=1
- trap_ne ;possibly no break flag on stack
- pla
- cmp_flag $ff-decmode ;actual passed flags should have decmode cleared
- trap_ne
- tsx
- cpx #$fc ;sp -3? (return addr, flags)
- trap_ne
- lda $1ff ;propper return on stack
- cmp #hi(brk_ret1)
- trap_ne
- lda $1fe
- cmp #lo(brk_ret1)
- trap_ne
- load_flag intdis
- pha
- ldx irq_x
- inx ;return registers with modifications
- lda irq_a
- eor #$aa
- plp ;N=0, V=0, Z=0, C=0 but original flags should be restored
- rti
- trap ;runover protection
- jmp start ;catastrophic error - cannot continue
-
- if report = 1
- include "report.i65"
- endif
-
-;copy of data to initialize BSS segment
- if load_data_direct != 1
-zp_init
-zp1_ db $c3,$82,$41,0 ;test patterns for LDx BIT ROL ROR ASL LSR
-zp7f_ db $7f ;test pattern for compare
-;logical zeropage operands
-zpOR_ db 0,$1f,$71,$80 ;test pattern for OR
-zpAN_ db $0f,$ff,$7f,$80 ;test pattern for AND
-zpEO_ db $ff,$0f,$8f,$8f ;test pattern for EOR
-;indirect addressing pointers
-ind1_ dw abs1 ;indirect pointer to pattern in absolute memory
- dw abs1+1
- dw abs1+2
- dw abs1+3
- dw abs7f
-inw1_ dw abs1-$f8 ;indirect pointer for wrap-test pattern
-indt_ dw abst ;indirect pointer to store area in absolute memory
- dw abst+1
- dw abst+2
- dw abst+3
-inwt_ dw abst-$f8 ;indirect pointer for wrap-test store
-indAN_ dw absAN ;indirect pointer to AND pattern in absolute memory
- dw absAN+1
- dw absAN+2
- dw absAN+3
-indEO_ dw absEO ;indirect pointer to EOR pattern in absolute memory
- dw absEO+1
- dw absEO+2
- dw absEO+3
-indOR_ dw absOR ;indirect pointer to OR pattern in absolute memory
- dw absOR+1
- dw absOR+2
- dw absOR+3
-;add/subtract indirect pointers
-adi2_ dw ada2 ;indirect pointer to operand 2 in absolute memory
-sbi2_ dw sba2 ;indirect pointer to complemented operand 2 (SBC)
-adiy2_ dw ada2-$ff ;with offset for indirect indexed
-sbiy2_ dw sba2-$ff
-zp_end
- if (zp_end - zp_init) != (zp_bss_end - zp_bss)
- ;force assembler error if size is different
- ERROR ERROR ERROR ;mismatch between bss and zeropage data
- endif
-data_init
-ex_adc_ adc #0 ;execute immediate opcodes
- rts
-ex_sbc_ sbc #0 ;execute immediate opcodes
- rts
-abs1_ db $c3,$82,$41,0 ;test patterns for LDx BIT ROL ROR ASL LSR
-abs7f_ db $7f ;test pattern for compare
-;loads
-fLDx_ db fn,fn,0,fz ;expected flags for load
-;shifts
-rASL_ ;expected result ASL & ROL -carry
-rROL_ db $86,$04,$82,0 ; "
-rROLc_ db $87,$05,$83,1 ;expected result ROL +carry
-rLSR_ ;expected result LSR & ROR -carry
-rROR_ db $61,$41,$20,0 ; "
-rRORc_ db $e1,$c1,$a0,$80 ;expected result ROR +carry
-fASL_ ;expected flags for shifts
-fROL_ db fnc,fc,fn,fz ;no carry in
-fROLc_ db fnc,fc,fn,0 ;carry in
-fLSR_
-fROR_ db fc,0,fc,fz ;no carry in
-fRORc_ db fnc,fn,fnc,fn ;carry in
-;increments (decrements)
-rINC_ db $7f,$80,$ff,0,1 ;expected result for INC/DEC
-fINC_ db 0,fn,fn,fz,0 ;expected flags for INC/DEC
-;logical memory operand
-absOR_ db 0,$1f,$71,$80 ;test pattern for OR
-absAN_ db $0f,$ff,$7f,$80 ;test pattern for AND
-absEO_ db $ff,$0f,$8f,$8f ;test pattern for EOR
-;logical accu operand
-absORa_ db 0,$f1,$1f,0 ;test pattern for OR
-absANa_ db $f0,$ff,$ff,$ff ;test pattern for AND
-absEOa_ db $ff,$f0,$f0,$0f ;test pattern for EOR
-;logical results
-absrlo_ db 0,$ff,$7f,$80
-absflo_ db fz,fn,0,fn
-data_end
- if (data_end - data_init) != (data_bss_end - data_bss)
- ;force assembler error if size is different
- ERROR ERROR ERROR ;mismatch between bss and data
- endif
-
-vec_init
- dw nmi_trap
- dw res_trap
- dw irq_trap
-vec_bss equ $fffa
- endif ;end of RAM init data
-
-; code at end of image due to the need to add blank space as required
- if ($ff & (ji_ret - * - 2)) < ($ff & (jxi_ret - * - 2))
-; JMP (abs) when $xxff and $xx00 are from same page
- ds lo(ji_ret - * - 2)
- nop
- nop
-ji_px nop ;low address byte matched with ji_ret
- nop
- trap ;jmp indirect page cross bug
-
-; JMP (abs,x) when $xxff and $xx00 are from same page
- ds lo(jxi_ret - * - 2)
- nop
- nop
-jxi_px nop ;low address byte matched with jxi_ret
- nop
- trap ;jmp indexed indirect page cross bug
- else
-; JMP (abs,x) when $xxff and $xx00 are from same page
- ds lo(jxi_ret - * - 2)
- nop
- nop
-jxi_px nop ;low address byte matched with jxi_ret
- nop
- trap ;jmp indexed indirect page cross bug
-
-; JMP (abs) when $xxff and $xx00 are from same page
- ds lo(ji_ret - * - 2)
- nop
- nop
-ji_px nop ;low address byte matched with ji_ret
- nop
- trap ;jmp indirect page cross bug
- endif
-
- if (load_data_direct = 1) & (ROM_vectors = 1)
- org $fffa ;vectors
- dw nmi_trap
- dw res_trap
- dw irq_trap
- endif
-
- end start
+;
+; 6 5 C 0 2 E X T E N D E D O P C O D E S T E S T
+;
+; Copyright (C) 2013-2017 Klaus Dormann
+;
+; This program is free software: you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation, either version 3 of the License, or
+; (at your option) any later version.
+;
+; This program is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with this program. If not, see .
+
+
+; This program is designed to test all additional 65C02 opcodes, addressing
+; modes and functionality not available in the NMOS version of the 6502.
+; The 6502_functional_test is a prerequisite to this test.
+; NMI, IRQ, STP & WAI are covered in the 6502_interrupt_test.
+;
+; version 04-dec-2017
+; contact info at http://2m5.de or email K@2m5.de
+;
+; assembled with AS65 from http://www.kingswood-consulting.co.uk/assemblers/
+; command line switches: -l -m -s2 -w -x -h0
+; | | | | | no page headers in listing
+; | | | | 65C02 extensions
+; | | | wide listing (133 char/col)
+; | | write intel hex file instead of binary
+; | expand macros in listing
+; generate pass2 listing
+;
+; No IO - should be run from a monitor with access to registers.
+; To run load intel hex image with a load command, than alter PC to 400 hex
+; (code_segment) and enter a go command.
+; Loop on program counter determines error or successful completion of test.
+; Check listing for relevant traps (jump/branch *).
+; Please note that in early tests some instructions will have to be used before
+; they are actually tested!
+;
+; RESET, NMI or IRQ should not occur and will be trapped if vectors are enabled.
+; Tests documented behavior of the original 65C02 only!
+; Decimal ops will only be tested with valid BCD operands and the V flag will
+; be ignored as it is absolutely useless in decimal mode.
+;
+; Debugging hints:
+; Most of the code is written sequentially. if you hit a trap, check the
+; immediately preceeding code for the instruction to be tested. Results are
+; tested first, flags are checked second by pushing them onto the stack and
+; pulling them to the accumulator after the result was checked. The "real"
+; flags are no longer valid for the tested instruction at this time!
+; If the tested instruction was indexed, the relevant index (X or Y) must
+; also be checked. Opposed to the flags, X and Y registers are still valid.
+;
+; versions:
+; 19-jul-2013 1st version distributed for testing
+; 23-jul-2013 fixed BRA out of range due to larger trap macros
+; added RAM integrity check
+; 16-aug-2013 added error report to standard output option
+; 23-aug-2015 change revoked
+; 24-aug-2015 all self modifying immediate opcodes now execute in data RAM
+; 28-aug-2015 fixed decimal adc/sbc immediate only testing carry
+; 09-feb-2017 fixed RMB/SMB tested when they shouldn't be tested
+; 04-dec-2017 fixed BRK not tested for actually going through the IRQ vector
+; added option to skip the remainder of a failing test
+; in report.i65
+; added skip override to undefined opcode as NOP test
+
+
+; C O N F I G U R A T I O N
+
+;ROM_vectors writable (0=no, 1=yes)
+;if ROM vectors can not be used interrupts will not be trapped
+;as a consequence BRK can not be tested but will be emulated to test RTI
+ROM_vectors = 1
+
+;load_data_direct (0=move from code segment, 1=load directly)
+;loading directly is preferred but may not be supported by your platform
+;0 produces only consecutive object code, 1 is not suitable for a binary image
+load_data_direct = 1
+
+;I_flag behavior (0=force enabled, 1=force disabled, 2=prohibit change, 3=allow
+;change) 2 requires extra code and is not recommended.
+I_flag = 3
+
+;configure memory - try to stay away from memory used by the system
+;zero_page memory start address, $4e (78) consecutive Bytes required
+; add 2 if I_flag = 2
+zero_page = $a
+
+;data_segment memory start address, $63 (99) consecutive Bytes required
+; + 12 Bytes at data_segment + $f9 (JMP indirect page cross test)
+data_segment = $200
+ if (data_segment & $ff) != 0
+ ERROR ERROR ERROR low byte of data_segment MUST be $00 !!
+ endif
+
+;code_segment memory start address, 10kB of consecutive space required
+; add 1 kB if I_flag = 2
+code_segment = $400
+
+;added WDC only opcodes WAI & STP (0=test as NOPs, >0=no test)
+wdc_op = 1
+
+;added Rockwell & WDC opcodes BBR, BBS, RMB & SMB
+;(0=test as NOPs, 1=full test, >1=no test)
+rkwl_wdc_op = 1
+
+;skip testing all undefined opcodes override
+;0=test as NOP, >0=skip
+skip_nop = 0
+
+;report errors through I/O channel (0=use standard self trap loops, 1=include
+;report.i65 as I/O channel, add 3 kB)
+report = 0
+
+;RAM integrity test option. Checks for undesired RAM writes.
+;set lowest non RAM or RAM mirror address page (-1=disable, 0=64k, $40=16k)
+;leave disabled if a monitor, OS or background interrupt is allowed to alter RAM
+ram_top = -1
+
+ noopt ;do not take shortcuts
+
+;macros for error & success traps to allow user modification
+;example:
+;trap macro
+; jsr my_error_handler
+; endm
+;trap_eq macro
+; bne skip\?
+; trap ;failed equal (zero)
+;skip\?
+; endm
+;
+; my_error_handler should pop the calling address from the stack and report it.
+; putting larger portions of code (more than 3 bytes) inside the trap macro
+; may lead to branch range problems for some tests.
+ if report = 0
+trap macro
+ jmp * ;failed anyway
+ endm
+trap_eq macro
+ beq * ;failed equal (zero)
+ endm
+trap_ne macro
+ bne * ;failed not equal (non zero)
+ endm
+trap_cs macro
+ bcs * ;failed carry set
+ endm
+trap_cc macro
+ bcc * ;failed carry clear
+ endm
+trap_mi macro
+ bmi * ;failed minus (bit 7 set)
+ endm
+trap_pl macro
+ bpl * ;failed plus (bit 7 clear)
+ endm
+trap_vs macro
+ bvs * ;failed overflow set
+ endm
+trap_vc macro
+ bvc * ;failed overflow clear
+ endm
+; please observe that during the test the stack gets invalidated
+; therefore a RTS inside the success macro is not possible
+success macro
+ jmp * ;test passed, no errors
+ endm
+ endif
+ if report = 1
+trap macro
+ jsr report_error
+ endm
+trap_eq macro
+ bne skip\?
+ trap ;failed equal (zero)
+skip\?
+ endm
+trap_ne macro
+ beq skip\?
+ trap ;failed not equal (non zero)
+skip\?
+ endm
+trap_cs macro
+ bcc skip\?
+ trap ;failed carry set
+skip\?
+ endm
+trap_cc macro
+ bcs skip\?
+ trap ;failed carry clear
+skip\?
+ endm
+trap_mi macro
+ bpl skip\?
+ trap ;failed minus (bit 7 set)
+skip\?
+ endm
+trap_pl macro
+ bmi skip\?
+ trap ;failed plus (bit 7 clear)
+skip\?
+ endm
+trap_vs macro
+ bvc skip\?
+ trap ;failed overflow set
+skip\?
+ endm
+trap_vc macro
+ bvs skip\?
+ trap ;failed overflow clear
+skip\?
+ endm
+; please observe that during the test the stack gets invalidated
+; therefore a RTS inside the success macro is not possible
+success macro
+ jsr report_success
+ endm
+ endif
+
+
+carry equ %00000001 ;flag bits in status
+zero equ %00000010
+intdis equ %00000100
+decmode equ %00001000
+break equ %00010000
+reserv equ %00100000
+overfl equ %01000000
+minus equ %10000000
+
+fc equ carry
+fz equ zero
+fzc equ carry+zero
+fv equ overfl
+fvz equ overfl+zero
+fn equ minus
+fnc equ minus+carry
+fnz equ minus+zero
+fnzc equ minus+zero+carry
+fnv equ minus+overfl
+
+fao equ break+reserv ;bits always on after PHP, BRK
+fai equ fao+intdis ;+ forced interrupt disable
+m8 equ $ff ;8 bit mask
+m8i equ $ff&~intdis ;8 bit mask - interrupt disable
+
+;macros to allow masking of status bits.
+;masking of interrupt enable/disable on load and compare
+;masking of always on bits after PHP or BRK (unused & break) on compare
+ if I_flag = 0
+load_flag macro
+ lda #\1&m8i ;force enable interrupts (mask I)
+ endm
+cmp_flag macro
+ cmp #(\1|fao)&m8i ;I_flag is always enabled + always on bits
+ endm
+eor_flag macro
+ eor #(\1&m8i|fao) ;mask I, invert expected flags + always on bits
+ endm
+ endif
+ if I_flag = 1
+load_flag macro
+ lda #\1|intdis ;force disable interrupts
+ endm
+cmp_flag macro
+ cmp #(\1|fai)&m8 ;I_flag is always disabled + always on bits
+ endm
+eor_flag macro
+ eor #(\1|fai) ;invert expected flags + always on bits + I
+ endm
+ endif
+ if I_flag = 2
+load_flag macro
+ lda #\1
+ ora flag_I_on ;restore I-flag
+ and flag_I_off
+ endm
+cmp_flag macro
+ eor flag_I_on ;I_flag is never changed
+ cmp #(\1|fao)&m8i ;expected flags + always on bits, mask I
+ endm
+eor_flag macro
+ eor flag_I_on ;I_flag is never changed
+ eor #(\1&m8i|fao) ;mask I, invert expected flags + always on bits
+ endm
+ endif
+ if I_flag = 3
+load_flag macro
+ lda #\1 ;allow test to change I-flag (no mask)
+ endm
+cmp_flag macro
+ cmp #(\1|fao)&m8 ;expected flags + always on bits
+ endm
+eor_flag macro
+ eor #\1|fao ;invert expected flags + always on bits
+ endm
+ endif
+
+;macros to set (register|memory|zeropage) & status
+set_stat macro ;setting flags in the processor status register
+ load_flag \1
+ pha ;use stack to load status
+ plp
+ endm
+
+set_a macro ;precharging accu & status
+ load_flag \2
+ pha ;use stack to load status
+ lda #\1 ;precharge accu
+ plp
+ endm
+
+set_x macro ;precharging index & status
+ load_flag \2
+ pha ;use stack to load status
+ ldx #\1 ;precharge index x
+ plp
+ endm
+
+set_y macro ;precharging index & status
+ load_flag \2
+ pha ;use stack to load status
+ ldy #\1 ;precharge index y
+ plp
+ endm
+
+set_ax macro ;precharging indexed accu & immediate status
+ load_flag \2
+ pha ;use stack to load status
+ lda \1,x ;precharge accu
+ plp
+ endm
+
+set_ay macro ;precharging indexed accu & immediate status
+ load_flag \2
+ pha ;use stack to load status
+ lda \1,y ;precharge accu
+ plp
+ endm
+
+set_z macro ;precharging indexed zp & immediate status
+ load_flag \2
+ pha ;use stack to load status
+ lda \1,x ;load to zeropage
+ sta zpt
+ plp
+ endm
+
+set_zx macro ;precharging zp,x & immediate status
+ load_flag \2
+ pha ;use stack to load status
+ lda \1,x ;load to indexed zeropage
+ sta zpt,x
+ plp
+ endm
+
+set_abs macro ;precharging indexed memory & immediate status
+ load_flag \2
+ pha ;use stack to load status
+ lda \1,x ;load to memory
+ sta abst
+ plp
+ endm
+
+set_absx macro ;precharging abs,x & immediate status
+ load_flag \2
+ pha ;use stack to load status
+ lda \1,x ;load to indexed memory
+ sta abst,x
+ plp
+ endm
+
+;macros to test (register|memory|zeropage) & status & (mask)
+tst_stat macro ;testing flags in the processor status register
+ php ;save status
+ pla ;use stack to retrieve status
+ pha
+ cmp_flag \1
+ trap_ne
+ plp ;restore status
+ endm
+
+tst_a macro ;testing result in accu & flags
+ php ;save flags
+ cmp #\1 ;test result
+ trap_ne
+ pla ;load status
+ pha
+ cmp_flag \2
+ trap_ne
+ plp ;restore status
+ endm
+
+tst_as macro ;testing result in accu & flags, save accu
+ pha
+ php ;save flags
+ cmp #\1 ;test result
+ trap_ne
+ pla ;load status
+ pha
+ cmp_flag \2
+ trap_ne
+ plp ;restore status
+ pla
+ endm
+
+tst_x macro ;testing result in x index & flags
+ php ;save flags
+ cpx #\1 ;test result
+ trap_ne
+ pla ;load status
+ pha
+ cmp_flag \2
+ trap_ne
+ plp ;restore status
+ endm
+
+tst_y macro ;testing result in y index & flags
+ php ;save flags
+ cpy #\1 ;test result
+ trap_ne
+ pla ;load status
+ pha
+ cmp_flag \2
+ trap_ne
+ plp ;restore status
+ endm
+
+tst_ax macro ;indexed testing result in accu & flags
+ php ;save flags
+ cmp \1,x ;test result
+ trap_ne
+ pla ;load status
+ eor_flag \3
+ cmp \2,x ;test flags
+ trap_ne ;
+ endm
+
+tst_ay macro ;indexed testing result in accu & flags
+ php ;save flags
+ cmp \1,y ;test result
+ trap_ne ;
+ pla ;load status
+ eor_flag \3
+ cmp \2,y ;test flags
+ trap_ne
+ endm
+
+tst_z macro ;indexed testing result in zp & flags
+ php ;save flags
+ lda zpt
+ cmp \1,x ;test result
+ trap_ne
+ pla ;load status
+ eor_flag \3
+ cmp \2,x ;test flags
+ trap_ne
+ endm
+
+tst_zx macro ;testing result in zp,x & flags
+ php ;save flags
+ lda zpt,x
+ cmp \1,x ;test result
+ trap_ne
+ pla ;load status
+ eor_flag \3
+ cmp \2,x ;test flags
+ trap_ne
+ endm
+
+tst_abs macro ;indexed testing result in memory & flags
+ php ;save flags
+ lda abst
+ cmp \1,x ;test result
+ trap_ne
+ pla ;load status
+ eor_flag \3
+ cmp \2,x ;test flags
+ trap_ne
+ endm
+
+tst_absx macro ;testing result in abs,x & flags
+ php ;save flags
+ lda abst,x
+ cmp \1,x ;test result
+ trap_ne
+ pla ;load status
+ eor_flag \3
+ cmp \2,x ;test flags
+ trap_ne
+ endm
+
+; RAM integrity test
+; verifies that none of the previous tests has altered RAM outside of the
+; designated write areas.
+; uses zpt word as indirect pointer, zpt+2 word as checksum
+ if ram_top > -1
+check_ram macro
+ cld
+ lda #0
+ sta zpt ;set low byte of indirect pointer
+ sta zpt+3 ;checksum high byte
+ ldx #11 ;reset modifiable RAM
+ccs1\? sta jxi_tab,x ;JMP indirect page cross area
+ dex
+ bpl ccs1\?
+ clc
+ ldx #zp_bss-zero_page ;zeropage - write test area
+ccs3\? adc zero_page,x
+ bcc ccs2\?
+ inc zpt+3 ;carry to high byte
+ clc
+ccs2\? inx
+ bne ccs3\?
+ ldx #hi(abs1) ;set high byte of indirect pointer
+ stx zpt+1
+ ldy #lo(abs1) ;data after write & execute test area
+ccs5\? adc (zpt),y
+ bcc ccs4\?
+ inc zpt+3 ;carry to high byte
+ clc
+ccs4\? iny
+ bne ccs5\?
+ inx ;advance RAM high address
+ stx zpt+1
+ cpx #ram_top
+ bne ccs5\?
+ sta zpt+2 ;checksum low is
+ cmp ram_chksm ;checksum low expected
+ trap_ne ;checksum mismatch
+ lda zpt+3 ;checksum high is
+ cmp ram_chksm+1 ;checksum high expected
+ trap_ne ;checksum mismatch
+ endm
+ else
+check_ram macro
+ ;RAM check disabled - RAM size not set
+ endm
+ endif
+
+next_test macro ;make sure, tests don't jump the fence
+ lda test_case ;previous test
+ cmp #test_num
+ trap_ne ;test is out of sequence
+test_num = test_num + 1
+ lda #test_num ;*** next tests' number
+ sta test_case
+ ;check_ram ;uncomment to find altered RAM after each test
+ endm
+
+ if load_data_direct = 1
+ data
+ else
+ bss ;uninitialized segment, copy of data at end of code!
+ endif
+ org zero_page
+;break test interrupt save
+irq_a ds 1 ;a register
+irq_x ds 1 ;x register
+ if I_flag = 2
+;masking for I bit in status
+flag_I_on ds 1 ;or mask to load flags
+flag_I_off ds 1 ;and mask to load flags
+ endif
+zpt ;5 bytes store/modify test area
+;add/subtract operand generation and result/flag prediction
+adfc ds 1 ;carry flag before op
+ad1 ds 1 ;operand 1 - accumulator
+ad2 ds 1 ;operand 2 - memory / immediate
+adrl ds 1 ;expected result bits 0-7
+adrh ds 1 ;expected result bit 8 (carry)
+adrf ds 1 ;expected flags NV0000ZC (-V in decimal mode)
+sb2 ds 1 ;operand 2 complemented for subtract
+zp_bss
+zp1 db $c3,$82,$41,0 ;test patterns for LDx BIT ROL ROR ASL LSR
+zp7f db $7f ;test pattern for compare
+;logical zeropage operands
+zpOR db 0,$1f,$71,$80 ;test pattern for OR
+zpAN db $0f,$ff,$7f,$80 ;test pattern for AND
+zpEO db $ff,$0f,$8f,$8f ;test pattern for EOR
+;indirect addressing pointers
+ind1 dw abs1 ;indirect pointer to pattern in absolute memory
+ dw abs1+1
+ dw abs1+2
+ dw abs1+3
+ dw abs7f
+inw1 dw abs1-$f8 ;indirect pointer for wrap-test pattern
+indt dw abst ;indirect pointer to store area in absolute memory
+ dw abst+1
+ dw abst+2
+ dw abst+3
+inwt dw abst-$f8 ;indirect pointer for wrap-test store
+indAN dw absAN ;indirect pointer to AND pattern in absolute memory
+ dw absAN+1
+ dw absAN+2
+ dw absAN+3
+indEO dw absEO ;indirect pointer to EOR pattern in absolute memory
+ dw absEO+1
+ dw absEO+2
+ dw absEO+3
+indOR dw absOR ;indirect pointer to OR pattern in absolute memory
+ dw absOR+1
+ dw absOR+2
+ dw absOR+3
+;add/subtract indirect pointers
+adi2 dw ada2 ;indirect pointer to operand 2 in absolute memory
+sbi2 dw sba2 ;indirect pointer to complemented operand 2 (SBC)
+adiy2 dw ada2-$ff ;with offset for indirect indexed
+sbiy2 dw sba2-$ff
+zp_bss_end
+
+ org data_segment
+pg_x ds 2 ;high JMP indirect address for page cross bug
+test_case ds 1 ;current test number
+ram_chksm ds 2 ;checksum for RAM integrity test
+;add/subtract operand copy - abs tests write area
+abst ;5 bytes store/modify test area
+ada2 ds 1 ;operand 2
+sba2 ds 1 ;operand 2 complemented for subtract
+ ds 3 ;fill remaining bytes
+data_bss
+ if load_data_direct = 1
+ex_adci adc #0 ;execute immediate opcodes
+ rts
+ex_sbci sbc #0 ;execute immediate opcodes
+ rts
+ else
+ex_adci ds 3
+ex_sbci ds 3
+ endif
+abs1 db $c3,$82,$41,0 ;test patterns for LDx BIT ROL ROR ASL LSR
+abs7f db $7f ;test pattern for compare
+;loads
+fLDx db fn,fn,0,fz ;expected flags for load
+;shifts
+rASL ;expected result ASL & ROL -carry
+rROL db $86,$04,$82,0 ; "
+rROLc db $87,$05,$83,1 ;expected result ROL +carry
+rLSR ;expected result LSR & ROR -carry
+rROR db $61,$41,$20,0 ; "
+rRORc db $e1,$c1,$a0,$80 ;expected result ROR +carry
+fASL ;expected flags for shifts
+fROL db fnc,fc,fn,fz ;no carry in
+fROLc db fnc,fc,fn,0 ;carry in
+fLSR
+fROR db fc,0,fc,fz ;no carry in
+fRORc db fnc,fn,fnc,fn ;carry in
+;increments (decrements)
+rINC db $7f,$80,$ff,0,1 ;expected result for INC/DEC
+fINC db 0,fn,fn,fz,0 ;expected flags for INC/DEC
+;logical memory operand
+absOR db 0,$1f,$71,$80 ;test pattern for OR
+absAN db $0f,$ff,$7f,$80 ;test pattern for AND
+absEO db $ff,$0f,$8f,$8f ;test pattern for EOR
+;logical accu operand
+absORa db 0,$f1,$1f,0 ;test pattern for OR
+absANa db $f0,$ff,$ff,$ff ;test pattern for AND
+absEOa db $ff,$f0,$f0,$0f ;test pattern for EOR
+;logical results
+absrlo db 0,$ff,$7f,$80
+absflo db fz,fn,0,fn
+data_bss_end
+;define area for page crossing JMP (abs) & JMP (abs,x) test
+jxi_tab equ data_segment + $100 - 7 ;JMP (jxi_tab,x) x=6
+ji_tab equ data_segment + $100 - 3 ;JMP (ji_tab+2)
+jxp_tab equ data_segment + $100 ;JMP (jxp_tab-255) x=255
+
+
+ code
+ org code_segment
+start cld
+ ldx #$ff
+ txs
+ lda #0 ;*** test 0 = initialize
+ sta test_case
+test_num = 0
+
+;stop interrupts before initializing BSS
+ if I_flag = 1
+ sei
+ endif
+
+;initialize I/O for report channel
+ if report = 1
+ jsr report_init
+ endif
+
+;initialize BSS segment
+ if load_data_direct != 1
+ ldx #zp_end-zp_init-1
+ld_zp lda zp_init,x
+ sta zp_bss,x
+ dex
+ bpl ld_zp
+ ldx #data_end-data_init-1
+ld_data lda data_init,x
+ sta data_bss,x
+ dex
+ bpl ld_data
+ if ROM_vectors = 1
+ ldx #5
+ld_vect lda vec_init,x
+ sta vec_bss,x
+ dex
+ bpl ld_vect
+ endif
+ endif
+
+;retain status of interrupt flag
+ if I_flag = 2
+ php
+ pla
+ and #4 ;isolate flag
+ sta flag_I_on ;or mask
+ eor #lo(~4) ;reverse
+ sta flag_I_off ;and mask
+ endif
+
+;generate checksum for RAM integrity test
+ if ram_top > -1
+ lda #0
+ sta zpt ;set low byte of indirect pointer
+ sta ram_chksm+1 ;checksum high byte
+ ldx #11 ;reset modifiable RAM
+gcs1 sta jxi_tab,x ;JMP indirect page cross area
+ dex
+ bpl gcs1
+ clc
+ ldx #zp_bss-zero_page ;zeropage - write test area
+gcs3 adc zero_page,x
+ bcc gcs2
+ inc ram_chksm+1 ;carry to high byte
+ clc
+gcs2 inx
+ bne gcs3
+ ldx #hi(abs1) ;set high byte of indirect pointer
+ stx zpt+1
+ ldy #lo(abs1) ;data after write & execute test area
+gcs5 adc (zpt),y
+ bcc gcs4
+ inc ram_chksm+1 ;carry to high byte
+ clc
+gcs4 iny
+ bne gcs5
+ inx ;advance RAM high address
+ stx zpt+1
+ cpx #ram_top
+ bne gcs5
+ sta ram_chksm ;checksum complete
+ endif
+ next_test
+
+;testing stack operations PHX PHY PLX PLY
+ lda #$99 ;protect a
+ ldx #$ff ;initialize stack
+ txs
+ ldx #$55
+ phx
+ ldx #$aa
+ phx
+ cpx $1fe ;on stack ?
+ trap_ne
+ tsx
+ cpx #$fd ;sp decremented?
+ trap_ne
+ ply
+ cpy #$aa ;successful retreived from stack?
+ trap_ne
+ ply
+ cpy #$55
+ trap_ne
+ cpy $1ff ;remains on stack?
+ trap_ne
+ tsx
+ cpx #$ff ;sp incremented?
+ trap_ne
+
+ ldy #$a5
+ phy
+ ldy #$5a
+ phy
+ cpy $1fe ;on stack ?
+ trap_ne
+ tsx
+ cpx #$fd ;sp decremented?
+ trap_ne
+ plx
+ cpx #$5a ;successful retreived from stack?
+ trap_ne
+ plx
+ cpx #$a5
+ trap_ne
+ cpx $1ff ;remains on stack?
+ trap_ne
+ tsx
+ cpx #$ff ;sp incremented?
+ trap_ne
+ cmp #$99 ;unchanged?
+ trap_ne
+ next_test
+
+; test PHX does not alter flags or X but PLX does
+ ldy #$aa ;protect y
+ set_x 1,$ff ;push
+ phx
+ tst_x 1,$ff
+ set_x 0,0
+ phx
+ tst_x 0,0
+ set_x $ff,$ff
+ phx
+ tst_x $ff,$ff
+ set_x 1,0
+ phx
+ tst_x 1,0
+ set_x 0,$ff
+ phx
+ tst_x 0,$ff
+ set_x $ff,0
+ phx
+ tst_x $ff,0
+ set_x 0,$ff ;pull
+ plx
+ tst_x $ff,$ff-zero
+ set_x $ff,0
+ plx
+ tst_x 0,zero
+ set_x $fe,$ff
+ plx
+ tst_x 1,$ff-zero-minus
+ set_x 0,0
+ plx
+ tst_x $ff,minus
+ set_x $ff,$ff
+ plx
+ tst_x 0,$ff-minus
+ set_x $fe,0
+ plx
+ tst_x 1,0
+ cpy #$aa ;Y unchanged
+ trap_ne
+ next_test
+
+; test PHY does not alter flags or Y but PLY does
+ ldx #$55 ;x & a protected
+ set_y 1,$ff ;push
+ phy
+ tst_y 1,$ff
+ set_y 0,0
+ phy
+ tst_y 0,0
+ set_y $ff,$ff
+ phy
+ tst_y $ff,$ff
+ set_y 1,0
+ phy
+ tst_y 1,0
+ set_y 0,$ff
+ phy
+ tst_y 0,$ff
+ set_y $ff,0
+ phy
+ tst_y $ff,0
+ set_y 0,$ff ;pull
+ ply
+ tst_y $ff,$ff-zero
+ set_y $ff,0
+ ply
+ tst_y 0,zero
+ set_y $fe,$ff
+ ply
+ tst_y 1,$ff-zero-minus
+ set_y 0,0
+ ply
+ tst_y $ff,minus
+ set_y $ff,$ff
+ ply
+ tst_y 0,$ff-minus
+ set_y $fe,0
+ ply
+ tst_y 1,0
+ cpx #$55 ;x unchanged?
+ trap_ne
+ next_test
+
+; PC modifying instructions (BRA, BBR, BBS, 1, 2, 3 byte NOPs, JMP(abs,x))
+; testing unconditional branch BRA
+
+ ldx #$81 ;protect unused registers
+ ldy #$7e
+ set_a 0,$ff
+ bra br1 ;branch should always be taken
+ trap
+br1
+ tst_a 0,$ff
+ set_a $ff,0
+ bra br2 ;branch should always be taken
+ trap
+br2
+ tst_a $ff,0
+ cpx #$81
+ trap_ne
+ cpy #$7e
+ trap_ne
+ next_test
+
+ ldy #0 ;branch range test
+ bra bra0
+
+bra1 cpy #1
+ trap_ne ;long range backward
+ iny
+ bra bra2
+
+bra3 cpy #3
+ trap_ne ;long range backward
+ iny
+ bra bra4
+
+bra5 cpy #5
+ trap_ne ;long range backward
+ iny
+ ldy #0
+ bra brf0
+
+ iny
+ iny
+ iny
+ iny
+brf0 bra brf1
+
+ iny
+ iny
+ iny
+brf1 iny
+ bra brf2
+
+ iny
+ iny
+brf2 iny
+ iny
+ bra brf3
+
+ iny
+brf3 iny
+ iny
+ iny
+ bra brf4
+
+brf4 iny
+ iny
+ iny
+ iny
+ cpy #10
+ trap_ne ;short range forward
+ bra brb0
+
+brb4 dey
+ dey
+ dey
+ dey
+ bra brb5
+
+brb3 dey
+ dey
+ dey
+ bra brb4
+
+brb2 dey
+ dey
+ bra brb3
+
+brb1 dey
+ bra brb2
+
+brb0 bra brb1
+
+brb5 cpy #0
+ trap_ne ;short range backward
+ bra bra6
+
+bra4 cpy #4
+ trap_ne ;long range forward
+ iny
+ bra bra5
+
+bra2 cpy #2
+ trap_ne ;long range forward
+ iny
+ bra bra3
+
+bra0 cpy #0
+ trap_ne ;long range forward
+ iny
+ bra bra1
+
+bra6
+ next_test
+
+ if rkwl_wdc_op = 1
+; testing BBR & BBS
+
+bbt macro ;\1 = bitnum
+ lda #(1<<\1) ;testing 1 bit on
+ sta zpt
+ set_a $33,0 ;with flags off
+ bbr \1,zpt,fail1\?
+ bbs \1,zpt,ok1\?
+ trap ;bbs branch not taken
+fail1\?
+ trap ;bbr branch taken
+ok1\?
+ tst_a $33,0
+ set_a $cc,$ff ;with flags on
+ bbr \1,zpt,fail2\?
+ bbs \1,zpt,ok2\?
+ trap ;bbs branch not taken
+fail2\?
+ trap ;bbr branch taken
+ok2\?
+ tst_a $cc,$ff
+ lda zpt
+ cmp #(1<<\1)
+ trap_ne ;zp altered
+ lda #$ff-(1<<\1) ;testing 1 bit off
+ sta zpt
+ set_a $33,0 ;with flags off
+ bbs \1,zpt,fail3\?
+ bbr \1,zpt,ok3\?
+ trap ;bbr branch not taken
+fail3\?
+ trap ;bbs branch taken
+ok3\?
+ tst_a $33,0
+ set_a $cc,$ff ;with flags on
+ bbs \1,zpt,fail4\?
+ bbr \1,zpt,ok4\?
+ trap ;bbr branch not taken
+fail4\?
+ trap ;bbs branch taken
+ok4\?
+ tst_a $cc,$ff
+ lda zpt
+ cmp #$ff-(1<<\1)
+ trap_ne ;zp altered
+ endm
+
+ ldx #$11 ;test bbr/bbs integrity
+ ldy #$22
+ bbt 0
+ bbt 1
+ bbt 2
+ bbt 3
+ bbt 4
+ bbt 5
+ bbt 6
+ bbt 7
+ cpx #$11
+ trap_ne ;x overwritten
+ cpy #$22
+ trap_ne ;y overwritten
+ next_test
+
+bbrc macro ;\1 = bitnum
+ bbr \1,zpt,skip\?
+ eor #(1<<\1)
+skip\?
+ endm
+bbsc macro ;\1 = bitnum
+ bbs \1,zpt,skip\?
+ eor #(1<<\1)
+skip\?
+ endm
+
+ lda #0 ;combined bit test
+ sta zpt
+bbcl lda #0
+ bbrc 0
+ bbrc 1
+ bbrc 2
+ bbrc 3
+ bbrc 4
+ bbrc 5
+ bbrc 6
+ bbrc 7
+ eor zpt
+ trap_ne ;failed bbr bitnum in accu
+ lda #$ff
+ bbsc 0
+ bbsc 1
+ bbsc 2
+ bbsc 3
+ bbsc 4
+ bbsc 5
+ bbsc 6
+ bbsc 7
+ eor zpt
+ trap_ne ;failed bbs bitnum in accu
+ inc zpt
+ bne bbcl
+ next_test
+ endif
+
+; testing NOP
+
+nop_test macro ;\1 = opcode, \2 = # of bytes
+ ldy #$42
+ ldx #4-\2
+ db \1 ;test nop length
+ if \2 = 1
+ dex
+ dex
+ endif
+ if \2 = 2
+ iny
+ dex
+ endif
+ if \2 = 3
+ iny
+ iny
+ endif
+ dex
+ trap_ne ;wrong number of bytes
+ set_a $ff-\1,0
+ db \1 ;test nop integrity - flags off
+ nop
+ nop
+ tst_a $ff-\1,0
+ set_a $aa-\1,$ff
+ db \1 ;test nop integrity - flags on
+ nop
+ nop
+ tst_a $aa-\1,$ff
+ cpy #$42
+ trap_ne ;y changed
+ cpx #0
+ trap_ne ;x changed
+ endm
+
+ if skip_nop = 0
+ nop_test $02,2
+ nop_test $22,2
+ nop_test $42,2
+ nop_test $62,2
+ nop_test $82,2
+ nop_test $c2,2
+ nop_test $e2,2
+ nop_test $44,2
+ nop_test $54,2
+ nop_test $d4,2
+ nop_test $f4,2
+ nop_test $5c,3
+ nop_test $dc,3
+ nop_test $fc,3
+ nop_test $03,1
+ nop_test $13,1
+ nop_test $23,1
+ nop_test $33,1
+ nop_test $43,1
+ nop_test $53,1
+ nop_test $63,1
+ nop_test $73,1
+ nop_test $83,1
+ nop_test $93,1
+ nop_test $a3,1
+ nop_test $b3,1
+ nop_test $c3,1
+ nop_test $d3,1
+ nop_test $e3,1
+ nop_test $f3,1
+ nop_test $0b,1
+ nop_test $1b,1
+ nop_test $2b,1
+ nop_test $3b,1
+ nop_test $4b,1
+ nop_test $5b,1
+ nop_test $6b,1
+ nop_test $7b,1
+ nop_test $8b,1
+ nop_test $9b,1
+ nop_test $ab,1
+ nop_test $bb,1
+ nop_test $eb,1
+ nop_test $fb,1
+ if rkwl_wdc_op = 0 ;NOPs not available on Rockwell & WDC 65C02
+ nop_test $07,1
+ nop_test $17,1
+ nop_test $27,1
+ nop_test $37,1
+ nop_test $47,1
+ nop_test $57,1
+ nop_test $67,1
+ nop_test $77,1
+ nop_test $87,1
+ nop_test $97,1
+ nop_test $a7,1
+ nop_test $b7,1
+ nop_test $c7,1
+ nop_test $d7,1
+ nop_test $e7,1
+ nop_test $f7,1
+ nop_test $0f,1
+ nop_test $1f,1
+ nop_test $2f,1
+ nop_test $3f,1
+ nop_test $4f,1
+ nop_test $5f,1
+ nop_test $6f,1
+ nop_test $7f,1
+ nop_test $8f,1
+ nop_test $9f,1
+ nop_test $af,1
+ nop_test $bf,1
+ nop_test $cf,1
+ nop_test $df,1
+ nop_test $ef,1
+ nop_test $ff,1
+ endif
+ if wdc_op = 0 ;NOPs not available on WDC 65C02 (WAI, STP)
+ nop_test $cb,1
+ nop_test $db,1
+ endif
+ next_test
+ endif
+
+; jump indirect (test page cross bug is fixed)
+ ldx #3 ;prepare table
+ji1 lda ji_adr,x
+ sta ji_tab,x
+ dex
+ bpl ji1
+ lda #hi(ji_px) ;high address if page cross bug
+ sta pg_x
+ set_stat 0
+ lda #'I'
+ ldx #'N'
+ ldy #'D' ;N=0, V=0, Z=0, C=0
+ jmp (ji_tab)
+ nop
+ trap_ne ;runover protection
+
+ dey
+ dey
+ji_ret php ;either SP or Y count will fail, if we do not hit
+ dey
+ dey
+ dey
+ plp
+ trap_eq ;returned flags OK?
+ trap_pl
+ trap_cc
+ trap_vc
+ cmp #('I'^$aa) ;returned registers OK?
+ trap_ne
+ cpx #('N'+1)
+ trap_ne
+ cpy #('D'-6)
+ trap_ne
+ tsx ;SP check
+ cpx #$ff
+ trap_ne
+ next_test
+
+; jump indexed indirect
+ ldx #11 ;prepare table
+jxi1 lda jxi_adr,x
+ sta jxi_tab,x
+ dex
+ bpl jxi1
+ lda #hi(jxi_px) ;high address if page cross bug
+ sta pg_x
+ set_stat 0
+ lda #'X'
+ ldx #4
+ ldy #'I' ;N=0, V=0, Z=0, C=0
+ jmp (jxi_tab,x)
+ nop
+ trap_ne ;runover protection
+
+ dey
+ dey
+jxi_ret php ;either SP or Y count will fail, if we do not hit
+ dey
+ dey
+ dey
+ plp
+ trap_eq ;returned flags OK?
+ trap_pl
+ trap_cc
+ trap_vc
+ cmp #('X'^$aa) ;returned registers OK?
+ trap_ne
+ cpx #6
+ trap_ne
+ cpy #('I'-6)
+ trap_ne
+ tsx ;SP check
+ cpx #$ff
+ trap_ne
+
+ lda #lo(jxp_ok) ;test with index causing a page cross
+ sta jxp_tab
+ lda #hi(jxp_ok)
+ sta jxp_tab+1
+ lda #lo(jxp_px)
+ sta pg_x
+ lda #hi(jxp_px)
+ sta pg_x+1
+ ldx #$ff
+ jmp (jxp_tab-$ff,x)
+
+jxp_px
+ trap ;page cross by index to wrong page
+
+jxp_ok
+ next_test
+
+ if ROM_vectors = 1
+; test BRK clears decimal mode
+ load_flag 0 ;with interrupts enabled if allowed!
+ pha
+ lda #'B'
+ ldx #'R'
+ ldy #'K'
+ plp ;N=0, V=0, Z=0, C=0
+ brk
+ dey ;should not be executed
+brk_ret0 ;address of break return
+ php ;either SP or Y count will fail, if we do not hit
+ dey
+ dey
+ dey
+ cmp #'B'^$aa ;returned registers OK?
+ ;the IRQ vector was never executed if A & X stay unmodified
+ trap_ne
+ cpx #'R'+1
+ trap_ne
+ cpy #'K'-6
+ trap_ne
+ pla ;returned flags OK (unchanged)?
+ cmp_flag 0
+ trap_ne
+ tsx ;sp?
+ cpx #$ff
+ trap_ne
+;pass 2
+ load_flag $ff ;with interrupts disabled if allowed!
+ pha
+ lda #$ff-'B'
+ ldx #$ff-'R'
+ ldy #$ff-'K'
+ plp ;N=1, V=1, Z=1, C=1
+ brk
+ dey ;should not be executed
+brk_ret1 ;address of break return
+ php ;either SP or Y count will fail, if we do not hit
+ dey
+ dey
+ dey
+ cmp #($ff-'B')^$aa ;returned registers OK?
+ ;the IRQ vector was never executed if A & X stay unmodified
+ trap_ne
+ cpx #$ff-'R'+1
+ trap_ne
+ cpy #$ff-'K'-6
+ trap_ne
+ pla ;returned flags OK (unchanged)?
+ cmp_flag $ff
+ trap_ne
+ tsx ;sp?
+ cpx #$ff
+ trap_ne
+ next_test
+ endif
+
+; testing accumulator increment/decrement INC A & DEC A
+ ldx #$ac ;protect x & y
+ ldy #$dc
+ set_a $fe,$ff
+ inc a ;ff
+ tst_as $ff,$ff-zero
+ inc a ;00
+ tst_as 0,$ff-minus
+ inc a ;01
+ tst_as 1,$ff-minus-zero
+ dec a ;00
+ tst_as 0,$ff-minus
+ dec a ;ff
+ tst_as $ff,$ff-zero
+ dec a ;fe
+ set_a $fe,0
+ inc a ;ff
+ tst_as $ff,minus
+ inc a ;00
+ tst_as 0,zero
+ inc a ;01
+ tst_as 1,0
+ dec a ;00
+ tst_as 0,zero
+ dec a ;ff
+ tst_as $ff,minus
+ cpx #$ac
+ trap_ne ;x altered during test
+ cpy #$dc
+ trap_ne ;y altered during test
+ tsx
+ cpx #$ff
+ trap_ne ;sp push/pop mismatch
+ next_test
+
+; testing load / store accumulator LDA / STA (zp)
+ ldx #$99 ;protect x & y
+ ldy #$66
+ set_stat 0
+ lda (ind1)
+ php ;test stores do not alter flags
+ eor #$c3
+ plp
+ sta (indt)
+ php ;flags after load/store sequence
+ eor #$c3
+ cmp #$c3 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag 0
+ cmp fLDx ;test flags
+ trap_ne
+ set_stat 0
+ lda (ind1+2)
+ php ;test stores do not alter flags
+ eor #$c3
+ plp
+ sta (indt+2)
+ php ;flags after load/store sequence
+ eor #$c3
+ cmp #$82 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag 0
+ cmp fLDx+1 ;test flags
+ trap_ne
+ set_stat 0
+ lda (ind1+4)
+ php ;test stores do not alter flags
+ eor #$c3
+ plp
+ sta (indt+4)
+ php ;flags after load/store sequence
+ eor #$c3
+ cmp #$41 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag 0
+ cmp fLDx+2 ;test flags
+ trap_ne
+ set_stat 0
+ lda (ind1+6)
+ php ;test stores do not alter flags
+ eor #$c3
+ plp
+ sta (indt+6)
+ php ;flags after load/store sequence
+ eor #$c3
+ cmp #0 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag 0
+ cmp fLDx+3 ;test flags
+ trap_ne
+ cpx #$99
+ trap_ne ;x altered during test
+ cpy #$66
+ trap_ne ;y altered during test
+
+ ldy #3 ;testing store result
+ ldx #0
+tstai1 lda abst,y
+ eor #$c3
+ cmp abs1,y
+ trap_ne ;store to indirect data
+ txa
+ sta abst,y ;clear
+ dey
+ bpl tstai1
+
+ ldx #$99 ;protect x & y
+ ldy #$66
+ set_stat $ff
+ lda (ind1)
+ php ;test stores do not alter flags
+ eor #$c3
+ plp
+ sta (indt)
+ php ;flags after load/store sequence
+ eor #$c3
+ cmp #$c3 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag lo~fnz ;mask bits not altered
+ cmp fLDx ;test flags
+ trap_ne
+ set_stat $ff
+ lda (ind1+2)
+ php ;test stores do not alter flags
+ eor #$c3
+ plp
+ sta (indt+2)
+ php ;flags after load/store sequence
+ eor #$c3
+ cmp #$82 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag lo~fnz ;mask bits not altered
+ cmp fLDx+1 ;test flags
+ trap_ne
+ set_stat $ff
+ lda (ind1+4)
+ php ;test stores do not alter flags
+ eor #$c3
+ plp
+ sta (indt+4)
+ php ;flags after load/store sequence
+ eor #$c3
+ cmp #$41 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag lo~fnz ;mask bits not altered
+ cmp fLDx+2 ;test flags
+ trap_ne
+ set_stat $ff
+ lda (ind1+6)
+ php ;test stores do not alter flags
+ eor #$c3
+ plp
+ sta (indt+6)
+ php ;flags after load/store sequence
+ eor #$c3
+ cmp #0 ;test result
+ trap_ne
+ pla ;load status
+ eor_flag lo~fnz ;mask bits not altered
+ cmp fLDx+3 ;test flags
+ trap_ne
+ cpx #$99
+ trap_ne ;x altered during test
+ cpy #$66
+ trap_ne ;y altered during test
+
+ ldy #3 ;testing store result
+ ldx #0
+tstai2 lda abst,y
+ eor #$c3
+ cmp abs1,y
+ trap_ne ;store to indirect data
+ txa
+ sta abst,y ;clear
+ dey
+ bpl tstai2
+ tsx
+ cpx #$ff
+ trap_ne ;sp push/pop mismatch
+ next_test
+
+; testing STZ - zp / abs / zp,x / abs,x
+ ldy #123 ;protect y
+ ldx #4 ;precharge test area
+ lda #7
+tstz1 sta zpt,x
+ asl a
+ dex
+ bpl tstz1
+ ldx #4
+ set_a $55,$ff
+ stz zpt
+ stz zpt+1
+ stz zpt+2
+ stz zpt+3
+ stz zpt+4
+ tst_a $55,$ff
+tstz2 lda zpt,x ;verify zeros stored
+ trap_ne ;non zero after STZ zp
+ dex
+ bpl tstz2
+ ldx #4 ;precharge test area
+ lda #7
+tstz3 sta zpt,x
+ asl a
+ dex
+ bpl tstz3
+ ldx #4
+ set_a $aa,0
+ stz zpt
+ stz zpt+1
+ stz zpt+2
+ stz zpt+3
+ stz zpt+4
+ tst_a $aa,0
+tstz4 lda zpt,x ;verify zeros stored
+ trap_ne ;non zero after STZ zp
+ dex
+ bpl tstz4
+
+ ldx #4 ;precharge test area
+ lda #7
+tstz5 sta abst,x
+ asl a
+ dex
+ bpl tstz5
+ ldx #4
+ set_a $55,$ff
+ stz abst
+ stz abst+1
+ stz abst+2
+ stz abst+3
+ stz abst+4
+ tst_a $55,$ff
+tstz6 lda abst,x ;verify zeros stored
+ trap_ne ;non zero after STZ abs
+ dex
+ bpl tstz6
+ ldx #4 ;precharge test area
+ lda #7
+tstz7 sta abst,x
+ asl a
+ dex
+ bpl tstz7
+ ldx #4
+ set_a $aa,0
+ stz abst
+ stz abst+1
+ stz abst+2
+ stz abst+3
+ stz abst+4
+ tst_a $aa,0
+tstz8 lda abst,x ;verify zeros stored
+ trap_ne ;non zero after STZ abs
+ dex
+ bpl tstz8
+
+ ldx #4 ;precharge test area
+ lda #7
+tstz11 sta zpt,x
+ asl a
+ dex
+ bpl tstz11
+ ldx #4
+tstz15
+ set_a $55,$ff
+ stz zpt,x
+ tst_a $55,$ff
+ dex
+ bpl tstz15
+ ldx #4
+tstz12 lda zpt,x ;verify zeros stored
+ trap_ne ;non zero after STZ zp
+ dex
+ bpl tstz12
+ ldx #4 ;precharge test area
+ lda #7
+tstz13 sta zpt,x
+ asl a
+ dex
+ bpl tstz13
+ ldx #4
+tstz16
+ set_a $aa,0
+ stz zpt,x
+ tst_a $aa,0
+ dex
+ bpl tstz16
+ ldx #4
+tstz14 lda zpt,x ;verify zeros stored
+ trap_ne ;non zero after STZ zp
+ dex
+ bpl tstz14
+
+ ldx #4 ;precharge test area
+ lda #7
+tstz21 sta abst,x
+ asl a
+ dex
+ bpl tstz21
+ ldx #4
+tstz25
+ set_a $55,$ff
+ stz abst,x
+ tst_a $55,$ff
+ dex
+ bpl tstz25
+ ldx #4
+tstz22 lda abst,x ;verify zeros stored
+ trap_ne ;non zero after STZ zp
+ dex
+ bpl tstz22
+ ldx #4 ;precharge test area
+ lda #7
+tstz23 sta abst,x
+ asl a
+ dex
+ bpl tstz23
+ ldx #4
+tstz26
+ set_a $aa,0
+ stz abst,x
+ tst_a $aa,0
+ dex
+ bpl tstz26
+ ldx #4
+tstz24 lda abst,x ;verify zeros stored
+ trap_ne ;non zero after STZ zp
+ dex
+ bpl tstz24
+
+ cpy #123
+ trap_ne ;y altered during test
+ tsx
+ cpx #$ff
+ trap_ne ;sp push/pop mismatch
+ next_test
+
+; testing BIT - zp,x / abs,x / #
+ ldy #$42
+ ldx #3
+ set_a $ff,0
+ bit zp1,x ;00 - should set Z / clear NV
+ tst_a $ff,fz
+ dex
+ set_a 1,0
+ bit zp1,x ;41 - should set V (M6) / clear NZ
+ tst_a 1,fv
+ dex
+ set_a 1,0
+ bit zp1,x ;82 - should set N (M7) & Z / clear V
+ tst_a 1,fnz
+ dex
+ set_a 1,0
+ bit zp1,x ;c3 - should set N (M7) & V (M6) / clear Z
+ tst_a 1,fnv
+
+ set_a 1,$ff
+ bit zp1,x ;c3 - should set N (M7) & V (M6) / clear Z
+ tst_a 1,~fz
+ inx
+ set_a 1,$ff
+ bit zp1,x ;82 - should set N (M7) & Z / clear V
+ tst_a 1,~fv
+ inx
+ set_a 1,$ff
+ bit zp1,x ;41 - should set V (M6) / clear NZ
+ tst_a 1,~fnz
+ inx
+ set_a $ff,$ff
+ bit zp1,x ;00 - should set Z / clear NV
+ tst_a $ff,~fnv
+
+ set_a $ff,0
+ bit abs1,x ;00 - should set Z / clear NV
+ tst_a $ff,fz
+ dex
+ set_a 1,0
+ bit abs1,x ;41 - should set V (M6) / clear NZ
+ tst_a 1,fv
+ dex
+ set_a 1,0
+ bit abs1,x ;82 - should set N (M7) & Z / clear V
+ tst_a 1,fnz
+ dex
+ set_a 1,0
+ bit abs1,x ;c3 - should set N (M7) & V (M6) / clear Z
+ tst_a 1,fnv
+
+ set_a 1,$ff
+ bit abs1,x ;c3 - should set N (M7) & V (M6) / clear Z
+ tst_a 1,~fz
+ inx
+ set_a 1,$ff
+ bit abs1,x ;82 - should set N (M7) & Z / clear V
+ tst_a 1,~fv
+ inx
+ set_a 1,$ff
+ bit abs1,x ;41 - should set V (M6) / clear NZ
+ tst_a 1,~fnz
+ inx
+ set_a $ff,$ff
+ bit abs1,x ;00 - should set Z / clear NV
+ tst_a $ff,~fnv
+
+ set_a $ff,0
+ bit #$00 ;00 - should set Z
+ tst_a $ff,fz
+ dex
+ set_a 1,0
+ bit #$41 ;41 - should clear Z
+ tst_a 1,0
+; *** DEBUG INFO ***
+; if it fails the previous test and your BIT # has set the V flag
+; see http://forum.6502.org/viewtopic.php?f=2&t=2241&p=27243#p27239
+; why it shouldn't alter N or V flags on a BIT #
+ dex
+ set_a 1,0
+ bit #$82 ;82 - should set Z
+ tst_a 1,fz
+ dex
+ set_a 1,0
+ bit #$c3 ;c3 - should clear Z
+ tst_a 1,0
+
+ set_a 1,$ff
+ bit #$c3 ;c3 - clear Z
+ tst_a 1,~fz
+ inx
+ set_a 1,$ff
+ bit #$82 ;82 - should set Z
+ tst_a 1,$ff
+ inx
+ set_a 1,$ff
+ bit #$41 ;41 - should clear Z
+ tst_a 1,~fz
+ inx
+ set_a $ff,$ff
+ bit #$00 ;00 - should set Z
+ tst_a $ff,$ff
+
+ cpx #3
+ trap_ne ;x altered during test
+ cpy #$42
+ trap_ne ;y altered during test
+ tsx
+ cpx #$ff
+ trap_ne ;sp push/pop mismatch
+ next_test
+
+; testing TRB, TSB - zp / abs
+
+trbt macro ;\1 = memory, \2 = flags
+ sty \1
+ load_flag \2
+ pha
+ lda zpt+1
+ plp
+ trb \1
+ php
+ cmp zpt+1
+ trap_ne ;accu was changed
+ pla
+ pha
+ ora #fz ;mask Z
+ cmp_flag \2|fz
+ trap_ne ;flags changed except Z
+ pla
+ and #fz
+ cmp zpt+2
+ trap_ne ;Z flag invalid
+ lda zpt+3
+ cmp zpt
+ trap_ne ;altered bits in memory wrong
+ endm
+
+tsbt macro ;\1 = memory, \2 = flags
+ sty \1
+ load_flag \2
+ pha
+ lda zpt+1
+ plp
+ tsb \1
+ php
+ cmp zpt+1
+ trap_ne ;accu was changed
+ pla
+ pha
+ ora #fz ;mask Z
+ cmp_flag \2|fz
+ trap_ne ;flags changed except Z
+ pla
+ and #fz
+ cmp zpt+2
+ trap_ne ;Z flag invalid
+ lda zpt+4
+ cmp zpt
+ trap_ne ;altered bits in memory wrong
+ endm
+
+ ldx #$c0
+ ldy #0 ;op1 - memory save
+ ; zpt ;op1 - memory modifiable
+ stz zpt+1 ;op2 - accu
+ ; zpt+2 ;and flags
+ ; zpt+3 ;memory after reset
+ ; zpt+4 ;memory after set
+
+tbt1 tya
+ and zpt+1 ;set Z by anding the 2 operands
+ php
+ pla
+ and #fz ;mask Z
+ sta zpt+2
+ tya ;reset op1 bits by op2
+ eor #$ff
+ ora zpt+1
+ eor #$ff
+ sta zpt+3
+ tya ;set op1 bits by op2
+ ora zpt+1
+ sta zpt+4
+
+ trbt zpt,$ff
+ trbt abst,$ff
+ trbt zpt,0
+ trbt abst,0
+ tsbt zpt,$ff
+ tsbt abst,$ff
+ tsbt zpt,0
+ tsbt abst,0
+
+ iny ;iterate op1
+ bne tbt3
+ inc zpt+1 ;iterate op2
+ beq tbt2
+tbt3 jmp tbt1
+tbt2
+ cpx #$c0
+ trap_ne ;x altered during test
+ tsx
+ cpx #$ff
+ trap_ne ;sp push/pop mismatch
+ next_test
+
+ if rkwl_wdc_op = 1
+; testing RMB, SMB - zp
+rmbt macro ;\1 = bitnum
+ lda #$ff
+ sta zpt
+ set_a $a5,0
+ rmb \1,zpt
+ tst_a $a5,0
+ lda zpt
+ cmp #$ff-(1<<\1)
+ trap_ne ;wrong bits set or cleared
+ lda #1<<\1
+ sta zpt
+ set_a $5a,$ff
+ rmb \1,zpt
+ tst_a $5a,$ff
+ lda zpt
+ trap_ne ;wrong bits set or cleared
+ endm
+smbt macro ;\1 = bitnum
+ lda #$ff-(1<<\1)
+ sta zpt
+ set_a $a5,0
+ smb \1,zpt
+ tst_a $a5,0
+ lda zpt
+ cmp #$ff
+ trap_ne ;wrong bits set or cleared
+ lda #0
+ sta zpt
+ set_a $5a,$ff
+ smb \1,zpt
+ tst_a $5a,$ff
+ lda zpt
+ cmp #1<<\1
+ trap_ne ;wrong bits set or cleared
+ endm
+
+ ldx #$ba ;protect x & y
+ ldy #$d0
+ rmbt 0
+ rmbt 1
+ rmbt 2
+ rmbt 3
+ rmbt 4
+ rmbt 5
+ rmbt 6
+ rmbt 7
+ smbt 0
+ smbt 1
+ smbt 2
+ smbt 3
+ smbt 4
+ smbt 5
+ smbt 6
+ smbt 7
+ cpx #$ba
+ trap_ne ;x altered during test
+ cpy #$d0
+ trap_ne ;y altered during test
+ tsx
+ cpx #$ff
+ trap_ne ;sp push/pop mismatch
+ next_test
+ endif
+
+; testing CMP - (zp)
+ ldx #$de ;protect x & y
+ ldy #$ad
+ set_a $80,0
+ cmp (ind1+8)
+ tst_a $80,fc
+ set_a $7f,0
+ cmp (ind1+8)
+ tst_a $7f,fzc
+ set_a $7e,0
+ cmp (ind1+8)
+ tst_a $7e,fn
+ set_a $80,$ff
+ cmp (ind1+8)
+ tst_a $80,~fnz
+ set_a $7f,$ff
+ cmp (ind1+8)
+ tst_a $7f,~fn
+ set_a $7e,$ff
+ cmp (ind1+8)
+ tst_a $7e,~fzc
+ cpx #$de
+ trap_ne ;x altered during test
+ cpy #$ad
+ trap_ne ;y altered during test
+ tsx
+ cpx #$ff
+ trap_ne ;sp push/pop mismatch
+ next_test
+
+; testing logical instructions - AND EOR ORA (zp)
+ ldx #$42 ;protect x & y
+
+ ldy #0 ;AND
+ lda indAN ;set indirect address
+ sta zpt
+ lda indAN+1
+ sta zpt+1
+tand1
+ set_ay absANa,0
+ and (zpt)
+ tst_ay absrlo,absflo,0
+ inc zpt
+ iny
+ cpy #4
+ bne tand1
+ dey
+ dec zpt
+tand2
+ set_ay absANa,$ff
+ and (zpt)
+ tst_ay absrlo,absflo,$ff-fnz
+ dec zpt
+ dey
+ bpl tand2
+
+ ldy #0 ;EOR
+ lda indEO ;set indirect address
+ sta zpt
+ lda indEO+1
+ sta zpt+1
+teor1
+ set_ay absEOa,0
+ eor (zpt)
+ tst_ay absrlo,absflo,0
+ inc zpt
+ iny
+ cpy #4
+ bne teor1
+ dey
+ dec zpt
+teor2
+ set_ay absEOa,$ff
+ eor (zpt)
+ tst_ay absrlo,absflo,$ff-fnz
+ dec zpt
+ dey
+ bpl teor2
+
+ ldy #0 ;ORA
+ lda indOR ;set indirect address
+ sta zpt
+ lda indOR+1
+ sta zpt+1
+tora1
+ set_ay absORa,0
+ ora (zpt)
+ tst_ay absrlo,absflo,0
+ inc zpt
+ iny
+ cpy #4
+ bne tora1
+ dey
+ dec zpt
+tora2
+ set_ay absORa,$ff
+ ora (zpt)
+ tst_ay absrlo,absflo,$ff-fnz
+ dec zpt
+ dey
+ bpl tora2
+
+ cpx #$42
+ trap_ne ;x altered during test
+ tsx
+ cpx #$ff
+ trap_ne ;sp push/pop mismatch
+ next_test
+
+ if I_flag = 3
+ cli
+ endif
+
+; full binary add/subtract test - (zp) only
+; iterates through all combinations of operands and carry input
+; uses increments/decrements to predict result & result flags
+ cld
+ ldx #ad2 ;for indexed test
+ ldy #$ff ;max range
+ lda #0 ;start with adding zeroes & no carry
+ sta adfc ;carry in - for diag
+ sta ad1 ;operand 1 - accumulator
+ sta ad2 ;operand 2 - memory or immediate
+ sta ada2 ;non zp
+ sta adrl ;expected result bits 0-7
+ sta adrh ;expected result bit 8 (carry out)
+ lda #$ff ;complemented operand 2 for subtract
+ sta sb2
+ sta sba2 ;non zp
+ lda #2 ;expected Z-flag
+ sta adrf
+tadd clc ;test with carry clear
+ jsr chkadd
+ inc adfc ;now with carry
+ inc adrl ;result +1
+ php ;save N & Z from low result
+ php
+ pla ;accu holds expected flags
+ and #$82 ;mask N & Z
+ plp
+ bne tadd1
+ inc adrh ;result bit 8 - carry
+tadd1 ora adrh ;merge C to expected flags
+ sta adrf ;save expected flags except overflow
+ sec ;test with carry set
+ jsr chkadd
+ dec adfc ;same for operand +1 but no carry
+ inc ad1
+ bne tadd ;iterate op1
+ lda #0 ;preset result to op2 when op1 = 0
+ sta adrh
+ inc ada2
+ inc ad2
+ php ;save NZ as operand 2 becomes the new result
+ pla
+ and #$82 ;mask N00000Z0
+ sta adrf ;no need to check carry as we are adding to 0
+ dec sb2 ;complement subtract operand 2
+ dec sba2
+ lda ad2
+ sta adrl
+ bne tadd ;iterate op2
+
+ cpx #ad2
+ trap_ne ;x altered during test
+ cpy #$ff
+ trap_ne ;y altered during test
+ tsx
+ cpx #$ff
+ trap_ne ;sp push/pop mismatch
+ next_test
+
+; decimal add/subtract test
+; *** WARNING - tests documented behavior only! ***
+; only valid BCD operands are tested, the V flag is ignored
+; although V is declared as beeing valid on the 65C02 it has absolutely
+; no use in BCD math. No sign = no overflow!
+; iterates through all valid combinations of operands and carry input
+; uses increments/decrements to predict result & carry flag
+ sed
+ ldx #ad2 ;for indexed test
+ ldy #$ff ;max range
+ lda #$99 ;start with adding 99 to 99 with carry
+ sta ad1 ;operand 1 - accumulator
+ sta ad2 ;operand 2 - memory or immediate
+ sta ada2 ;non zp
+ sta adrl ;expected result bits 0-7
+ lda #1 ;set carry in & out
+ sta adfc ;carry in - for diag
+ sta adrh ;expected result bit 8 (carry out)
+ lda #$81 ;set N & C (99 + 99 + C = 99 + C)
+ sta adrf
+ lda #0 ;complemented operand 2 for subtract
+ sta sb2
+ sta sba2 ;non zp
+tdad sec ;test with carry set
+ jsr chkdad
+ dec adfc ;now with carry clear
+ lda adrl ;decimal adjust result
+ bne tdad1 ;skip clear carry & preset result 99 (9A-1)
+ dec adrh
+ lda #$99
+ sta adrl
+ bne tdad3
+tdad1 and #$f ;lower nibble mask
+ bne tdad2 ;no decimal adjust needed
+ dec adrl ;decimal adjust (?0-6)
+ dec adrl
+ dec adrl
+ dec adrl
+ dec adrl
+ dec adrl
+tdad2 dec adrl ;result -1
+tdad3 php ;save valid flags
+ pla
+ and #$82 ;N-----Z-
+ ora adrh ;N-----ZC
+ sta adrf
+ clc ;test with carry clear
+ jsr chkdad
+ inc adfc ;same for operand -1 but with carry
+ lda ad1 ;decimal adjust operand 1
+ beq tdad5 ;iterate operand 2
+ and #$f ;lower nibble mask
+ bne tdad4 ;skip decimal adjust
+ dec ad1 ;decimal adjust (?0-6)
+ dec ad1
+ dec ad1
+ dec ad1
+ dec ad1
+ dec ad1
+tdad4 dec ad1 ;operand 1 -1
+ jmp tdad ;iterate op1
+
+tdad5 lda #$99 ;precharge op1 max
+ sta ad1
+ lda ad2 ;decimal adjust operand 2
+ beq tdad7 ;end of iteration
+ and #$f ;lower nibble mask
+ bne tdad6 ;skip decimal adjust
+ dec ad2 ;decimal adjust (?0-6)
+ dec ad2
+ dec ad2
+ dec ad2
+ dec ad2
+ dec ad2
+ inc sb2 ;complemented decimal adjust for subtract (?9+6)
+ inc sb2
+ inc sb2
+ inc sb2
+ inc sb2
+ inc sb2
+tdad6 dec ad2 ;operand 2 -1
+ inc sb2 ;complemented operand for subtract
+ lda sb2
+ sta sba2 ;copy as non zp operand
+ lda ad2
+ sta ada2 ;copy as non zp operand
+ sta adrl ;new result since op1+carry=00+carry +op2=op2
+ php ;save flags
+ pla
+ and #$82 ;N-----Z-
+ ora #1 ;N-----ZC
+ sta adrf
+ inc adrh ;result carry
+ jmp tdad ;iterate op2
+
+tdad7 cpx #ad2
+ trap_ne ;x altered during test
+ cpy #$ff
+ trap_ne ;y altered during test
+ tsx
+ cpx #$ff
+ trap_ne ;sp push/pop mismatch
+ cld
+
+ lda test_case
+ cmp #test_num
+ trap_ne ;previous test is out of sequence
+ lda #$f0 ;mark opcode testing complete
+ sta test_case
+
+; final RAM integrity test
+; verifies that none of the previous tests has altered RAM outside of the
+; designated write areas.
+ check_ram
+; *** DEBUG INFO ***
+; to debug checksum errors uncomment check_ram in the next_test macro to
+; narrow down the responsible opcode.
+; may give false errors when monitor, OS or other background activity is
+; allowed during previous tests.
+
+
+; S U C C E S S ************************************************
+; -------------
+ success ;if you get here everything went well
+; -------------
+; S U C C E S S ************************************************
+ jmp start ;run again
+
+; core subroutine of the decimal add/subtract test
+; *** WARNING - tests documented behavior only! ***
+; only valid BCD operands are tested, V flag is ignored
+; iterates through all valid combinations of operands and carry input
+; uses increments/decrements to predict result & carry flag
+chkdad
+; decimal ADC / SBC zp
+ php ;save carry for subtract
+ lda ad1
+ adc ad2 ;perform add
+ php
+ cmp adrl ;check result
+ trap_ne ;bad result
+ pla ;check flags
+ and #$83 ;mask N-----ZC
+ cmp adrf
+ trap_ne ;bad flags
+ plp
+ php ;save carry for next add
+ lda ad1
+ sbc sb2 ;perform subtract
+ php
+ cmp adrl ;check result
+ trap_ne ;bad result
+ pla ;check flags
+ and #$83 ;mask N-----ZC
+ cmp adrf
+ trap_ne ;bad flags
+ plp
+; decimal ADC / SBC abs
+ php ;save carry for subtract
+ lda ad1
+ adc ada2 ;perform add
+ php
+ cmp adrl ;check result
+ trap_ne ;bad result
+ pla ;check flags
+ and #$83 ;mask N-----ZC
+ cmp adrf
+ trap_ne ;bad flags
+ plp
+ php ;save carry for next add
+ lda ad1
+ sbc sba2 ;perform subtract
+ php
+ cmp adrl ;check result
+ trap_ne ;bad result
+ pla ;check flags
+ and #$83 ;mask N-----ZC
+ cmp adrf
+ trap_ne ;bad flags
+ plp
+; decimal ADC / SBC #
+ php ;save carry for subtract
+ lda ad2
+ sta ex_adci+1 ;set ADC # operand
+ lda ad1
+ jsr ex_adci ;execute ADC # in RAM
+ php
+ cmp adrl ;check result
+ trap_ne ;bad result
+ pla ;check flags
+ and #$83 ;mask N-----ZC
+ cmp adrf
+ trap_ne ;bad flags
+ plp
+ php ;save carry for next add
+ lda sb2
+ sta ex_sbci+1 ;set SBC # operand
+ lda ad1
+ jsr ex_sbci ;execute SBC # in RAM
+ php
+ cmp adrl ;check result
+ trap_ne ;bad result
+ pla ;check flags
+ and #$83 ;mask N-----ZC
+ cmp adrf
+ trap_ne ;bad flags
+ plp
+; decimal ADC / SBC zp,x
+ php ;save carry for subtract
+ lda ad1
+ adc 0,x ;perform add
+ php
+ cmp adrl ;check result
+ trap_ne ;bad result
+ pla ;check flags
+ and #$83 ;mask N-----ZC
+ cmp adrf
+ trap_ne ;bad flags
+ plp
+ php ;save carry for next add
+ lda ad1
+ sbc sb2-ad2,x ;perform subtract
+ php
+ cmp adrl ;check result
+ trap_ne ;bad result
+ pla ;check flags
+ and #$83 ;mask N-----ZC
+ cmp adrf
+ trap_ne ;bad flags
+ plp
+; decimal ADC / SBC abs,x
+ php ;save carry for subtract
+ lda ad1
+ adc ada2-ad2,x ;perform add
+ php
+ cmp adrl ;check result
+ trap_ne ;bad result
+ pla ;check flags
+ and #$83 ;mask N-----ZC
+ cmp adrf
+ trap_ne ;bad flags
+ plp
+ php ;save carry for next add
+ lda ad1
+ sbc sba2-ad2,x ;perform subtract
+ php
+ cmp adrl ;check result
+ trap_ne ;bad result
+ pla ;check flags
+ and #$83 ;mask N-----ZC
+ cmp adrf
+ trap_ne ;bad flags
+ plp
+; decimal ADC / SBC abs,y
+ php ;save carry for subtract
+ lda ad1
+ adc ada2-$ff,y ;perform add
+ php
+ cmp adrl ;check result
+ trap_ne ;bad result
+ pla ;check flags
+ and #$83 ;mask N-----ZC
+ cmp adrf
+ trap_ne ;bad flags
+ plp
+ php ;save carry for next add
+ lda ad1
+ sbc sba2-$ff,y ;perform subtract
+ php
+ cmp adrl ;check result
+ trap_ne ;bad result
+ pla ;check flags
+ and #$83 ;mask N-----ZC
+ cmp adrf
+ trap_ne ;bad flags
+ plp
+; decimal ADC / SBC (zp,x)
+ php ;save carry for subtract
+ lda ad1
+ adc (lo adi2-ad2,x) ;perform add
+ php
+ cmp adrl ;check result
+ trap_ne ;bad result
+ pla ;check flags
+ and #$83 ;mask N-----ZC
+ cmp adrf
+ trap_ne ;bad flags
+ plp
+ php ;save carry for next add
+ lda ad1
+ sbc (lo sbi2-ad2,x) ;perform subtract
+ php
+ cmp adrl ;check result
+ trap_ne ;bad result
+ pla ;check flags
+ and #$83 ;mask N-----ZC
+ cmp adrf
+ trap_ne ;bad flags
+ plp
+; decimal ADC / SBC (abs),y
+ php ;save carry for subtract
+ lda ad1
+ adc (adiy2),y ;perform add
+ php
+ cmp adrl ;check result
+ trap_ne ;bad result
+ pla ;check flags
+ and #$83 ;mask N-----ZC
+ cmp adrf
+ trap_ne ;bad flags
+ plp
+ php ;save carry for next add
+ lda ad1
+ sbc (sbiy2),y ;perform subtract
+ php
+ cmp adrl ;check result
+ trap_ne ;bad result
+ pla ;check flags
+ and #$83 ;mask N-----ZC
+ cmp adrf
+ trap_ne ;bad flags
+ plp
+; decimal ADC / SBC (zp)
+ php ;save carry for subtract
+ lda ad1
+ adc (adi2) ;perform add
+ php
+ cmp adrl ;check result
+ trap_ne ;bad result
+ pla ;check flags
+ and #$83 ;mask N-----ZC
+ cmp adrf
+ trap_ne ;bad flags
+ plp
+ php ;save carry for next add
+ lda ad1
+ sbc (sbi2) ;perform subtract
+ php
+ cmp adrl ;check result
+ trap_ne ;bad result
+ pla ;check flags
+ and #$83 ;mask N-----ZC
+ cmp adrf
+ trap_ne ;bad flags
+ plp
+ rts
+
+; core subroutine of the full binary add/subtract test
+; iterates through all combinations of operands and carry input
+; uses increments/decrements to predict result & result flags
+chkadd lda adrf ;add V-flag if overflow
+ and #$83 ;keep N-----ZC / clear V
+ pha
+ lda ad1 ;test sign unequal between operands
+ eor ad2
+ bmi ckad1 ;no overflow possible - operands have different sign
+ lda ad1 ;test sign equal between operands and result
+ eor adrl
+ bpl ckad1 ;no overflow occured - operand and result have same sign
+ pla
+ ora #$40 ;set V
+ pha
+ckad1 pla
+ sta adrf ;save expected flags
+; binary ADC / SBC (zp)
+ php ;save carry for subtract
+ lda ad1
+ adc (adi2) ;perform add
+ php
+ cmp adrl ;check result
+ trap_ne ;bad result
+ pla ;check flags
+ and #$c3 ;mask NV----ZC
+ cmp adrf
+ trap_ne ;bad flags
+ plp
+ php ;save carry for next add
+ lda ad1
+ sbc (sbi2) ;perform subtract
+ php
+ cmp adrl ;check result
+ trap_ne ;bad result
+ pla ;check flags
+ and #$c3 ;mask NV----ZC
+ cmp adrf
+ trap_ne ;bad flags
+ plp
+ rts
+
+; target for the jump indirect test
+ji_adr dw test_ji
+ dw ji_ret
+
+ dey
+ dey
+test_ji
+ php ;either SP or Y count will fail, if we do not hit
+ dey
+ dey
+ dey
+ plp
+ trap_cs ;flags loaded?
+ trap_vs
+ trap_mi
+ trap_eq
+ cmp #'I' ;registers loaded?
+ trap_ne
+ cpx #'N'
+ trap_ne
+ cpy #('D'-3)
+ trap_ne
+ pha ;save a,x
+ txa
+ pha
+ tsx
+ cpx #$fd ;check SP
+ trap_ne
+ pla ;restore x
+ tax
+ set_stat $ff
+ pla ;restore a
+ inx ;return registers with modifications
+ eor #$aa ;N=1, V=1, Z=0, C=1
+ jmp (ji_tab+2)
+ nop
+ nop
+ trap ;runover protection
+ jmp start ;catastrophic error - cannot continue
+
+; target for the jump indirect test
+jxi_adr dw trap_ind
+ dw trap_ind
+ dw test_jxi ;+4
+ dw jxi_ret ;+6
+ dw trap_ind
+ dw trap_ind
+
+ dey
+ dey
+test_jxi
+ php ;either SP or Y count will fail, if we do not hit
+ dey
+ dey
+ dey
+ plp
+ trap_cs ;flags loaded?
+ trap_vs
+ trap_mi
+ trap_eq
+ cmp #'X' ;registers loaded?
+ trap_ne
+ cpx #4
+ trap_ne
+ cpy #('I'-3)
+ trap_ne
+ pha ;save a,x
+ txa
+ pha
+ tsx
+ cpx #$fd ;check SP
+ trap_ne
+ pla ;restore x
+ tax
+ set_stat $ff
+ pla ;restore a
+ inx ;return registers with modifications
+ inx
+ eor #$aa ;N=1, V=1, Z=0, C=1
+ jmp (jxi_tab,x)
+ nop
+ nop
+ trap ;runover protection
+ jmp start ;catastrophic error - cannot continue
+
+; JMP (abs,x) with bad x
+ nop
+ nop
+trap_ind
+ nop
+ nop
+ trap ;near miss indexed indirect jump
+ jmp start ;catastrophic error - cannot continue
+
+;trap in case of unexpected IRQ, NMI, BRK, RESET
+nmi_trap
+ trap ;check stack for conditions at NMI
+ jmp start ;catastrophic error - cannot continue
+res_trap
+ trap ;unexpected RESET
+ jmp start ;catastrophic error - cannot continue
+
+ dey
+ dey
+irq_trap ;BRK test or unextpected BRK or IRQ
+ php ;either SP or Y count will fail, if we do not hit
+ dey
+ dey
+ dey
+ ;next traps could be caused by unexpected BRK or IRQ
+ ;check stack for BREAK and originating location
+ ;possible jump/branch into weeds (uninitialized space)
+ cmp #$ff-'B' ;BRK pass 2 registers loaded?
+ beq break2
+ cmp #'B' ;BRK pass 1 registers loaded?
+ trap_ne
+ cpx #'R'
+ trap_ne
+ cpy #'K'-3
+ trap_ne
+ sta irq_a ;save registers during break test
+ stx irq_x
+ tsx ;test break on stack
+ lda $102,x
+ cmp_flag 0 ;break test should have B=1 & unused=1 on stack
+ trap_ne ;possible no break flag on stack
+ pla
+ cmp_flag intdis ;should have added interrupt disable
+ trap_ne
+ tsx
+ cpx #$fc ;sp -3? (return addr, flags)
+ trap_ne
+ lda $1ff ;propper return on stack
+ cmp #hi(brk_ret0)
+ trap_ne
+ lda $1fe
+ cmp #lo(brk_ret0)
+ trap_ne
+ load_flag $ff
+ pha
+ ldx irq_x
+ inx ;return registers with modifications
+ lda irq_a
+ eor #$aa
+ plp ;N=1, V=1, Z=1, C=1 but original flags should be restored
+ rti
+ trap ;runover protection
+ jmp start ;catastrophic error - cannot continue
+
+break2 ;BRK pass 2
+ cpx #$ff-'R'
+ trap_ne
+ cpy #$ff-'K'-3
+ trap_ne
+ sta irq_a ;save registers during break test
+ stx irq_x
+ tsx ;test break on stack
+ lda $102,x
+ cmp_flag $ff ;break test should have B=1
+ trap_ne ;possibly no break flag on stack
+ pla
+ cmp_flag $ff-decmode ;actual passed flags should have decmode cleared
+ trap_ne
+ tsx
+ cpx #$fc ;sp -3? (return addr, flags)
+ trap_ne
+ lda $1ff ;propper return on stack
+ cmp #hi(brk_ret1)
+ trap_ne
+ lda $1fe
+ cmp #lo(brk_ret1)
+ trap_ne
+ load_flag intdis
+ pha
+ ldx irq_x
+ inx ;return registers with modifications
+ lda irq_a
+ eor #$aa
+ plp ;N=0, V=0, Z=0, C=0 but original flags should be restored
+ rti
+ trap ;runover protection
+ jmp start ;catastrophic error - cannot continue
+
+ if report = 1
+ include "report.i65"
+ endif
+
+;copy of data to initialize BSS segment
+ if load_data_direct != 1
+zp_init
+zp1_ db $c3,$82,$41,0 ;test patterns for LDx BIT ROL ROR ASL LSR
+zp7f_ db $7f ;test pattern for compare
+;logical zeropage operands
+zpOR_ db 0,$1f,$71,$80 ;test pattern for OR
+zpAN_ db $0f,$ff,$7f,$80 ;test pattern for AND
+zpEO_ db $ff,$0f,$8f,$8f ;test pattern for EOR
+;indirect addressing pointers
+ind1_ dw abs1 ;indirect pointer to pattern in absolute memory
+ dw abs1+1
+ dw abs1+2
+ dw abs1+3
+ dw abs7f
+inw1_ dw abs1-$f8 ;indirect pointer for wrap-test pattern
+indt_ dw abst ;indirect pointer to store area in absolute memory
+ dw abst+1
+ dw abst+2
+ dw abst+3
+inwt_ dw abst-$f8 ;indirect pointer for wrap-test store
+indAN_ dw absAN ;indirect pointer to AND pattern in absolute memory
+ dw absAN+1
+ dw absAN+2
+ dw absAN+3
+indEO_ dw absEO ;indirect pointer to EOR pattern in absolute memory
+ dw absEO+1
+ dw absEO+2
+ dw absEO+3
+indOR_ dw absOR ;indirect pointer to OR pattern in absolute memory
+ dw absOR+1
+ dw absOR+2
+ dw absOR+3
+;add/subtract indirect pointers
+adi2_ dw ada2 ;indirect pointer to operand 2 in absolute memory
+sbi2_ dw sba2 ;indirect pointer to complemented operand 2 (SBC)
+adiy2_ dw ada2-$ff ;with offset for indirect indexed
+sbiy2_ dw sba2-$ff
+zp_end
+ if (zp_end - zp_init) != (zp_bss_end - zp_bss)
+ ;force assembler error if size is different
+ ERROR ERROR ERROR ;mismatch between bss and zeropage data
+ endif
+data_init
+ex_adc_ adc #0 ;execute immediate opcodes
+ rts
+ex_sbc_ sbc #0 ;execute immediate opcodes
+ rts
+abs1_ db $c3,$82,$41,0 ;test patterns for LDx BIT ROL ROR ASL LSR
+abs7f_ db $7f ;test pattern for compare
+;loads
+fLDx_ db fn,fn,0,fz ;expected flags for load
+;shifts
+rASL_ ;expected result ASL & ROL -carry
+rROL_ db $86,$04,$82,0 ; "
+rROLc_ db $87,$05,$83,1 ;expected result ROL +carry
+rLSR_ ;expected result LSR & ROR -carry
+rROR_ db $61,$41,$20,0 ; "
+rRORc_ db $e1,$c1,$a0,$80 ;expected result ROR +carry
+fASL_ ;expected flags for shifts
+fROL_ db fnc,fc,fn,fz ;no carry in
+fROLc_ db fnc,fc,fn,0 ;carry in
+fLSR_
+fROR_ db fc,0,fc,fz ;no carry in
+fRORc_ db fnc,fn,fnc,fn ;carry in
+;increments (decrements)
+rINC_ db $7f,$80,$ff,0,1 ;expected result for INC/DEC
+fINC_ db 0,fn,fn,fz,0 ;expected flags for INC/DEC
+;logical memory operand
+absOR_ db 0,$1f,$71,$80 ;test pattern for OR
+absAN_ db $0f,$ff,$7f,$80 ;test pattern for AND
+absEO_ db $ff,$0f,$8f,$8f ;test pattern for EOR
+;logical accu operand
+absORa_ db 0,$f1,$1f,0 ;test pattern for OR
+absANa_ db $f0,$ff,$ff,$ff ;test pattern for AND
+absEOa_ db $ff,$f0,$f0,$0f ;test pattern for EOR
+;logical results
+absrlo_ db 0,$ff,$7f,$80
+absflo_ db fz,fn,0,fn
+data_end
+ if (data_end - data_init) != (data_bss_end - data_bss)
+ ;force assembler error if size is different
+ ERROR ERROR ERROR ;mismatch between bss and data
+ endif
+
+vec_init
+ dw nmi_trap
+ dw res_trap
+ dw irq_trap
+vec_bss equ $fffa
+ endif ;end of RAM init data
+
+; code at end of image due to the need to add blank space as required
+ if ($ff & (ji_ret - * - 2)) < ($ff & (jxi_ret - * - 2))
+; JMP (abs) when $xxff and $xx00 are from same page
+ ds lo(ji_ret - * - 2)
+ nop
+ nop
+ji_px nop ;low address byte matched with ji_ret
+ nop
+ trap ;jmp indirect page cross bug
+
+; JMP (abs,x) when $xxff and $xx00 are from same page
+ ds lo(jxi_ret - * - 2)
+ nop
+ nop
+jxi_px nop ;low address byte matched with jxi_ret
+ nop
+ trap ;jmp indexed indirect page cross bug
+ else
+; JMP (abs,x) when $xxff and $xx00 are from same page
+ ds lo(jxi_ret - * - 2)
+ nop
+ nop
+jxi_px nop ;low address byte matched with jxi_ret
+ nop
+ trap ;jmp indexed indirect page cross bug
+
+; JMP (abs) when $xxff and $xx00 are from same page
+ ds lo(ji_ret - * - 2)
+ nop
+ nop
+ji_px nop ;low address byte matched with ji_ret
+ nop
+ trap ;jmp indirect page cross bug
+ endif
+
+ if (load_data_direct = 1) & (ROM_vectors = 1)
+ org $fffa ;vectors
+ dw nmi_trap
+ dw res_trap
+ dw irq_trap
+ endif
+
+ end start
diff --git a/6502_65C02_functional_tests/license.txt b/6502_65C02_functional_tests/license.txt
index 94a9ed0..818433e 100644
--- a/6502_65C02_functional_tests/license.txt
+++ b/6502_65C02_functional_tests/license.txt
@@ -1,674 +1,674 @@
- GNU GENERAL PUBLIC LICENSE
- Version 3, 29 June 2007
-
- Copyright (C) 2007 Free Software Foundation, Inc.
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The GNU General Public License is a free, copyleft license for
-software and other kinds of works.
-
- The licenses for most software and other practical works are designed
-to take away your freedom to share and change the works. By contrast,
-the GNU General Public License is intended to guarantee your freedom to
-share and change all versions of a program--to make sure it remains free
-software for all its users. We, the Free Software Foundation, use the
-GNU General Public License for most of our software; it applies also to
-any other work released this way by its authors. You can apply it to
-your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-them if you wish), that you receive source code or can get it if you
-want it, that you can change the software or use pieces of it in new
-free programs, and that you know you can do these things.
-
- To protect your rights, we need to prevent others from denying you
-these rights or asking you to surrender the rights. Therefore, you have
-certain responsibilities if you distribute copies of the software, or if
-you modify it: responsibilities to respect the freedom of others.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must pass on to the recipients the same
-freedoms that you received. You must make sure that they, too, receive
-or can get the source code. And you must show them these terms so they
-know their rights.
-
- Developers that use the GNU GPL protect your rights with two steps:
-(1) assert copyright on the software, and (2) offer you this License
-giving you legal permission to copy, distribute and/or modify it.
-
- For the developers' and authors' protection, the GPL clearly explains
-that there is no warranty for this free software. For both users' and
-authors' sake, the GPL requires that modified versions be marked as
-changed, so that their problems will not be attributed erroneously to
-authors of previous versions.
-
- Some devices are designed to deny users access to install or run
-modified versions of the software inside them, although the manufacturer
-can do so. This is fundamentally incompatible with the aim of
-protecting users' freedom to change the software. The systematic
-pattern of such abuse occurs in the area of products for individuals to
-use, which is precisely where it is most unacceptable. Therefore, we
-have designed this version of the GPL to prohibit the practice for those
-products. If such problems arise substantially in other domains, we
-stand ready to extend this provision to those domains in future versions
-of the GPL, as needed to protect the freedom of users.
-
- Finally, every program is threatened constantly by software patents.
-States should not allow patents to restrict development and use of
-software on general-purpose computers, but in those that do, we wish to
-avoid the special danger that patents applied to a free program could
-make it effectively proprietary. To prevent this, the GPL assures that
-patents cannot be used to render the program non-free.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- TERMS AND CONDITIONS
-
- 0. Definitions.
-
- "This License" refers to version 3 of the GNU General Public License.
-
- "Copyright" also means copyright-like laws that apply to other kinds of
-works, such as semiconductor masks.
-
- "The Program" refers to any copyrightable work licensed under this
-License. Each licensee is addressed as "you". "Licensees" and
-"recipients" may be individuals or organizations.
-
- To "modify" a work means to copy from or adapt all or part of the work
-in a fashion requiring copyright permission, other than the making of an
-exact copy. The resulting work is called a "modified version" of the
-earlier work or a work "based on" the earlier work.
-
- A "covered work" means either the unmodified Program or a work based
-on the Program.
-
- To "propagate" a work means to do anything with it that, without
-permission, would make you directly or secondarily liable for
-infringement under applicable copyright law, except executing it on a
-computer or modifying a private copy. Propagation includes copying,
-distribution (with or without modification), making available to the
-public, and in some countries other activities as well.
-
- To "convey" a work means any kind of propagation that enables other
-parties to make or receive copies. Mere interaction with a user through
-a computer network, with no transfer of a copy, is not conveying.
-
- An interactive user interface displays "Appropriate Legal Notices"
-to the extent that it includes a convenient and prominently visible
-feature that (1) displays an appropriate copyright notice, and (2)
-tells the user that there is no warranty for the work (except to the
-extent that warranties are provided), that licensees may convey the
-work under this License, and how to view a copy of this License. If
-the interface presents a list of user commands or options, such as a
-menu, a prominent item in the list meets this criterion.
-
- 1. Source Code.
-
- The "source code" for a work means the preferred form of the work
-for making modifications to it. "Object code" means any non-source
-form of a work.
-
- A "Standard Interface" means an interface that either is an official
-standard defined by a recognized standards body, or, in the case of
-interfaces specified for a particular programming language, one that
-is widely used among developers working in that language.
-
- The "System Libraries" of an executable work include anything, other
-than the work as a whole, that (a) is included in the normal form of
-packaging a Major Component, but which is not part of that Major
-Component, and (b) serves only to enable use of the work with that
-Major Component, or to implement a Standard Interface for which an
-implementation is available to the public in source code form. A
-"Major Component", in this context, means a major essential component
-(kernel, window system, and so on) of the specific operating system
-(if any) on which the executable work runs, or a compiler used to
-produce the work, or an object code interpreter used to run it.
-
- The "Corresponding Source" for a work in object code form means all
-the source code needed to generate, install, and (for an executable
-work) run the object code and to modify the work, including scripts to
-control those activities. However, it does not include the work's
-System Libraries, or general-purpose tools or generally available free
-programs which are used unmodified in performing those activities but
-which are not part of the work. For example, Corresponding Source
-includes interface definition files associated with source files for
-the work, and the source code for shared libraries and dynamically
-linked subprograms that the work is specifically designed to require,
-such as by intimate data communication or control flow between those
-subprograms and other parts of the work.
-
- The Corresponding Source need not include anything that users
-can regenerate automatically from other parts of the Corresponding
-Source.
-
- The Corresponding Source for a work in source code form is that
-same work.
-
- 2. Basic Permissions.
-
- All rights granted under this License are granted for the term of
-copyright on the Program, and are irrevocable provided the stated
-conditions are met. This License explicitly affirms your unlimited
-permission to run the unmodified Program. The output from running a
-covered work is covered by this License only if the output, given its
-content, constitutes a covered work. This License acknowledges your
-rights of fair use or other equivalent, as provided by copyright law.
-
- You may make, run and propagate covered works that you do not
-convey, without conditions so long as your license otherwise remains
-in force. You may convey covered works to others for the sole purpose
-of having them make modifications exclusively for you, or provide you
-with facilities for running those works, provided that you comply with
-the terms of this License in conveying all material for which you do
-not control copyright. Those thus making or running the covered works
-for you must do so exclusively on your behalf, under your direction
-and control, on terms that prohibit them from making any copies of
-your copyrighted material outside their relationship with you.
-
- Conveying under any other circumstances is permitted solely under
-the conditions stated below. Sublicensing is not allowed; section 10
-makes it unnecessary.
-
- 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
-
- No covered work shall be deemed part of an effective technological
-measure under any applicable law fulfilling obligations under article
-11 of the WIPO copyright treaty adopted on 20 December 1996, or
-similar laws prohibiting or restricting circumvention of such
-measures.
-
- When you convey a covered work, you waive any legal power to forbid
-circumvention of technological measures to the extent such circumvention
-is effected by exercising rights under this License with respect to
-the covered work, and you disclaim any intention to limit operation or
-modification of the work as a means of enforcing, against the work's
-users, your or third parties' legal rights to forbid circumvention of
-technological measures.
-
- 4. Conveying Verbatim Copies.
-
- You may convey verbatim copies of the Program's source code as you
-receive it, in any medium, provided that you conspicuously and
-appropriately publish on each copy an appropriate copyright notice;
-keep intact all notices stating that this License and any
-non-permissive terms added in accord with section 7 apply to the code;
-keep intact all notices of the absence of any warranty; and give all
-recipients a copy of this License along with the Program.
-
- You may charge any price or no price for each copy that you convey,
-and you may offer support or warranty protection for a fee.
-
- 5. Conveying Modified Source Versions.
-
- You may convey a work based on the Program, or the modifications to
-produce it from the Program, in the form of source code under the
-terms of section 4, provided that you also meet all of these conditions:
-
- a) The work must carry prominent notices stating that you modified
- it, and giving a relevant date.
-
- b) The work must carry prominent notices stating that it is
- released under this License and any conditions added under section
- 7. This requirement modifies the requirement in section 4 to
- "keep intact all notices".
-
- c) You must license the entire work, as a whole, under this
- License to anyone who comes into possession of a copy. This
- License will therefore apply, along with any applicable section 7
- additional terms, to the whole of the work, and all its parts,
- regardless of how they are packaged. This License gives no
- permission to license the work in any other way, but it does not
- invalidate such permission if you have separately received it.
-
- d) If the work has interactive user interfaces, each must display
- Appropriate Legal Notices; however, if the Program has interactive
- interfaces that do not display Appropriate Legal Notices, your
- work need not make them do so.
-
- A compilation of a covered work with other separate and independent
-works, which are not by their nature extensions of the covered work,
-and which are not combined with it such as to form a larger program,
-in or on a volume of a storage or distribution medium, is called an
-"aggregate" if the compilation and its resulting copyright are not
-used to limit the access or legal rights of the compilation's users
-beyond what the individual works permit. Inclusion of a covered work
-in an aggregate does not cause this License to apply to the other
-parts of the aggregate.
-
- 6. Conveying Non-Source Forms.
-
- You may convey a covered work in object code form under the terms
-of sections 4 and 5, provided that you also convey the
-machine-readable Corresponding Source under the terms of this License,
-in one of these ways:
-
- a) Convey the object code in, or embodied in, a physical product
- (including a physical distribution medium), accompanied by the
- Corresponding Source fixed on a durable physical medium
- customarily used for software interchange.
-
- b) Convey the object code in, or embodied in, a physical product
- (including a physical distribution medium), accompanied by a
- written offer, valid for at least three years and valid for as
- long as you offer spare parts or customer support for that product
- model, to give anyone who possesses the object code either (1) a
- copy of the Corresponding Source for all the software in the
- product that is covered by this License, on a durable physical
- medium customarily used for software interchange, for a price no
- more than your reasonable cost of physically performing this
- conveying of source, or (2) access to copy the
- Corresponding Source from a network server at no charge.
-
- c) Convey individual copies of the object code with a copy of the
- written offer to provide the Corresponding Source. This
- alternative is allowed only occasionally and noncommercially, and
- only if you received the object code with such an offer, in accord
- with subsection 6b.
-
- d) Convey the object code by offering access from a designated
- place (gratis or for a charge), and offer equivalent access to the
- Corresponding Source in the same way through the same place at no
- further charge. You need not require recipients to copy the
- Corresponding Source along with the object code. If the place to
- copy the object code is a network server, the Corresponding Source
- may be on a different server (operated by you or a third party)
- that supports equivalent copying facilities, provided you maintain
- clear directions next to the object code saying where to find the
- Corresponding Source. Regardless of what server hosts the
- Corresponding Source, you remain obligated to ensure that it is
- available for as long as needed to satisfy these requirements.
-
- e) Convey the object code using peer-to-peer transmission, provided
- you inform other peers where the object code and Corresponding
- Source of the work are being offered to the general public at no
- charge under subsection 6d.
-
- A separable portion of the object code, whose source code is excluded
-from the Corresponding Source as a System Library, need not be
-included in conveying the object code work.
-
- A "User Product" is either (1) a "consumer product", which means any
-tangible personal property which is normally used for personal, family,
-or household purposes, or (2) anything designed or sold for incorporation
-into a dwelling. In determining whether a product is a consumer product,
-doubtful cases shall be resolved in favor of coverage. For a particular
-product received by a particular user, "normally used" refers to a
-typical or common use of that class of product, regardless of the status
-of the particular user or of the way in which the particular user
-actually uses, or expects or is expected to use, the product. A product
-is a consumer product regardless of whether the product has substantial
-commercial, industrial or non-consumer uses, unless such uses represent
-the only significant mode of use of the product.
-
- "Installation Information" for a User Product means any methods,
-procedures, authorization keys, or other information required to install
-and execute modified versions of a covered work in that User Product from
-a modified version of its Corresponding Source. The information must
-suffice to ensure that the continued functioning of the modified object
-code is in no case prevented or interfered with solely because
-modification has been made.
-
- If you convey an object code work under this section in, or with, or
-specifically for use in, a User Product, and the conveying occurs as
-part of a transaction in which the right of possession and use of the
-User Product is transferred to the recipient in perpetuity or for a
-fixed term (regardless of how the transaction is characterized), the
-Corresponding Source conveyed under this section must be accompanied
-by the Installation Information. But this requirement does not apply
-if neither you nor any third party retains the ability to install
-modified object code on the User Product (for example, the work has
-been installed in ROM).
-
- The requirement to provide Installation Information does not include a
-requirement to continue to provide support service, warranty, or updates
-for a work that has been modified or installed by the recipient, or for
-the User Product in which it has been modified or installed. Access to a
-network may be denied when the modification itself materially and
-adversely affects the operation of the network or violates the rules and
-protocols for communication across the network.
-
- Corresponding Source conveyed, and Installation Information provided,
-in accord with this section must be in a format that is publicly
-documented (and with an implementation available to the public in
-source code form), and must require no special password or key for
-unpacking, reading or copying.
-
- 7. Additional Terms.
-
- "Additional permissions" are terms that supplement the terms of this
-License by making exceptions from one or more of its conditions.
-Additional permissions that are applicable to the entire Program shall
-be treated as though they were included in this License, to the extent
-that they are valid under applicable law. If additional permissions
-apply only to part of the Program, that part may be used separately
-under those permissions, but the entire Program remains governed by
-this License without regard to the additional permissions.
-
- When you convey a copy of a covered work, you may at your option
-remove any additional permissions from that copy, or from any part of
-it. (Additional permissions may be written to require their own
-removal in certain cases when you modify the work.) You may place
-additional permissions on material, added by you to a covered work,
-for which you have or can give appropriate copyright permission.
-
- Notwithstanding any other provision of this License, for material you
-add to a covered work, you may (if authorized by the copyright holders of
-that material) supplement the terms of this License with terms:
-
- a) Disclaiming warranty or limiting liability differently from the
- terms of sections 15 and 16 of this License; or
-
- b) Requiring preservation of specified reasonable legal notices or
- author attributions in that material or in the Appropriate Legal
- Notices displayed by works containing it; or
-
- c) Prohibiting misrepresentation of the origin of that material, or
- requiring that modified versions of such material be marked in
- reasonable ways as different from the original version; or
-
- d) Limiting the use for publicity purposes of names of licensors or
- authors of the material; or
-
- e) Declining to grant rights under trademark law for use of some
- trade names, trademarks, or service marks; or
-
- f) Requiring indemnification of licensors and authors of that
- material by anyone who conveys the material (or modified versions of
- it) with contractual assumptions of liability to the recipient, for
- any liability that these contractual assumptions directly impose on
- those licensors and authors.
-
- All other non-permissive additional terms are considered "further
-restrictions" within the meaning of section 10. If the Program as you
-received it, or any part of it, contains a notice stating that it is
-governed by this License along with a term that is a further
-restriction, you may remove that term. If a license document contains
-a further restriction but permits relicensing or conveying under this
-License, you may add to a covered work material governed by the terms
-of that license document, provided that the further restriction does
-not survive such relicensing or conveying.
-
- If you add terms to a covered work in accord with this section, you
-must place, in the relevant source files, a statement of the
-additional terms that apply to those files, or a notice indicating
-where to find the applicable terms.
-
- Additional terms, permissive or non-permissive, may be stated in the
-form of a separately written license, or stated as exceptions;
-the above requirements apply either way.
-
- 8. Termination.
-
- You may not propagate or modify a covered work except as expressly
-provided under this License. Any attempt otherwise to propagate or
-modify it is void, and will automatically terminate your rights under
-this License (including any patent licenses granted under the third
-paragraph of section 11).
-
- However, if you cease all violation of this License, then your
-license from a particular copyright holder is reinstated (a)
-provisionally, unless and until the copyright holder explicitly and
-finally terminates your license, and (b) permanently, if the copyright
-holder fails to notify you of the violation by some reasonable means
-prior to 60 days after the cessation.
-
- Moreover, your license from a particular copyright holder is
-reinstated permanently if the copyright holder notifies you of the
-violation by some reasonable means, this is the first time you have
-received notice of violation of this License (for any work) from that
-copyright holder, and you cure the violation prior to 30 days after
-your receipt of the notice.
-
- Termination of your rights under this section does not terminate the
-licenses of parties who have received copies or rights from you under
-this License. If your rights have been terminated and not permanently
-reinstated, you do not qualify to receive new licenses for the same
-material under section 10.
-
- 9. Acceptance Not Required for Having Copies.
-
- You are not required to accept this License in order to receive or
-run a copy of the Program. Ancillary propagation of a covered work
-occurring solely as a consequence of using peer-to-peer transmission
-to receive a copy likewise does not require acceptance. However,
-nothing other than this License grants you permission to propagate or
-modify any covered work. These actions infringe copyright if you do
-not accept this License. Therefore, by modifying or propagating a
-covered work, you indicate your acceptance of this License to do so.
-
- 10. Automatic Licensing of Downstream Recipients.
-
- Each time you convey a covered work, the recipient automatically
-receives a license from the original licensors, to run, modify and
-propagate that work, subject to this License. You are not responsible
-for enforcing compliance by third parties with this License.
-
- An "entity transaction" is a transaction transferring control of an
-organization, or substantially all assets of one, or subdividing an
-organization, or merging organizations. If propagation of a covered
-work results from an entity transaction, each party to that
-transaction who receives a copy of the work also receives whatever
-licenses to the work the party's predecessor in interest had or could
-give under the previous paragraph, plus a right to possession of the
-Corresponding Source of the work from the predecessor in interest, if
-the predecessor has it or can get it with reasonable efforts.
-
- You may not impose any further restrictions on the exercise of the
-rights granted or affirmed under this License. For example, you may
-not impose a license fee, royalty, or other charge for exercise of
-rights granted under this License, and you may not initiate litigation
-(including a cross-claim or counterclaim in a lawsuit) alleging that
-any patent claim is infringed by making, using, selling, offering for
-sale, or importing the Program or any portion of it.
-
- 11. Patents.
-
- A "contributor" is a copyright holder who authorizes use under this
-License of the Program or a work on which the Program is based. The
-work thus licensed is called the contributor's "contributor version".
-
- A contributor's "essential patent claims" are all patent claims
-owned or controlled by the contributor, whether already acquired or
-hereafter acquired, that would be infringed by some manner, permitted
-by this License, of making, using, or selling its contributor version,
-but do not include claims that would be infringed only as a
-consequence of further modification of the contributor version. For
-purposes of this definition, "control" includes the right to grant
-patent sublicenses in a manner consistent with the requirements of
-this License.
-
- Each contributor grants you a non-exclusive, worldwide, royalty-free
-patent license under the contributor's essential patent claims, to
-make, use, sell, offer for sale, import and otherwise run, modify and
-propagate the contents of its contributor version.
-
- In the following three paragraphs, a "patent license" is any express
-agreement or commitment, however denominated, not to enforce a patent
-(such as an express permission to practice a patent or covenant not to
-sue for patent infringement). To "grant" such a patent license to a
-party means to make such an agreement or commitment not to enforce a
-patent against the party.
-
- If you convey a covered work, knowingly relying on a patent license,
-and the Corresponding Source of the work is not available for anyone
-to copy, free of charge and under the terms of this License, through a
-publicly available network server or other readily accessible means,
-then you must either (1) cause the Corresponding Source to be so
-available, or (2) arrange to deprive yourself of the benefit of the
-patent license for this particular work, or (3) arrange, in a manner
-consistent with the requirements of this License, to extend the patent
-license to downstream recipients. "Knowingly relying" means you have
-actual knowledge that, but for the patent license, your conveying the
-covered work in a country, or your recipient's use of the covered work
-in a country, would infringe one or more identifiable patents in that
-country that you have reason to believe are valid.
-
- If, pursuant to or in connection with a single transaction or
-arrangement, you convey, or propagate by procuring conveyance of, a
-covered work, and grant a patent license to some of the parties
-receiving the covered work authorizing them to use, propagate, modify
-or convey a specific copy of the covered work, then the patent license
-you grant is automatically extended to all recipients of the covered
-work and works based on it.
-
- A patent license is "discriminatory" if it does not include within
-the scope of its coverage, prohibits the exercise of, or is
-conditioned on the non-exercise of one or more of the rights that are
-specifically granted under this License. You may not convey a covered
-work if you are a party to an arrangement with a third party that is
-in the business of distributing software, under which you make payment
-to the third party based on the extent of your activity of conveying
-the work, and under which the third party grants, to any of the
-parties who would receive the covered work from you, a discriminatory
-patent license (a) in connection with copies of the covered work
-conveyed by you (or copies made from those copies), or (b) primarily
-for and in connection with specific products or compilations that
-contain the covered work, unless you entered into that arrangement,
-or that patent license was granted, prior to 28 March 2007.
-
- Nothing in this License shall be construed as excluding or limiting
-any implied license or other defenses to infringement that may
-otherwise be available to you under applicable patent law.
-
- 12. No Surrender of Others' Freedom.
-
- If conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot convey a
-covered work so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you may
-not convey it at all. For example, if you agree to terms that obligate you
-to collect a royalty for further conveying from those to whom you convey
-the Program, the only way you could satisfy both those terms and this
-License would be to refrain entirely from conveying the Program.
-
- 13. Use with the GNU Affero General Public License.
-
- Notwithstanding any other provision of this License, you have
-permission to link or combine any covered work with a work licensed
-under version 3 of the GNU Affero General Public License into a single
-combined work, and to convey the resulting work. The terms of this
-License will continue to apply to the part which is the covered work,
-but the special requirements of the GNU Affero General Public License,
-section 13, concerning interaction through a network will apply to the
-combination as such.
-
- 14. Revised Versions of this License.
-
- The Free Software Foundation may publish revised and/or new versions of
-the GNU General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
- Each version is given a distinguishing version number. If the
-Program specifies that a certain numbered version of the GNU General
-Public License "or any later version" applies to it, you have the
-option of following the terms and conditions either of that numbered
-version or of any later version published by the Free Software
-Foundation. If the Program does not specify a version number of the
-GNU General Public License, you may choose any version ever published
-by the Free Software Foundation.
-
- If the Program specifies that a proxy can decide which future
-versions of the GNU General Public License can be used, that proxy's
-public statement of acceptance of a version permanently authorizes you
-to choose that version for the Program.
-
- Later license versions may give you additional or different
-permissions. However, no additional obligations are imposed on any
-author or copyright holder as a result of your choosing to follow a
-later version.
-
- 15. Disclaimer of Warranty.
-
- THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
-APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
-HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
-OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
-THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
-IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
-ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
-
- 16. Limitation of Liability.
-
- IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
-THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
-GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
-USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
-DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
-PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
-EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGES.
-
- 17. Interpretation of Sections 15 and 16.
-
- If the disclaimer of warranty and limitation of liability provided
-above cannot be given local legal effect according to their terms,
-reviewing courts shall apply local law that most closely approximates
-an absolute waiver of all civil liability in connection with the
-Program, unless a warranty or assumption of liability accompanies a
-copy of the Program in return for a fee.
-
- END OF TERMS AND CONDITIONS
-
- How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-state the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
-
- Copyright (C)
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see .
-
-Also add information on how to contact you by electronic and paper mail.
-
- If the program does terminal interaction, make it output a short
-notice like this when it starts in an interactive mode:
-
- Copyright (C)
- This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License. Of course, your program's commands
-might be different; for a GUI interface, you would use an "about box".
-
- You should also get your employer (if you work as a programmer) or school,
-if any, to sign a "copyright disclaimer" for the program, if necessary.
-For more information on this, and how to apply and follow the GNU GPL, see
-.
-
- The GNU General Public License does not permit incorporating your program
-into proprietary programs. If your program is a subroutine library, you
-may consider it more useful to permit linking proprietary applications with
-the library. If this is what you want to do, use the GNU Lesser General
-Public License instead of this License. But first, please read
-.
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ Copyright (C)
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+.
diff --git a/6502_65C02_functional_tests/readme.txt b/6502_65C02_functional_tests/readme.txt
index 12aacac..eaac413 100644
--- a/6502_65C02_functional_tests/readme.txt
+++ b/6502_65C02_functional_tests/readme.txt
@@ -1,29 +1,29 @@
-This is a set of functional tests for the 6502/65C02 type processors.
-
-The 6502_functional_test.a65 is an assembler sourcecode to test all valid
-opcodes and addressing modes of the original NMOS 6502 cpu.
-
-The 65C02_extended_opcodes_test.a65c tests all additional opcodes of the
-65C02 processor including undefined opcodes.
-
-The 6502_interrupt_test.a65 is a simple test to check the interrupt system
-of both processors. A feedback register is required to inject IRQ and NMI
-requests.
-
-The 6502_decimal_test.a65 is Bruce Clark's code to accurately test decimal mode
-of the various 6502 cores (6502, 65c02 & 65816 in 8-bit mode) with added
-configuration options (invalid bcd or not, which flags to ignore).
-
-Detailed information about how to configure, assemble and run the tests is
-included in each source file.
-
-The assembler used is no longer available on the author's website. as65_142.zip
-is now included in this repository.
-
-And no, I will not switch to another assembler. However, GitHub user amb5l has
-a CA65 compatible version in his repository.
-
-Good luck debugging your emulator, simulator, fpga core, discrete
-logic implementation or whatever you have!
-
-
+This is a set of functional tests for the 6502/65C02 type processors.
+
+The 6502_functional_test.a65 is an assembler sourcecode to test all valid
+opcodes and addressing modes of the original NMOS 6502 cpu.
+
+The 65C02_extended_opcodes_test.a65c tests all additional opcodes of the
+65C02 processor including undefined opcodes.
+
+The 6502_interrupt_test.a65 is a simple test to check the interrupt system
+of both processors. A feedback register is required to inject IRQ and NMI
+requests.
+
+The 6502_decimal_test.a65 is Bruce Clark's code to accurately test decimal mode
+of the various 6502 cores (6502, 65c02 & 65816 in 8-bit mode) with added
+configuration options (invalid bcd or not, which flags to ignore).
+
+Detailed information about how to configure, assemble and run the tests is
+included in each source file.
+
+The assembler used is no longer available on the author's website. as65_142.zip
+is now included in this repository.
+
+And no, I will not switch to another assembler. However, GitHub user amb5l has
+a CA65 compatible version in his repository.
+
+Good luck debugging your emulator, simulator, fpga core, discrete
+logic implementation or whatever you have!
+
+
diff --git a/6502_65C02_functional_tests/report.i65 b/6502_65C02_functional_tests/report.i65
index 4e8d0e3..96e27d8 100644
--- a/6502_65C02_functional_tests/report.i65
+++ b/6502_65C02_functional_tests/report.i65
@@ -1,224 +1,224 @@
-;**** report 6502 funtional test errors to standard I/O ****
-;
-;this include file is part of the 6502 functional tests
-;it is used when you configure report = 1 in the tests
-;
-;to adopt the standard output vectors of your test environment
-;you must modify the rchar and rget subroutines in this include
-;
-;I/O hardware may have to be initialized in report_init
-
-;print message macro - \1 = message location
-rprt macro
- ldx #0
- lda \1
-loop\?
- jsr rchar
- inx
- lda \1,x
- bne loop\?
- endm
-
-;initialize I/O as required (example: configure & enable ACIA)
-report_init
- ;nothing to initialize
- rprt rmsg_start
- rts
-
-;show stack (with saved registers), zeropage and absolute memory workspace
-;after an error was trapped in the test program
-report_error
-;save registers
- php
- pha
- txa
- pha
- tya
- pha
- cld
-;show stack with index to registers at error
- rprt rmsg_stack
- tsx
- inx
- lda #1 ;address high
- jsr rhex
- txa ;address low
- jsr rhex
-rstack jsr rspace
- lda $100,x ;stack data
- jsr rhex
- inx
- bne rstack
- jsr rcrlf ;new line
-;show zero page workspace
- lda #0
- jsr rhex
- lda #zpt
- tax
- jsr rhex
-rzp jsr rspace
- lda 0,x
- jsr rhex
- inx
- cpx #zp_bss
- bne rzp
- jsr rcrlf
- jmp rend ; Skip Workspace since 65k is large
-;show absolute workspace
- lda #hi(data_segment)
- jsr rhex
- lda #lo(data_segment)
- jsr rhex
- ldx #0
-rabs jsr rspace
- lda data_segment,x
- jsr rhex
- inx
- cpx #(data_bss-data_segment)
- bne rabs
-;ask to continue
-rend
- rprt rmsg_cont
-rerr1 jsr rget
- cmp #'S'
- beq rskip
- cmp #'C'
- bne rerr1
-;restore registers
- pla
- tay
- pla
- tax
- pla
- plp
- rts
-;skip the current test
-rskip lda #$f0 ;already end of tests?
- cmp test_case
- beq rerr1 ;skip is not available
- ldx #$ff ;clear stack
- txs
- inc test_case ;next test
- lda #lo(start) ;find begin of test
- sta zpt
- lda #hi(start)
- sta zpt+1
-rskipl1 ldy #4 ;search pattern
-rskipl2 lda (zpt),y ;next byte
- cmp rmark,y
- bne rskipnx ;no match
- dey
- bmi rskipf ;found pattern
- cpy #1 ;skip immediate value
- bne rskipl2
- dey
- beq rskipl2
-
-rskipnx inc zpt ;next RAM location
- bne rskipl1
- inc zpt+1
- bne rskipl1
-
-rskipf ldy #1 ;pattern found - check test number
- lda (zpt),y ;test number
- cmp #$f0 ;end of last test?
- beq rskipe ;ask to rerun all
- cmp test_case ;is next test?
- bne rskipnx ;continue searching
-rskipe jmp (zpt) ;start next test or rerun at end of tests
-
-rmark lda #0 ;begin of test search pattern
- sta test_case
-
-;show test has ended, ask to repeat
-report_success
- if rep_int = 1
- rprt rmsg_priority
- lda data_segment ;show interrupt sequence
- jsr rhex
- jsr rspace
- lda data_segment+1
- jsr rhex
- jsr rspace
- lda data_segment+2
- jsr rhex
- endif
- rprt rmsg_success
-rsuc1 jsr rget
- cmp #'R'
- bne rsuc1
- rts
-
-;input subroutine
-;get a character from standard input
-;adjust according to the needs in your test environment
-rget ;get character in A
-;rget1
-; lda $bff1 ;wait RDRF
-; and #8
-; beq rget1
-;not a real ACIA - so RDRF is not checked
-; lda $bff0 ;read acia rx reg
-; lda $f004 ;Kowalski simulator default
- lda $dc01 ;KILIAN
-;the load can be replaced by a call to a kernal routine
-; jsr $ffcf ;example: CHRIN for a C64
- cmp #'a' ;lower case
- bcc rget1
- and #$5f ;convert to upper case
-rget1 rts
-
-;output subroutines
-rcrlf lda #10
- jsr rchar
- lda #13
- bne rchar
-
-rspace lda #' '
- bne rchar
-
-rhex pha ;report hex byte in A
- lsr a ;high nibble first
- lsr a
- lsr a
- lsr a
- jsr rnib
- pla ;now low nibble
- and #$f
-
-rnib clc ;report nibble in A
- adc #'0' ;make printable 0-9
- cmp #'9'+1
- bcc rchar
- adc #6 ;make printable A-F
-
-;send a character to standard output
-;adjust according to the needs in your test environment
-;register X needs to be preserved!
-rchar ;report character in A
-; pha ;wait TDRF
-;rchar1 lda $bff1
-; and #$10
-; beq rchar1
-; pla
-;not a real ACIA - so TDRF is not checked
-; sta $bff0 ;write acia tx reg
-; sta $f001 ;Kowalski simulator default
- sta $dc00 ;KILIAN
-;the store can be replaced by a call to a kernal routine
-; jsr $ffd2 ;example: CHROUT for a C64
- rts
-
-rmsg_start
- db 10,13,"Started testing",10,13,0
-rmsg_stack
- db 10,13,"regs Y X A PS PCLPCH",10,13,0
-rmsg_cont
- db 10,13,"press C to continue or S to skip current test",10,13,0
-rmsg_success
- db 10,13,"All tests completed, press R to repeat",10,13,0
- if rep_int = 1
-rmsg_priority
- db 10,13,"interrupt sequence (NMI IRQ BRK) ",0
- endif
+;**** report 6502 funtional test errors to standard I/O ****
+;
+;this include file is part of the 6502 functional tests
+;it is used when you configure report = 1 in the tests
+;
+;to adopt the standard output vectors of your test environment
+;you must modify the rchar and rget subroutines in this include
+;
+;I/O hardware may have to be initialized in report_init
+
+;print message macro - \1 = message location
+rprt macro
+ ldx #0
+ lda \1
+loop\?
+ jsr rchar
+ inx
+ lda \1,x
+ bne loop\?
+ endm
+
+;initialize I/O as required (example: configure & enable ACIA)
+report_init
+ ;nothing to initialize
+ rprt rmsg_start
+ rts
+
+;show stack (with saved registers), zeropage and absolute memory workspace
+;after an error was trapped in the test program
+report_error
+;save registers
+ php
+ pha
+ txa
+ pha
+ tya
+ pha
+ cld
+;show stack with index to registers at error
+ rprt rmsg_stack
+ tsx
+ inx
+ lda #1 ;address high
+ jsr rhex
+ txa ;address low
+ jsr rhex
+rstack jsr rspace
+ lda $100,x ;stack data
+ jsr rhex
+ inx
+ bne rstack
+ jsr rcrlf ;new line
+;show zero page workspace
+ lda #0
+ jsr rhex
+ lda #zpt
+ tax
+ jsr rhex
+rzp jsr rspace
+ lda 0,x
+ jsr rhex
+ inx
+ cpx #zp_bss
+ bne rzp
+ jsr rcrlf
+ jmp rend ; Skip Workspace since 65k is large
+;show absolute workspace
+ lda #hi(data_segment)
+ jsr rhex
+ lda #lo(data_segment)
+ jsr rhex
+ ldx #0
+rabs jsr rspace
+ lda data_segment,x
+ jsr rhex
+ inx
+ cpx #(data_bss-data_segment)
+ bne rabs
+;ask to continue
+rend
+ rprt rmsg_cont
+rerr1 jsr rget
+ cmp #'S'
+ beq rskip
+ cmp #'C'
+ bne rerr1
+;restore registers
+ pla
+ tay
+ pla
+ tax
+ pla
+ plp
+ rts
+;skip the current test
+rskip lda #$f0 ;already end of tests?
+ cmp test_case
+ beq rerr1 ;skip is not available
+ ldx #$ff ;clear stack
+ txs
+ inc test_case ;next test
+ lda #lo(start) ;find begin of test
+ sta zpt
+ lda #hi(start)
+ sta zpt+1
+rskipl1 ldy #4 ;search pattern
+rskipl2 lda (zpt),y ;next byte
+ cmp rmark,y
+ bne rskipnx ;no match
+ dey
+ bmi rskipf ;found pattern
+ cpy #1 ;skip immediate value
+ bne rskipl2
+ dey
+ beq rskipl2
+
+rskipnx inc zpt ;next RAM location
+ bne rskipl1
+ inc zpt+1
+ bne rskipl1
+
+rskipf ldy #1 ;pattern found - check test number
+ lda (zpt),y ;test number
+ cmp #$f0 ;end of last test?
+ beq rskipe ;ask to rerun all
+ cmp test_case ;is next test?
+ bne rskipnx ;continue searching
+rskipe jmp (zpt) ;start next test or rerun at end of tests
+
+rmark lda #0 ;begin of test search pattern
+ sta test_case
+
+;show test has ended, ask to repeat
+report_success
+ if rep_int = 1
+ rprt rmsg_priority
+ lda data_segment ;show interrupt sequence
+ jsr rhex
+ jsr rspace
+ lda data_segment+1
+ jsr rhex
+ jsr rspace
+ lda data_segment+2
+ jsr rhex
+ endif
+ rprt rmsg_success
+rsuc1 jsr rget
+ cmp #'R'
+ bne rsuc1
+ rts
+
+;input subroutine
+;get a character from standard input
+;adjust according to the needs in your test environment
+rget ;get character in A
+;rget1
+; lda $bff1 ;wait RDRF
+; and #8
+; beq rget1
+;not a real ACIA - so RDRF is not checked
+; lda $bff0 ;read acia rx reg
+; lda $f004 ;Kowalski simulator default
+ lda $bc01 ;KILIAN
+;the load can be replaced by a call to a kernal routine
+; jsr $ffcf ;example: CHRIN for a C64
+ cmp #'a' ;lower case
+ bcc rget1
+ and #$5f ;convert to upper case
+rget1 rts
+
+;output subroutines
+rcrlf lda #10
+ jsr rchar
+ lda #13
+ bne rchar
+
+rspace lda #' '
+ bne rchar
+
+rhex pha ;report hex byte in A
+ lsr a ;high nibble first
+ lsr a
+ lsr a
+ lsr a
+ jsr rnib
+ pla ;now low nibble
+ and #$f
+
+rnib clc ;report nibble in A
+ adc #'0' ;make printable 0-9
+ cmp #'9'+1
+ bcc rchar
+ adc #6 ;make printable A-F
+
+;send a character to standard output
+;adjust according to the needs in your test environment
+;register X needs to be preserved!
+rchar ;report character in A
+; pha ;wait TDRF
+;rchar1 lda $bff1
+; and #$10
+; beq rchar1
+; pla
+;not a real ACIA - so TDRF is not checked
+; sta $bff0 ;write acia tx reg
+; sta $f001 ;Kowalski simulator default
+ sta $bc00 ;KILIAN
+;the store can be replaced by a call to a kernal routine
+; jsr $ffd2 ;example: CHROUT for a C64
+ rts
+
+rmsg_start
+ db 10,13,"Started testing",10,13,0
+rmsg_stack
+ db 10,13,"regs Y X A PS PCLPCH",10,13,0
+rmsg_cont
+ db 10,13,"press C to continue or S to skip current test",10,13,0
+rmsg_success
+ db 10,13,"All tests completed, press R to repeat",10,13,0
+ if rep_int = 1
+rmsg_priority
+ db 10,13,"interrupt sequence (NMI IRQ BRK) ",0
+ endif
\ No newline at end of file
diff --git a/CMakelists.txt b/CMakelists.txt
index fc8fdad..3bc0253 100644
--- a/CMakelists.txt
+++ b/CMakelists.txt
@@ -1,30 +1,30 @@
-cmake_minimum_required(VERSION 3.11)
-
-set(CMAKE_C_STANDARD 11)
-set(CMAKE_C_STANDARD_REQUIRED ON)
-set(CMAKE_PROJECT_NAME 6502PC)
-
-project(${CMAKE_PROJECT_NAME})
-
-enable_language(C)
-
-add_executable(${CMAKE_PROJECT_NAME})
-
-if(MSVC)
- target_compile_options(${CMAKE_PROJECT_NAME} PRIVATE /W4)
-else()
- target_compile_options(${CMAKE_PROJECT_NAME} PRIVATE -Wall -Wextra -Wpedantic)
-endif()
-
-target_sources(${CMAKE_PROJECT_NAME} PRIVATE
- "src/main.c"
- "src/ram.c"
- src/cpu.c
- src/rom.c
- src/io.c
- src/memoryMap.c
-)
-
-target_include_directories(${CMAKE_PROJECT_NAME} PRIVATE
- "inc"
+cmake_minimum_required(VERSION 3.11)
+
+set(CMAKE_C_STANDARD 11)
+set(CMAKE_C_STANDARD_REQUIRED ON)
+set(CMAKE_PROJECT_NAME 6502PC)
+
+project(${CMAKE_PROJECT_NAME})
+
+enable_language(C)
+
+add_executable(${CMAKE_PROJECT_NAME})
+
+if(MSVC)
+ target_compile_options(${CMAKE_PROJECT_NAME} PRIVATE /W4)
+else()
+ target_compile_options(${CMAKE_PROJECT_NAME} PRIVATE -Wall -Wextra -Wpedantic)
+endif()
+
+target_sources(${CMAKE_PROJECT_NAME} PRIVATE
+ "src/main.c"
+ "src/ram.c"
+ src/cpu.c
+ src/rom.c
+ src/io.c
+ src/memoryMap.c
+)
+
+target_include_directories(${CMAKE_PROJECT_NAME} PRIVATE
+ "inc"
)
\ No newline at end of file
diff --git a/inc/cpu.h b/inc/cpu.h
index 595019f..f6639ec 100644
--- a/inc/cpu.h
+++ b/inc/cpu.h
@@ -1,33 +1,33 @@
-#ifndef CPU_H
-#define CPU_H
-
-#include
-
-typedef struct {
- uint16_t ProgrammeCounter;
- uint8_t StackPointer;
-
- uint8_t Accumulator;
- uint8_t X;
- uint8_t Y;
-
- union {
- uint8_t FlagsByte;
- struct {
- uint8_t CarryFlag : 1;
- uint8_t ZeroFlag : 1;
- uint8_t InterruptDisable : 1;
- uint8_t DecimalMode : 1;
- uint8_t BreakCommand : 1;
- uint8_t UNUSED : 1;
- uint8_t OverflowFlag : 1;
- uint8_t NegativeFlag : 1;
- } Flags;
- };
-} CPU;
-
-void initCPU(CPU *cpu);
-void resetCPU(CPU *cpu, uint8_t *rom);
-uint8_t runCycle(CPU *cpu, uint8_t *ram, uint8_t *rom);
-
+#ifndef CPU_H
+#define CPU_H
+
+#include
+
+typedef struct {
+ uint16_t ProgrammeCounter;
+ uint8_t StackPointer;
+
+ uint8_t Accumulator;
+ uint8_t X;
+ uint8_t Y;
+
+ union {
+ uint8_t FlagsByte;
+ struct {
+ uint8_t CarryFlag : 1;
+ uint8_t ZeroFlag : 1;
+ uint8_t InterruptDisable : 1;
+ uint8_t DecimalMode : 1;
+ uint8_t BreakCommand : 1;
+ uint8_t UNUSED : 1;
+ uint8_t OverflowFlag : 1;
+ uint8_t NegativeFlag : 1;
+ } Flags;
+ };
+} CPU;
+
+void initCPU(CPU *cpu);
+void resetCPU(CPU *cpu, uint8_t *rom);
+uint8_t runCycle(CPU *cpu, uint8_t *ram, uint8_t *rom);
+
#endif // CPU_H
\ No newline at end of file
diff --git a/inc/io.h b/inc/io.h
index e33f2b7..c48496d 100644
--- a/inc/io.h
+++ b/inc/io.h
@@ -1,16 +1,16 @@
-#ifndef IO_H
-#define IO_H
-
-#include
-
-#define IO_SIZE (1 * 1024) // 1KiB
-#define IO_BASE (55 * 1024) // 55KiB RAM, hard coded
-
-#define SCREEN_ADDRESS 0
-#define KEYBOARD_ADDRESS 1
-#define ROM_BANKED_OUT 2
-
-int putChar(uint8_t c);
-int getChar(void);
-
+#ifndef IO_H
+#define IO_H
+
+#include
+
+#define IO_SIZE (1 * 1024) // 1KiB
+#define IO_BASE (47 * 1024) // 47KiB RAM, hard coded, 0xBC00
+
+#define SCREEN_ADDRESS 0
+#define KEYBOARD_ADDRESS 1
+#define ROM_BANKED_OUT 2
+
+int putChar(uint8_t c);
+int getChar(void);
+
#endif // IO_H
\ No newline at end of file
diff --git a/inc/memoryMap.h b/inc/memoryMap.h
index bd6017b..7df0a4a 100644
--- a/inc/memoryMap.h
+++ b/inc/memoryMap.h
@@ -1,16 +1,16 @@
-#ifndef MEMORY_MAP_H
-#define MEMORY_MAP_H
-
-#include "io.h"
-#include "ram.h"
-#include "rom.h"
-
-#include
-
-uint8_t readMemory(uint16_t address, uint8_t *ram, uint8_t *rom);
-void writeMemory(uint16_t address, uint8_t value, uint8_t *ram);
-
-uint8_t readStack(uint8_t address, uint8_t *ram);
-void writeStack(uint8_t address, uint8_t value, uint8_t *ram);
-
+#ifndef MEMORY_MAP_H
+#define MEMORY_MAP_H
+
+#include "io.h"
+#include "ram.h"
+#include "rom.h"
+
+#include
+
+uint8_t readMemory(uint16_t address, uint8_t *ram, uint8_t *rom);
+void writeMemory(uint16_t address, uint8_t value, uint8_t *ram);
+
+uint8_t readStack(uint8_t address, uint8_t *ram);
+void writeStack(uint8_t address, uint8_t value, uint8_t *ram);
+
#endif // MEMORY_MAP_H
\ No newline at end of file
diff --git a/inc/opcodes.h b/inc/opcodes.h
index 5e08cf6..b971be0 100644
--- a/inc/opcodes.h
+++ b/inc/opcodes.h
@@ -1,173 +1,173 @@
-#ifndef OPCODES_H
-#define OPCODES_H
-
-/* 0 */
-#define BRK 0x00 // Break;
-#define ORA_XZi 0x01 // OR memory with accumulator, X-indexed zero page indirect
-#define ORA_Z 0x05 // OR memory with accumulator, zero page
-#define ASL_Z 0x06 // Arithmetic shift left, zero page
-#define PHP 0x08 // Push processor status on stack
-#define ORA_I 0x09 // OR memory with accumulator, immediate
-#define ASL 0x0a // Arithmetic shift left, accumulator
-#define ORA_A 0x0d // OR memory with accumulator, absolute
-#define ASL_A 0x0e // Arithmetic shift left, absolute
-/* 9 */
-#define BPL 0x10 // Branch on result plus
-#define ORA_ZiY 0x11 // OR memory with accumulator, zero page indirect Y-indexed
-#define ORA_XZ 0x15 // OR memory with accumulator, X-indexed zero page
-#define ASL_XZ 0x16 // Arithmetic shift left, X-indexed zero page
-#define CLC 0x18 // Clear carry flag
-#define ORA_YA 0x19 // OR memory with accumulator, Y-indexed absolute
-#define ORA_XA 0x1d // OR memory with accumulator, X-indexed absolute
-#define ASL_XA 0x1e // Arithmetic shift left, X-indexed absolute
-/* 17 */
-#define JSR 0x20 // Jump to subroutine
-#define AND_XZi 0x21 // AND memory with accumulator, X-indexed zero page indirect
-#define BIT_Z 0x24 // Test bist in memory with accumulator, zero page
-#define AND_Z 0x25 // AND memory with accumulator, zero page
-#define ROL_Z 0x26 // Rotate left, zero page
-#define PLP 0x28 // Pull processor status from stack
-#define AND_I 0x29 // AND memory with accumulator, immediate
-#define ROL 0x2a // Rotate left, accumulator
-#define BIT_A 0x2c // Test bist in memory with accumulator, absolute
-#define AND_A 0x2d // AND memory with accumulator, absolute
-#define ROL_A 0x2e // Rotate left, absolute
-/* 28 */
-#define BMI 0x30 // Branch on result minus
-#define AND_ZiY 0x31 // AND memory with accumulator, zero page indirect Y-indexed
-#define AND_XZ 0x35 // AND memory with accumulator, X-indexed zero page
-#define ROL_XZ 0x36 // Rotate left, X-indexed zero page
-#define SEC 0x38 // Set carry flag
-#define AND_YA 0x39 // AND memory with accumulator, Y-indexed absolute
-#define AND_XA 0x3d // AND memory with accumulator, X-indexed absolute
-#define ROL_XA 0x3e // Rotate left, X-indexed absolute
-/* 36 */
-#define RTI 0x40 // Return from interrupt
-#define EOR_XZi 0x41 // XOR with accumulator, X-indexed zero page indirect
-#define EOR_Z 0x45 // XOR with accumulator, zero page
-#define LSR_Z 0x46 // Logical shift right, zero page
-#define PHA 0x48 // Push accumulator on stack
-#define EOR_I 0x49 // XOR with accumulator, immediate
-#define LSR 0x4a // Logical shift right, accumulator
-#define JMP_A 0x4c // Jump indirect, absolute
-#define EOR_A 0x4d // XOR with accumulator, absolute
-#define LSR_A 0x4e // Logical shift right, absolute
-/* 46 */
-#define BVC 0x50 // Branch on overflow clear
-#define EOR_ZiY 0x51 // XOR with accumulator, zero page indirect Y-indexed
-#define EOR_XZ 0x55 // XOR with accumulator, X-indexed zero page
-#define LSR_XZ 0x56 // Logical shift right, X-indexed zero page
-#define CLI 0x58 // Clear interrupt disable
-#define EOR_YA 0x59 // XOR with accumulator, Y-indexed absolute
-#define EOR_XA 0x5d // XOR with accumulator, X-indexed absolute
-#define LSR_XA 0x5e // Logical shift right, X-indexed absolute
-/* 54 */
-#define RTS 0x60 // Return from subroutine
-#define ADC_XZi 0x61 // Add memory to accumulator with carry, X-indexed zero page indirect
-#define ADC_Z 0x65 // Add memory to accumulator with carry, zero page
-#define ROR_Z 0x66 // Rotate right, zero page
-#define PLA 0x68 // Pull accumulator from stack
-#define ADC_I 0x69 // Add memory to accumulator with carry, immediate
-#define ROR 0x6a // Rotate right, accumulator
-#define JMP_Ai 0x6c // Jump indirect, absolute indirect
-#define ADC_A 0x6d // Add memory to accumulator with carry, absolute
-#define ROR_A 0x6e // Rotate right, absolute
-/* 64 */
-#define BVS 0x70 // Branch on overflow set
-#define ADC_ZiY 0x71 // Add memory to accumulator with carry, zero page indirect Y-indexed
-#define ADC_XZ 0x75 // Add memory to accumulator with carry, X-indexed zero page
-#define ROR_XZ 0x76 // Rotate right, X-indexed zero page
-#define SEI 0x78 // Set Interrupt Disable
-#define ADC_YA 0x79 // Add memory to accumulator with carry, Y-indexed absolute
-#define ADC_XA 0x7d // Add memory to accumulator with carry, X-indexed absolute
-#define ROR_XA 0x7e // Rotate right, X-indexed absolute
-/* 72 */
-#define STA_XZi 0x81 // Store accumulator in memory, X-indexed zero page indirect
-#define STY_Z 0x84 // Store Y in memory, zero page
-#define STA_Z 0x85 // Store accumulator in memory, zero page
-#define STX_Z 0x86 // Store X in memory, zero page
-#define DEY 0x88 // Decrement Y by one
-#define TXA 0x8a // Transfer X to accumulator
-#define STY_A 0x8c // Store Y in memory, absolute
-#define STA_A 0x8d // Store accumulator in memory, absolute
-#define STX_A 0x8e // Store X in memory, absolute
-/* 81 */
-#define BCC 0x90 // Branch on carry clear
-#define STA_ZiY 0x91 // Store accumulator in memory, zero page indirect Y-indexed
-#define STY_XZ 0x94 // Store Y in memory, X-indexed zero page
-#define STA_XZ 0x95 // Store accumulator in memory, X-indexed zero page
-#define STX_YZ 0x96 // Store X in memory, Y-indexed zero page
-#define TYA 0x98 // Transfer Y to accumulator
-#define STA_YA 0x99 // Store accumulator to memory, Y-indexed absolute
-#define TXS 0x9a // Transfer X to stack pointer
-#define STA_XA 0x9d // Store accumulator to memory, X-indexed absolute
-/* 90 */
-#define LDY_I 0xa0 // Load Y from memory, immediate
-#define LDA_XZi 0xa1 // Load accumulator from memory, X-indexed zero page indirect
-#define LDX_I 0xa2 // Load X from memory, immediate
-#define LDY_Z 0xa4 // Load Y from memory, zero page
-#define LDA_Z 0xa5 // Load accumulator from memory, zero page
-#define LDX_Z 0xa6 // Load X from memory, zero page
-#define TAY 0xa8 // Transfer accumulator to Y
-#define LDA_I 0xa9 // Load accumulator from memory, immediate
-#define TAX 0xaa // Transfer accumulator to X
-#define LDY_A 0xac // Load Y from memory, absolute
-#define LDA_A 0xad // Load accumulator from memory, absolute
-#define LDX_A 0xae // Load X from memory, absolute
-/* 102 */
-#define BCS 0xb0 // Branch on carry set
-#define LDA_ZiY 0xb1 // Load accumulator from memory, zero page indirect Y-indexed
-#define LDY_XZ 0xb4 // Load Y from memory, X-indexed zero page
-#define LDA_XZ 0xb5 // Load A from memory, X-indexed zero page
-#define LDX_YZ 0xb6 // Load X from memory, Y-indexed zero page
-#define CLV 0xb8 // Clear overflow flag
-#define LDA_YA 0xb9 // Load A from memory, Y-indexed absolute
-#define TSX 0xba // Transfer stack pointer to X
-#define LDY_XA 0xbc // Load Y from memory, X-indexed absolute
-#define LDA_XA 0xbd // Load A from memory, X-indexed absolute
-#define LDX_YA 0xbe // Load X from memory, Y-indexed absolute
-/* 113 */
-#define CPY_I 0xc0 // Compare Y to memory, immediate
-#define CMP_XZi 0xc1 // Compare accumulator to memory, X-indexed zero page indirect
-#define CPY_Z 0xc4 // Compare Y to memory, zero page
-#define CMP_Z 0xc5 // Compare accumulator to memory, zero page
-#define DEC_Z 0xc6 // Decrement memory by one, zero page
-#define INY 0xc8 // Increment Y by one
-#define CMP_I 0xc9 // Compare accumulator to memory, immediate
-#define DEX 0xca // Decrement X by one
-#define CPY_A 0xcc // Compare Y to memory, absolute
-#define CMP_A 0xcd // Compare accumulator to memory, absolute
-#define DEC_A 0xce // Decrement memory by one, absolute
-/* 124 */
-#define BNE 0xd0 // Branch on result not zero
-#define CMP_ZiY 0xd1 // Compare accumulator to memory, zero page indirect Y-indexed
-#define CMP_XZ 0xd5 // Compare accumulator to memory, X-indexed zero page
-#define DEC_XZ 0xd6 // Decrement memory by one, X-indexed zero page
-#define CLD 0xd8 // Clear decimal mode
-#define CMP_YA 0xd9 // Compare accumulator to memory, Y-indexed absolute
-#define CMP_XA 0xdd // Compare accumulator to memory, X-indexed absolute
-#define DEC_XA 0xde // Decrement memory by one, X-indexed absolute
-/* 132 */
-#define CPX_I 0xe0 // Compare X to memory, immediate
-#define SBC_XZi 0xe1 // Subtract memory from accumulator with borrow, X-indexed zero page indirect
-#define CPX_Z 0xe4 // Compare X to memory, zero page
-#define SBC_Z 0xe5 // Subtract memory from accumulator with borrow, zero page
-#define INC_Z 0xe6 // Increment memory by one, zero page
-#define INX 0xe8 // Increment X by one
-#define SBC_I 0xe9 // Subtract memory from accumulator with borrow, immediate
-#define NOP 0xea // No operation
-#define CPX_A 0xec // Compare X to memory, absolute
-#define SBC_A 0xed // Subtract memory from accumulator with borrow, absolute
-#define INC_A 0xee // Increment memory by one, absolute
-/* 143 */
-#define BEQ 0xf0 // Branch on result zero
-#define SBC_ZiY 0xf1 // Subtract memory from accumulator with borrow, zero page indirect Y-indexed
-#define SBC_XZ 0xf5 // Subtract memory from accumulator with borrow, X-indexed zero page
-#define INC_XZ 0xf6 // Increment memory by one, X-indexed zero page
-#define SED 0xf8 // Set decimal mode
-#define SBC_YA 0xf9 // Subtract memory from accumulator with borrow, Y-indexed absolute
-#define SBC_XA 0xfd // Subtract memory from accumulator with borrow, X-indexed absolute
-#define INC_XA 0xfe // Increment memory by one, X-indexed absolute
-/* 151 */
-
+#ifndef OPCODES_H
+#define OPCODES_H
+
+/* 0 */
+#define BRK 0x00 // Break;
+#define ORA_XZi 0x01 // OR memory with accumulator, X-indexed zero page indirect
+#define ORA_Z 0x05 // OR memory with accumulator, zero page
+#define ASL_Z 0x06 // Arithmetic shift left, zero page
+#define PHP 0x08 // Push processor status on stack
+#define ORA_I 0x09 // OR memory with accumulator, immediate
+#define ASL 0x0a // Arithmetic shift left, accumulator
+#define ORA_A 0x0d // OR memory with accumulator, absolute
+#define ASL_A 0x0e // Arithmetic shift left, absolute
+/* 9 */
+#define BPL 0x10 // Branch on result plus
+#define ORA_ZiY 0x11 // OR memory with accumulator, zero page indirect Y-indexed
+#define ORA_XZ 0x15 // OR memory with accumulator, X-indexed zero page
+#define ASL_XZ 0x16 // Arithmetic shift left, X-indexed zero page
+#define CLC 0x18 // Clear carry flag
+#define ORA_YA 0x19 // OR memory with accumulator, Y-indexed absolute
+#define ORA_XA 0x1d // OR memory with accumulator, X-indexed absolute
+#define ASL_XA 0x1e // Arithmetic shift left, X-indexed absolute
+/* 17 */
+#define JSR 0x20 // Jump to subroutine
+#define AND_XZi 0x21 // AND memory with accumulator, X-indexed zero page indirect
+#define BIT_Z 0x24 // Test bist in memory with accumulator, zero page
+#define AND_Z 0x25 // AND memory with accumulator, zero page
+#define ROL_Z 0x26 // Rotate left, zero page
+#define PLP 0x28 // Pull processor status from stack
+#define AND_I 0x29 // AND memory with accumulator, immediate
+#define ROL 0x2a // Rotate left, accumulator
+#define BIT_A 0x2c // Test bist in memory with accumulator, absolute
+#define AND_A 0x2d // AND memory with accumulator, absolute
+#define ROL_A 0x2e // Rotate left, absolute
+/* 28 */
+#define BMI 0x30 // Branch on result minus
+#define AND_ZiY 0x31 // AND memory with accumulator, zero page indirect Y-indexed
+#define AND_XZ 0x35 // AND memory with accumulator, X-indexed zero page
+#define ROL_XZ 0x36 // Rotate left, X-indexed zero page
+#define SEC 0x38 // Set carry flag
+#define AND_YA 0x39 // AND memory with accumulator, Y-indexed absolute
+#define AND_XA 0x3d // AND memory with accumulator, X-indexed absolute
+#define ROL_XA 0x3e // Rotate left, X-indexed absolute
+/* 36 */
+#define RTI 0x40 // Return from interrupt
+#define EOR_XZi 0x41 // XOR with accumulator, X-indexed zero page indirect
+#define EOR_Z 0x45 // XOR with accumulator, zero page
+#define LSR_Z 0x46 // Logical shift right, zero page
+#define PHA 0x48 // Push accumulator on stack
+#define EOR_I 0x49 // XOR with accumulator, immediate
+#define LSR 0x4a // Logical shift right, accumulator
+#define JMP_A 0x4c // Jump indirect, absolute
+#define EOR_A 0x4d // XOR with accumulator, absolute
+#define LSR_A 0x4e // Logical shift right, absolute
+/* 46 */
+#define BVC 0x50 // Branch on overflow clear
+#define EOR_ZiY 0x51 // XOR with accumulator, zero page indirect Y-indexed
+#define EOR_XZ 0x55 // XOR with accumulator, X-indexed zero page
+#define LSR_XZ 0x56 // Logical shift right, X-indexed zero page
+#define CLI 0x58 // Clear interrupt disable
+#define EOR_YA 0x59 // XOR with accumulator, Y-indexed absolute
+#define EOR_XA 0x5d // XOR with accumulator, X-indexed absolute
+#define LSR_XA 0x5e // Logical shift right, X-indexed absolute
+/* 54 */
+#define RTS 0x60 // Return from subroutine
+#define ADC_XZi 0x61 // Add memory to accumulator with carry, X-indexed zero page indirect
+#define ADC_Z 0x65 // Add memory to accumulator with carry, zero page
+#define ROR_Z 0x66 // Rotate right, zero page
+#define PLA 0x68 // Pull accumulator from stack
+#define ADC_I 0x69 // Add memory to accumulator with carry, immediate
+#define ROR 0x6a // Rotate right, accumulator
+#define JMP_Ai 0x6c // Jump indirect, absolute indirect
+#define ADC_A 0x6d // Add memory to accumulator with carry, absolute
+#define ROR_A 0x6e // Rotate right, absolute
+/* 64 */
+#define BVS 0x70 // Branch on overflow set
+#define ADC_ZiY 0x71 // Add memory to accumulator with carry, zero page indirect Y-indexed
+#define ADC_XZ 0x75 // Add memory to accumulator with carry, X-indexed zero page
+#define ROR_XZ 0x76 // Rotate right, X-indexed zero page
+#define SEI 0x78 // Set Interrupt Disable
+#define ADC_YA 0x79 // Add memory to accumulator with carry, Y-indexed absolute
+#define ADC_XA 0x7d // Add memory to accumulator with carry, X-indexed absolute
+#define ROR_XA 0x7e // Rotate right, X-indexed absolute
+/* 72 */
+#define STA_XZi 0x81 // Store accumulator in memory, X-indexed zero page indirect
+#define STY_Z 0x84 // Store Y in memory, zero page
+#define STA_Z 0x85 // Store accumulator in memory, zero page
+#define STX_Z 0x86 // Store X in memory, zero page
+#define DEY 0x88 // Decrement Y by one
+#define TXA 0x8a // Transfer X to accumulator
+#define STY_A 0x8c // Store Y in memory, absolute
+#define STA_A 0x8d // Store accumulator in memory, absolute
+#define STX_A 0x8e // Store X in memory, absolute
+/* 81 */
+#define BCC 0x90 // Branch on carry clear
+#define STA_ZiY 0x91 // Store accumulator in memory, zero page indirect Y-indexed
+#define STY_XZ 0x94 // Store Y in memory, X-indexed zero page
+#define STA_XZ 0x95 // Store accumulator in memory, X-indexed zero page
+#define STX_YZ 0x96 // Store X in memory, Y-indexed zero page
+#define TYA 0x98 // Transfer Y to accumulator
+#define STA_YA 0x99 // Store accumulator to memory, Y-indexed absolute
+#define TXS 0x9a // Transfer X to stack pointer
+#define STA_XA 0x9d // Store accumulator to memory, X-indexed absolute
+/* 90 */
+#define LDY_I 0xa0 // Load Y from memory, immediate
+#define LDA_XZi 0xa1 // Load accumulator from memory, X-indexed zero page indirect
+#define LDX_I 0xa2 // Load X from memory, immediate
+#define LDY_Z 0xa4 // Load Y from memory, zero page
+#define LDA_Z 0xa5 // Load accumulator from memory, zero page
+#define LDX_Z 0xa6 // Load X from memory, zero page
+#define TAY 0xa8 // Transfer accumulator to Y
+#define LDA_I 0xa9 // Load accumulator from memory, immediate
+#define TAX 0xaa // Transfer accumulator to X
+#define LDY_A 0xac // Load Y from memory, absolute
+#define LDA_A 0xad // Load accumulator from memory, absolute
+#define LDX_A 0xae // Load X from memory, absolute
+/* 102 */
+#define BCS 0xb0 // Branch on carry set
+#define LDA_ZiY 0xb1 // Load accumulator from memory, zero page indirect Y-indexed
+#define LDY_XZ 0xb4 // Load Y from memory, X-indexed zero page
+#define LDA_XZ 0xb5 // Load A from memory, X-indexed zero page
+#define LDX_YZ 0xb6 // Load X from memory, Y-indexed zero page
+#define CLV 0xb8 // Clear overflow flag
+#define LDA_YA 0xb9 // Load A from memory, Y-indexed absolute
+#define TSX 0xba // Transfer stack pointer to X
+#define LDY_XA 0xbc // Load Y from memory, X-indexed absolute
+#define LDA_XA 0xbd // Load A from memory, X-indexed absolute
+#define LDX_YA 0xbe // Load X from memory, Y-indexed absolute
+/* 113 */
+#define CPY_I 0xc0 // Compare Y to memory, immediate
+#define CMP_XZi 0xc1 // Compare accumulator to memory, X-indexed zero page indirect
+#define CPY_Z 0xc4 // Compare Y to memory, zero page
+#define CMP_Z 0xc5 // Compare accumulator to memory, zero page
+#define DEC_Z 0xc6 // Decrement memory by one, zero page
+#define INY 0xc8 // Increment Y by one
+#define CMP_I 0xc9 // Compare accumulator to memory, immediate
+#define DEX 0xca // Decrement X by one
+#define CPY_A 0xcc // Compare Y to memory, absolute
+#define CMP_A 0xcd // Compare accumulator to memory, absolute
+#define DEC_A 0xce // Decrement memory by one, absolute
+/* 124 */
+#define BNE 0xd0 // Branch on result not zero
+#define CMP_ZiY 0xd1 // Compare accumulator to memory, zero page indirect Y-indexed
+#define CMP_XZ 0xd5 // Compare accumulator to memory, X-indexed zero page
+#define DEC_XZ 0xd6 // Decrement memory by one, X-indexed zero page
+#define CLD 0xd8 // Clear decimal mode
+#define CMP_YA 0xd9 // Compare accumulator to memory, Y-indexed absolute
+#define CMP_XA 0xdd // Compare accumulator to memory, X-indexed absolute
+#define DEC_XA 0xde // Decrement memory by one, X-indexed absolute
+/* 132 */
+#define CPX_I 0xe0 // Compare X to memory, immediate
+#define SBC_XZi 0xe1 // Subtract memory from accumulator with borrow, X-indexed zero page indirect
+#define CPX_Z 0xe4 // Compare X to memory, zero page
+#define SBC_Z 0xe5 // Subtract memory from accumulator with borrow, zero page
+#define INC_Z 0xe6 // Increment memory by one, zero page
+#define INX 0xe8 // Increment X by one
+#define SBC_I 0xe9 // Subtract memory from accumulator with borrow, immediate
+#define NOP 0xea // No operation
+#define CPX_A 0xec // Compare X to memory, absolute
+#define SBC_A 0xed // Subtract memory from accumulator with borrow, absolute
+#define INC_A 0xee // Increment memory by one, absolute
+/* 143 */
+#define BEQ 0xf0 // Branch on result zero
+#define SBC_ZiY 0xf1 // Subtract memory from accumulator with borrow, zero page indirect Y-indexed
+#define SBC_XZ 0xf5 // Subtract memory from accumulator with borrow, X-indexed zero page
+#define INC_XZ 0xf6 // Increment memory by one, X-indexed zero page
+#define SED 0xf8 // Set decimal mode
+#define SBC_YA 0xf9 // Subtract memory from accumulator with borrow, Y-indexed absolute
+#define SBC_XA 0xfd // Subtract memory from accumulator with borrow, X-indexed absolute
+#define INC_XA 0xfe // Increment memory by one, X-indexed absolute
+/* 151 */
+
#endif // OPCODES_H
\ No newline at end of file
diff --git a/inc/ram.h b/inc/ram.h
index 9c460c5..784e540 100644
--- a/inc/ram.h
+++ b/inc/ram.h
@@ -1,12 +1,12 @@
-#ifndef RAM_H
-#define RAM_H
-
-#include "stdint.h"
-
-#define RAM_SIZE (64 * 1024) // 55KiB
-#define RAM_BASE (0x00) // 0
-
-int createRAM(uint8_t **ram);
-void destroyRAM(uint8_t *ram);
-
+#ifndef RAM_H
+#define RAM_H
+
+#include "stdint.h"
+
+#define RAM_SIZE (64 * 1024) // 55KiB
+#define RAM_BASE (0x00) // 0
+
+int createRAM(uint8_t **ram);
+void destroyRAM(uint8_t *ram);
+
#endif // RAM_H
\ No newline at end of file
diff --git a/inc/rom.h b/inc/rom.h
index dc3de75..6f2e499 100644
--- a/inc/rom.h
+++ b/inc/rom.h
@@ -1,13 +1,13 @@
-#ifndef ROM_H
-#define ROM_H
-
-#include
-
-#define ROM_SIZE (8 * 1024) // 8KiB
-#define ROM_BASE (56 * 1024) // 55KiB RAM + 1KiB IO, hard coded
-
-extern uint8_t rom[ROM_SIZE];
-
-void initRom(uint8_t *rom);
-
+#ifndef ROM_H
+#define ROM_H
+
+#include
+
+#define ROM_SIZE (16 * 1024) // 16KiB
+#define ROM_BASE (48 * 1024) // 47KiB RAM + 1KiB IO, hard coded
+
+extern uint8_t rom[ROM_SIZE];
+
+void initRom(uint8_t *rom);
+
#endif // ROM_H
\ No newline at end of file
diff --git a/msbasic/.gitignore b/msbasic/.gitignore
new file mode 100644
index 0000000..ff67fb5
--- /dev/null
+++ b/msbasic/.gitignore
@@ -0,0 +1 @@
+tmp/
diff --git a/msbasic/README.md b/msbasic/README.md
new file mode 100644
index 0000000..a377118
--- /dev/null
+++ b/msbasic/README.md
@@ -0,0 +1,81 @@
+# Microsoft BASIC for 6502
+
+This is a single integrated assembly source tree that can generate nine different versions of Microsoft BASIC for 6502.
+
+By running ./make.sh, this will generate all versions and compare them to the original files byte by byte. The CC65 compiler suite is need to build this project.
+
+These are the first ten (known) versions of Microsoft BASIC for 6502:
+
+| Name | Release | MS Version | ROM | 9digit | INPUTBUFFER | extensions | .define |
+| ------------------- |:--------:| ------------ |:----:|:------:|:------------:|:-----------:| ---------- |
+| Commodore BASIC 1 | 1977 | | Y | Y | ZP | CBM | |
+| OSI BASIC | 1977 | 1.0 REV 3.2 | Y | N | ZP | - | CONFIG_10A |
+| AppleSoft I | 1977 | 1.1 | N | Y | $0200 | Apple | CONFIG_11 |
+| KIM BASIC | 1977 | 1.1 | N | Y | ZP | - | CONFIG_11A |
+| AppleSoft II | 1978 | | Y | Y | $0200 | Apple | CONFIG_2 |
+| AIM-65 BASIC | 1978 | 1.1? | Y | N | ZP | AIM | CONFIG_2A |
+| SYM-1 BASIC | 1978 | 1.1? | Y | N | ZP | SYM | CONFIG_2A |
+| Commodore BASIC 2 | 1979 | | Y | Y | $0200 | CBM | CONFIG_2A |
+| KBD BASIC | 1982 | | Y | N | $0700 | KBD | CONFIG_2B |
+| MicroTAN | 1980 | | Y | Y | ZP | - | CONFIG_2C |
+
+(Note that this assembly source cannot (yet) build AppleSoft II.)
+
+This lists the versions in the order in which they were forked from the Microsoft source base. Commodore BASIC 1, as used on the original PET is the oldest known version of Microsoft BASIC for 6502. It contains some additions to Microsoft's version, like Commodore-style file I/O.
+
+The CONFIG_n defines specify what Microsoft-version the OEM version is based on. If CONFIG_2B is defined, for example, CONFIG_2A, CONFIG_2, CONFIG_11A, CONFIG_11 and CONFIG_10A will be defined as well, and all bugfixes up to version 2B will be enabled.
+
+Additionally these releases are built for computer originally not having "original" Microsoft BASIC
+| Name | Release | .define |
+| ------------------- |:--------:| ---------- |
+| W65C816SXB | 2014 | CONFIG_2C |
+
+
+The following symbols can be defined in addition:
+
+| Configuration Symbol | Description
+| --------------------------------- | --------------------------------------------------------------------------------
+| CONFIG_CBM1_PATCHES | jump out into CBM1's binary patches instead of doing the right thing inline
+| CONFIG_CBM_ALL | add all Commodore-specific additions except file I/O
+| CONFIG_DATAFLG | ?
+| CONFIG_EASTER_EGG | include the CBM2 "WAIT 6502" easter egg
+| CONFIG_FILE | support Commodore PRINT#, INPUT#, GET#, CMD
+| CONFIG_IO_MSB | all I/O has bit #7 set
+| CONFIG_MONCOUT_DESTROYS_Y | Y needs to be preserved when calling MONCOUT
+| CONFIG_NO_CR | terminal doesn't need explicit CRs on line ends
+| CONFIG_NO_LINE_EDITING | disable support for Microsoft-style "@", "_", BEL etc.
+| CONFIG_NO_POKE | don't support PEEK, POKE and WAIT
+| CONFIG_NO_READ_Y_IS_ZERO_HACK | don't do a very volatile trick that saves one byte
+| CONFIG_NULL | support for the NULL statement
+| CONFIG_PEEK_SAVE_LINNUM | preserve LINNUM on a PEEK
+| CONFIG_PRINTNULLS | whether PRINTNULLS does anything
+| CONFIG_PRINT_CR | print CR when line end reached
+| CONFIG_RAM | optimizations for RAM version of BASIC, only use on 1.x
+| CONFIG_ROR_WORKAROUND | use workaround for buggy 6502s from 1975/1976; not safe for CONFIG_SMALL!
+| CONFIG_SAFE_NAMENOTFOUND | check both bytes of the caller's address in NAMENOTFOUND
+| CONFIG_SCRTCH_ORDER | where in the init code to call SCRTCH
+| CONFIG_SMALL | use 6 digit FP instead of 9 digit, use 2 character error messages, don't have GET
+| CONFIG_SMALL_ERROR | use 2 character error messages
+
+Changing symbol definitions can alter an existing base configuration, but it not guaranteed to assemble
+or work correctly.
+
+## More Information
+
+More information on the differences of the respective versions can be found on this blog entry: [Create your own Version of Microsoft BASIC for 6502](http://www.pagetable.com/?p=46).
+
+Also, Ben Eater has an published excellent video demonstrating how to port BASIC to a new system: [Running MSBASIC on my breadboard 6502 computer
+](https://www.youtube.com/watch?v=XlbPnihCM0E)
+
+## License
+
+2-clause BSD
+
+## Credits
+
+* Main work by Michael Steil .
+* AIM-65 and SYM-1 by Martin Hoffmann-Vetter
+* Function names and all uppercase comments taken from Bob Sander-Cederlof's excellent [AppleSoft II disassembly](http://www.txbobsc.com/scsc/scdocumentor/).
+* [Applesoft lite](http://cowgod.org/replica1/applesoft/) by Tom Greene helped a lot, too.
+* Thanks to Joe Zbicak for help with Intellision Keyboard BASIC
+* This work is dedicated to the memory of my dear hacking pal Michael "acidity" Kollmann.
diff --git a/msbasic/TODO.txt b/msbasic/TODO.txt
new file mode 100644
index 0000000..8339ab9
--- /dev/null
+++ b/msbasic/TODO.txt
@@ -0,0 +1,10 @@
+* convert messy init code into completely different
+ files without ifdefs (not much in common!)
+* move all machine specific code into separate files
+* rename all labels that point to RTS to RTSn
+* add AppleSoft comments
+* look for all " $", i.e. (zeropage) constants, replace them
+ with symbols
+* convert platform ifdefs in generic files into feature ifdefs or macros
+* reconstruct pre-CBM1, i.e. CBM1 without the patches
+* add some comments to every file
diff --git a/msbasic/aim65.cfg b/msbasic/aim65.cfg
new file mode 100644
index 0000000..b30d0e3
--- /dev/null
+++ b/msbasic/aim65.cfg
@@ -0,0 +1,19 @@
+MEMORY {
+ ZP: start = $0000, size = $0100, type = rw;
+ BASROM: start = $B000, size = $2000, fill = no, file = %O;
+ DUMMY: start = $0000, size = $00FF, file = "";
+}
+
+SEGMENTS {
+ ZEROPAGE: load = ZP, type = zp;
+ HEADER: load = BASROM, type = ro;
+ VECTORS: load = BASROM, type = ro;
+ KEYWORDS: load = BASROM, type = ro;
+ ERROR: load = BASROM, type = ro;
+ CODE: load = BASROM, type = ro;
+ CHRGET: load = BASROM, type = ro;
+ INIT: load = BASROM, type = ro;
+ EXTRA: load = BASROM, type = ro;
+ DUMMY: load = DUMMY; # don't include
+}
+
diff --git a/msbasic/aim65_extra.s b/msbasic/aim65_extra.s
new file mode 100644
index 0000000..b7bc655
--- /dev/null
+++ b/msbasic/aim65_extra.s
@@ -0,0 +1,5 @@
+.segment "EXTRA"
+
+LCFFA:
+ jsr CHRGOT
+ jmp LB89D
\ No newline at end of file
diff --git a/msbasic/aim65_iscntc.s b/msbasic/aim65_iscntc.s
new file mode 100644
index 0000000..d85f8bf
--- /dev/null
+++ b/msbasic/aim65_iscntc.s
@@ -0,0 +1,18 @@
+.segment "CODE"
+ISCNTC:
+ lda DRA2
+ pha
+ lda #$7f
+ sta DRA2
+ pha
+ pla
+ lda DRB2
+ rol a
+ pla
+ sta DRA2
+ bcs RET2
+
+ jsr GETKEY
+ lda #$03
+ cmp #$03
+;!!! runs into "STOP"
\ No newline at end of file
diff --git a/msbasic/aim65_loadsave.s b/msbasic/aim65_loadsave.s
new file mode 100644
index 0000000..974b116
--- /dev/null
+++ b/msbasic/aim65_loadsave.s
@@ -0,0 +1,51 @@
+.segment "CODE"
+
+SAVE:
+ pha
+ jsr WHEREO
+ jsr OUTSP
+ lda #$ff
+ jmp LB4BF
+
+MONRDKEY:
+ lda INFLG
+ jsr COUT5
+ bne LOAD2
+ jmp INALL
+LOAD2:
+ jmp CUREAD
+
+MONCOUT:
+ pha
+ lda OUTFLG
+ jsr COUT5
+ bne COUT3
+ pla
+ jmp OUTALL
+
+COUT3:
+ pla
+ cmp #LF
+ beq COUT6
+ cmp #CR
+ beq COUT4
+ jmp OUTPUT
+COUT4:
+ jsr CRCK
+ lda #CR
+ rts
+
+COUT5:
+ cmp #$54
+ beq COUT6
+ cmp #$55
+ beq COUT6
+ cmp #$4C
+COUT6:
+ rts
+
+MONRDKEY2:
+ jsr ROONEK
+ tya
+ beq COUT5
+ jmp GETKY
diff --git a/msbasic/apple_extra.s b/msbasic/apple_extra.s
new file mode 100644
index 0000000..ee4062f
--- /dev/null
+++ b/msbasic/apple_extra.s
@@ -0,0 +1,128 @@
+.segment "EXTRA"
+
+ .byte 0,0,0
+L2900:
+ jsr LFD6A
+ stx $33
+ ldx #$00
+L2907:
+ lda $0200,x
+ and #$7F
+ cmp #$0D
+ bne L2912
+ lda #$00
+L2912:
+ sta $0200,x
+ inx
+ bne L2907
+ ldx $33
+ rts
+PLT:
+ jmp L29F0
+L291E:
+ cmp #$47
+ bne L2925
+ jmp L29E0
+L2925:
+ cmp #$43
+ bne L292B
+ beq L2988
+L292B:
+ cmp #$50
+ beq L2930
+ inx
+L2930:
+ stx $33
+L2932:
+ jsr FRMEVL
+ jsr ROUND_FAC
+ jsr AYINT
+ lda FAC+4
+ ldx $33
+ sta $0300,x
+ dec $33
+ bmi L294Dx
+ lda #$2C
+ jsr SYNCHR
+ bpl L2932
+L294Dx:
+ tay
+ pla
+ cmp #$43
+ bne L2957
+ tya
+ jmp LF864
+L2957:
+ cmp #$50
+ bne L2962
+ tya
+ ldy $0301
+ jmp LF800
+L2962:
+ pha
+ lda $0301
+ sta $2C
+ sta $2D
+ pla
+ cmp #$48
+ bne L2978
+ lda $0300
+ ldy $0302
+ jmp LF819
+L2978:
+ cmp #$56
+ beq L297F
+ jmp SYNERR
+L297F:
+ ldy $0300
+ lda $0302
+ jmp LF828
+L2988:
+ dex
+ beq L2930
+INLINX:
+ jsr OUTQUES
+ jsr OUTSP
+ ldx #$80
+ jmp INLIN1
+ .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+ .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+ .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+ .byte 0,0,0,0,0,0,0,0,0,0
+USR_FUNC:
+ jsr L29DA
+ lda FAC+3
+ sta FAC+5
+ jmp (FAC+4)
+L29DA:
+ jmp (GOAYINT)
+ brk
+ brk
+ brk
+L29E0:
+ pla
+ jmp LFB40
+ .byte 0,0,0,0,0,0,0,0,0,0,0,0
+L29F0:
+ pha
+ ldx #$01
+ inc $B9
+ bne L29F9
+ inc $BA
+L29F9:
+ jmp L291E
+ .byte $00,$00,$00,$00,$41,$53,$21,$D2
+ .byte $02,$FA,$00
+ lda $12
+ beq L2A0E
+ jmp (GOGIVEAYF)
+L2A0E:
+ jsr LF689
+ .byte $15,$BC,$08,$10,$52,$45,$75,$10
+ .byte $CD,$00,$55,$15,$9E,$08,$10,$4C
+ .byte $45,$75,$10,$D4,$00,$55,$15,$0E
+ .byte $08,$10,$89,$10,$75,$15,$1C,$08
+ .byte $10,$1F,$10,$75,$00
+ jmp (GOGIVEAYF)
+; ----------------------------------------------------------------------------
+ .byte 0,0,0,0,0,0
diff --git a/msbasic/apple_iscntc.s b/msbasic/apple_iscntc.s
new file mode 100644
index 0000000..6b998a5
--- /dev/null
+++ b/msbasic/apple_iscntc.s
@@ -0,0 +1,10 @@
+.segment "CODE"
+ISCNTC:
+ lda $C000
+ cmp #$83
+ beq L0ECC
+ rts
+L0ECC:
+ jsr RDKEY
+ cmp #$03
+;!!! runs into "STOP"
\ No newline at end of file
diff --git a/msbasic/apple_loadsave.s b/msbasic/apple_loadsave.s
new file mode 100644
index 0000000..39f0d79
--- /dev/null
+++ b/msbasic/apple_loadsave.s
@@ -0,0 +1,39 @@
+.segment "CODE"
+
+SAVE:
+ jsr L0F42
+ jsr LFECD
+ jsr L0F51
+ jmp LFECD
+LOAD:
+ jsr L0F42
+ jsr LFEFD
+ jsr L0F51
+ jsr LFEFD
+ lda #QT_LOADED
+ jsr STROUT
+ jmp FIX_LINKS
+QT_LOADED:
+ .byte 0 ; XXX PATCHED
+ .byte "OADED"
+ .byte 0
+L0F42:
+ lda #$6C
+ ldy #$00
+ sta $3C
+ sty $3D
+ lda #$6E
+ sta $3E
+ sty $3F
+ rts
+L0F51:
+ lda $6A
+ ldy $6B
+ sta $3C
+ sty $3D
+ lda $6C
+ ldy $6D
+ sta $3E
+ sty $3F
+ rts
diff --git a/msbasic/applesoft.cfg b/msbasic/applesoft.cfg
new file mode 100644
index 0000000..0589c64
--- /dev/null
+++ b/msbasic/applesoft.cfg
@@ -0,0 +1,19 @@
+MEMORY {
+ ZP: start = $0000, size = $0100, type = rw;
+ BASROM: start = $0800, size = $3F00, fill = no, file = %O;
+ DUMMY: start = $0000, size = $00FF, file = "";
+}
+
+SEGMENTS {
+ ZEROPAGE: load = ZP, type = zp;
+ HEADER: load = BASROM, type = ro;
+ VECTORS: load = BASROM, type = ro;
+ KEYWORDS: load = BASROM, type = ro;
+ ERROR: load = BASROM, type = ro;
+ CODE: load = BASROM, type = ro;
+ CHRGET: load = BASROM, type = ro;
+ INIT: load = BASROM, type = ro;
+ EXTRA: load = BASROM, type = ro;
+ DUMMY: load = DUMMY; # don't include
+}
+
diff --git a/msbasic/array.s b/msbasic/array.s
new file mode 100644
index 0000000..44f6920
--- /dev/null
+++ b/msbasic/array.s
@@ -0,0 +1,413 @@
+.segment "CODE"
+
+; ----------------------------------------------------------------------------
+; COMPUTE ADDRESS OF FIRST VALUE IN ARRAY
+; ARYPNT = (LOWTR) + #DIMS*2 + 5
+; ----------------------------------------------------------------------------
+GETARY:
+ lda EOLPNTR
+ asl a
+ adc #$05
+ adc LOWTR
+ ldy LOWTR+1
+ bcc L2FAF
+ iny
+L2FAF:
+ sta HIGHDS
+ sty HIGHDS+1
+ rts
+
+; ----------------------------------------------------------------------------
+NEG32768:
+ .byte $90,$80,$00,$00
+
+.ifdef CONFIG_2C
+ .byte $00; bugfix: short number
+.endif
+
+; ----------------------------------------------------------------------------
+; EVALUATE NUMERIC FORMULA AT TXTPTR
+; CONVERTING RESULT TO INTEGER 0 <= X <= 32767
+; IN FAC+3,4
+; ----------------------------------------------------------------------------
+MAKINT:
+ jsr CHRGET
+.ifdef CONFIG_2
+ jsr FRMEVL
+.else
+ jsr FRMNUM
+.endif
+
+; ----------------------------------------------------------------------------
+; CONVERT FAC TO INTEGER
+; MUST BE POSITIVE AND LESS THAN 32768
+; ----------------------------------------------------------------------------
+MKINT:
+.ifdef CONFIG_2
+ jsr CHKNUM
+.endif
+ lda FACSIGN
+ bmi MI1
+
+; ----------------------------------------------------------------------------
+; CONVERT FAC TO INTEGER
+; MUST BE -32767 <= FAC <= 32767
+; ----------------------------------------------------------------------------
+AYINT:
+ lda FAC
+ cmp #$90
+ bcc MI2
+ lda #NEG32768
+ jsr FCOMP
+MI1:
+ bne IQERR
+MI2:
+ jmp QINT
+
+; ----------------------------------------------------------------------------
+; LOCATE ARRAY ELEMENT OR CREATE AN ARRAY
+; ----------------------------------------------------------------------------
+ARRAY:
+ lda DIMFLG
+.ifndef CONFIG_SMALL
+ ora VALTYP+1
+.endif
+ pha
+ lda VALTYP
+ pha
+ ldy #$00
+L2FDE:
+ tya
+ pha
+ lda VARNAM+1
+ pha
+ lda VARNAM
+ pha
+ jsr MAKINT
+ pla
+ sta VARNAM
+ pla
+ sta VARNAM+1
+ pla
+ tay
+ tsx
+ lda STACK+2,x
+ pha
+ lda STACK+1,x
+ pha
+ lda FAC_LAST-1
+ sta STACK+2,x
+ lda FAC_LAST
+ sta STACK+1,x
+ iny
+ jsr CHRGOT
+ cmp #$2C
+ beq L2FDE
+ sty EOLPNTR
+ jsr CHKCLS
+ pla
+ sta VALTYP
+ pla
+.ifndef CONFIG_SMALL
+ sta VALTYP+1
+ and #$7F
+.endif
+ sta DIMFLG
+; ----------------------------------------------------------------------------
+; SEARCH ARRAY TABLE FOR THIS ARRAY NAME
+; ----------------------------------------------------------------------------
+ ldx ARYTAB
+ lda ARYTAB+1
+L301F:
+ stx LOWTR
+ sta LOWTR+1
+ cmp STREND+1
+ bne L302B
+ cpx STREND
+ beq MAKE_NEW_ARRAY
+L302B:
+ ldy #$00
+ lda (LOWTR),y
+ iny
+ cmp VARNAM
+ bne L303A
+ lda VARNAM+1
+ cmp (LOWTR),y
+ beq USE_OLD_ARRAY
+L303A:
+ iny
+ lda (LOWTR),y
+ clc
+ adc LOWTR
+ tax
+ iny
+ lda (LOWTR),y
+ adc LOWTR+1
+ bcc L301F
+
+; ----------------------------------------------------------------------------
+; ERROR: BAD SUBSCRIPTS
+; ----------------------------------------------------------------------------
+SUBERR:
+ ldx #ERR_BADSUBS
+ .byte $2C
+
+; ----------------------------------------------------------------------------
+; ERROR: ILLEGAL QUANTITY
+; ----------------------------------------------------------------------------
+IQERR:
+ ldx #ERR_ILLQTY
+JER:
+ jmp ERROR
+
+; ----------------------------------------------------------------------------
+; FOUND THE ARRAY
+; ----------------------------------------------------------------------------
+USE_OLD_ARRAY:
+ ldx #ERR_REDIMD
+ lda DIMFLG
+ bne JER
+ jsr GETARY
+ lda EOLPNTR
+ ldy #$04
+ cmp (LOWTR),y
+ bne SUBERR
+ jmp FIND_ARRAY_ELEMENT
+
+; ----------------------------------------------------------------------------
+; CREATE A NEW ARRAY, UNLESS CALLED FROM GETARYPT
+; ----------------------------------------------------------------------------
+MAKE_NEW_ARRAY:
+ jsr GETARY
+ jsr REASON
+ lda #$00
+ tay
+ sta STRNG2+1
+ ldx #BYTES_PER_ELEMENT
+.if .def(CONFIG_SMALL) && (!.def(CONFIG_2))
+ stx STRNG2
+.endif
+ lda VARNAM
+ sta (LOWTR),y
+.ifndef CONFIG_SMALL
+ bpl L3078
+ dex
+L3078:
+.endif
+ iny
+ lda VARNAM+1
+ sta (LOWTR),y
+.if (!.def(CONFIG_SMALL)) || .def(CONFIG_2)
+ bpl L3081
+ dex
+ .if !(.def(CONFIG_SMALL) && .def(CONFIG_2))
+ dex
+ .endif
+L3081:
+ stx STRNG2
+.endif
+ lda EOLPNTR
+ iny
+ iny
+ iny
+ sta (LOWTR),y
+L308A:
+ ldx #$0B
+ lda #$00
+ bit DIMFLG
+ bvc L309A
+ pla
+ clc
+ adc #$01
+ tax
+ pla
+ adc #$00
+L309A:
+ iny
+ sta (LOWTR),y
+ iny
+ txa
+ sta (LOWTR),y
+ jsr MULTIPLY_SUBSCRIPT
+ stx STRNG2
+ sta STRNG2+1
+ ldy INDEX
+ dec EOLPNTR
+ bne L308A
+ adc HIGHDS+1
+ bcs GME
+ sta HIGHDS+1
+ tay
+ txa
+ adc HIGHDS
+ bcc L30BD
+ iny
+ beq GME
+L30BD:
+ jsr REASON
+ sta STREND
+ sty STREND+1
+ lda #$00
+ inc STRNG2+1
+ ldy STRNG2
+ beq L30D1
+L30CC:
+ dey
+ sta (HIGHDS),y
+ bne L30CC
+L30D1:
+ dec HIGHDS+1
+ dec STRNG2+1
+ bne L30CC
+ inc HIGHDS+1
+ sec
+ lda STREND
+ sbc LOWTR
+ ldy #$02
+ sta (LOWTR),y
+ lda STREND+1
+ iny
+ sbc LOWTR+1
+ sta (LOWTR),y
+ lda DIMFLG
+ bne RTS9
+ iny
+
+; ----------------------------------------------------------------------------
+; FIND SPECIFIED ARRAY ELEMENT
+;
+; (LOWTR),Y POINTS AT # OF DIMS IN ARRAY DESCRIPTOR
+; THE SUBSCRIPTS ARE ALL ON THE STACK AS INTEGERS
+; ----------------------------------------------------------------------------
+FIND_ARRAY_ELEMENT:
+ lda (LOWTR),y
+ sta EOLPNTR
+ lda #$00
+ sta STRNG2
+L30F6:
+ sta STRNG2+1
+ iny
+ pla
+ tax
+ sta FAC_LAST-1
+ pla
+ sta FAC_LAST
+ cmp (LOWTR),y
+ bcc FAE2
+ bne GSE
+ iny
+ txa
+ cmp (LOWTR),y
+ bcc FAE3
+; ----------------------------------------------------------------------------
+GSE:
+ jmp SUBERR
+GME:
+ jmp MEMERR
+; ----------------------------------------------------------------------------
+FAE2:
+ iny
+FAE3:
+ lda STRNG2+1
+ ora STRNG2
+ clc
+ beq L3124
+ jsr MULTIPLY_SUBSCRIPT
+ txa
+ adc FAC_LAST-1
+ tax
+ tya
+ ldy INDEX
+L3124:
+ adc FAC_LAST
+ stx STRNG2
+ dec EOLPNTR
+ bne L30F6
+.if .def(CONFIG_SMALL) && (!.def(CONFIG_2))
+ asl STRNG2
+ rol a
+ bcs GSE
+ asl STRNG2
+ rol a
+ bcs GSE
+ tay
+ lda STRNG2
+.else
+ .ifdef CONFIG_11A
+ sta STRNG2+1
+ .endif
+ ldx #BYTES_FP
+ .ifdef CONFIG_SMALL
+ lda VARNAM+1
+ .else
+ lda VARNAM
+ .endif
+ bpl L3135
+ dex
+L3135:
+ .ifdef CONFIG_SMALL
+ stx RESULT+1
+ .else
+ lda VARNAM+1
+ bpl L313B
+ dex
+ dex
+L313B:
+ stx RESULT+2
+ .endif
+ lda #$00
+ jsr MULTIPLY_SUBS1
+ txa
+.endif
+ adc HIGHDS
+ sta VARPNT
+ tya
+ adc HIGHDS+1
+ sta VARPNT+1
+ tay
+ lda VARPNT
+RTS9:
+ rts
+
+; ----------------------------------------------------------------------------
+; MULTIPLY (STRNG2) BY ((LOWTR),Y)
+; LEAVING PRODUCT IN A,X. (HI-BYTE ALSO IN Y.)
+; USED ONLY BY ARRAY SUBSCRIPT ROUTINES
+; ----------------------------------------------------------------------------
+MULTIPLY_SUBSCRIPT:
+ sty INDEX
+ lda (LOWTR),y
+ sta RESULT_LAST-2
+ dey
+ lda (LOWTR),y
+MULTIPLY_SUBS1:
+ sta RESULT_LAST-1
+ lda #$10
+ sta INDX
+ ldx #$00
+ ldy #$00
+L3163:
+ txa
+ asl a
+ tax
+ tya
+ rol a
+ tay
+ bcs GME
+ asl STRNG2
+ rol STRNG2+1
+ bcc L317C
+ clc
+ txa
+ adc RESULT_LAST-2
+ tax
+ tya
+ adc RESULT_LAST-1
+ tay
+ bcs GME
+L317C:
+ dec INDX
+ bne L3163
+ rts
+
diff --git a/msbasic/build.sh b/msbasic/build.sh
new file mode 100644
index 0000000..2f1c53a
--- /dev/null
+++ b/msbasic/build.sh
@@ -0,0 +1,6 @@
+if [ ! -d tmp ]; then
+ mkdir tmp
+fi
+
+ca65 -D kilian msbasic.s -o tmp/kilian.o
+ld65 -C kilian.cfg tmp/kilian.o -o tmp/kilian.bin -Ln tmp/kilian.lbl
diff --git a/msbasic/cbm1_patches.s b/msbasic/cbm1_patches.s
new file mode 100644
index 0000000..2081eb5
--- /dev/null
+++ b/msbasic/cbm1_patches.s
@@ -0,0 +1,51 @@
+.segment "INIT"
+
+PATCH1:
+ clc
+ jmp CONTROL_C_TYPED
+PATCH2:
+ bit FAC+4
+ bpl LE1AA
+ cmp #$54
+ bne LE1AA
+ jmp LCE3B
+LE1AA:
+ rts
+PATCH3:
+ bit FAC+4
+ bmi LE1B2
+ jmp LCE90
+LE1B2:
+ cmp #$54
+ beq LE1B9
+ jmp LCE82
+LE1B9:
+ jmp LCE69
+PATCH4:
+ sta CHARAC
+ inx
+ jmp LE1D9
+PATCH5:
+ bpl LE1C9
+ lda Z8C
+ ldy Z8C+1
+ rts
+LE1C9:
+ ldy #$FF
+ rts
+PATCH6:
+ bne LE1D8
+LE1CE:
+ inc POSX
+ bne LE1D8
+ lda $E2
+ sta POSX
+ bne LE1CE
+LE1D8:
+ rts
+LE1D9:
+ stx TXTPTR
+ pla
+ pla
+ tya
+ jmp L2B1C
diff --git a/msbasic/cbm_iscntc.s b/msbasic/cbm_iscntc.s
new file mode 100644
index 0000000..188f6ef
--- /dev/null
+++ b/msbasic/cbm_iscntc.s
@@ -0,0 +1 @@
+; nothing - ISCNTC is a KERNAL function
\ No newline at end of file
diff --git a/msbasic/cbmbasic1.cfg b/msbasic/cbmbasic1.cfg
new file mode 100644
index 0000000..537b9a9
--- /dev/null
+++ b/msbasic/cbmbasic1.cfg
@@ -0,0 +1,19 @@
+MEMORY {
+ ZP: start = $0000, size = $0100, type = rw;
+ BASROM: start = $C000, size = $3F00, fill = no, file = %O;
+ DUMMY: start = $0000, size = $00FF, file = "";
+}
+
+SEGMENTS {
+ ZEROPAGE: load = ZP, type = zp;
+ HEADER: load = BASROM, type = ro;
+ VECTORS: load = BASROM, type = ro;
+ KEYWORDS: load = BASROM, type = ro;
+ ERROR: load = BASROM, type = ro;
+ CODE: load = BASROM, type = ro;
+ CHRGET: load = BASROM, type = ro;
+ INIT: load = BASROM, type = ro;
+ EXTRA: load = BASROM, type = ro;
+ DUMMY: load = DUMMY; # don't include
+}
+
diff --git a/msbasic/cbmbasic2.cfg b/msbasic/cbmbasic2.cfg
new file mode 100644
index 0000000..537b9a9
--- /dev/null
+++ b/msbasic/cbmbasic2.cfg
@@ -0,0 +1,19 @@
+MEMORY {
+ ZP: start = $0000, size = $0100, type = rw;
+ BASROM: start = $C000, size = $3F00, fill = no, file = %O;
+ DUMMY: start = $0000, size = $00FF, file = "";
+}
+
+SEGMENTS {
+ ZEROPAGE: load = ZP, type = zp;
+ HEADER: load = BASROM, type = ro;
+ VECTORS: load = BASROM, type = ro;
+ KEYWORDS: load = BASROM, type = ro;
+ ERROR: load = BASROM, type = ro;
+ CODE: load = BASROM, type = ro;
+ CHRGET: load = BASROM, type = ro;
+ INIT: load = BASROM, type = ro;
+ EXTRA: load = BASROM, type = ro;
+ DUMMY: load = DUMMY; # don't include
+}
+
diff --git a/msbasic/chrget.s b/msbasic/chrget.s
new file mode 100644
index 0000000..bfaada4
--- /dev/null
+++ b/msbasic/chrget.s
@@ -0,0 +1,23 @@
+.segment "CHRGET"
+RAMSTART1:
+GENERIC_CHRGET:
+ inc TXTPTR
+ bne GENERIC_CHRGOT
+ inc TXTPTR+1
+GENERIC_CHRGOT:
+GENERIC_TXTPTR = GENERIC_CHRGOT + 1
+ lda $EA60
+.ifdef KBD
+ jsr LF430
+.endif
+ cmp #$3A
+ bcs L4058
+GENERIC_CHRGOT2:
+ cmp #$20
+ beq GENERIC_CHRGET
+ sec
+ sbc #$30
+ sec
+ sbc #$D0
+L4058:
+ rts
diff --git a/msbasic/defines.s b/msbasic/defines.s
new file mode 100644
index 0000000..b0dbc05
--- /dev/null
+++ b/msbasic/defines.s
@@ -0,0 +1,99 @@
+.if .def(cbmbasic1)
+CBM1 := 1
+.include "defines_cbm1.s"
+.elseif .def(osi)
+OSI := 1
+.include "defines_osi.s"
+.elseif .def(applesoft)
+APPLE := 1
+.include "defines_apple.s"
+.elseif .def(kb9)
+KIM := 1
+.include "defines_kim.s"
+.elseif .def(cbmbasic2)
+CBM2 := 1
+.include "defines_cbm2.s"
+.elseif .def(kbdbasic)
+KBD := 1
+.include "defines_kbd.s"
+.elseif .def(microtan)
+MICROTAN := 1
+.include "defines_microtan.s"
+.elseif .def(aim65)
+AIM65 := 1
+.include "defines_aim65.s"
+.elseif .def(sym1)
+SYM1 := 1
+.include "defines_sym1.s"
+.elseif .def(w65c816sxb)
+W65C816SXB := 1
+.include "defines_w65c816sxb.s"
+.elseif .def(kilian)
+KILIAN := 1
+.include "defines_kilian.s"
+.endif
+
+.ifdef CONFIG_2C
+CONFIG_2B := 1
+.endif
+.ifdef CONFIG_2B
+CONFIG_2A := 1
+.endif
+.ifdef CONFIG_2A
+CONFIG_2 := 1
+.endif
+.ifdef CONFIG_2
+CONFIG_11A := 1
+.endif
+.ifdef CONFIG_11A
+CONFIG_11 := 1
+.endif
+.ifdef CONFIG_11
+CONFIG_10A := 1
+.endif
+
+.ifdef CONFIG_SMALL
+BYTES_FP := 4
+CONFIG_SMALL_ERROR := 1
+.else
+BYTES_FP := 5
+.endif
+
+.ifndef BYTES_PER_ELEMENT
+BYTES_PER_ELEMENT := BYTES_FP
+.endif
+BYTES_PER_VARIABLE := BYTES_FP+2
+MANTISSA_BYTES := BYTES_FP-1
+BYTES_PER_FRAME := 2*BYTES_FP+8
+FOR_STACK1 := 2*BYTES_FP+5
+FOR_STACK2 := BYTES_FP+4
+
+.ifndef MAX_EXPON
+MAX_EXPON = 10
+.endif
+
+STACK := $0100
+.ifndef STACK2
+STACK2 := STACK
+.endif
+
+.ifdef INPUTBUFFER
+ .if INPUTBUFFER >= $0100
+CONFIG_NO_INPUTBUFFER_ZP := 1
+ .endif
+ .if INPUTBUFFER = $0200
+CONFIG_INPUTBUFFER_0200 := 1
+ .endif
+.endif
+INPUTBUFFERX = INPUTBUFFER & $FF00
+
+CR=13
+LF=10
+
+.ifndef CRLF_1
+CRLF_1 := CR
+CRLF_2 := LF
+.endif
+
+
+
diff --git a/msbasic/defines_aim65.s b/msbasic/defines_aim65.s
new file mode 100644
index 0000000..a12b656
--- /dev/null
+++ b/msbasic/defines_aim65.s
@@ -0,0 +1,59 @@
+; configuration
+CONFIG_2A := 1
+
+CONFIG_NULL := 1
+CONFIG_PRINT_CR := 1 ; print CR when line end reached
+CONFIG_SAFE_NAMENOTFOUND := 1
+CONFIG_SCRTCH_ORDER := 1
+CONFIG_PEEK_SAVE_LINNUM := 1
+CONFIG_SMALL_ERROR := 1
+
+; zero page
+ZP_START1 = $00
+ZP_START2 = $10
+ZP_START3 = $06
+ZP_START4 = $5E
+
+;extra ZP variables
+USR := $03
+TXPSV := LASTOP
+
+NULL := IQERR
+
+; inputbuffer
+INPUTBUFFER := $0016
+
+;extra stack
+STACK2 := $0200
+
+; constants
+STACK_TOP := $FD
+SPACE_FOR_GOSUB := $44
+NULL_MAX := $F2
+CRLF_1 := CR
+CRLF_2 := LF
+WIDTH := 20
+WIDTH2 := 10
+
+; memory layout
+RAMSTART2 := $0211
+
+; monitor functions
+PRIFLG := $A411
+INFLG := $A412
+OUTFLG := $A413
+DRA2 := $A480
+DRB2 := $A482
+
+DU13 := $E520
+PSLS := $E7DC
+LOAD := $E848
+WHEREO := $E871
+OUTPUT := $E97A
+INALL := $E993
+OUTALL := $E9BC
+CRCK := $EA24
+GETKEY := $EC40
+GETKY := $EC43
+ROONEK := $ECEF
+CUREAD := $FE83
\ No newline at end of file
diff --git a/msbasic/defines_apple.s b/msbasic/defines_apple.s
new file mode 100644
index 0000000..7d2360d
--- /dev/null
+++ b/msbasic/defines_apple.s
@@ -0,0 +1,49 @@
+; configuration
+CONFIG_11 := 1
+
+APPLE_BAD_BYTE := 1
+CONFIG_IO_MSB := 1 ; all I/O has bit #7 set
+CONFIG_PRINT_CR := 1 ; print CR when line end reached
+CONFIG_SAFE_NAMENOTFOUND := 1
+CONFIG_SCRTCH_ORDER := 3
+
+BYTES_PER_ELEMENT := 6 ; XXX override
+
+; zero page
+ZP_START1 = $00
+ZP_START2 = $4F
+ZP_START3 = $0D
+ZP_START4 = $55
+
+;extra ZP variables
+USR := $000A
+
+; inputbuffer
+INPUTBUFFER := $0200
+
+; constants
+STACK_TOP := $F8
+SPACE_FOR_GOSUB := $36
+CRLF_1 := CR
+CRLF_2 := $80
+WIDTH := 40
+WIDTH2 := 14
+
+; memory layout
+RAMSTART2 := $2A00
+
+; monitor functions
+MONRDKEY := $FD0C
+MONCOUT := $FDED
+LF689 := $F689
+LF800 := $F800
+LF819 := $F819
+LF828 := $F828
+LF864 := $F864
+TEX := $FB2F
+LFB40 := $FB40
+LFD0C := $FD0C
+LFD6A := $FD6A
+LFECD := $FECD
+LFEFD := $FEFD
+
diff --git a/msbasic/defines_cbm1.s b/msbasic/defines_cbm1.s
new file mode 100644
index 0000000..06ece6f
--- /dev/null
+++ b/msbasic/defines_cbm1.s
@@ -0,0 +1,54 @@
+; configuration
+; oldest known version, no CONFIG_n
+
+CONFIG_CBM_ALL := 1
+CONFIG_CBM1_PATCHES := 1 ; ** don't turn off! **
+
+CONFIG_DATAFLG := 1
+CONFIG_FILE := 1; support PRINT#, INPUT#, GET#, CMD
+CONFIG_NO_CR := 1; terminal doesn't need explicit CRs on line ends
+CONFIG_NO_LINE_EDITING := 1; support for "@", "_", BEL etc.
+CONFIG_PRINTNULLS := 1; whether PRINTNULLS does anything
+CONFIG_SCRTCH_ORDER := 2
+
+; zero page
+ZP_START1 = $00
+ZP_START2 = $04
+ZP_START3 = $5A
+ZP_START4 = $65
+
+; extra ZP variables
+CURDVC := $0003
+TISTR := $0200
+Z96 := $020C
+USR := GORESTART
+
+; constants
+SPACE_FOR_GOSUB := $36
+STACK_TOP := $FC
+NULL_MAX := $0A
+MAX_EXPON := 12 ; XXX override
+
+RAMSTART2 := $0400
+
+; magic memory locations
+ENTROPY = $9044
+
+; monitor functions
+OPEN := $FFC0
+CLOSE := $FFC3
+CHKIN := $FFC6
+CHKOUT := $FFC9
+CLRCH := $FFCC
+CHRIN := $FFCF
+CHROUT := $FFD2
+LOAD := $FFD5
+SAVE := $FFD8
+VERIFY := $FFDB
+SYS := $FFDE
+ISCNTC := $FFE1
+GETIN := $FFE4
+CLALL := $FFE7
+LE7F3 := $E7F3; for CBM1
+MONCOUT := CHROUT
+MONRDKEY := GETIN
diff --git a/msbasic/defines_cbm2.s b/msbasic/defines_cbm2.s
new file mode 100644
index 0000000..c38b80e
--- /dev/null
+++ b/msbasic/defines_cbm2.s
@@ -0,0 +1,60 @@
+; configuration
+CONFIG_2A := 1
+
+CONFIG_CBM_ALL := 1
+
+CONFIG_DATAFLG := 1
+CONFIG_EASTER_EGG := 1
+CONFIG_FILE := 1; support PRINT#, INPUT#, GET#, CMD
+CONFIG_NO_CR := 1; terminal doesn't need explicit CRs on line ends
+CONFIG_NO_LINE_EDITING := 1; support for "@", "_", BEL etc.
+CONFIG_NO_READ_Y_IS_ZERO_HACK := 1
+CONFIG_PEEK_SAVE_LINNUM := 1
+CONFIG_SCRTCH_ORDER := 2
+
+; zero page
+ZP_START1 = $00
+ZP_START2 = $0D
+ZP_START3 = $03
+ZP_START4 = $13
+
+; extra/override ZP variables
+CURDVC := $000E
+TISTR := $008D
+Z96 := $0096
+POSX := $00C6
+TXPSV := LASTOP
+USR := GORESTART ; XXX
+
+; inputbuffer
+INPUTBUFFER := $0200
+
+; constants
+SPACE_FOR_GOSUB := $3E
+STACK_TOP := $FA
+WIDTH := 40
+WIDTH2 := 30
+
+RAMSTART2 := $0400
+
+; magic memory locations
+ENTROPY = $E844
+
+; monitor functions
+OPEN := $FFC0
+CLOSE := $FFC3
+CHKIN := $FFC6
+CHKOUT := $FFC9
+CLRCH := $FFCC
+CHRIN := $FFCF
+CHROUT := $FFD2
+LOAD := $FFD5
+SAVE := $FFD8
+VERIFY := $FFDB
+SYS := $FFDE
+ISCNTC := $FFE1
+GETIN := $FFE4
+CLALL := $FFE7
+LE7F3 := $E7F3; for CBM1
+MONCOUT := CHROUT
+MONRDKEY := GETIN
diff --git a/msbasic/defines_kbd.s b/msbasic/defines_kbd.s
new file mode 100644
index 0000000..b0b5577
--- /dev/null
+++ b/msbasic/defines_kbd.s
@@ -0,0 +1,52 @@
+; configuration
+CONFIG_2B := 1
+
+CONFIG_NO_POKE := 1
+CONFIG_NO_READ_Y_IS_ZERO_HACK := 1
+CONFIG_SAFE_NAMENOTFOUND := 1
+CONFIG_SCRTCH_ORDER := 3
+CONFIG_SMALL := 1
+
+; zero page
+ZP_START1 = $00
+ZP_START2 = $0F
+ZP_START3 = $06
+ZP_START4 = $15
+
+; extra/override ZP variables
+TXPSV := $0049
+JMPADRS := $0093
+LOWTRX := $0094 ; $AB also EXPSGN?
+Z96 := $0096
+Z17 := $06FC
+Z18 := $06FD
+
+; inputbuffer
+INPUTBUFFER := $0700
+
+; constants
+STACK_TOP := $FE
+SPACE_FOR_GOSUB := $49
+CRLF_1 := LF
+CRLF_2 := CR
+
+; magic memory locations
+L06FE := $06FE
+L6874 := $6874
+
+; memory layout
+RAMSTART2 := $0300
+CONST_MEMSIZ := $3FFF
+
+; monitor functions
+MONCOUT := $FDFA
+LC000 := $C000
+LC009 := $C009
+LDE24 := $DE24
+PRIMM := $DE42
+LDE48 := $DE48
+LDE53 := $DE53
+LDE7F := $DE7F
+LDE8C := $DE8C
+
+
diff --git a/msbasic/defines_kilian.s b/msbasic/defines_kilian.s
new file mode 100644
index 0000000..c55b11a
--- /dev/null
+++ b/msbasic/defines_kilian.s
@@ -0,0 +1,21 @@
+; configuration
+CONFIG_2A := 1
+CONFIG_SCRTCH_ORDER := 2
+
+; zero page
+ZP_START0 = $00
+ZP_START1 = $02
+ZP_START2 = $0C
+ZP_START3 = $62
+ZP_START4 = $6D
+
+; extra/override ZP variables
+USR := GORESTART ; XXX
+
+; constants
+SPACE_FOR_GOSUB := $3E
+STACK_TOP := $FA
+WIDTH := 40
+WIDTH2 := 30
+
+RAMSTART2 := $0400
diff --git a/msbasic/defines_kim.s b/msbasic/defines_kim.s
new file mode 100644
index 0000000..144acd4
--- /dev/null
+++ b/msbasic/defines_kim.s
@@ -0,0 +1,32 @@
+; configuration
+CONFIG_11A := 1
+
+CONFIG_MONCOUT_DESTROYS_Y := 1
+CONFIG_NULL := 1
+CONFIG_PRINT_CR := 1 ; print CR when line end reached
+CONFIG_RAM := 1
+CONFIG_ROR_WORKAROUND := 1
+CONFIG_SAFE_NAMENOTFOUND := 1
+CONFIG_SCRTCH_ORDER := 2
+
+; zero page
+ZP_START1 = $00
+ZP_START2 = $15
+ZP_START3 = $0A
+ZP_START4 = $63
+
+; constants
+STACK_TOP := $FC
+SPACE_FOR_GOSUB := $36
+NULL_MAX := $F2 ; probably different in original version; the image I have seems to be modified; see PDF
+WIDTH := 72
+WIDTH2 := 56
+
+; magic memory locations
+L1800 := $1800
+L1873 := $1873
+
+; monitor functions
+MONRDKEY := $1E5A
+MONCOUT := $1EA0
+
diff --git a/msbasic/defines_microtan.s b/msbasic/defines_microtan.s
new file mode 100644
index 0000000..a054ad9
--- /dev/null
+++ b/msbasic/defines_microtan.s
@@ -0,0 +1,47 @@
+; configuration
+CONFIG_2C := 1
+
+CONFIG_NULL := 1
+CONFIG_MONCOUT_DESTROYS_Y := 1
+CONFIG_PEEK_SAVE_LINNUM := 1
+CONFIG_PRINT_CR := 1 ; print CR when line end reached
+CONFIG_ROR_WORKAROUND := 1
+CONFIG_SAFE_NAMENOTFOUND := 1
+CONFIG_SCRTCH_ORDER := 1
+
+; zero page
+ZP_START1 = $17
+ZP_START2 = $2F
+ZP_START3 = $24
+ZP_START4 = $85
+
+;extra ZP variables
+USR := $0021
+TXPSV := $00BA
+
+; constants
+STACK_TOP := $FE
+SPACE_FOR_GOSUB := $3E
+NULL_MAX := $F0
+WIDTH := 80
+WIDTH2 := 56
+; memory layout
+RAMSTART2 := $0400
+
+; monitor functions
+MONRDKEY := $E210
+MONRDKEY2 := $E213
+MONCOUT := $E216
+LF000 := $F000
+LF003 := $F003
+LF006 := $F006
+LF009 := $F009
+LF00C := $F00C
+LF00F := $F00F
+LF018 := $F018
+LF01B := $F01B
+LF01E := $F01E
+LF021 := $F021
+LFDFA := $FDFA
+LFE73 := $FE73
+LFE75 := $FE75
diff --git a/msbasic/defines_osi.s b/msbasic/defines_osi.s
new file mode 100644
index 0000000..9ccc41e
--- /dev/null
+++ b/msbasic/defines_osi.s
@@ -0,0 +1,37 @@
+; configuration
+CONFIG_10A := 1
+
+CONFIG_DATAFLG := 1
+CONFIG_NULL := 1
+CONFIG_PRINT_CR := 1 ; print CR when line end reached
+CONFIG_SCRTCH_ORDER := 3
+CONFIG_SMALL := 1
+
+; zero page
+ZP_START1 = $00
+ZP_START2 = $0D
+ZP_START3 = $5B
+ZP_START4 = $65
+
+;extra ZP variables
+USR := $000A
+
+; constants
+STACK_TOP := $FC
+SPACE_FOR_GOSUB := $33
+NULL_MAX := $0A
+WIDTH := 72
+WIDTH2 := 56
+
+; memory layout
+RAMSTART2 := $0300
+
+; magic memory locations
+L0200 := $0200
+
+; monitor functions
+MONRDKEY := $FFEB
+MONCOUT := $FFEE
+MONISCNTC := $FFF1
+LOAD := $FFF4
+SAVE := $FFF7
diff --git a/msbasic/defines_sym1.s b/msbasic/defines_sym1.s
new file mode 100644
index 0000000..8b37585
--- /dev/null
+++ b/msbasic/defines_sym1.s
@@ -0,0 +1,57 @@
+; configuration
+CONFIG_2A := 1
+
+CONFIG_NULL := 1
+CONFIG_PRINT_CR := 1 ; print CR when line end reached
+CONFIG_SAFE_NAMENOTFOUND := 1
+CONFIG_SCRTCH_ORDER := 1
+CONFIG_PEEK_SAVE_LINNUM := 1
+CONFIG_SMALL_ERROR := 1
+
+; zero page
+ZP_START1 = $00
+ZP_START2 = $18
+ZP_START3 = $0d
+ZP_START4 = $66
+
+;extra ZP variables
+USR := $0A
+TXPSV := LASTOP
+ZD3 := $D3
+ZD4 := $D4
+
+GET := IQERR
+COS := USR1
+SIN := USR1
+TAN := USR1
+ATN := USR1
+
+; inputbuffer
+INPUTBUFFER := $001E
+
+; constants
+STACK_TOP := $FE
+SPACE_FOR_GOSUB := $3E
+NULL_MAX := $F0
+CRLF_1 := CR
+CRLF_2 := LF
+WIDTH := 72
+WIDTH2 := 56
+
+; memory layout
+RAMSTART2 := $0200
+
+; monitor functions
+ASCNIB := $8275
+INSTAT := $8386
+MONRDKEY := $8A1B
+MONCOUT := $8A47
+ACCESS := $8B86
+L8C78 := $8C78
+DUMPT := $8E87
+
+P3L := $A64A
+P3H := P3L+1
+P2L := $A64C
+P2H := P2L+1
+P1L := $A64E
\ No newline at end of file
diff --git a/msbasic/defines_w65c816sxb.s b/msbasic/defines_w65c816sxb.s
new file mode 100644
index 0000000..2d98877
--- /dev/null
+++ b/msbasic/defines_w65c816sxb.s
@@ -0,0 +1,26 @@
+; configuration
+CONFIG_2C := 1
+
+CONFIG_NO_CR := 1
+CONFIG_SCRTCH_ORDER := 2
+
+; zero page
+ZP_START1 := $00
+ZP_START2 := $0D
+ZP_START3 := $5B
+ZP_START4 := $65
+
+;extra ZP variables
+USR := $000A
+
+; constants
+STACK_TOP := $FC
+SPACE_FOR_GOSUB := $33
+WIDTH := 72
+WIDTH2 := 56
+
+; memory layout
+RAMSTART2 := $5000
+SAVE:
+LOAD:
+ rts
diff --git a/msbasic/error.s b/msbasic/error.s
new file mode 100644
index 0000000..e05ce65
--- /dev/null
+++ b/msbasic/error.s
@@ -0,0 +1,49 @@
+init_error_table
+
+.ifdef CONFIG_SMALL_ERROR
+define_error ERR_NOFOR, "NF"
+define_error ERR_SYNTAX, "SN"
+define_error ERR_NOGOSUB, "RG"
+define_error ERR_NODATA, "OD"
+define_error ERR_ILLQTY, "FC"
+define_error ERR_OVERFLOW, "OV"
+define_error ERR_MEMFULL, "OM"
+define_error ERR_UNDEFSTAT, "US"
+define_error ERR_BADSUBS, "BS"
+define_error ERR_REDIMD, "DD"
+define_error ERR_ZERODIV, "/0"
+define_error ERR_ILLDIR, "ID"
+define_error ERR_BADTYPE, "TM"
+define_error ERR_STRLONG, "LS"
+define_error ERR_FRMCPX, "ST"
+define_error ERR_CANTCONT, "CN"
+define_error ERR_UNDEFFN, "UF"
+.else
+define_error ERR_NOFOR, "NEXT WITHOUT FOR"
+define_error ERR_SYNTAX, "SYNTAX"
+define_error ERR_NOGOSUB, "RETURN WITHOUT GOSUB"
+define_error ERR_NODATA, "OUT OF DATA"
+define_error ERR_ILLQTY, "ILLEGAL QUANTITY"
+.ifdef CBM1
+ .byte 0,0,0,0,0
+.endif
+define_error ERR_OVERFLOW, "OVERFLOW"
+define_error ERR_MEMFULL, "OUT OF MEMORY"
+define_error ERR_UNDEFSTAT, "UNDEF'D STATEMENT"
+define_error ERR_BADSUBS, "BAD SUBSCRIPT"
+define_error ERR_REDIMD, "REDIM'D ARRAY"
+define_error ERR_ZERODIV, "DIVISION BY ZERO"
+define_error ERR_ILLDIR, "ILLEGAL DIRECT"
+define_error ERR_BADTYPE, "TYPE MISMATCH"
+define_error ERR_STRLONG, "STRING TOO LONG"
+.ifdef CONFIG_FILE
+ .ifdef CBM1
+define_error ERR_BADDATA, "BAD DATA"
+ .else
+define_error ERR_BADDATA, "FILE DATA"
+ .endif
+.endif
+define_error ERR_FRMCPX, "FORMULA TOO COMPLEX"
+define_error ERR_CANTCONT, "CAN'T CONTINUE"
+define_error ERR_UNDEFFN, "UNDEF'D FUNCTION"
+.endif
\ No newline at end of file
diff --git a/msbasic/eval.s b/msbasic/eval.s
new file mode 100644
index 0000000..1024c22
--- /dev/null
+++ b/msbasic/eval.s
@@ -0,0 +1,788 @@
+.segment "CODE"
+
+; ----------------------------------------------------------------------------
+; "NEXT" STATEMENT
+; ----------------------------------------------------------------------------
+NEXT:
+ bne NEXT1
+ ldy #$00
+ beq NEXT2
+NEXT1:
+ jsr PTRGET
+NEXT2:
+ sta FORPNT
+ sty FORPNT+1
+ jsr GTFORPNT
+ beq NEXT3
+ ldx #$00
+GERR:
+ beq JERROR
+NEXT3:
+ txs
+.ifndef CONFIG_2
+ inx
+ inx
+ inx
+ inx
+.endif
+ txa
+.ifdef CONFIG_2
+ clc
+ adc #$04
+ pha
+ adc #BYTES_FP+1
+ sta DEST
+ pla
+.else
+ inx
+ inx
+ inx
+ inx
+ inx
+.ifndef CONFIG_SMALL
+ inx
+.endif
+ stx DEST
+.endif
+ ldy #>STACK
+ jsr LOAD_FAC_FROM_YA
+ tsx
+ lda STACK+BYTES_FP+4,x
+ sta FACSIGN
+ lda FORPNT
+ ldy FORPNT+1
+ jsr FADD
+ jsr SETFOR
+ ldy #>STACK
+ jsr FCOMP2
+ tsx
+ sec
+ sbc STACK+BYTES_FP+4,x
+ beq L2C22
+ lda STACK+2*BYTES_FP+5,x
+ sta CURLIN
+ lda STACK+2*BYTES_FP+6,x
+ sta CURLIN+1
+ lda STACK+2*BYTES_FP+8,x
+ sta TXTPTR
+ lda STACK+2*BYTES_FP+7,x
+ sta TXTPTR+1
+L2C1F:
+ jmp NEWSTT
+L2C22:
+ txa
+ adc #2*BYTES_FP+7
+ tax
+ txs
+ jsr CHRGOT
+ cmp #$2C
+ bne L2C1F
+ jsr CHRGET
+ jsr NEXT1
+
+; ----------------------------------------------------------------------------
+; EVALUATE EXPRESSION, MAKE SURE IT IS NUMERIC
+; ----------------------------------------------------------------------------
+FRMNUM:
+ jsr FRMEVL
+
+; ----------------------------------------------------------------------------
+; MAKE SURE (FAC) IS NUMERIC
+; ----------------------------------------------------------------------------
+CHKNUM:
+ clc
+ .byte $24
+
+; ----------------------------------------------------------------------------
+; MAKE SURE (FAC) IS STRING
+; ----------------------------------------------------------------------------
+CHKSTR:
+ sec
+
+; ----------------------------------------------------------------------------
+; MAKE SURE (FAC) IS CORRECT TYPE
+; IF C=0, TYPE MUST BE NUMERIC
+; IF C=1, TYPE MUST BE STRING
+; ----------------------------------------------------------------------------
+CHKVAL:
+ bit VALTYP
+ bmi L2C41
+ bcs L2C43
+L2C40:
+ rts
+L2C41:
+ bcs L2C40
+L2C43:
+ ldx #ERR_BADTYPE
+JERROR:
+ jmp ERROR
+
+; ----------------------------------------------------------------------------
+; EVALUATE THE EXPRESSION AT TXTPTR, LEAVING THE
+; RESULT IN FAC. WORKS FOR BOTH STRING AND NUMERIC
+; EXPRESSIONS.
+; ----------------------------------------------------------------------------
+FRMEVL:
+ ldx TXTPTR
+ bne L2C4E
+ dec TXTPTR+1
+L2C4E:
+ dec TXTPTR
+ ldx #$00
+ .byte $24
+FRMEVL1:
+ pha
+ txa
+ pha
+ lda #$01
+ jsr CHKMEM
+ jsr FRM_ELEMENT
+ lda #$00
+ sta CPRTYP
+FRMEVL2:
+ jsr CHRGOT
+L2C65:
+ sec
+ sbc #TOKEN_GREATER
+ bcc L2C81
+ cmp #$03
+ bcs L2C81
+ cmp #$01
+ rol a
+ eor #$01
+ eor CPRTYP
+ cmp CPRTYP
+ bcc SNTXERR
+ sta CPRTYP
+ jsr CHRGET
+ jmp L2C65
+L2C81:
+ ldx CPRTYP
+ bne FRM_RELATIONAL
+ bcs L2D02
+ adc #$07
+ bcc L2D02
+ adc VALTYP
+ bne L2C92
+ jmp CAT
+L2C92:
+ adc #$FF
+ sta INDEX
+ asl a
+ adc INDEX
+ tay
+FRM_PRECEDENCE_TEST:
+ pla
+ cmp MATHTBL,y
+ bcs FRM_PERFORM1
+ jsr CHKNUM
+L2CA3:
+ pha
+L2CA4:
+ jsr FRM_RECURSE
+ pla
+ ldy LASTOP
+ bpl PREFNC
+ tax
+ beq GOEX
+ bne FRM_PERFORM2
+
+; ----------------------------------------------------------------------------
+; FOUND ONE OR MORE RELATIONAL OPERATORS <,=,>
+; ----------------------------------------------------------------------------
+FRM_RELATIONAL:
+ lsr VALTYP
+ txa
+ rol a
+ ldx TXTPTR
+ bne L2CBB
+ dec TXTPTR+1
+L2CBB:
+ dec TXTPTR
+ ldy #$1B
+ sta CPRTYP
+ bne FRM_PRECEDENCE_TEST
+PREFNC:
+ cmp MATHTBL,y
+ bcs FRM_PERFORM2
+ bcc L2CA3
+
+; ----------------------------------------------------------------------------
+; STACK THIS OPERATION AND CALL FRMEVL FOR
+; ANOTHER ONE
+; ----------------------------------------------------------------------------
+FRM_RECURSE:
+ lda MATHTBL+2,y
+ pha
+ lda MATHTBL+1,y
+ pha
+ jsr FRM_STACK1
+ lda CPRTYP
+ jmp FRMEVL1
+SNTXERR:
+ jmp SYNERR
+
+; ----------------------------------------------------------------------------
+; STACK (FAC)
+; THREE ENTRY POINTS:
+; 1, FROM FRMEVL
+; 2, FROM "STEP"
+; 3, FROM "FOR"
+; ----------------------------------------------------------------------------
+FRM_STACK1:
+ lda FACSIGN
+ ldx MATHTBL,y
+
+; ----------------------------------------------------------------------------
+; ENTER HERE FROM "STEP", TO PUSH STEP SIGN AND VALUE
+; ----------------------------------------------------------------------------
+FRM_STACK2:
+ tay
+ pla
+ sta INDEX
+.ifndef CONFIG_2B
+ inc INDEX ; bug: assumes not on page boundary
+; bug exists on AppleSoft II
+.endif
+ pla
+ sta INDEX+1
+.ifdef CONFIG_2B
+ inc INDEX
+ bne LEB69
+ inc INDEX+1
+LEB69:
+.endif
+ tya
+ pha
+
+; ----------------------------------------------------------------------------
+; ENTER HERE FROM "FOR", WITH (INDEX) = STEP,
+; TO PUSH INITIAL VALUE OF "FOR" VARIABLE
+; ----------------------------------------------------------------------------
+FRM_STACK3:
+ jsr ROUND_FAC
+.ifndef CONFIG_SMALL
+ lda FAC+4
+ pha
+.endif
+ lda FAC+3
+ pha
+ lda FAC+2
+ pha
+ lda FAC+1
+ pha
+ lda FAC
+ pha
+ jmp (INDEX)
+L2D02:
+ ldy #$FF
+ pla
+GOEX:
+ beq EXIT
+
+; ----------------------------------------------------------------------------
+; PERFORM STACKED OPERATION
+;
+; (A) = PRECEDENCE BYTE
+; STACK: 1 -- CPRMASK
+; 5 -- (ARG)
+; 2 -- ADDR OF PERFORMER
+; ----------------------------------------------------------------------------
+FRM_PERFORM1:
+ cmp #$64
+ beq L2D0E
+ jsr CHKNUM
+L2D0E:
+ sty LASTOP
+FRM_PERFORM2:
+ pla
+ lsr a
+ sta CPRMASK
+ pla
+ sta ARG
+ pla
+ sta ARG+1
+ pla
+ sta ARG+2
+ pla
+ sta ARG+3
+ pla
+.ifndef CONFIG_SMALL
+ sta ARG+4
+ pla
+.endif
+ sta ARGSIGN
+ eor FACSIGN
+ sta SGNCPR
+EXIT:
+ lda FAC
+ rts
+
+; ----------------------------------------------------------------------------
+; GET ELEMENT IN EXPRESSION
+;
+; GET VALUE OF VARIABLE OR NUMBER AT TXTPNT, OR POINT
+; TO STRING DESCRIPTOR IF A STRING, AND PUT IN FAC.
+; ----------------------------------------------------------------------------
+FRM_ELEMENT:
+ lda #$00
+ sta VALTYP
+L2D31:
+ jsr CHRGET
+ bcs L2D39
+L2D36:
+ jmp FIN
+L2D39:
+ jsr ISLETC
+ bcs FRM_VARIABLE
+.ifdef CONFIG_CBM_ALL
+ cmp #$FF
+ bne LCDC1
+ lda #CON_PI
+ jsr LOAD_FAC_FROM_YA
+ jmp CHRGET
+CON_PI:
+ .byte $82,$49,$0f,$DA,$A1
+LCDC1:
+.endif
+ cmp #$2E
+ beq L2D36
+ cmp #TOKEN_MINUS
+ beq MIN
+ cmp #TOKEN_PLUS
+ beq L2D31
+ cmp #$22
+ bne NOT_
+
+; ----------------------------------------------------------------------------
+; STRING CONSTANT ELEMENT
+;
+; SET Y,A = (TXTPTR)+CARRY
+; ----------------------------------------------------------------------------
+STRTXT:
+ lda TXTPTR
+ ldy TXTPTR+1
+ adc #$00
+ bcc L2D57
+ iny
+L2D57:
+ jsr STRLIT
+ jmp POINT
+
+; ----------------------------------------------------------------------------
+; "NOT" FUNCTION
+; IF FAC=0, RETURN FAC=1
+; IF FAC<>0, RETURN FAC=0
+; ----------------------------------------------------------------------------
+NOT_:
+ cmp #TOKEN_NOT
+ bne L2D74
+ ldy #$18
+ bne EQUL
+
+; ----------------------------------------------------------------------------
+; COMPARISON FOR EQUALITY (= OPERATOR)
+; ALSO USED TO EVALUATE "NOT" FUNCTION
+; ----------------------------------------------------------------------------
+EQUOP:
+ jsr AYINT
+ lda FAC_LAST
+ eor #$FF
+ tay
+ lda FAC_LAST-1
+ eor #$FF
+ jmp GIVAYF
+L2D74:
+.ifdef SYM1
+ cmp #TOKEN_USR
+ bne LCC8A
+ jmp LCDBD
+LCC8A:
+ cmp #$26
+ bne LCC91
+ jmp LCDFE
+LCC91:
+.endif
+ cmp #TOKEN_FN
+ bne L2D7B
+ jmp L31F3
+L2D7B:
+ cmp #TOKEN_SGN
+ bcc PARCHK
+ jmp UNARY
+
+; ----------------------------------------------------------------------------
+; EVALUATE "(EXPRESSION)"
+; ----------------------------------------------------------------------------
+PARCHK:
+ jsr CHKOPN
+ jsr FRMEVL
+CHKCLS:
+ lda #$29
+ .byte $2C
+CHKOPN:
+ lda #$28
+ .byte $2C
+CHKCOM:
+ lda #$2C
+
+; ----------------------------------------------------------------------------
+; UNLESS CHAR AT TXTPTR = (A), SYNTAX ERROR
+; ----------------------------------------------------------------------------
+SYNCHR: ; XXX all CBM code calls SYNCHR instead of CHKCOM
+ ldy #$00
+ cmp (TXTPTR),y
+ bne SYNERR
+ jmp CHRGET
+; ----------------------------------------------------------------------------
+SYNERR:
+ ldx #ERR_SYNTAX
+ jmp ERROR
+; ----------------------------------------------------------------------------
+MIN:
+ ldy #$15
+EQUL:
+ pla
+ pla
+ jmp L2CA4
+; ----------------------------------------------------------------------------
+FRM_VARIABLE:
+ jsr PTRGET
+FRM_VARIABLE_CALL = *-1
+ sta FAC_LAST-1
+ sty FAC_LAST
+.ifdef CONFIG_CBM_ALL
+ lda VARNAM
+ ldy VARNAM+1
+.endif
+ ldx VALTYP
+ beq L2DB1
+.ifdef CONFIG_CBM_ALL
+ .ifdef CONFIG_CBM1_PATCHES
+ jmp PATCH2
+ clc
+LCE3B:
+ .else
+ ldx #$00
+ stx STRNG1+1
+ bit FAC+4
+ bpl LCE53
+ cmp #$54 ; T
+ bne LCE53
+ .endif
+ cpy #$C9 ; I$
+ bne LCE53
+ jsr LCE76
+ sty EXPON
+ dey
+ sty STRNG2
+ ldy #$06
+ sty INDX
+ ldy #$24
+ jsr LDD3A
+ jmp LD353
+LCE53:
+.endif
+.ifdef CONFIG_2
+ .ifndef CBM2
+; bugfix?
+; fixed on AppleSoft II, not on any CBM
+ ldx #$00
+ stx STRNG1+1
+ .endif
+.endif
+ rts
+L2DB1:
+.ifndef CONFIG_SMALL
+ ldx VALTYP+1
+ bpl L2DC2
+ ldy #$00
+ lda (FAC+3),y
+ tax
+ iny
+ lda (FAC+3),y
+ tay
+ txa
+ jmp GIVAYF
+L2DC2:
+.endif
+.ifdef CONFIG_CBM1_PATCHES
+ jmp PATCH3
+ .byte $19
+.endif
+.ifdef CBM2
+ bit FAC+4
+ bpl LCE90
+ cmp #$54
+ bne LCE82
+.endif
+.ifndef CONFIG_CBM_ALL
+ jmp LOAD_FAC_FROM_YA
+.endif
+.ifdef CONFIG_CBM_ALL
+LCE69:
+ cpy #$49
+.ifdef CBM1
+ bne LCE82
+.else
+ bne LCE90
+.endif
+ jsr LCE76
+ tya
+ ldx #$A0
+ jmp LDB21
+LCE76:
+.ifdef CBM1
+ lda #$FE
+ ldy #$01
+.else
+ lda #$8B
+ ldy #$00
+.endif
+ sei
+ jsr LOAD_FAC_FROM_YA
+ cli
+ sty FAC+1
+ rts
+LCE82:
+ cmp #$53
+ bne LCE90
+ cpy #$54
+ bne LCE90
+ lda Z96
+ jmp FLOAT
+LCE90:
+ lda FAC+3
+ ldy FAC+4
+ jmp LOAD_FAC_FROM_YA
+.endif
+
+; ----------------------------------------------------------------------------
+UNARY:
+ asl a
+ pha
+ tax
+ jsr CHRGET
+ cpx #<(TOKEN_LEFTSTR*2-1)
+ bcc L2DEF
+ jsr CHKOPN
+ jsr FRMEVL
+ jsr CHKCOM
+ jsr CHKSTR
+ pla
+ tax
+ lda FAC_LAST
+ pha
+ lda FAC_LAST-1
+ pha
+ txa
+ pha
+ jsr GETBYT
+ pla
+ tay
+ txa
+ pha
+ jmp L2DF4
+L2DEF:
+ jsr PARCHK
+ pla
+ tay
+L2DF4:
+ lda UNFNC-TOKEN_SGN-TOKEN_SGN+$100,y
+ sta JMPADRS+1
+ lda UNFNC-TOKEN_SGN-TOKEN_SGN+$101,y
+ sta JMPADRS+2
+.ifdef KBD
+ jsr LF47D
+.else
+ jsr JMPADRS
+.endif
+ jmp CHKNUM
+
+; ----------------------------------------------------------------------------
+OR:
+ ldy #$FF
+ .byte $2C
+; ----------------------------------------------------------------------------
+TAND:
+ ldy #$00
+ sty EOLPNTR
+ jsr AYINT
+ lda FAC_LAST-1
+ eor EOLPNTR
+ sta CHARAC
+ lda FAC_LAST
+ eor EOLPNTR
+ sta ENDCHR
+ jsr COPY_ARG_TO_FAC
+ jsr AYINT
+ lda FAC_LAST
+ eor EOLPNTR
+ and ENDCHR
+ eor EOLPNTR
+ tay
+ lda FAC_LAST-1
+ eor EOLPNTR
+ and CHARAC
+ eor EOLPNTR
+ jmp GIVAYF
+
+; ----------------------------------------------------------------------------
+; PERFORM RELATIONAL OPERATIONS
+; ----------------------------------------------------------------------------
+RELOPS:
+ jsr CHKVAL
+ bcs STRCMP
+ lda ARGSIGN
+ ora #$7F
+ and ARG+1
+ sta ARG+1
+ lda #CON_HALF
+ jmp FADD
+
+; ----------------------------------------------------------------------------
+; FAC = (Y,A) - FAC
+; ----------------------------------------------------------------------------
+FSUB:
+ jsr LOAD_ARG_FROM_YA
+
+; ----------------------------------------------------------------------------
+; FAC = ARG - FAC
+; ----------------------------------------------------------------------------
+FSUBT:
+ lda FACSIGN
+ eor #$FF
+ sta FACSIGN
+ eor ARGSIGN
+ sta SGNCPR
+ lda FAC
+ jmp FADDT
+
+; ----------------------------------------------------------------------------
+; Commodore BASIC V2 Easter Egg
+; ----------------------------------------------------------------------------
+.ifdef CONFIG_EASTER_EGG
+EASTER_EGG:
+ lda LINNUM
+ cmp #<6502
+ bne L3628
+ lda LINNUM+1
+ sbc #>6502
+ bne L3628
+ sta LINNUM
+ tay
+ lda #$80
+ sta LINNUM+1
+LD758:
+ ldx #$0A
+LD75A:
+ lda MICROSOFT-1,x
+ and #$3F
+ sta (LINNUM),y
+ iny
+ bne LD766
+ inc LINNUM+1
+LD766:
+ dex
+ bne LD75A
+ dec FORPNT
+ bne LD758
+ rts
+.endif
+
+; ----------------------------------------------------------------------------
+; SHIFT SMALLER ARGUMENT MORE THAN 7 BITS
+; ----------------------------------------------------------------------------
+FADD1:
+ jsr SHIFT_RIGHT
+ bcc FADD3
+
+; ----------------------------------------------------------------------------
+; FAC = (Y,A) + FAC
+; ----------------------------------------------------------------------------
+FADD:
+ jsr LOAD_ARG_FROM_YA
+
+; ----------------------------------------------------------------------------
+; FAC = ARG + FAC
+; ----------------------------------------------------------------------------
+FADDT:
+ bne L365B
+ jmp COPY_ARG_TO_FAC
+L365B:
+ ldx FACEXTENSION
+ stx ARGEXTENSION
+ ldx #ARG
+ lda ARG
+FADD2:
+ tay
+.ifdef KBD
+ beq RTS4
+.else
+ beq RTS3
+.endif
+ sec
+ sbc FAC
+ beq FADD3
+ bcc L367F
+ sty FAC
+ ldy ARGSIGN
+ sty FACSIGN
+ eor #$FF
+ adc #$00
+ ldy #$00
+ sty ARGEXTENSION
+ ldx #FAC
+ bne L3683
+L367F:
+ ldy #$00
+ sty FACEXTENSION
+L3683:
+ cmp #$F9
+ bmi FADD1
+ tay
+ lda FACEXTENSION
+ lsr 1,x
+ jsr SHIFT_RIGHT4
+FADD3:
+ bit SGNCPR
+ bpl FADD4
+ ldy #FAC
+ cpx #ARG
+ beq L369B
+ ldy #ARG
+L369B:
+ sec
+ eor #$FF
+ adc ARGEXTENSION
+ sta FACEXTENSION
+.ifndef CONFIG_SMALL
+ lda 4,y
+ sbc 4,x
+ sta FAC+4
+.endif
+ lda 3,y
+ sbc 3,x
+ sta FAC+3
+ lda 2,y
+ sbc 2,x
+ sta FAC+2
+ lda 1,y
+ sbc 1,x
+ sta FAC+1
+
+; ----------------------------------------------------------------------------
+; NORMALIZE VALUE IN FAC
+; ----------------------------------------------------------------------------
+NORMALIZE_FAC1:
+ bcs NORMALIZE_FAC2
+ jsr COMPLEMENT_FAC
+NORMALIZE_FAC2:
+ ldy #$00
+ tya
+ clc
+L36C7:
+ ldx FAC+1
+ bne NORMALIZE_FAC4
+ ldx FAC+2
+ stx FAC+1
+ ldx FAC+3
+ stx FAC+2
+.ifdef CONFIG_SMALL
+ ldx FACEXTENSION
+ stx FAC+3
+.else
+ ldx FAC+4
+ stx FAC+3
+ ldx FACEXTENSION
+ stx FAC+4
+.endif
+ sty FACEXTENSION
+ adc #$08
+.ifdef CONFIG_2B
+; bugfix?
+; fix does not exist on AppleSoft 2
+ cmp #(MANTISSA_BYTES+1)*8
+.else
+ cmp #MANTISSA_BYTES*8
+.endif
+ bne L36C7
+
+; ----------------------------------------------------------------------------
+; SET FAC = 0
+; (ONLY NECESSARY TO ZERO EXPONENT AND SIGN CELLS)
+; ----------------------------------------------------------------------------
+ZERO_FAC:
+ lda #$00
+STA_IN_FAC_SIGN_AND_EXP:
+ sta FAC
+STA_IN_FAC_SIGN:
+ sta FACSIGN
+ rts
+
+; ----------------------------------------------------------------------------
+; ADD MANTISSAS OF FAC AND ARG INTO FAC
+; ----------------------------------------------------------------------------
+FADD4:
+ adc ARGEXTENSION
+ sta FACEXTENSION
+.ifndef CONFIG_SMALL
+ lda FAC+4
+ adc ARG+4
+ sta FAC+4
+.endif
+ lda FAC+3
+ adc ARG+3
+ sta FAC+3
+ lda FAC+2
+ adc ARG+2
+ sta FAC+2
+ lda FAC+1
+ adc ARG+1
+ sta FAC+1
+ jmp NORMALIZE_FAC5
+
+; ----------------------------------------------------------------------------
+; FINISH NORMALIZING FAC
+; ----------------------------------------------------------------------------
+NORMALIZE_FAC3:
+ adc #$01
+ asl FACEXTENSION
+.ifndef CONFIG_SMALL
+ rol FAC+4
+.endif
+ rol FAC+3
+ rol FAC+2
+ rol FAC+1
+NORMALIZE_FAC4:
+ bpl NORMALIZE_FAC3
+ sec
+ sbc FAC
+ bcs ZERO_FAC
+ eor #$FF
+ adc #$01
+ sta FAC
+NORMALIZE_FAC5:
+ bcc L3764
+NORMALIZE_FAC6:
+ inc FAC
+ beq OVERFLOW
+.ifndef CONFIG_ROR_WORKAROUND
+ ror FAC+1
+ ror FAC+2
+ ror FAC+3
+ .ifndef CONFIG_SMALL
+ ror FAC+4
+ .endif
+ ror FACEXTENSION
+.else
+ lda #$00
+ bcc L372E
+ lda #$80
+L372E:
+ lsr FAC+1
+ ora FAC+1
+ sta FAC+1
+ lda #$00
+ bcc L373A
+ lda #$80
+L373A:
+ lsr FAC+2
+ ora FAC+2
+ sta FAC+2
+ lda #$00
+ bcc L3746
+ lda #$80
+L3746:
+ lsr FAC+3
+ ora FAC+3
+ sta FAC+3
+ lda #$00
+ bcc L3752
+ lda #$80
+L3752:
+ lsr FAC+4
+ ora FAC+4
+ sta FAC+4
+ lda #$00
+ bcc L375E
+ lda #$80
+L375E:
+ lsr FACEXTENSION
+ ora FACEXTENSION
+ sta FACEXTENSION
+.endif
+L3764:
+ rts
+
+; ----------------------------------------------------------------------------
+; 2'S COMPLEMENT OF FAC
+; ----------------------------------------------------------------------------
+COMPLEMENT_FAC:
+ lda FACSIGN
+ eor #$FF
+ sta FACSIGN
+
+; ----------------------------------------------------------------------------
+; 2'S COMPLEMENT OF FAC MANTISSA ONLY
+; ----------------------------------------------------------------------------
+COMPLEMENT_FAC_MANTISSA:
+ lda FAC+1
+ eor #$FF
+ sta FAC+1
+ lda FAC+2
+ eor #$FF
+ sta FAC+2
+ lda FAC+3
+ eor #$FF
+ sta FAC+3
+.ifndef CONFIG_SMALL
+ lda FAC+4
+ eor #$FF
+ sta FAC+4
+.endif
+ lda FACEXTENSION
+ eor #$FF
+ sta FACEXTENSION
+ inc FACEXTENSION
+ bne RTS12
+
+; ----------------------------------------------------------------------------
+; INCREMENT FAC MANTISSA
+; ----------------------------------------------------------------------------
+INCREMENT_FAC_MANTISSA:
+.ifndef CONFIG_SMALL
+ inc FAC+4
+ bne RTS12
+.endif
+ inc FAC+3
+ bne RTS12
+ inc FAC+2
+ bne RTS12
+ inc FAC+1
+RTS12:
+ rts
+OVERFLOW:
+ ldx #ERR_OVERFLOW
+ jmp ERROR
+
+; ----------------------------------------------------------------------------
+; SHIFT 1,X THRU 5,X RIGHT
+; (A) = NEGATIVE OF SHIFT COUNT
+; (X) = POINTER TO BYTES TO BE SHIFTED
+;
+; RETURN WITH (Y)=0, CARRY=0, EXTENSION BITS IN A-REG
+; ----------------------------------------------------------------------------
+SHIFT_RIGHT1:
+ ldx #RESULT-1
+SHIFT_RIGHT2:
+.ifdef CONFIG_SMALL
+ ldy 3,x
+.else
+ ldy 4,x
+.endif
+ sty FACEXTENSION
+.ifndef CONFIG_SMALL
+ ldy 3,x
+ sty 4,x
+.endif
+ ldy 2,x
+ sty 3,x
+ ldy 1,x
+ sty 2,x
+ ldy SHIFTSIGNEXT
+ sty 1,x
+
+; ----------------------------------------------------------------------------
+; MAIN ENTRY TO RIGHT SHIFT SUBROUTINE
+; ----------------------------------------------------------------------------
+SHIFT_RIGHT:
+ adc #$08
+ bmi SHIFT_RIGHT2
+ beq SHIFT_RIGHT2
+ sbc #$08
+ tay
+ lda FACEXTENSION
+ bcs SHIFT_RIGHT5
+.ifndef CONFIG_ROR_WORKAROUND
+LB588:
+ asl 1,x
+ bcc LB58E
+ inc 1,x
+LB58E:
+ ror 1,x
+ ror 1,x
+
+; ----------------------------------------------------------------------------
+; ENTER HERE FOR SHORT SHIFTS WITH NO SIGN EXTENSION
+; ----------------------------------------------------------------------------
+SHIFT_RIGHT4:
+ ror 2,x
+ ror 3,x
+ .ifndef CONFIG_SMALL
+ ror 4,x
+ .endif
+ ror a
+ iny
+ bne LB588
+.else
+L37C4:
+ pha
+ lda 1,x
+ and #$80
+ lsr 1,x
+ ora 1,x
+ sta 1,x
+ .byte $24
+SHIFT_RIGHT4:
+ pha
+ lda #$00
+ bcc L37D7
+ lda #$80
+L37D7:
+ lsr 2,x
+ ora 2,x
+ sta 2,x
+ lda #$00
+ bcc L37E3
+ lda #$80
+L37E3:
+ lsr 3,x
+ ora 3,x
+ sta 3,x
+ lda #$00
+ bcc L37EF
+ lda #$80
+L37EF:
+ lsr 4,x
+ ora 4,x
+ sta 4,x
+ pla
+ php
+ lsr a
+ plp
+ bcc L37FD
+ ora #$80
+L37FD:
+ iny
+ bne L37C4
+.endif
+SHIFT_RIGHT5:
+ clc
+ rts
+
+; ----------------------------------------------------------------------------
+.ifdef CONFIG_SMALL
+CON_ONE:
+ .byte $81,$00,$00,$00
+POLY_LOG:
+ .byte $02
+ .byte $80,$19,$56,$62
+ .byte $80,$76,$22,$F3
+ .byte $82,$38,$AA,$40
+CON_SQR_HALF:
+ .byte $80,$35,$04,$F3
+CON_SQR_TWO:
+ .byte $81,$35,$04,$F3
+CON_NEG_HALF:
+ .byte $80,$80,$00,$00
+CON_LOG_TWO:
+ .byte $80,$31,$72,$18
+.else
+CON_ONE:
+ .byte $81,$00,$00,$00,$00
+POLY_LOG:
+ .byte $03
+ .byte $7F,$5E,$56,$CB,$79
+ .byte $80,$13,$9B,$0B,$64
+ .byte $80,$76,$38,$93,$16
+ .byte $82,$38,$AA,$3B,$20
+CON_SQR_HALF:
+ .byte $80,$35,$04,$F3,$34
+CON_SQR_TWO:
+ .byte $81,$35,$04,$F3,$34
+CON_NEG_HALF:
+ .byte $80,$80,$00,$00,$00
+CON_LOG_TWO:
+ .byte $80,$31,$72,$17,$F8
+.endif
+
+; ----------------------------------------------------------------------------
+; "LOG" FUNCTION
+; ----------------------------------------------------------------------------
+LOG:
+ jsr SIGN
+ beq GIQ
+ bpl LOG2
+GIQ:
+ jmp IQERR
+LOG2:
+ lda FAC
+ sbc #$7F
+ pha
+ lda #$80
+ sta FAC
+ lda #CON_SQR_HALF
+ jsr FADD
+ lda #CON_SQR_TWO
+ jsr FDIV
+ lda #CON_ONE
+ jsr FSUB
+ lda #POLY_LOG
+ jsr POLYNOMIAL_ODD
+ lda #CON_NEG_HALF
+ jsr FADD
+ pla
+ jsr ADDACC
+ lda #CON_LOG_TWO
+
+; ----------------------------------------------------------------------------
+; FAC = (Y,A) * FAC
+; ----------------------------------------------------------------------------
+FMULT:
+ jsr LOAD_ARG_FROM_YA
+
+; ----------------------------------------------------------------------------
+; FAC = ARG * FAC
+; ----------------------------------------------------------------------------
+FMULTT:
+.ifndef CONFIG_11
+ beq L3903
+.else
+ jeq L3903
+.endif
+ jsr ADD_EXPONENTS
+ lda #$00
+ sta RESULT
+ sta RESULT+1
+ sta RESULT+2
+.ifndef CONFIG_SMALL
+ sta RESULT+3
+.endif
+ lda FACEXTENSION
+ jsr MULTIPLY1
+.ifndef CONFIG_SMALL
+ lda FAC+4
+ jsr MULTIPLY1
+.endif
+ lda FAC+3
+ jsr MULTIPLY1
+ lda FAC+2
+ jsr MULTIPLY1
+ lda FAC+1
+ jsr MULTIPLY2
+ jmp COPY_RESULT_INTO_FAC
+
+; ----------------------------------------------------------------------------
+; MULTIPLY ARG BY (A) INTO RESULT
+; ----------------------------------------------------------------------------
+MULTIPLY1:
+ bne MULTIPLY2
+ jmp SHIFT_RIGHT1
+MULTIPLY2:
+ lsr a
+ ora #$80
+L38A7:
+ tay
+ bcc L38C3
+ clc
+.ifndef CONFIG_SMALL
+ lda RESULT+3
+ adc ARG+4
+ sta RESULT+3
+.endif
+ lda RESULT+2
+ adc ARG+3
+ sta RESULT+2
+ lda RESULT+1
+ adc ARG+2
+ sta RESULT+1
+ lda RESULT
+ adc ARG+1
+ sta RESULT
+L38C3:
+.ifndef CONFIG_ROR_WORKAROUND
+ ror RESULT
+ ror RESULT+1
+.ifdef APPLE_BAD_BYTE
+; this seems to be a bad byte in the dump
+ .byte RESULT+2,RESULT+2 ; XXX BUG!
+.else
+ ror RESULT+2
+.endif
+.ifndef CONFIG_SMALL
+ ror RESULT+3
+.endif
+ ror FACEXTENSION
+.else
+ lda #$00
+ bcc L38C9
+ lda #$80
+L38C9:
+ lsr RESULT
+ ora RESULT
+ sta RESULT
+ lda #$00
+ bcc L38D5
+ lda #$80
+L38D5:
+ lsr RESULT+1
+ ora RESULT+1
+ sta RESULT+1
+ lda #$00
+ bcc L38E1
+ lda #$80
+L38E1:
+ lsr RESULT+2
+ ora RESULT+2
+ sta RESULT+2
+ lda #$00
+ bcc L38ED
+ lda #$80
+L38ED:
+ lsr RESULT+3
+ ora RESULT+3
+ sta RESULT+3
+ lda #$00
+ bcc L38F9
+ lda #$80
+L38F9:
+ lsr FACEXTENSION
+ ora FACEXTENSION
+ sta FACEXTENSION
+.endif
+ tya
+ lsr a
+ bne L38A7
+L3903:
+ rts
+
+; ----------------------------------------------------------------------------
+; UNPACK NUMBER AT (Y,A) INTO ARG
+; ----------------------------------------------------------------------------
+LOAD_ARG_FROM_YA:
+ sta INDEX
+ sty INDEX+1
+ ldy #BYTES_FP-1
+.ifndef CONFIG_SMALL
+ lda (INDEX),y
+ sta ARG+4
+ dey
+.endif
+ lda (INDEX),y
+ sta ARG+3
+ dey
+ lda (INDEX),y
+ sta ARG+2
+ dey
+ lda (INDEX),y
+ sta ARGSIGN
+ eor FACSIGN
+ sta SGNCPR
+ lda ARGSIGN
+ ora #$80
+ sta ARG+1
+ dey
+ lda (INDEX),y
+ sta ARG
+ lda FAC
+ rts
+
+; ----------------------------------------------------------------------------
+; ADD EXPONENTS OF ARG AND FAC
+; (CALLED BY FMULT AND FDIV)
+;
+; ALSO CHECK FOR OVERFLOW, AND SET RESULT SIGN
+; ----------------------------------------------------------------------------
+ADD_EXPONENTS:
+ lda ARG
+ADD_EXPONENTS1:
+ beq ZERO
+ clc
+ adc FAC
+ bcc L393C
+ bmi JOV
+ clc
+ .byte $2C
+L393C:
+ bpl ZERO
+ adc #$80
+ sta FAC
+ bne L3947
+ jmp STA_IN_FAC_SIGN
+L3947:
+ lda SGNCPR
+ sta FACSIGN
+ rts
+
+; ----------------------------------------------------------------------------
+; IF (FAC) IS POSITIVE, GIVE "OVERFLOW" ERROR
+; IF (FAC) IS NEGATIVE, SET FAC=0, POP ONE RETURN, AND RTS
+; CALLED FROM "EXP" FUNCTION
+; ----------------------------------------------------------------------------
+OUTOFRNG:
+ lda FACSIGN
+ eor #$FF
+ bmi JOV
+
+; ----------------------------------------------------------------------------
+; POP RETURN ADDRESS AND SET FAC=0
+; ----------------------------------------------------------------------------
+ZERO:
+ pla
+ pla
+ jmp ZERO_FAC
+JOV:
+ jmp OVERFLOW
+
+; ----------------------------------------------------------------------------
+; MULTIPLY FAC BY 10
+; ----------------------------------------------------------------------------
+MUL10:
+ jsr COPY_FAC_TO_ARG_ROUNDED
+ tax
+ beq L3970
+ clc
+ adc #$02
+ bcs JOV
+LD9BF:
+ ldx #$00
+ stx SGNCPR
+ jsr FADD2
+ inc FAC
+ beq JOV
+L3970:
+ rts
+
+; ----------------------------------------------------------------------------
+CONTEN:
+.ifdef CONFIG_SMALL
+ .byte $84,$20,$00,$00
+.else
+ .byte $84,$20,$00,$00,$00
+.endif
+
+; ----------------------------------------------------------------------------
+; DIVIDE FAC BY 10
+; ----------------------------------------------------------------------------
+DIV10:
+ jsr COPY_FAC_TO_ARG_ROUNDED
+ lda #CONTEN
+ ldx #$00
+
+; ----------------------------------------------------------------------------
+; FAC = ARG / (Y,A)
+; ----------------------------------------------------------------------------
+DIV:
+ stx SGNCPR
+ jsr LOAD_FAC_FROM_YA
+ jmp FDIVT
+
+; ----------------------------------------------------------------------------
+; FAC = (Y,A) / FAC
+; ----------------------------------------------------------------------------
+FDIV:
+ jsr LOAD_ARG_FROM_YA
+
+; ----------------------------------------------------------------------------
+; FAC = ARG / FAC
+; ----------------------------------------------------------------------------
+FDIVT:
+ beq L3A02
+ jsr ROUND_FAC
+ lda #$00
+ sec
+ sbc FAC
+ sta FAC
+ jsr ADD_EXPONENTS
+ inc FAC
+ beq JOV
+ ldx #<-MANTISSA_BYTES
+ lda #$01
+L39A1:
+ ldy ARG+1
+ cpy FAC+1
+ bne L39B7
+ ldy ARG+2
+ cpy FAC+2
+ bne L39B7
+ ldy ARG+3
+ cpy FAC+3
+.ifndef CONFIG_SMALL
+ bne L39B7
+ ldy ARG+4
+ cpy FAC+4
+.endif
+L39B7:
+ php
+ rol a
+ bcc L39C4
+ inx
+ sta RESULT_LAST-1,x
+ beq L39F2
+ bpl L39F6
+ lda #$01
+L39C4:
+ plp
+ bcs L39D5
+L39C7:
+ asl ARG_LAST
+.ifndef CONFIG_SMALL
+ rol ARG+3
+.endif
+ rol ARG+2
+ rol ARG+1
+ bcs L39B7
+ bmi L39A1
+ bpl L39B7
+L39D5:
+ tay
+.ifndef CONFIG_SMALL
+ lda ARG+4
+ sbc FAC+4
+ sta ARG+4
+.endif
+ lda ARG+3
+ sbc FAC+3
+ sta ARG+3
+ lda ARG+2
+ sbc FAC+2
+ sta ARG+2
+ lda ARG+1
+ sbc FAC+1
+ sta ARG+1
+ tya
+ jmp L39C7
+L39F2:
+ lda #$40
+ bne L39C4
+L39F6:
+ asl a
+ asl a
+ asl a
+ asl a
+ asl a
+ asl a
+ sta FACEXTENSION
+ plp
+ jmp COPY_RESULT_INTO_FAC
+L3A02:
+ ldx #ERR_ZERODIV
+ jmp ERROR
+
+; ----------------------------------------------------------------------------
+; COPY RESULT INTO FAC MANTISSA, AND NORMALIZE
+; ----------------------------------------------------------------------------
+COPY_RESULT_INTO_FAC:
+ lda RESULT
+ sta FAC+1
+ lda RESULT+1
+ sta FAC+2
+ lda RESULT+2
+ sta FAC+3
+.ifndef CONFIG_SMALL
+ lda RESULT+3
+ sta FAC+4
+.endif
+ jmp NORMALIZE_FAC2
+
+; ----------------------------------------------------------------------------
+; UNPACK (Y,A) INTO FAC
+; ----------------------------------------------------------------------------
+LOAD_FAC_FROM_YA:
+ sta INDEX
+ sty INDEX+1
+ ldy #MANTISSA_BYTES
+.ifndef CONFIG_SMALL
+ lda (INDEX),y
+ sta FAC+4
+ dey
+.endif
+ lda (INDEX),y
+ sta FAC+3
+ dey
+ lda (INDEX),y
+ sta FAC+2
+ dey
+ lda (INDEX),y
+ sta FACSIGN
+ ora #$80
+ sta FAC+1
+ dey
+ lda (INDEX),y
+ sta FAC
+ sty FACEXTENSION
+ rts
+
+; ----------------------------------------------------------------------------
+; ROUND FAC, STORE IN TEMP2
+; ----------------------------------------------------------------------------
+STORE_FAC_IN_TEMP2_ROUNDED:
+ ldx #TEMP2
+ .byte $2C
+
+; ----------------------------------------------------------------------------
+; ROUND FAC, STORE IN TEMP1
+; ----------------------------------------------------------------------------
+STORE_FAC_IN_TEMP1_ROUNDED:
+ ldx #TEMP1X
+ ldy #$00
+ beq STORE_FAC_AT_YX_ROUNDED
+
+; ----------------------------------------------------------------------------
+; ROUND FAC, AND STORE WHERE FORPNT POINTS
+; ----------------------------------------------------------------------------
+SETFOR:
+ ldx FORPNT
+ ldy FORPNT+1
+
+; ----------------------------------------------------------------------------
+; ROUND FAC, AND STORE AT (Y,X)
+; ----------------------------------------------------------------------------
+STORE_FAC_AT_YX_ROUNDED:
+ jsr ROUND_FAC
+ stx INDEX
+ sty INDEX+1
+ ldy #MANTISSA_BYTES
+.ifndef CONFIG_SMALL
+ lda FAC+4
+ sta (INDEX),y
+ dey
+.endif
+ lda FAC+3
+ sta (INDEX),y
+ dey
+ lda FAC+2
+ sta (INDEX),y
+ dey
+ lda FACSIGN
+ ora #$7F
+ and FAC+1
+ sta (INDEX),y
+ dey
+ lda FAC
+ sta (INDEX),y
+ sty FACEXTENSION
+ rts
+
+; ----------------------------------------------------------------------------
+; COPY ARG INTO FAC
+; ----------------------------------------------------------------------------
+COPY_ARG_TO_FAC:
+ lda ARGSIGN
+MFA:
+ sta FACSIGN
+ ldx #BYTES_FP
+L3A7A:
+ lda SHIFTSIGNEXT,x
+ sta EXPSGN,x
+ dex
+ bne L3A7A
+ stx FACEXTENSION
+ rts
+
+; ----------------------------------------------------------------------------
+; ROUND FAC AND COPY TO ARG
+; ----------------------------------------------------------------------------
+COPY_FAC_TO_ARG_ROUNDED:
+ jsr ROUND_FAC
+MAF:
+ ldx #BYTES_FP+1
+L3A89:
+ lda EXPSGN,x
+ sta SHIFTSIGNEXT,x
+ dex
+ bne L3A89
+ stx FACEXTENSION
+RTS14:
+ rts
+
+; ----------------------------------------------------------------------------
+; ROUND FAC USING EXTENSION BYTE
+; ----------------------------------------------------------------------------
+ROUND_FAC:
+ lda FAC
+ beq RTS14
+ asl FACEXTENSION
+ bcc RTS14
+
+; ----------------------------------------------------------------------------
+; INCREMENT MANTISSA AND RE-NORMALIZE IF CARRY
+; ----------------------------------------------------------------------------
+INCREMENT_MANTISSA:
+ jsr INCREMENT_FAC_MANTISSA
+ bne RTS14
+ jmp NORMALIZE_FAC6
+
+; ----------------------------------------------------------------------------
+; TEST FAC FOR ZERO AND SIGN
+;
+; FAC > 0, RETURN +1
+; FAC = 0, RETURN 0
+; FAC < 0, RETURN -1
+; ----------------------------------------------------------------------------
+SIGN:
+ lda FAC
+ beq RTS15
+L3AA7:
+ lda FACSIGN
+SIGN2:
+ rol a
+ lda #$FF
+ bcs RTS15
+ lda #$01
+RTS15:
+ rts
+
+; ----------------------------------------------------------------------------
+; "SGN" FUNCTION
+; ----------------------------------------------------------------------------
+SGN:
+ jsr SIGN
+
+; ----------------------------------------------------------------------------
+; CONVERT (A) INTO FAC, AS SIGNED VALUE -128 TO +127
+; ----------------------------------------------------------------------------
+FLOAT:
+ sta FAC+1
+ lda #$00
+ sta FAC+2
+ ldx #$88
+
+; ----------------------------------------------------------------------------
+; FLOAT UNSIGNED VALUE IN FAC+1,2
+; (X) = EXPONENT
+; ----------------------------------------------------------------------------
+FLOAT1:
+ lda FAC+1
+ eor #$FF
+ rol a
+
+; ----------------------------------------------------------------------------
+; FLOAT UNSIGNED VALUE IN FAC+1,2
+; (X) = EXPONENT
+; C=0 TO MAKE VALUE NEGATIVE
+; C=1 TO MAKE VALUE POSITIVE
+; ----------------------------------------------------------------------------
+FLOAT2:
+ lda #$00
+.ifndef CONFIG_SMALL
+ sta FAC+4
+.endif
+ sta FAC+3
+LDB21:
+ stx FAC
+ sta FACEXTENSION
+ sta FACSIGN
+ jmp NORMALIZE_FAC1
+
+; ----------------------------------------------------------------------------
+; "ABS" FUNCTION
+; ----------------------------------------------------------------------------
+ABS:
+ lsr FACSIGN
+ rts
+
+; ----------------------------------------------------------------------------
+; COMPARE FAC WITH PACKED # AT (Y,A)
+; RETURN A=1,0,-1 AS (Y,A) IS <,=,> FAC
+; ----------------------------------------------------------------------------
+FCOMP:
+ sta DEST
+
+; ----------------------------------------------------------------------------
+; SPECIAL ENTRY FROM "NEXT" PROCESSOR
+; "DEST" ALREADY SET UP
+; ----------------------------------------------------------------------------
+FCOMP2:
+ sty DEST+1
+ ldy #$00
+ lda (DEST),y
+ iny
+ tax
+ beq SIGN
+ lda (DEST),y
+ eor FACSIGN
+ bmi L3AA7
+ cpx FAC
+ bne L3B0A
+ lda (DEST),y
+ ora #$80
+ cmp FAC+1
+ bne L3B0A
+ iny
+ lda (DEST),y
+ cmp FAC+2
+ bne L3B0A
+ iny
+.ifndef CONFIG_SMALL
+ lda (DEST),y
+ cmp FAC+3
+ bne L3B0A
+ iny
+.endif
+ lda #$7F
+ cmp FACEXTENSION
+ lda (DEST),y
+ sbc FAC_LAST
+ beq L3B32
+L3B0A:
+ lda FACSIGN
+ bcc L3B10
+ eor #$FF
+L3B10:
+ jmp SIGN2
+
+; ----------------------------------------------------------------------------
+; QUICK INTEGER FUNCTION
+;
+; CONVERTS FP VALUE IN FAC TO INTEGER VALUE
+; IN FAC+1...FAC+4, BY SHIFTING RIGHT WITH SIGN
+; EXTENSION UNTIL FRACTIONAL BITS ARE OUT.
+;
+; THIS SUBROUTINE ASSUMES THE EXPONENT < 32.
+; ----------------------------------------------------------------------------
+QINT:
+ lda FAC
+ beq QINT3
+ sec
+ sbc #120+8*BYTES_FP
+ bit FACSIGN
+ bpl L3B27
+ tax
+ lda #$FF
+ sta SHIFTSIGNEXT
+ jsr COMPLEMENT_FAC_MANTISSA
+ txa
+L3B27:
+ ldx #FAC
+ cmp #$F9
+ bpl QINT2
+ jsr SHIFT_RIGHT
+ sty SHIFTSIGNEXT
+L3B32:
+ rts
+QINT2:
+ tay
+ lda FACSIGN
+ and #$80
+ lsr FAC+1
+ ora FAC+1
+ sta FAC+1
+ jsr SHIFT_RIGHT4
+ sty SHIFTSIGNEXT
+ rts
+
+; ----------------------------------------------------------------------------
+; "INT" FUNCTION
+;
+; USES QINT TO CONVERT (FAC) TO INTEGER FORM,
+; AND THEN REFLOATS THE INTEGER.
+; ----------------------------------------------------------------------------
+INT:
+ lda FAC
+ cmp #120+8*BYTES_FP
+ bcs RTS17
+ jsr QINT
+ sty FACEXTENSION
+ lda FACSIGN
+ sty FACSIGN
+ eor #$80
+ rol a
+ lda #120+8*BYTES_FP
+ sta FAC
+ lda FAC_LAST
+ sta CHARAC
+ jmp NORMALIZE_FAC1
+QINT3:
+ sta FAC+1
+ sta FAC+2
+ sta FAC+3
+.ifndef CONFIG_SMALL
+ sta FAC+4
+.endif
+ tay
+RTS17:
+ rts
+
+; ----------------------------------------------------------------------------
+; CONVERT STRING TO FP VALUE IN FAC
+;
+; STRING POINTED TO BY TXTPTR
+; FIRST CHAR ALREADY SCANNED BY CHRGET
+; (A) = FIRST CHAR, C=0 IF DIGIT.
+; ----------------------------------------------------------------------------
+FIN:
+ ldy #$00
+ ldx #SERLEN-TMPEXP
+L3B6F:
+ sty TMPEXP,x
+ dex
+ bpl L3B6F
+ bcc FIN2
+.ifdef SYM1
+ cmp #$26
+ bne LDABB
+ jmp LCDFE
+LDABB:
+.endif
+ cmp #$2D
+ bne L3B7E
+ stx SERLEN
+ beq FIN1
+L3B7E:
+ cmp #$2B
+ bne FIN3
+FIN1:
+ jsr CHRGET
+FIN2:
+ bcc FIN9
+FIN3:
+ cmp #$2E
+ beq FIN10
+ cmp #$45
+ bne FIN7
+ jsr CHRGET
+ bcc FIN5
+ cmp #TOKEN_MINUS
+ beq L3BA6
+ cmp #$2D
+ beq L3BA6
+ cmp #TOKEN_PLUS
+ beq FIN4
+ cmp #$2B
+ beq FIN4
+ bne FIN6
+L3BA6:
+.ifndef CONFIG_ROR_WORKAROUND
+ ror EXPSGN
+.else
+ lda #$00
+ bcc L3BAC
+ lda #$80
+L3BAC:
+ lsr EXPSGN
+ ora EXPSGN
+ sta EXPSGN
+.endif
+FIN4:
+ jsr CHRGET
+FIN5:
+ bcc GETEXP
+FIN6:
+ bit EXPSGN
+ bpl FIN7
+ lda #$00
+ sec
+ sbc EXPON
+ jmp FIN8
+
+; ----------------------------------------------------------------------------
+; FOUND A DECIMAL POINT
+; ----------------------------------------------------------------------------
+FIN10:
+.ifndef CONFIG_ROR_WORKAROUND
+ ror LOWTR
+.else
+ lda #$00
+ bcc L3BC9
+ lda #$80
+L3BC9:
+ lsr LOWTR
+ ora LOWTR
+ sta LOWTR
+.endif
+ bit LOWTR
+ bvc FIN1
+
+; ----------------------------------------------------------------------------
+; NUMBER TERMINATED, ADJUST EXPONENT NOW
+; ----------------------------------------------------------------------------
+FIN7:
+ lda EXPON
+FIN8:
+ sec
+ sbc INDX
+ sta EXPON
+ beq L3BEE
+ bpl L3BE7
+L3BDE:
+ jsr DIV10
+ inc EXPON
+ bne L3BDE
+ beq L3BEE
+L3BE7:
+ jsr MUL10
+ dec EXPON
+ bne L3BE7
+L3BEE:
+ lda SERLEN
+ bmi L3BF3
+ rts
+L3BF3:
+ jmp NEGOP
+
+; ----------------------------------------------------------------------------
+; ACCUMULATE A DIGIT INTO FAC
+; ----------------------------------------------------------------------------
+FIN9:
+ pha
+ bit LOWTR
+ bpl L3BFD
+ inc INDX
+L3BFD:
+ jsr MUL10
+ pla
+ sec
+ sbc #$30
+ jsr ADDACC
+ jmp FIN1
+
+; ----------------------------------------------------------------------------
+; ADD (A) TO FAC
+; ----------------------------------------------------------------------------
+ADDACC:
+ pha
+ jsr COPY_FAC_TO_ARG_ROUNDED
+ pla
+ jsr FLOAT
+ lda ARGSIGN
+ eor FACSIGN
+ sta SGNCPR
+ ldx FAC
+ jmp FADDT
+
+; ----------------------------------------------------------------------------
+; ACCUMULATE DIGIT OF EXPONENT
+; ----------------------------------------------------------------------------
+GETEXP:
+ lda EXPON
+ cmp #MAX_EXPON
+ bcc L3C2C
+.ifdef CONFIG_10A
+ lda #$64
+.endif
+ bit EXPSGN
+.ifdef CONFIG_10A
+ bmi L3C3A
+.else
+ bmi LDC70
+.endif
+ jmp OVERFLOW
+LDC70:
+.ifndef CONFIG_10A
+ lda #$0B
+.endif
+L3C2C:
+ asl a
+ asl a
+ clc
+ adc EXPON
+ asl a
+ clc
+ ldy #$00
+ adc (TXTPTR),y
+ sec
+ sbc #$30
+L3C3A:
+ sta EXPON
+ jmp FIN4
+
+; ----------------------------------------------------------------------------
+.ifdef CONFIG_SMALL
+; these values are /1000 of what the labels say
+CON_99999999_9:
+ .byte $91,$43,$4F,$F8
+CON_999999999:
+ .byte $94,$74,$23,$F7
+CON_BILLION:
+ .byte $94,$74,$24,$00
+.else
+CON_99999999_9:
+ .byte $9B,$3E,$BC,$1F,$FD
+CON_999999999:
+.ifndef CONFIG_10A
+ .byte $9E,$6E,$6B,$27,$FE
+.else
+ .byte $9E,$6E,$6B,$27,$FD
+.endif
+CON_BILLION:
+ .byte $9E,$6E,$6B,$28,$00
+.endif
+
+; ----------------------------------------------------------------------------
+; PRINT "IN "
+; ----------------------------------------------------------------------------
+INPRT:
+.ifdef KBD
+ jsr LFE0B
+ .byte " in"
+ .byte 0
+.else
+ lda #QT_IN
+ jsr GOSTROUT2
+.endif
+ lda CURLIN+1
+ ldx CURLIN
+
+; ----------------------------------------------------------------------------
+; PRINT A,X AS DECIMAL INTEGER
+; ----------------------------------------------------------------------------
+LINPRT:
+ sta FAC+1
+ stx FAC+2
+ ldx #$90
+ sec
+ jsr FLOAT2
+ jsr FOUT
+GOSTROUT2:
+ jmp STROUT
+
+; ----------------------------------------------------------------------------
+; CONVERT (FAC) TO STRING STARTING AT STACK
+; RETURN WITH (Y,A) POINTING AT STRING
+; ----------------------------------------------------------------------------
+FOUT:
+ ldy #$01
+
+; ----------------------------------------------------------------------------
+; "STR$" FUNCTION ENTERS HERE, WITH (Y)=0
+; SO THAT RESULT STRING STARTS AT STACK-1
+; (THIS IS USED AS A FLAG)
+; ----------------------------------------------------------------------------
+FOUT1:
+ lda #$20
+ bit FACSIGN
+ bpl L3C73
+ lda #$2D
+L3C73:
+ sta STACK2-1,y
+ sta FACSIGN
+ sty STRNG2
+ iny
+ lda #$30
+ ldx FAC
+ bne L3C84
+ jmp FOUT4
+L3C84:
+ lda #$00
+ cpx #$80
+ beq L3C8C
+ bcs L3C95
+L3C8C:
+ lda #CON_BILLION
+ jsr FMULT
+.ifdef CONFIG_SMALL
+ lda #<-6 ; exponent adjustment
+.else
+ lda #<-9
+.endif
+L3C95:
+ sta INDX
+; ----------------------------------------------------------------------------
+; ADJUST UNTIL 1E8 <= (FAC) <1E9
+; ----------------------------------------------------------------------------
+L3C97:
+ lda #CON_999999999
+ jsr FCOMP
+ beq L3CBE
+ bpl L3CB4
+L3CA2:
+ lda #CON_99999999_9
+ jsr FCOMP
+ beq L3CAD
+ bpl L3CBB
+L3CAD:
+ jsr MUL10
+ dec INDX
+ bne L3CA2
+L3CB4:
+ jsr DIV10
+ inc INDX
+ bne L3C97
+L3CBB:
+ jsr FADDH
+L3CBE:
+ jsr QINT
+; ----------------------------------------------------------------------------
+; FAC+1...FAC+4 IS NOW IN INTEGER FORM
+; WITH POWER OF TEN ADJUSTMENT IN TMPEXP
+;
+; IF -10 < TMPEXP > 1, PRINT IN DECIMAL FORM
+; OTHERWISE, PRINT IN EXPONENTIAL FORM
+; ----------------------------------------------------------------------------
+ ldx #$01
+ lda INDX
+ clc
+ adc #3*BYTES_FP-5
+ bmi L3CD3
+ cmp #3*BYTES_FP-4
+ bcs L3CD4
+ adc #$FF
+ tax
+ lda #$02
+L3CD3:
+ sec
+L3CD4:
+ sbc #$02
+ sta EXPON
+ stx INDX
+ txa
+ beq L3CDF
+ bpl L3CF2
+L3CDF:
+ ldy STRNG2
+ lda #$2E
+ iny
+ sta STACK2-1,y
+ txa
+ beq L3CF0
+ lda #$30
+ iny
+ sta STACK2-1,y
+L3CF0:
+ sty STRNG2
+; ----------------------------------------------------------------------------
+; NOW DIVIDE BY POWERS OF TEN TO GET SUCCESSIVE DIGITS
+; ----------------------------------------------------------------------------
+L3CF2:
+ ldy #$00
+LDD3A:
+ ldx #$80
+L3CF6:
+ lda FAC_LAST
+ clc
+.ifndef CONFIG_SMALL
+ adc DECTBL+3,y
+ sta FAC+4
+ lda FAC+3
+.endif
+ adc DECTBL+2,y
+ sta FAC+3
+ lda FAC+2
+ adc DECTBL+1,y
+ sta FAC+2
+ lda FAC+1
+ adc DECTBL,y
+ sta FAC+1
+ inx
+ bcs L3D1A
+ bpl L3CF6
+ bmi L3D1C
+L3D1A:
+ bmi L3CF6
+L3D1C:
+ txa
+ bcc L3D23
+ eor #$FF
+ adc #$0A
+L3D23:
+ adc #$2F
+ iny
+ iny
+ iny
+.ifndef CONFIG_SMALL
+ iny
+.endif
+ sty VARPNT
+ ldy STRNG2
+ iny
+ tax
+ and #$7F
+ sta STACK2-1,y
+ dec INDX
+ bne L3D3E
+ lda #$2E
+ iny
+ sta STACK2-1,y
+L3D3E:
+ sty STRNG2
+ ldy VARPNT
+ txa
+ eor #$FF
+ and #$80
+ tax
+ cpy #DECTBL_END-DECTBL
+.ifdef CONFIG_CBM_ALL
+ beq LDD96
+ cpy #$3C ; XXX
+.endif
+ bne L3CF6
+; ----------------------------------------------------------------------------
+; NINE DIGITS HAVE BEEN STORED IN STRING. NOW LOOK
+; BACK AND LOP OFF TRAILING ZEROES AND A TRAILING
+; DECIMAL POINT.
+; ----------------------------------------------------------------------------
+LDD96:
+ ldy STRNG2
+L3D4E:
+ lda STACK2-1,y
+ dey
+ cmp #$30
+ beq L3D4E
+ cmp #$2E
+ beq L3D5B
+ iny
+L3D5B:
+ lda #$2B
+ ldx EXPON
+ beq L3D8F
+ bpl L3D6B
+ lda #$00
+ sec
+ sbc EXPON
+ tax
+ lda #$2D
+L3D6B:
+ sta STACK2+1,y
+ lda #$45
+ sta STACK2,y
+ txa
+ ldx #$2F
+ sec
+L3D77:
+ inx
+ sbc #$0A
+ bcs L3D77
+ adc #$3A
+ sta STACK2+3,y
+ txa
+ sta STACK2+2,y
+ lda #$00
+ sta STACK2+4,y
+ beq L3D94
+FOUT4:
+ sta STACK2-1,y
+L3D8F:
+ lda #$00
+ sta STACK2,y
+L3D94:
+ lda #STACK2
+ rts
+
+; ----------------------------------------------------------------------------
+CON_HALF:
+.ifdef CONFIG_SMALL
+ .byte $80,$00,$00,$00
+.else
+ .byte $80,$00,$00,$00,$00
+.endif
+
+; ----------------------------------------------------------------------------
+; POWERS OF 10 FROM 1E8 DOWN TO 1,
+; AS 32-BIT INTEGERS, WITH ALTERNATING SIGNS
+; ----------------------------------------------------------------------------
+DECTBL:
+.ifdef CONFIG_SMALL
+ .byte $FE,$79,$60 ; -100000
+ .byte $00,$27,$10 ; 10000
+ .byte $FF,$FC,$18 ; -1000
+ .byte $00,$00,$64 ; 100
+ .byte $FF,$FF,$F6 ; -10
+ .byte $00,$00,$01 ; 1
+.else
+ .byte $FA,$0A,$1F,$00 ; -100000000
+ .byte $00,$98,$96,$80 ; 10000000
+ .byte $FF,$F0,$BD,$C0 ; -1000000
+ .byte $00,$01,$86,$A0 ; 100000
+ .byte $FF,$FF,$D8,$F0 ; -10000
+ .byte $00,$00,$03,$E8 ; 1000
+ .byte $FF,$FF,$FF,$9C ; -100
+ .byte $00,$00,$00,$0A ; 10
+ .byte $FF,$FF,$FF,$FF ; -1
+.endif
+DECTBL_END:
+.ifdef CONFIG_CBM_ALL
+ .byte $FF,$DF,$0A,$80 ; TI$
+ .byte $00,$03,$4B,$C0
+ .byte $FF,$FF,$73,$60
+ .byte $00,$00,$0E,$10
+ .byte $FF,$FF,$FD,$A8
+ .byte $00,$00,$00,$3C
+.endif
+.ifdef CONFIG_2
+C_ZERO = CON_HALF + 2
+.endif
+
+; ----------------------------------------------------------------------------
+; "SQR" FUNCTION
+; ----------------------------------------------------------------------------
+SQR:
+ jsr COPY_FAC_TO_ARG_ROUNDED
+ lda #CON_HALF
+ jsr LOAD_FAC_FROM_YA
+
+; ----------------------------------------------------------------------------
+; EXPONENTIATION OPERATION
+;
+; ARG ^ FAC = EXP( LOG(ARG) * FAC )
+; ----------------------------------------------------------------------------
+FPWRT:
+ beq EXP
+ lda ARG
+ bne L3DD5
+ jmp STA_IN_FAC_SIGN_AND_EXP
+L3DD5:
+ ldx #TEMP3
+ ldy #$00
+ jsr STORE_FAC_AT_YX_ROUNDED
+ lda ARGSIGN
+ bpl L3DEF
+ jsr INT
+ lda #TEMP3
+ ldy #$00
+ jsr FCOMP
+ bne L3DEF
+ tya
+ ldy CHARAC
+L3DEF:
+ jsr MFA
+ tya
+ pha
+ jsr LOG
+ lda #TEMP3
+ ldy #$00
+ jsr FMULT
+ jsr EXP
+ pla
+ lsr a
+ bcc L3E0F
+
+; ----------------------------------------------------------------------------
+; NEGATE VALUE IN FAC
+; ----------------------------------------------------------------------------
+NEGOP:
+ lda FAC
+ beq L3E0F
+ lda FACSIGN
+ eor #$FF
+ sta FACSIGN
+L3E0F:
+ rts
+
+; ----------------------------------------------------------------------------
+.ifdef CONFIG_SMALL
+CON_LOG_E:
+ .byte $81,$38,$AA,$3B
+POLY_EXP:
+ .byte $06
+ .byte $74,$63,$90,$8C
+ .byte $77,$23,$0C,$AB
+ .byte $7A,$1E,$94,$00
+ .byte $7C,$63,$42,$80
+ .byte $7E,$75,$FE,$D0
+ .byte $80,$31,$72,$15
+ .byte $81,$00,$00,$00
+.else
+CON_LOG_E:
+ .byte $81,$38,$AA,$3B,$29
+POLY_EXP:
+ .byte $07
+ .byte $71,$34,$58,$3E,$56
+ .byte $74,$16,$7E,$B3,$1B
+ .byte $77,$2F,$EE,$E3,$85
+ .byte $7A,$1D,$84,$1C,$2A
+ .byte $7C,$63,$59,$58,$0A
+ .byte $7E,$75,$FD,$E7,$C6
+ .byte $80,$31,$72,$18,$10
+ .byte $81,$00,$00,$00,$00
+.endif
+
+; ----------------------------------------------------------------------------
+; "EXP" FUNCTION
+;
+; FAC = E ^ FAC
+; ----------------------------------------------------------------------------
+EXP:
+ lda #CON_LOG_E
+ jsr FMULT
+ lda FACEXTENSION
+ adc #$50
+ bcc L3E4E
+ jsr INCREMENT_MANTISSA
+L3E4E:
+ sta ARGEXTENSION
+ jsr MAF
+ lda FAC
+ cmp #$88
+ bcc L3E5C
+L3E59:
+ jsr OUTOFRNG
+L3E5C:
+ jsr INT
+ lda CHARAC
+ clc
+ adc #$81
+ beq L3E59
+ sec
+ sbc #$01
+ pha
+ ldx #BYTES_FP
+L3E6C:
+ lda ARG,x
+ ldy FAC,x
+ sta FAC,x
+ sty ARG,x
+ dex
+ bpl L3E6C
+ lda ARGEXTENSION
+ sta FACEXTENSION
+ jsr FSUBT
+ jsr NEGOP
+ lda #POLY_EXP
+ jsr POLYNOMIAL
+ lda #$00
+ sta SGNCPR
+ pla
+ jsr ADD_EXPONENTS1
+ rts
+
+; ----------------------------------------------------------------------------
+; ODD POLYNOMIAL SUBROUTINE
+;
+; F(X) = X * P(X^2)
+;
+; WHERE: X IS VALUE IN FAC
+; Y,A POINTS AT COEFFICIENT TABLE
+; FIRST BYTE OF COEFF. TABLE IS N
+; COEFFICIENTS FOLLOW, HIGHEST POWER FIRST
+;
+; P(X^2) COMPUTED USING NORMAL POLYNOMIAL SUBROUTINE
+; ----------------------------------------------------------------------------
+POLYNOMIAL_ODD:
+ sta STRNG2
+ sty STRNG2+1
+ jsr STORE_FAC_IN_TEMP1_ROUNDED
+ lda #TEMP1X
+ jsr FMULT
+ jsr SERMAIN
+ lda #TEMP1X
+ ldy #$00
+ jmp FMULT
+
+; ----------------------------------------------------------------------------
+; NORMAL POLYNOMIAL SUBROUTINE
+;
+; P(X) = C(0)*X^N + C(1)*X^(N-1) + ... + C(N)
+;
+; WHERE: X IS VALUE IN FAC
+; Y,A POINTS AT COEFFICIENT TABLE
+; FIRST BYTE OF COEFF. TABLE IS N
+; COEFFICIENTS FOLLOW, HIGHEST POWER FIRST
+; ----------------------------------------------------------------------------
+POLYNOMIAL:
+ sta STRNG2
+ sty STRNG2+1
+SERMAIN:
+ jsr STORE_FAC_IN_TEMP2_ROUNDED
+ lda (STRNG2),y
+ sta SERLEN
+ ldy STRNG2
+ iny
+ tya
+ bne L3EBA
+ inc STRNG2+1
+L3EBA:
+ sta STRNG2
+ ldy STRNG2+1
+L3EBE:
+ jsr FMULT
+ lda STRNG2
+ ldy STRNG2+1
+ clc
+ adc #BYTES_FP
+ bcc L3ECB
+ iny
+L3ECB:
+ sta STRNG2
+ sty STRNG2+1
+ jsr FADD
+ lda #TEMP2
+ ldy #$00
+ dec SERLEN
+ bne L3EBE
+RTS19:
+ rts
diff --git a/msbasic/flow1.s b/msbasic/flow1.s
new file mode 100644
index 0000000..465f3c1
--- /dev/null
+++ b/msbasic/flow1.s
@@ -0,0 +1,324 @@
+.segment "CODE"
+
+; ----------------------------------------------------------------------------
+; "FOR" STATEMENT
+;
+; FOR PUSHES 18 BYTES ON THE STACK:
+; 2 -- TXTPTR
+; 2 -- LINE NUMBER
+; 5 -- INITIAL (CURRENT) FOR VARIABLE VALUE
+; 1 -- STEP SIGN
+; 5 -- STEP VALUE
+; 2 -- ADDRESS OF FOR VARIABLE IN VARTAB
+; 1 -- FOR TOKEN ($81)
+; ----------------------------------------------------------------------------
+FOR:
+ lda #$80
+ sta SUBFLG
+ jsr LET
+ jsr GTFORPNT
+ bne L2619
+ txa
+ adc #FOR_STACK1
+ tax
+ txs
+L2619:
+ pla
+ pla
+ lda #FOR_STACK2
+ jsr CHKMEM
+ jsr DATAN
+ clc
+ tya
+ adc TXTPTR
+ pha
+ lda TXTPTR+1
+ adc #$00
+ pha
+ lda CURLIN+1
+ pha
+ lda CURLIN
+ pha
+ lda #TOKEN_TO
+ jsr SYNCHR
+ jsr CHKNUM
+ jsr FRMNUM
+ lda FACSIGN
+ ora #$7F
+ and FAC+1
+ sta FAC+1
+ lda #STEP
+ sta INDEX
+ sty INDEX+1
+ jmp FRM_STACK3
+
+; ----------------------------------------------------------------------------
+; "STEP" PHRASE OF "FOR" STATEMENT
+; ----------------------------------------------------------------------------
+STEP:
+ lda #CON_ONE
+ jsr LOAD_FAC_FROM_YA
+ jsr CHRGOT
+ cmp #TOKEN_STEP
+ bne L2665
+ jsr CHRGET
+ jsr FRMNUM
+L2665:
+ jsr SIGN
+ jsr FRM_STACK2
+ lda FORPNT+1
+ pha
+ lda FORPNT
+ pha
+ lda #$81
+ pha
+
+; ----------------------------------------------------------------------------
+; PERFORM NEXT STATEMENT
+; ----------------------------------------------------------------------------
+NEWSTT:
+ jsr ISCNTC
+ lda TXTPTR
+ ldy TXTPTR+1
+.if .def(CONFIG_NO_INPUTBUFFER_ZP) && .def(CONFIG_2)
+ cpy #>INPUTBUFFER
+ .ifdef CBM2
+ nop
+ .endif
+ beq LC6D4
+.else
+; BUG on AppleSoft I,
+; fixed differently on AppleSoft II (ldx/inx)
+ beq L2683
+.endif
+ sta OLDTEXT
+ sty OLDTEXT+1
+LC6D4:
+ ldy #$00
+L2683:
+ lda (TXTPTR),y
+.ifndef CONFIG_11
+ beq LA5DC ; old: 1 cycle more on generic case
+ cmp #$3A
+ beq NEWSTT2
+SYNERR1:
+ jmp SYNERR
+LA5DC:
+.else
+ bne COLON; new: 1 cycle more on ":" case
+.endif
+ ldy #$02
+ lda (TXTPTR),y
+ clc
+.ifdef CONFIG_2
+ jeq L2701
+.else
+ beq L2701
+.endif
+ iny
+ lda (TXTPTR),y
+ sta CURLIN
+ iny
+ lda (TXTPTR),y
+ sta CURLIN+1
+ tya
+ adc TXTPTR
+ sta TXTPTR
+ bcc NEWSTT2
+ inc TXTPTR+1
+NEWSTT2:
+ jsr CHRGET
+ jsr EXECUTE_STATEMENT
+ jmp NEWSTT
+
+; ----------------------------------------------------------------------------
+; EXECUTE A STATEMENT
+;
+; (A) IS FIRST CHAR OF STATEMENT
+; CARRY IS SET
+; ----------------------------------------------------------------------------
+EXECUTE_STATEMENT:
+.ifndef CONFIG_11A
+ beq RET1
+.else
+ beq RET2
+.endif
+.ifndef CONFIG_11
+ sec
+.endif
+EXECUTE_STATEMENT1:
+ sbc #$80
+.ifndef CONFIG_11
+ jcc LET ; old: 1 cycle more on instr.
+.else
+ bcc LET1; new: 1 cycle more on assignment
+.endif
+ cmp #NUM_TOKENS
+.ifdef CONFIG_2
+ bcs LC721
+.else
+ bcs SYNERR1
+.endif
+ asl a
+ tay
+ lda TOKEN_ADDRESS_TABLE+1,y
+ pha
+ lda TOKEN_ADDRESS_TABLE,y
+ pha
+ jmp CHRGET
+
+.ifdef CONFIG_11
+LET1:
+ jmp LET
+
+COLON:
+ cmp #$3A
+ beq NEWSTT2
+SYNERR1:
+ jmp SYNERR
+.endif
+
+.ifdef CONFIG_2; GO TO
+LC721:
+ cmp #TOKEN_GO-$80
+ bne SYNERR1
+ jsr CHRGET
+ lda #TOKEN_TO
+ jsr SYNCHR
+ jmp GOTO
+.endif
+
+; ----------------------------------------------------------------------------
+; "RESTORE" STATEMENT
+; ----------------------------------------------------------------------------
+RESTORE:
+ sec
+ lda TXTTAB
+ sbc #$01
+ ldy TXTTAB+1
+ bcs SETDA
+ dey
+SETDA:
+ sta DATPTR
+ sty DATPTR+1
+RET2:
+ rts
+
+.include "iscntc.s"
+;!!! runs into "STOP"
+; ----------------------------------------------------------------------------
+; "STOP" STATEMENT
+; ----------------------------------------------------------------------------
+STOP:
+ bcs END2
+
+; ----------------------------------------------------------------------------
+; "END" STATEMENT
+; ----------------------------------------------------------------------------
+END:
+ clc
+END2:
+ bne RET1
+ lda TXTPTR
+ ldy TXTPTR+1
+.if .def(CONFIG_NO_INPUTBUFFER_ZP) && .def(CONFIG_2)
+; BUG on AppleSoft I
+; fix exists on AppleSoft II
+; TXTPTR+1 will always be > 0
+ ldx CURLIN+1
+ inx
+.endif
+ beq END4
+ sta OLDTEXT
+ sty OLDTEXT+1
+CONTROL_C_TYPED:
+ lda CURLIN
+ ldy CURLIN+1
+ sta OLDLIN
+ sty OLDLIN+1
+END4:
+ pla
+ pla
+L2701:
+ lda #QT_BREAK
+.ifndef KBD
+ ldx #$00
+ stx Z14
+.endif
+ bcc L270E
+ jmp PRINT_ERROR_LINNUM
+L270E:
+ jmp RESTART
+.ifdef KBD
+LE664:
+ tay
+ jmp SNGFLT
+.endif
+
+; ----------------------------------------------------------------------------
+; "CONT" COMMAND
+; ----------------------------------------------------------------------------
+CONT:
+ bne RET1
+ ldx #ERR_CANTCONT
+ ldy OLDTEXT+1
+ bne L271C
+ jmp ERROR
+L271C:
+ lda OLDTEXT
+ sta TXTPTR
+ sty TXTPTR+1
+ lda OLDLIN
+ ldy OLDLIN+1
+ sta CURLIN
+ sty CURLIN+1
+RET1:
+ rts
+
+.ifdef KBD
+PRT:
+ jsr GETBYT
+ txa
+; not ROR bug safe
+ ror a
+ ror a
+ ror a
+ sta $8F
+ rts
+
+LE68C:
+ ldy #$12
+LE68E:
+ lda LEA30,y
+ sta $03A2,y
+ dey
+ bpl LE68E
+ rts
+.endif
+
+.ifndef AIM65
+.if .def(CONFIG_NULL) || .def(CONFIG_PRINTNULLS)
+; CBM1 has the keyword removed,
+; but the code is still here
+NULL:
+ jsr GETBYT
+ bne RET1
+ inx
+ cpx #NULL_MAX
+ bcs L2739
+ dex
+ stx Z15
+L2738:
+ rts
+L2739:
+ jmp IQERR
+.endif
+.ifndef CONFIG_11A
+CLEAR:
+ bne RET1
+ jmp CLEARC
+.endif
+.endif
diff --git a/msbasic/flow2.s b/msbasic/flow2.s
new file mode 100644
index 0000000..8720004
--- /dev/null
+++ b/msbasic/flow2.s
@@ -0,0 +1,215 @@
+.segment "CODE"
+; ----------------------------------------------------------------------------
+; "RUN" COMMAND
+; ----------------------------------------------------------------------------
+RUN:
+ bne L27CF
+ jmp SETPTRS
+L27CF:
+ jsr CLEARC
+ jmp L27E9
+
+; ----------------------------------------------------------------------------
+; "GOSUB" STATEMENT
+;
+; LEAVES 7 BYTES ON STACK:
+; 2 -- RETURN ADDRESS (NEWSTT)
+; 2 -- TXTPTR
+; 2 -- LINE #
+; 1 -- GOSUB TOKEN
+; ----------------------------------------------------------------------------
+GOSUB:
+ lda #$03
+ jsr CHKMEM
+ lda TXTPTR+1
+ pha
+ lda TXTPTR
+ pha
+ lda CURLIN+1
+ pha
+ lda CURLIN
+ pha
+ lda #TOKEN_GOSUB
+ pha
+L27E9:
+ jsr CHRGOT
+ jsr GOTO
+ jmp NEWSTT
+
+; ----------------------------------------------------------------------------
+; "GOTO" STATEMENT
+; ALSO USED BY "RUN" AND "GOSUB"
+; ----------------------------------------------------------------------------
+GOTO:
+ jsr LINGET
+ jsr REMN
+ lda CURLIN+1
+ cmp LINNUM+1
+ bcs L2809
+ tya
+ sec
+ adc TXTPTR
+ ldx TXTPTR+1
+ bcc L280D
+ inx
+ bcs L280D
+L2809:
+ lda TXTTAB
+ ldx TXTTAB+1
+L280D:
+.ifdef KBD
+ jsr LF457
+ bne UNDERR
+.else
+ jsr FL1
+ bcc UNDERR
+.endif
+ lda LOWTRX
+ sbc #$01
+ sta TXTPTR
+ lda LOWTRX+1
+ sbc #$00
+ sta TXTPTR+1
+L281E:
+ rts
+
+; ----------------------------------------------------------------------------
+; "POP" AND "RETURN" STATEMENTS
+; ----------------------------------------------------------------------------
+POP:
+ bne L281E
+ lda #$FF
+.ifdef CONFIG_2A
+ sta FORPNT+1 ; bugfix, wrong in AppleSoft II
+.else
+ sta FORPNT
+.endif
+ jsr GTFORPNT
+ txs
+ cmp #TOKEN_GOSUB
+ beq RETURN
+ ldx #ERR_NOGOSUB
+ .byte $2C
+UNDERR:
+ ldx #ERR_UNDEFSTAT
+ jmp ERROR
+; ----------------------------------------------------------------------------
+SYNERR2:
+ jmp SYNERR
+; ----------------------------------------------------------------------------
+RETURN:
+ pla
+ pla
+ sta CURLIN
+ pla
+ sta CURLIN+1
+ pla
+ sta TXTPTR
+ pla
+ sta TXTPTR+1
+
+; ----------------------------------------------------------------------------
+; "DATA" STATEMENT
+; EXECUTED BY SKIPPING TO NEXT COLON OR EOL
+; ----------------------------------------------------------------------------
+DATA:
+ jsr DATAN
+
+; ----------------------------------------------------------------------------
+; ADD (Y) TO TXTPTR
+; ----------------------------------------------------------------------------
+ADDON:
+ tya
+ clc
+ adc TXTPTR
+ sta TXTPTR
+ bcc L2852
+ inc TXTPTR+1
+L2852:
+ rts
+
+; ----------------------------------------------------------------------------
+; SCAN AHEAD TO NEXT ":" OR EOL
+; ----------------------------------------------------------------------------
+DATAN:
+ ldx #$3A
+ .byte $2C
+REMN:
+ ldx #$00
+ stx CHARAC
+ ldy #$00
+ sty ENDCHR
+L285E:
+ lda ENDCHR
+ ldx CHARAC
+ sta CHARAC
+ stx ENDCHR
+L2866:
+ lda (TXTPTR),y
+ beq L2852
+ cmp ENDCHR
+ beq L2852
+ iny
+ cmp #$22
+.ifndef CONFIG_11
+ beq L285E; old: swap & cont is faster
+ bne L2866
+.else
+ bne L2866; new: cont is faster
+ beq L285E
+.endif
+
+; ----------------------------------------------------------------------------
+; "IF" STATEMENT
+; ----------------------------------------------------------------------------
+IF:
+ jsr FRMEVL
+ jsr CHRGOT
+ cmp #TOKEN_GOTO
+ beq L2884
+ lda #TOKEN_THEN
+ jsr SYNCHR
+L2884:
+ lda FAC
+ bne L288D
+
+; ----------------------------------------------------------------------------
+; "REM" STATEMENT, OR FALSE "IF" STATEMENT
+; ----------------------------------------------------------------------------
+REM:
+ jsr REMN
+ beq ADDON
+L288D:
+ jsr CHRGOT
+ bcs L2895
+ jmp GOTO
+L2895:
+ jmp EXECUTE_STATEMENT
+
+; ----------------------------------------------------------------------------
+; "ON" STATEMENT
+;
+; ON GOTO
+; ON GOSUB
+; ----------------------------------------------------------------------------
+ON:
+ jsr GETBYT
+ pha
+ cmp #TOKEN_GOSUB
+ beq L28A4
+L28A0:
+ cmp #TOKEN_GOTO
+ bne SYNERR2
+L28A4:
+ dec FAC_LAST
+ bne L28AC
+ pla
+ jmp EXECUTE_STATEMENT1
+L28AC:
+ jsr CHRGET
+ jsr LINGET
+ cmp #$2C
+ beq L28A4
+ pla
+L28B7:
+ rts
diff --git a/msbasic/header.s b/msbasic/header.s
new file mode 100644
index 0000000..429e150
--- /dev/null
+++ b/msbasic/header.s
@@ -0,0 +1,33 @@
+ .segment "HEADER"
+.ifdef W65C816SXB
+; Disable emulation mode (is left on from the monitor)
+.setcpu "65816"
+ SEC ;set carry for emulation mode
+ XCE ;go into emulation mode
+.setcpu "65C02"
+ jsr INITUSBSERIAL
+
+ ; Add a small delay to allow monitor to connect the terminal after
+ ; starting execution
+ ldy #0
+ ldx #0
+@loop:
+ dex
+ bne @loop
+ dey
+ bne @loop
+ jmp COLD_START
+.endif
+
+.ifdef KBD
+ jmp LE68C
+ .byte $00,$13,$56
+.endif
+.ifdef AIM65
+ jmp COLD_START
+ jmp RESTART
+ .word AYINT,GIVAYF
+.endif
+.ifdef SYM1
+ jmp PR_WRITTEN_BY
+.endif
diff --git a/msbasic/init.s b/msbasic/init.s
new file mode 100644
index 0000000..077d981
--- /dev/null
+++ b/msbasic/init.s
@@ -0,0 +1,533 @@
+.segment "INIT"
+
+.ifdef KBD
+FNDLIN2:
+ php
+ jmp FNDLIN
+.endif
+
+; ----------------------------------------------------------------------------
+PR_WRITTEN_BY:
+.ifndef KBD
+ .ifndef CONFIG_CBM_ALL
+ .ifndef AIM65
+ .ifndef SYM1
+ lda #QT_WRITTEN_BY
+ jsr STROUT
+ .endif
+ .endif
+ .endif
+.endif
+COLD_START:
+.ifdef SYM1
+ jsr ACCESS
+.endif
+.ifdef KBD
+ lda #LFD81
+ sta $03A1
+ lda #$20
+ sta $0480
+ lda $0352
+ sta $04
+ lda $0353
+ sta $05
+.else
+ .ifndef CBM2
+ ldx #$FF
+ stx CURLIN+1
+ .endif
+ .ifdef CONFIG_NO_INPUTBUFFER_ZP
+ ldx #$FB
+ .elseif .def(AIM65)
+ ldx #$FE
+ .endif
+ txs
+ .ifndef CONFIG_CBM_ALL
+ lda #COLD_START
+ sta GORESTART+1
+ sty GORESTART+2
+ .ifndef AIM65
+ sta GOSTROUT+1
+ sty GOSTROUT+2
+ lda #AYINT
+ sta GOAYINT
+ sty GOAYINT+1
+ lda #GIVAYF
+ sta GOGIVEAYF
+ sty GOGIVEAYF+1
+ .endif
+ .endif
+ lda #$4C
+ .ifdef CONFIG_CBM_ALL
+ sta JMPADRS
+ .endif
+ sta GORESTART
+ .ifdef AIM65
+ sta JMPADRS
+ sta ATN
+ sta GOSTROUT
+ .else
+ .ifndef CONFIG_CBM_ALL
+ sta GOSTROUT
+ sta JMPADRS
+ .endif
+ .ifdef SYM1
+ sta USR1
+ sta USR3
+ sta USR2
+ .endif
+ .if (!.def(CONFIG_RAM)) && (!.def(CONFIG_CBM_ALL))
+ sta USR
+ .endif
+ .endif
+
+ .ifndef CONFIG_RAM
+ .ifdef APPLE
+ lda #USR_FUNC
+ .else
+ lda #IQERR
+ .endif
+ .ifdef AIM65
+ sta ATN+1
+ sty ATN+2
+ sta GOSTROUT+1
+ sty GOSTROUT+2
+ .else
+ sta USR+1
+ sty USR+2
+ .ifdef SYM1
+ sta USR1+1
+ sty USR1+2
+ lda #DUMPT
+ sta USR2+1
+ sty USR2+2
+ lda #L8C78
+ sta USR3+1
+ sty USR3+2
+ .endif
+ .endif
+ .endif
+ .ifndef CBM1
+ lda #WIDTH
+ sta Z17
+ lda #WIDTH2
+ sta Z18
+ .endif
+.endif
+
+; All non-CONFIG_SMALL versions of BASIC have
+; the same bug here: While the number of bytes
+; to be copied is correct for CONFIG_SMALL,
+; it is one byte short on non-CONFIG_SMALL:
+; It seems the "ldx" value below has been
+; hardcoded. So on these configurations,
+; the last byte of GENERIC_RNDSEED, which
+; is 5 bytes instead of 4, does not get copied -
+; which is nothing major, because it is just
+; the least significant 8 bits of the mantissa
+; of the random number seed.
+; KBD added three bytes to CHRGET and removed
+; the random number seed, but only adjusted
+; the number of bytes by adding 3 - this
+; copies four bytes too many, which is no
+; problem.
+.ifdef CONFIG_SMALL
+ .ifdef KBD
+ ldx #GENERIC_CHRGET_END-GENERIC_CHRGET+4
+ .else
+ ldx #GENERIC_CHRGET_END-GENERIC_CHRGET
+ .endif
+.else
+ ldx #GENERIC_CHRGET_END-GENERIC_CHRGET-1 ; XXX
+.endif
+L4098:
+ lda GENERIC_CHRGET-1,x
+ sta CHRGET-1,x
+ dex
+ bne L4098
+.ifdef CONFIG_2
+ lda #$03
+ sta DSCLEN
+.endif
+.ifndef KBD
+ txa
+ sta SHIFTSIGNEXT
+ .ifdef CONFIG_CBM_ALL
+ sta CURDVC
+ .endif
+ sta LASTPT+1
+ .ifndef AIM65
+ .if .defined(CONFIG_NULL) || .defined(CONFIG_PRINTNULLS)
+ sta Z15
+ .endif
+ .endif
+ .ifndef CONFIG_11
+ sta POSX
+ .endif
+ pha
+ sta Z14
+ .ifndef CBM2
+ .ifndef AIM65
+ .ifndef SYM1
+ .ifndef MICROTAN
+ lda #$03
+ sta DSCLEN
+ .endif
+ .endif
+ .endif
+ .ifndef CONFIG_11
+ lda #$2C
+ sta LINNUM+1
+ .endif
+ jsr CRDO
+ .endif
+ .ifdef CBM2
+ inx
+ stx INPUTBUFFER-3
+ stx INPUTBUFFER-4
+ .endif
+ .ifdef APPLE
+ lda #$01
+ sta INPUTBUFFER-3
+ sta INPUTBUFFER-4
+ .endif
+ ldx #TEMPST
+ stx TEMPPT
+.ifndef CONFIG_CBM_ALL
+ lda #QT_MEMORY_SIZE
+ jsr STROUT
+ .ifdef APPLE
+ jsr INLINX
+ .else
+ jsr NXIN
+ .endif
+ stx TXTPTR
+ sty TXTPTR+1
+ jsr CHRGET
+ .ifndef AIM65
+ .ifndef SYM1
+ cmp #$41
+ beq PR_WRITTEN_BY
+ .endif
+ .endif
+ tay
+ bne L40EE
+.endif
+.ifndef CBM2
+ lda #RAMSTART2
+.ifdef CONFIG_2
+ sta TXTTAB
+ sty TXTTAB+1
+.endif
+ sta LINNUM
+ sty LINNUM+1
+.ifdef CBM2
+ tay
+.else
+ ldy #$00
+.endif
+L40D7:
+ inc LINNUM
+ bne L40DD
+ inc LINNUM+1
+.ifdef CBM1
+; CBM: hard RAM top limit is $8000
+ lda LINNUM+1
+ cmp #$80
+ beq L40FA
+.endif
+.ifdef CBM2
+; optimized version of the CBM1 code
+ bmi L40FA
+.endif
+.if .def(AIM65)
+; AIM65: hard RAM top limit is $A000
+ lda LINNUM+1
+ cmp #$A0
+ beq L40FA
+.endif
+L40DD:
+.ifdef CONFIG_2
+ lda #$55 ; 01010101 / 10101010
+.else
+ lda #$92 ; 10010010 / 00100100
+.endif
+ sta (LINNUM),y
+ cmp (LINNUM),y
+ bne L40FA
+ asl a
+ sta (LINNUM),y
+ cmp (LINNUM),y
+.ifdef CONFIG_CBM_ALL
+ beq L40D7
+.else
+ .ifndef CONFIG_11
+ beq L40D7; old: faster
+ bne L40FA
+ .else
+ bne L40FA; new: slower
+ beq L40D7
+ .endif
+L40EE:
+ jsr CHRGOT
+ jsr LINGET
+ tay
+ beq L40FA
+ jmp SYNERR
+.endif
+L40FA:
+ lda LINNUM
+ ldy LINNUM+1
+ sta MEMSIZ
+ sty MEMSIZ+1
+.if !(.def(MICROTAN) || .def(AIM65) || .def(SYM1))
+ sta FRETOP
+ sty FRETOP+1
+.endif
+L4106:
+.ifndef CONFIG_CBM_ALL
+ .ifdef APPLE
+ lda #$FF
+ jmp L2829
+ .word STROUT ; PATCH!
+ jsr NXIN
+ .else
+ lda #QT_TERMINAL_WIDTH
+ jsr STROUT
+ jsr NXIN
+ .endif
+ stx TXTPTR
+ sty TXTPTR+1
+ jsr CHRGET
+ tay
+ beq L4136
+ jsr LINGET
+ lda LINNUM+1
+ bne L4106
+ lda LINNUM
+ cmp #$10
+ bcc L4106
+L2829:
+ sta Z17
+L4129:
+ .ifdef AIM65
+ sbc #$0A
+ .else
+ sbc #$0E
+ .endif
+ bcs L4129
+ eor #$FF
+ .ifdef AIM65
+ sbc #$08
+ .else
+ sbc #$0C
+ .endif
+ clc
+ adc Z17
+ sta Z18
+.endif
+L4136:
+.ifdef CONFIG_RAM
+ lda #QT_WANT
+ jsr STROUT
+ jsr NXIN
+ stx TXTPTR
+ sty TXTPTR+1
+ jsr CHRGET
+ ldx #RAMSTART1
+ cmp #'Y'
+ beq L4183
+ cmp #'A'
+ beq L4157
+ cmp #'N'
+ bne L4136
+L4157:
+ ldx #IQERR
+ stx UNFNC_ATN
+ sty UNFNC_ATN+1
+ ldx #ATN ; with ATN
+ cmp #'A'
+ beq L4183
+ ldx #IQERR
+ stx UNFNC_COS
+ sty UNFNC_COS+1
+ stx UNFNC_TAN
+ sty UNFNC_TAN+1
+ stx UNFNC_SIN
+ sty UNFNC_SIN+1
+ ldx #SIN_COS_TAN_ATN ; all of trig.s
+L4183:
+.else
+ ldx #RAMSTART2
+.endif
+ stx TXTTAB
+ sty TXTTAB+1
+ ldy #$00
+ tya
+ sta (TXTTAB),y
+ inc TXTTAB
+.ifndef CBM2
+ bne L4192
+ inc TXTTAB+1
+L4192:
+.endif
+.if CONFIG_SCRTCH_ORDER = 1
+ jsr SCRTCH
+.endif
+ lda TXTTAB
+ ldy TXTTAB+1
+ jsr REASON
+.ifdef CBM2
+ lda #QT_BASIC
+ jsr STROUT
+.else
+ jsr CRDO
+.endif
+ lda MEMSIZ
+ sec
+ sbc TXTTAB
+ tax
+ lda MEMSIZ+1
+ sbc TXTTAB+1
+ jsr LINPRT
+ lda #QT_BYTES_FREE
+ jsr STROUT
+.if CONFIG_SCRTCH_ORDER = 2
+ jsr SCRTCH
+.endif
+.ifdef CONFIG_CBM_ALL
+ jmp RESTART
+.elseif .def(AIM65)
+ lda #CRDO
+ sta GORESTART+1
+ sty GORESTART+2
+ jmp RESTART
+.else
+ lda #STROUT
+ sta GOSTROUT+1
+ sty GOSTROUT+2
+ .if CONFIG_SCRTCH_ORDER = 3
+ jsr SCRTCH
+ .endif
+ lda #RESTART
+ sta GORESTART+1
+ sty GORESTART+2
+ jmp (GORESTART+1)
+.endif
+
+ .if .def(CONFIG_RAM) || .def(OSI)
+; OSI is compiled for ROM, but includes
+; this unused string
+QT_WANT:
+ .byte "WANT SIN-COS-TAN-ATN"
+ .byte 0
+ .endif
+QT_WRITTEN_BY:
+ .ifndef CONFIG_CBM_ALL
+ .if !(.def(AIM65) || .def(SYM1))
+ .ifdef APPLE
+ asc80 "COPYRIGHT 1977 BY MICROSOFT CO"
+ .byte CR,0
+ .else
+ .byte CR,LF,$0C ; FORM FEED
+ .ifndef CONFIG_11
+ .byte "WRITTEN BY RICHARD W. WEILAND."
+ .else
+ .byte "WRITTEN BY WEILAND & GATES"
+ .endif
+ .byte CR,LF,0
+ .endif
+ .endif
+QT_MEMORY_SIZE:
+ .byte "MEMORY SIZE"
+ .byte 0
+QT_TERMINAL_WIDTH:
+ .if !(.def(AIM65) || .def(SYM1))
+ .byte "TERMINAL "
+ .endif
+ .byte "WIDTH"
+ .byte 0
+ .endif
+QT_BYTES_FREE:
+ .byte " BYTES FREE"
+ .ifdef CBM1
+ .elseif .def(CBM2)
+ .byte CR,0
+ .elseif .def(APPLE)
+ .byte 0
+ .else
+ .byte CR,LF,CR,LF
+ .endif
+QT_BASIC:
+ .ifdef OSI
+ .byte "OSI 6502 BASIC VERSION 1.0 REV 3.2"
+ .endif
+ .ifdef KIM
+ .byte "MOS TECH 6502 BASIC V1.1"
+ .endif
+ .ifdef MICROTAN
+ .byte "MICROTAN BASIC"
+ .endif
+ .ifdef AIM65
+ .byte " AIM 65 BASIC V1.1"
+ .endif
+ .ifdef SYM1
+ .byte "BASIC V1.1"
+ .endif
+ .ifdef CBM1
+ .byte $13 ; HOME
+ .byte "*** COMMODORE BASIC ***"
+ .byte $11,$11,$11,0 ; DOWN/DOWN/DOWN
+ .endif
+ .ifdef CBM2
+ .byte "### COMMODORE BASIC ###"
+ .byte CR,CR,0
+ .endif
+ .ifdef APPLE
+ .byte LF,CR,LF
+ .byte "APPLE BASIC V1.1"
+ .endif
+ .ifndef CONFIG_CBM_ALL
+ .byte CR,LF
+ .ifdef MICROTAN
+ .byte "(C) 1980 MICROSOFT"
+ .elseif .def(AIM65)
+ .byte 0
+ .byte "(C) 1978 MICROSOFT"
+ .elseif .def(SYM1)
+ .byte "COPYRIGHT 1978 SYNERTEK SYSTEMS CORP."
+ .else
+ .byte "COPYRIGHT 1977 BY MICROSOFT CO."
+ .endif
+ .byte CR,LF
+ .ifndef AIM65
+ .byte 0
+ .endif
+ .endif
+.endif
diff --git a/msbasic/inline.s b/msbasic/inline.s
new file mode 100644
index 0000000..d28ed79
--- /dev/null
+++ b/msbasic/inline.s
@@ -0,0 +1,165 @@
+.segment "CODE"
+
+.ifndef CONFIG_NO_INPUTBUFFER_ZP
+L2420:
+ .ifdef OSI
+ jsr OUTDO
+ .endif
+ dex
+ .ifdef AIM65
+ bmi L2423
+ jsr PSLS
+ jmp INLIN2
+LB35F:
+ jsr OUTDO
+ .else
+ bpl INLIN2
+ .endif
+L2423:
+ .ifdef OSI
+ jsr OUTDO
+ .endif
+ jsr CRDO
+.endif
+
+; ----------------------------------------------------------------------------
+; READ A LINE, AND STRIP OFF SIGN BITS
+; ----------------------------------------------------------------------------
+.ifndef KBD
+INLIN:
+ .ifdef APPLE
+ ldx #$DD
+INLIN1:
+ stx $33
+ jsr L2900
+ cpx #$EF
+ bcs L0C32
+ ldx #$EF
+L0C32:
+ lda #$00
+ sta INPUTBUFFER,x
+ ldx #<(INPUTBUFFER-1)
+ ldy #>(INPUTBUFFER-1)
+ rts
+ .endif
+
+ .ifndef APPLE
+ ldx #$00
+INLIN2:
+ jsr GETLN
+ .ifdef AIM65
+ cmp #$1A
+ bne INLINAIM
+ jsr DU13
+ jmp INLIN
+INLINAIM:
+ .endif
+ .ifndef CONFIG_NO_LINE_EDITING
+ cmp #$07
+ beq L2443
+ .endif
+ cmp #$0D
+ beq L2453
+ .ifndef CONFIG_NO_LINE_EDITING
+ cmp #$20
+ .ifdef AIM65
+ bcc L244E
+ .else
+ bcc INLIN2
+ .endif
+ .ifdef MICROTAN
+ cmp #$80
+ .else
+ .ifdef AIM65
+ cmp #$7F
+ beq L2420
+ .endif
+ cmp #$7D
+ .endif
+ bcs INLIN2
+ cmp #$40 ; @
+ .ifdef AIM65
+ beq LB35F
+ .else
+ beq L2423
+ .ifdef MICROTAN
+ cmp #$7F ; DEL
+ .else
+ cmp #$5F ; _
+ .endif
+ beq L2420
+ .endif
+L2443:
+ .ifdef MICROTAN
+ cpx #$4F
+ .else
+ cpx #$47
+ .endif
+ bcs L244C
+ .endif
+ sta INPUTBUFFER,x
+ inx
+ .if .def(OSI) || .def(AIM65)
+ .byte $2C
+ .else
+ bne INLIN2
+ .endif
+L244C:
+ .ifndef CONFIG_NO_LINE_EDITING
+ lda #$07 ; BEL
+L244E:
+ jsr OUTDO
+ bne INLIN2
+ .endif
+L2453:
+ jmp L29B9
+ .endif
+.endif
+
+.ifndef KBD
+ .ifndef APPLE
+GETLN:
+ .ifdef CONFIG_FILE
+ jsr CHRIN
+ ldy CURDVC
+ bne L2465
+ .else
+ jsr MONRDKEY
+ .endif
+ .ifdef OSI
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ and #$7F
+ .endif
+ .endif
+ .ifdef APPLE
+RDKEY:
+ jsr LFD0C
+ and #$7F
+ .endif
+ .ifdef SYM1
+ cmp #$14
+ .else
+ cmp #$0F
+ .endif
+ bne L2465
+ pha
+ lda Z14
+ eor #$FF
+ sta Z14
+ pla
+L2465:
+ rts
+.endif
diff --git a/msbasic/input.s b/msbasic/input.s
new file mode 100644
index 0000000..3dcb22e
--- /dev/null
+++ b/msbasic/input.s
@@ -0,0 +1,459 @@
+.segment "CODE"
+
+; ----------------------------------------------------------------------------
+; INPUT CONVERSION ERROR: ILLEGAL CHARACTER
+; IN NUMERIC FIELD. MUST DISTINGUISH
+; BETWEEN INPUT, READ, AND GET
+; ----------------------------------------------------------------------------
+INPUTERR:
+ lda INPUTFLG
+ beq RESPERR ; INPUT
+.ifndef SYM1
+.ifndef CONFIG_SMALL
+.ifdef CONFIG_10A
+; without this, it treats GET errors
+; like READ errors
+ bmi L2A63 ; READ
+ ldy #$FF ; GET
+ bne L2A67
+L2A63:
+.endif
+.endif
+.endif
+.ifdef CONFIG_CBM1_PATCHES
+ jsr PATCH5
+ nop
+.else
+ lda Z8C
+ ldy Z8C+1
+.endif
+L2A67:
+ sta CURLIN
+ sty CURLIN+1
+SYNERR4:
+ jmp SYNERR
+RESPERR:
+.ifdef CONFIG_FILE
+ lda CURDVC
+ beq LCA8F
+ ldx #ERR_BADDATA
+ jmp ERROR
+LCA8F:
+.endif
+ lda #ERRREENTRY
+ jsr STROUT
+ lda OLDTEXT
+ ldy OLDTEXT+1
+ sta TXTPTR
+ sty TXTPTR+1
+RTS20:
+ rts
+
+; ----------------------------------------------------------------------------
+; "GET" STATEMENT
+; ----------------------------------------------------------------------------
+.ifndef CONFIG_SMALL
+.ifndef SYM1
+GET:
+ jsr ERRDIR
+; CBM: if GET#, then switch input
+.ifdef CONFIG_FILE
+ cmp #'#'
+ bne LCAB6
+ jsr CHRGET
+ jsr GETBYT
+ lda #','
+ jsr SYNCHR
+ jsr CHKIN
+ stx CURDVC
+LCAB6:
+.endif
+ ldx #<(INPUTBUFFER+1)
+ ldy #>(INPUTBUFFER+1)
+.ifdef CONFIG_NO_INPUTBUFFER_ZP
+ lda #$00
+ sta INPUTBUFFER+1
+.else
+ sty INPUTBUFFER+1
+.endif
+ lda #$40
+ jsr PROCESS_INPUT_LIST
+; CBM: if GET#, then switch input back
+.ifdef CONFIG_FILE
+ ldx CURDVC
+ bne LCAD8
+.endif
+ rts
+.endif
+.endif
+
+; ----------------------------------------------------------------------------
+; "INPUT#" STATEMENT
+; ----------------------------------------------------------------------------
+.ifdef CONFIG_FILE
+INPUTH:
+ jsr GETBYT
+ lda #$2C
+ jsr SYNCHR
+ jsr CHKIN
+ stx CURDVC
+ jsr L2A9E
+LCAD6:
+ lda CURDVC
+LCAD8:
+ jsr CLRCH
+ ldx #$00
+ stx CURDVC
+ rts
+LCAE0:
+.endif
+
+.ifdef SYM1
+LC9B0:
+ jsr OUTQUES ; '?'
+ jsr OUTSP
+ jmp L2A9E
+.endif
+; ----------------------------------------------------------------------------
+; "INPUT" STATEMENT
+; ----------------------------------------------------------------------------
+INPUT:
+.ifndef KBD
+ lsr Z14
+.endif
+.ifdef AIM65
+ lda PRIFLG
+ sta ZBE
+ jsr LCFFA
+.endif
+ cmp #$22
+.ifdef SYM1
+ bne LC9B0
+.else
+ bne L2A9E
+.endif
+ jsr STRTXT
+ lda #$3B
+ jsr SYNCHR
+ jsr STRPRT
+L2A9E:
+ jsr ERRDIR
+ lda #$2C
+ sta INPUTBUFFER-1
+LCAF8:
+.ifdef APPLE
+ jsr INLINX
+.elseif .def(SYM1)
+ jsr INLIN
+.else
+ jsr NXIN
+.endif
+.ifdef KBD
+ bmi L2ABE
+.else
+ .ifdef CONFIG_FILE
+ lda CURDVC
+ beq LCB0C
+ lda Z96
+ and #$02
+ beq LCB0C
+ jsr LCAD6
+ jmp DATA
+LCB0C:
+ .endif
+ lda INPUTBUFFER
+ bne L2ABE
+ .ifdef CONFIG_FILE
+ lda CURDVC
+ bne LCAF8
+ .endif
+ .ifdef CONFIG_CBM1_PATCHES
+ jmp PATCH1
+ .else
+ clc
+ jmp CONTROL_C_TYPED
+ .endif
+.endif
+
+NXIN:
+.ifdef KBD
+ jsr INLIN
+ bmi RTS20
+ pla
+ jmp LE86C
+.else
+ .ifdef CONFIG_FILE
+ lda CURDVC
+ bne LCB21
+ .endif
+ jsr OUTQUES ; '?'
+ jsr OUTSP
+LCB21:
+ jmp INLIN
+.endif
+
+; ----------------------------------------------------------------------------
+; "GETC" STATEMENT
+; ----------------------------------------------------------------------------
+.ifdef KBD
+GETC:
+ jsr CONINT
+ jsr LF43D
+ jmp LE664
+.endif
+
+; ----------------------------------------------------------------------------
+; "READ" STATEMENT
+; ----------------------------------------------------------------------------
+READ:
+ ldx DATPTR
+ ldy DATPTR+1
+.ifdef CONFIG_NO_READ_Y_IS_ZERO_HACK
+; AppleSoft II, too
+ lda #$98 ; READ
+ .byte $2C
+L2ABE:
+ lda #$00 ; INPUT
+.else
+ .byte $A9 ; LDA #$98
+L2ABE:
+ tya
+.endif
+
+; ----------------------------------------------------------------------------
+; PROCESS INPUT LIST
+;
+; (Y,X) IS ADDRESS OF INPUT DATA STRING
+; (A) = VALUE FOR INPUTFLG: $00 FOR INPUT
+; $40 FOR GET
+; $98 FOR READ
+; ----------------------------------------------------------------------------
+PROCESS_INPUT_LIST:
+ sta INPUTFLG
+ stx INPTR
+ sty INPTR+1
+PROCESS_INPUT_ITEM:
+ jsr PTRGET
+ sta FORPNT
+ sty FORPNT+1
+ lda TXTPTR
+ ldy TXTPTR+1
+ sta TXPSV
+ sty TXPSV+1
+ ldx INPTR
+ ldy INPTR+1
+ stx TXTPTR
+ sty TXTPTR+1
+ jsr CHRGOT
+ bne INSTART
+ bit INPUTFLG
+.ifndef CONFIG_SMALL ; GET
+ .ifndef SYM1
+ bvc L2AF0
+ .ifdef MICROTAN
+ jsr MONRDKEY2
+ .elseif .def(AIM65)
+ jsr MONRDKEY2
+ .else
+ jsr MONRDKEY
+ .endif
+ .ifdef CONFIG_IO_MSB
+ and #$7F
+ .endif
+ sta INPUTBUFFER
+; BUG: The beq/bne L2AF8 below is supposed
+; to be always taken. For this to happen,
+; the last load must be a 0 for beq
+; and != 0 for bne. The original Microsoft
+; code had ldx/ldy/bne here, which was only
+; correct for a non-ZP INPUTBUFFER. Commodore
+; fixed it in CBMBASIC V1 by swapping the
+; ldx and the ldy. It was broken on KIM,
+; but okay on APPLE and CBM2, because
+; these used a non-ZP INPUTBUFFER.
+; Microsoft fixed this somewhere after KIM
+; and before MICROTAN, by using beq instead
+; of bne in the ZP case.
+ .ifdef CBM1
+ ldy #>(INPUTBUFFER-1)
+ ldx #<(INPUTBUFFER-1)
+ .else
+ ldx #<(INPUTBUFFER-1)
+ ldy #>(INPUTBUFFER-1)
+ .endif
+ .if .def(CONFIG_2) && (!.def(CONFIG_NO_INPUTBUFFER_ZP))
+ beq L2AF8 ; always
+ .else
+ bne L2AF8 ; always
+ .endif
+L2AF0:
+ .endif
+.endif
+ bmi FINDATA
+.ifdef CONFIG_FILE
+ lda CURDVC
+ bne LCB64
+.endif
+.ifdef KBD
+ jsr OUTQUESSP
+.else
+ jsr OUTQUES
+.endif
+LCB64:
+ jsr NXIN
+L2AF8:
+ stx TXTPTR
+ sty TXTPTR+1
+
+; ----------------------------------------------------------------------------
+INSTART:
+ jsr CHRGET
+ bit VALTYP
+ bpl L2B34
+.ifndef CONFIG_SMALL ; GET
+ .ifndef SYM1
+ bit INPUTFLG
+ bvc L2B10
+ .ifdef CONFIG_CBM1_PATCHES
+ lda #$00
+ jsr PATCH4
+ nop
+ .else
+ inx
+ stx TXTPTR
+ lda #$00
+ sta CHARAC
+ beq L2B1C
+ .endif
+L2B10:
+ .endif
+.endif
+ sta CHARAC
+ cmp #$22
+ beq L2B1D
+ lda #$3A
+ sta CHARAC
+ lda #$2C
+L2B1C:
+ clc
+L2B1D:
+ sta ENDCHR
+ lda TXTPTR
+ ldy TXTPTR+1
+ adc #$00
+ bcc L2B28
+ iny
+L2B28:
+ jsr STRLT2
+ jsr POINT
+.ifdef CONFIG_SMALL
+ jsr LETSTRING
+.else
+ jsr PUTSTR
+.endif
+ jmp INPUT_MORE
+; ----------------------------------------------------------------------------
+L2B34:
+ jsr FIN
+.ifdef CONFIG_SMALL
+ jsr SETFOR
+.else
+ lda VALTYP+1
+ jsr LET2
+.endif
+; ----------------------------------------------------------------------------
+INPUT_MORE:
+ jsr CHRGOT
+ beq L2B48
+ cmp #$2C
+ beq L2B48
+ jmp INPUTERR
+L2B48:
+ lda TXTPTR
+ ldy TXTPTR+1
+ sta INPTR
+ sty INPTR+1
+ lda TXPSV
+ ldy TXPSV+1
+ sta TXTPTR
+ sty TXTPTR+1
+ jsr CHRGOT
+ beq INPDONE
+ jsr CHKCOM
+ jmp PROCESS_INPUT_ITEM
+; ----------------------------------------------------------------------------
+FINDATA:
+ jsr DATAN
+ iny
+ tax
+ bne L2B7C
+ ldx #ERR_NODATA
+ iny
+ lda (TXTPTR),y
+ beq GERR
+ iny
+ lda (TXTPTR),y
+ sta Z8C
+ iny
+ lda (TXTPTR),y
+ iny
+ sta Z8C+1
+L2B7C:
+ lda (TXTPTR),y
+ tax
+ jsr ADDON
+ cpx #$83
+ bne FINDATA
+ jmp INSTART
+; ---NO MORE INPUT REQUESTED------
+INPDONE:
+ lda INPTR
+ ldy INPTR+1
+ ldx INPUTFLG
+.if .def(CONFIG_SMALL) && (!.def(CONFIG_11))
+ beq L2B94 ; INPUT
+.else
+ bpl L2B94; INPUT or GET
+.endif
+ jmp SETDA
+L2B94:
+ ldy #$00
+.ifdef AIM65
+ jsr LB8B1
+.endif
+ lda (INPTR),y
+ beq L2BA1
+.ifdef CONFIG_FILE
+ lda CURDVC
+ bne L2BA1
+.endif
+ lda #ERREXTRA
+ jmp STROUT
+L2BA1:
+ rts
+
+; ----------------------------------------------------------------------------
+ERREXTRA:
+.ifdef KBD
+ .byte "?Extra"
+.else
+ .byte "?EXTRA IGNORED"
+.endif
+ .byte $0D,$0A,$00
+ERRREENTRY:
+.ifdef KBD
+ .byte "What?"
+.else
+ .byte "?REDO FROM START"
+.endif
+ .byte $0D,$0A,$00
+.ifdef KBD
+LEA30:
+ .byte "B"
+ .byte $FD
+ .byte "GsBASIC"
+ .byte $00,$1B,$0D,$13
+ .byte " BASIC"
+.endif
diff --git a/msbasic/iscntc.s b/msbasic/iscntc.s
new file mode 100644
index 0000000..b0fe231
--- /dev/null
+++ b/msbasic/iscntc.s
@@ -0,0 +1,32 @@
+.segment "CODE"
+; ----------------------------------------------------------------------------
+; SEE IF CONTROL-C TYPED
+; ----------------------------------------------------------------------------
+.ifndef CONFIG_CBM_ALL
+.include "cbm_iscntc.s"
+.endif
+.ifdef KBD
+.include "kbd_iscntc.s"
+.endif
+.ifdef OSI
+.include "osi_iscntc.s"
+.endif
+.ifdef APPLE
+.include "apple_iscntc.s"
+.endif
+.ifdef KIM
+.include "kim_iscntc.s"
+.endif
+.ifdef MICROTAN
+.include "microtan_iscntc.s"
+.endif
+.ifdef AIM65
+.include "aim65_iscntc.s"
+.endif
+.ifdef SYM1
+.include "sym1_iscntc.s"
+.endif
+.ifdef W65C816SXB
+.include "w65c816sxb_iscntc.s"
+.endif
+;!!! runs into "STOP"
diff --git a/msbasic/kb9.cfg b/msbasic/kb9.cfg
new file mode 100644
index 0000000..c4a5536
--- /dev/null
+++ b/msbasic/kb9.cfg
@@ -0,0 +1,19 @@
+MEMORY {
+ ZP: start = $0000, size = $0100, type = rw;
+ BASROM: start = $2000, size = $3F00, fill = no, file = %O;
+ DUMMY: start = $0000, size = $00FF, file = "";
+}
+
+SEGMENTS {
+ ZEROPAGE: load = ZP, type = zp;
+ HEADER: load = BASROM, type = ro;
+ VECTORS: load = BASROM, type = ro;
+ KEYWORDS: load = BASROM, type = ro;
+ ERROR: load = BASROM, type = ro;
+ CODE: load = BASROM, type = ro;
+ CHRGET: load = BASROM, type = ro;
+ INIT: load = BASROM, type = ro;
+ EXTRA: load = BASROM, type = ro;
+ DUMMY: load = DUMMY; # don't include
+}
+
diff --git a/msbasic/kbd_extra.s b/msbasic/kbd_extra.s
new file mode 100644
index 0000000..07114ea
--- /dev/null
+++ b/msbasic/kbd_extra.s
@@ -0,0 +1,335 @@
+.segment "EXTRA"
+ stx SHIFTSIGNEXT
+ stx $0800
+ inx
+ stx Z17
+ stx Z18
+ stx TXTTAB
+ lda #$08
+ sta TXTTAB+1
+ jsr SCRTCH
+ sta STACK+255
+LFD81:
+ jsr PRIMM
+ .byte $1B,$06,$01,$0C
+ .byte "INTELLIVISION BASIC"
+ .byte $0D,$0A,$0A
+ .byte "Copyright Microsoft, Mattel 1980"
+ .byte $0D,$0A,$00
+ sta $0435
+ sta $8F
+ ldy #$0F
+ lda #$FF
+ sta ($04),y
+ jsr LDE8C
+ .byte $0C ; NOP $xxxx
+ jmp RESTART
+OUTQUESSP:
+ jsr OUTQUES
+ jmp OUTSP
+INLIN:
+ ldy #$FF
+LFDDC:
+ iny
+LFDDD:
+ jsr GETLN
+ cmp #$03 ; CTRL+C
+ beq LFDF7
+ cmp #$20
+ bcs LFDEC ; no control char
+ sbc #$09
+ bne LFDDD
+LFDEC:
+ sta INPUTBUFFER,y
+ tax
+ bne LFDDC
+ jsr CRDO2
+ ldy #$06
+LFDF7:
+ tax
+ clc
+ rts
+LFDFA:
+ bit $8F
+ bmi LFE01
+ jsr LDE48
+LFE01:
+ bit $8F
+ bvc LFE10
+ jmp LDE53
+LFE08:
+ jsr LFDFA
+LFE0B:
+ jsr LDE24
+ bne LFE08
+LFE10:
+ rts
+VSAV:
+ jsr GARBAG
+ lda FRETOP
+ sta $00
+ lda FRETOP+1
+ .byte $85
+LFE1B:
+ ora ($A5,x)
+ .byte $2F
+ sta $02
+ lda STREND+1
+ sta $03
+ ldy #$00
+LFE26:
+ lda ($00),y
+ sta ($02),y
+ inc $02
+ bne LFE30
+ inc $03
+LFE30:
+ inc $00
+ bne LFE26
+ inc $01
+ bit $01
+ bvc LFE26
+ ldx VARTAB
+ ldy VARTAB+1
+ lda #$01
+ bne LFE50
+PSAV:
+ lda VARTAB
+ sta $02
+ lda VARTAB+1
+ sta $03
+ ldx #$01
+ ldy #$08
+ lda #$02
+LFE50:
+ sta $0513
+ stx $0503
+ stx $00
+ sty $0504
+ sty $01
+ ldy #$0D
+ lda #$00
+LFE61:
+ sta $0504,y
+ dey
+ bne LFE61
+ sty $0500
+ lda #$40
+ sta $0505
+ lda $02
+ sec
+ sbc $00
+ sta $00
+ lda $03
+ sbc $01
+ sta $01
+ lsr a
+ lsr a
+ lsr a
+ sta $03
+ jsr LE870
+ sta $02
+ jsr CHRGOT
+ beq LFEA6
+ cmp #$2C
+ beq L40FA
+ jmp SYNERR
+L40FA:
+ jsr CHRGET
+ jsr LE870
+ sec
+ sbc $02
+ cmp $03
+ bpl LFEBF
+ lda #$27
+ sta JMPADRS
+ jmp LFFBD
+LFEA6:
+ lda $02
+ clc
+ adc $03
+ jsr LE874
+ pha
+ jsr LFE0B
+ jsr L6874
+ .byte $72
+ adc $00,x
+ pla
+ tax
+ lda #$00
+ jsr LINPRT
+LFEBF:
+ ldx #$07
+LBF83:
+ dex
+ lda VARTAB,x
+ sec
+ sbc TXTTAB,x
+ sta $051B,x
+ lda VARTAB+1,x
+ sbc TXTTAB+1,x
+ sta $051C,x
+ dex
+ bpl LBF83
+ txa
+ sbc FRETOP
+ sta $0521
+ lda #>CONST_MEMSIZ
+ sbc FRETOP+1
+ sta $0522
+ lda FRETOP
+ sta $0523
+ lda FRETOP+1
+ sta $0524
+ ldx $02
+ jsr LFFDD
+ jsr LFFD1
+ lda $01
+ ldx #$05
+LFEF7:
+ stx $0511
+ ldy #$E4
+ sec
+ sbc #$08
+ sta $01
+ bpl LFF15
+ adc #$08
+ asl $00
+ rol a
+ asl $00
+ rol a
+ asl $00
+ rol a
+ adc #$01
+ sta $0505
+ ldy #$00
+LFF15:
+ sty $0512
+ jsr LE4C0
+ ldx #$00
+ lda $01
+ bpl LFEF7
+LFF21:
+ rts
+VLOD:
+ jsr LFFD1
+ stx JMPADRS
+ lda VARTAB
+ ldy VARTAB+1
+ ldx #$01
+ jsr LFF64
+ ldx #$00
+ ldy #$02
+LFF34:
+ jsr LE39A
+ iny
+ iny
+ inx
+ inx
+ cpx #$05
+ bmi LFF34
+ lda STREND
+ sta LOWTR
+ lda STREND+1
+ sta LOWTR+1
+ lda FRETOP
+ sta HIGHTR
+ lda FRETOP+1
+ sta HIGHTR+1
+ lda #CONST_MEMSIZ
+ sta HIGHDS+1
+ lda $0523
+ sta FRETOP
+ lda $0524
+ sta FRETOP+1
+ jmp BLTU2
+LFF64:
+ sta $9A
+ sty $9B
+ stx $00
+ jsr LE870
+ jsr LFFDD
+ lda JMPADRS
+ beq LFF7F
+ lda #$01
+ sta $9A
+ lda #$08
+ sta $9B
+ jsr STXTPT
+LFF7F:
+ lda $9A
+ sta $0503
+ lda $9B
+ sta $0504
+ lda #$ED
+ sta $0512
+ lda #$05
+ sta $01
+LFF92:
+ ldx $0512
+ beq LFF21
+ ldy #$04
+ jsr LE4C4
+ lda $01
+ cmp $0511
+ bne LFFB2
+ lda #$00
+ sta $01
+ lda $00
+ cmp $0513
+ beq LFF92
+ lda #$18
+ bne LFFB8
+LFFB2:
+ lda #$27
+ bne LFFB8
+LFFB6:
+ lda #$3C
+LFFB8:
+ sta JMPADRS
+ jsr CLEARC
+LFFBD:
+ jsr VARTAB_MINUS_2_TO_AY
+ sta $9A
+ sty $9B
+ lda #$00
+ tay
+ sta ($9A),y
+ iny
+ sta ($9A),y
+ ldx JMPADRS
+ jmp ERROR
+LFFD1:
+ ldx #$00
+LFFD3:
+ lda #$02
+ .byte $2C
+LFFD6:
+ lda #$03
+ jsr LDE8C
+ asl FACSIGN
+LFFDD:
+ jsr CHRGOT
+ beq LFFE5
+ jmp SYNERR
+LFFE5:
+ lda #$0D
+ ldy #$00
+ jsr LDE8C
+ .byte $06
+LFFED:
+ lda $034C
+ bmi LFFED
+ ldy #$01
+ lda ($04),y
+ bne LFFB6
+ rts
+ .byte $FF
+; NMI
+ .addr LC000
+; RESET
+ .addr LC000
+; IRQ
+ .addr LC009
diff --git a/msbasic/kbd_iscntc.s b/msbasic/kbd_iscntc.s
new file mode 100644
index 0000000..ce19cd4
--- /dev/null
+++ b/msbasic/kbd_iscntc.s
@@ -0,0 +1,10 @@
+.segment "CODE"
+ISCNTC:
+ jsr LE8F3
+ bcc RET1
+LE633:
+ jsr LDE7F
+ beq STOP
+ cmp #$03
+ bne LE633
+;!!! runs into "STOP"
\ No newline at end of file
diff --git a/msbasic/kbd_loadsave.s b/msbasic/kbd_loadsave.s
new file mode 100644
index 0000000..fd48196
--- /dev/null
+++ b/msbasic/kbd_loadsave.s
@@ -0,0 +1,37 @@
+.segment "CODE"
+SLOD:
+ ldx #$01
+ .byte $2C
+PLOD:
+ ldx #$00
+ ldy CURLIN+1
+ iny
+ sty JMPADRS
+ jsr LFFD3
+ jsr VARTAB_MINUS_2_TO_AY
+ ldx #$02
+ jsr LFF64
+ ldx #$6F
+ ldy #$00
+ jsr LE39A
+ jsr LE33D
+ jmp CLEARC
+ .byte $FF,$FF,$FF
+
+; ----------------------------------------------------------------------------
+VER:
+ lda #$13
+ ldx FAC
+ beq LE397
+ lda $DFF9
+LE397:
+ jmp FLOAT
+LE39A:
+ lda VARTAB,x
+ clc
+ adc $051B,y
+ sta VARTAB,y
+ lda VARTAB+1,x
+ adc $051C,y
+ sta VARTAB+1,y
+; !!! next instruction is an RTS!
\ No newline at end of file
diff --git a/msbasic/kbdbasic.cfg b/msbasic/kbdbasic.cfg
new file mode 100644
index 0000000..e27dc0c
--- /dev/null
+++ b/msbasic/kbdbasic.cfg
@@ -0,0 +1,19 @@
+MEMORY {
+ ZP: start = $0000, size = $0100, type = rw;
+ BASROM: start = $E000, size = $3F00, fill = no, file = %O;
+ DUMMY: start = $0000, size = $00FF, file = "";
+}
+
+SEGMENTS {
+ ZEROPAGE: load = ZP, type = zp;
+ HEADER: load = BASROM, type = ro;
+ VECTORS: load = BASROM, type = ro;
+ KEYWORDS: load = BASROM, type = ro;
+ ERROR: load = BASROM, type = ro;
+ CODE: load = BASROM, type = ro;
+ CHRGET: load = BASROM, type = ro;
+ INIT: load = BASROM, type = ro;
+ EXTRA: load = BASROM, type = ro;
+ DUMMY: load = DUMMY; # don't include
+}
+
diff --git a/msbasic/kilian.cfg b/msbasic/kilian.cfg
new file mode 100644
index 0000000..4e3dca2
--- /dev/null
+++ b/msbasic/kilian.cfg
@@ -0,0 +1,22 @@
+MEMORY {
+ ZP: start = $0000, size = $0100, type = rw;
+ BASROM: start = $C000, size = $3FFA, fill = yes, file = %O;
+ RESETVEC: start = $FFFA, size = 6, fill = yes, file = %O;
+ DUMMY: start = $0000, size = $00FF, file = "";
+}
+
+SEGMENTS {
+ ZEROPAGE: load = ZP, type = zp;
+ HEADER: load = BASROM, type = ro;
+ VECTORS: load = BASROM, type = ro;
+ KEYWORDS: load = BASROM, type = ro;
+ ERROR: load = BASROM, type = ro;
+ CODE: load = BASROM, type = ro;
+ CHRGET: load = BASROM, type = ro;
+ INIT: load = BASROM, type = ro;
+ EXTRA: load = BASROM, type = ro;
+ RESETVEC: load = RESETVEC, type = ro;
+
+ DUMMY: load = DUMMY; # don't include
+}
+
diff --git a/msbasic/kilian_extra.s b/msbasic/kilian_extra.s
new file mode 100644
index 0000000..8f96738
--- /dev/null
+++ b/msbasic/kilian_extra.s
@@ -0,0 +1,28 @@
+.segment "EXTRA"
+.export MONRDKEY, MONCOUT, LOAD; SAVE; ISCNTC
+
+LOAD:
+ rts
+
+SAVE:
+ rts
+
+ISCNTC:
+ rts
+
+MONRDKEY:
+ lda $BC01
+ bmi MONRDKEY_SKIP_ECHO
+ sta $BC00 ; echo
+MONRDKEY_SKIP_ECHO:
+ rts
+
+MONCOUT:
+ sta $BC00
+
+ rts
+
+.segment "RESETVEC"
+ .word $0000 ; NMI vector
+ .word COLD_START ; RESET vector
+ .word $0000 ; IRQ vector
diff --git a/msbasic/kim_extra.s b/msbasic/kim_extra.s
new file mode 100644
index 0000000..e483d3a
--- /dev/null
+++ b/msbasic/kim_extra.s
@@ -0,0 +1,5 @@
+.segment "EXTRA"
+
+RAMSTART2:
+ .byte $08,$29,$25,$20,$60,$2A,$E5,$E4
+ .byte $20,$66,$24,$65,$AC,$04,$A4
diff --git a/msbasic/kim_iscntc.s b/msbasic/kim_iscntc.s
new file mode 100644
index 0000000..a4544c8
--- /dev/null
+++ b/msbasic/kim_iscntc.s
@@ -0,0 +1,10 @@
+.segment "CODE"
+ISCNTC:
+ lda #$01
+ bit $1740
+ bmi RET2
+ ldx #$08
+ lda #$03
+ clc
+ cmp #$03
+;!!! runs into "STOP"
\ No newline at end of file
diff --git a/msbasic/kim_loadsave.s b/msbasic/kim_loadsave.s
new file mode 100644
index 0000000..e1dcd1e
--- /dev/null
+++ b/msbasic/kim_loadsave.s
@@ -0,0 +1,62 @@
+.segment "CODE"
+SAVE:
+ tsx
+ stx INPUTFLG
+ lda #$37
+ sta $F2
+ lda #$FE
+ sta $17F9
+ lda TXTTAB
+ ldy TXTTAB+1
+ sta $17F5
+ sty $17F6
+ lda VARTAB
+ ldy VARTAB+1
+ sta $17F7
+ sty $17F8
+ jmp L1800
+ ldx INPUTFLG
+ txs
+ lda #QT_SAVED
+ jmp STROUT
+QT_LOADED:
+ .byte "LOADED"
+ .byte $00
+QT_SAVED:
+ .byte "SAVED"
+ .byte $0D,$0A,$00,$00,$00,$00,$00,$00
+ .byte $00,$00,$00,$00,$00,$00,$00,$00
+ .byte $00,$00,$00,$00,$00,$00,$00
+LOAD:
+ lda TXTTAB
+ ldy TXTTAB+1
+ sta $17F5
+ sty $17F6
+ lda #$FF
+ sta $17F9
+ lda #L27A6
+ sta GORESTART+1
+ sty GORESTART+2
+ jmp L1873
+L27A6:
+ ldx #$FF
+ txs
+ lda #RESTART
+ sta GORESTART+1
+ sty GORESTART+2
+ lda #QT_LOADED
+ jsr STROUT
+ ldx $17ED
+ ldy $17EE
+ txa
+ bne L27C2
+ nop
+L27C2:
+ nop
+ stx VARTAB
+ sty VARTAB+1
+ jmp FIX_LINKS
diff --git a/msbasic/loadsave.s b/msbasic/loadsave.s
new file mode 100644
index 0000000..f567bd2
--- /dev/null
+++ b/msbasic/loadsave.s
@@ -0,0 +1,17 @@
+.segment "CODE"
+
+.ifdef APPLE
+.include "apple_loadsave.s"
+.endif
+.ifdef KIM
+.include "kim_loadsave.s"
+.endif
+.ifdef MICROTAN
+.include "microtan_loadsave.s"
+.endif
+.ifdef AIM65
+.include "aim65_loadsave.s"
+.endif
+.ifdef SYM1
+.include "sym1_loadsave.s"
+.endif
\ No newline at end of file
diff --git a/msbasic/macros.s b/msbasic/macros.s
new file mode 100644
index 0000000..2f6a3c8
--- /dev/null
+++ b/msbasic/macros.s
@@ -0,0 +1,78 @@
+; htasc - set the hi bit on the last byte of a string for termination
+; (by Tom Greene)
+.macro htasc str
+ .repeat .strlen(str)-1,I
+ .byte .strat(str,I)
+ .endrep
+ .byte .strat(str,.strlen(str)-1) | $80
+.endmacro
+
+; For every token, a byte gets put into segment "DUMMY".
+; This way, we count up with every token. The DUMMY segment
+; doesn't get linked into the binary.
+.macro init_token_tables
+ .segment "VECTORS"
+TOKEN_ADDRESS_TABLE:
+ .segment "KEYWORDS"
+TOKEN_NAME_TABLE:
+ .segment "DUMMY"
+DUMMY_START:
+.endmacro
+
+; optionally define token symbol
+; count up token number
+.macro define_token token
+ .segment "DUMMY"
+ .ifnblank token
+ token := <(*-DUMMY_START)+$80
+ .endif
+ .res 1; count up in any case
+.endmacro
+
+; lay down a keyword, optionally define a token symbol
+.macro keyword key, token
+ .segment "KEYWORDS"
+ htasc key
+ define_token token
+.endmacro
+
+; lay down a keyword and an address (RTS style),
+; optionally define a token symbol
+.macro keyword_rts key, vec, token
+ .segment "VECTORS"
+ .word vec-1
+ keyword key, token
+.endmacro
+
+; lay down a keyword and an address,
+; optionally define a token symbol
+.macro keyword_addr key, vec, token
+ .segment "VECTORS"
+ .addr vec
+ keyword key, token
+.endmacro
+
+.macro count_tokens
+ .segment "DUMMY"
+ NUM_TOKENS := <(*-DUMMY_START)
+.endmacro
+
+.macro init_error_table
+ .segment "ERROR"
+ERROR_MESSAGES:
+.endmacro
+
+.macro define_error error, msg
+ .segment "ERROR"
+ error := <(*-ERROR_MESSAGES)
+ htasc msg
+.endmacro
+
+;---------------------------------------------
+; set the MSB of every byte of a string
+.macro asc80 str
+ .repeat .strlen(str),I
+ .byte .strat(str,I)+$80
+ .endrep
+.endmacro
+
diff --git a/msbasic/memory.s b/msbasic/memory.s
new file mode 100644
index 0000000..d78607e
--- /dev/null
+++ b/msbasic/memory.s
@@ -0,0 +1,154 @@
+; generic stack and memory management code
+; this code is identical across all versions of
+; BASIC
+
+.segment "CODE"
+
+; ----------------------------------------------------------------------------
+; CALLED BY "NEXT" AND "FOR" TO SCAN THROUGH
+; THE STACK FOR A FRAME WITH THE SAME VARIABLE.
+;
+; (FORPNT) = ADDRESS OF VARIABLE IF "FOR" OR "NEXT"
+; = $XXFF IF CALLED FROM "RETURN"
+; <<< BUG: SHOULD BE $FFXX >>>
+;
+; RETURNS .NE. IF VARIABLE NOT FOUND,
+; (X) = STACK PNTR AFTER SKIPPING ALL FRAMES
+;
+; .EQ. IF FOUND
+; (X) = STACK PNTR OF FRAME FOUND
+; ----------------------------------------------------------------------------
+GTFORPNT:
+ tsx
+ inx
+ inx
+ inx
+ inx
+L2279:
+ lda STACK+1,x
+ cmp #$81
+ bne L22A1
+ lda FORPNT+1
+ bne L228E
+ lda STACK+2,x
+ sta FORPNT
+ lda STACK+3,x
+ sta FORPNT+1
+L228E:
+ cmp STACK+3,x
+ bne L229A
+ lda FORPNT
+ cmp STACK+2,x
+ beq L22A1
+L229A:
+ txa
+ clc
+ adc #BYTES_PER_FRAME
+ tax
+ bne L2279
+L22A1:
+ rts
+
+; ----------------------------------------------------------------------------
+; MOVE BLOCK OF MEMORY UP
+;
+; ON ENTRY:
+; (Y,A) = (HIGHDS) = DESTINATION END+1
+; (LOWTR) = LOWEST ADDRESS OF SOURCE
+; (HIGHTR) = HIGHEST SOURCE ADDRESS+1
+; ----------------------------------------------------------------------------
+BLTU:
+ jsr REASON
+ sta STREND
+ sty STREND+1
+BLTU2:
+ sec
+ lda HIGHTR
+ sbc LOWTR
+ sta INDEX
+ tay
+ lda HIGHTR+1
+ sbc LOWTR+1
+ tax
+ inx
+ tya
+ beq L22DD
+ lda HIGHTR
+ sec
+ sbc INDEX
+ sta HIGHTR
+ bcs L22C6
+ dec HIGHTR+1
+ sec
+L22C6:
+ lda HIGHDS
+ sbc INDEX
+ sta HIGHDS
+ bcs L22D6
+ dec HIGHDS+1
+ bcc L22D6
+L22D2:
+ lda (HIGHTR),y
+ sta (HIGHDS),y
+L22D6:
+ dey
+ bne L22D2
+ lda (HIGHTR),y
+ sta (HIGHDS),y
+L22DD:
+ dec HIGHTR+1
+ dec HIGHDS+1
+ dex
+ bne L22D6
+ rts
+
+; ----------------------------------------------------------------------------
+; CHECK IF ENOUGH ROOM LEFT ON STACK
+; FOR "FOR", "GOSUB", OR EXPRESSION EVALUATION
+; ----------------------------------------------------------------------------
+CHKMEM:
+ asl a
+ adc #SPACE_FOR_GOSUB
+ bcs MEMERR
+ sta INDEX
+ tsx
+ cpx INDEX
+ bcc MEMERR
+ rts
+
+; ----------------------------------------------------------------------------
+; CHECK IF ENOUGH ROOM BETWEEN ARRAYS AND STRINGS
+; (Y,A) = ADDR ARRAYS NEED TO GROW TO
+; ----------------------------------------------------------------------------
+REASON:
+ cpy FRETOP+1
+ bcc L231E
+ bne L22FC
+ cmp FRETOP
+ bcc L231E
+L22FC:
+ pha
+ ldx #FAC-TEMP1-1
+ tya
+L2300:
+ pha
+ lda TEMP1,x
+ dex
+ bpl L2300
+ jsr GARBAG
+ ldx #<(TEMP1-FAC+1)
+L230B:
+ pla
+ sta FAC,x
+ inx
+ bmi L230B
+ pla
+ tay
+ pla
+ cpy FRETOP+1
+ bcc L231E
+ bne MEMERR
+ cmp FRETOP
+ bcs MEMERR
+L231E:
+ rts
diff --git a/msbasic/message.s b/msbasic/message.s
new file mode 100644
index 0000000..79f7800
--- /dev/null
+++ b/msbasic/message.s
@@ -0,0 +1,60 @@
+; global messages: "error", "in", "ready", "break"
+
+.segment "CODE"
+
+QT_ERROR:
+.ifdef KBD
+ .byte " err"
+.else
+ .ifdef APPLE
+ .byte " ERR"
+ .byte $07,$07
+ .else
+ .byte " ERROR"
+ .endif
+.endif
+ .byte 0
+
+.ifndef KBD
+QT_IN:
+ .byte " IN "
+ .byte $00
+.endif
+
+.ifdef KBD
+ .byte $54,$D2 ; ???
+OKPRT:
+ jsr PRIMM
+ .byte CR,CR,">>",CR,LF
+ .byte 0
+ rts
+ nop
+.else
+ .ifndef AIM65
+QT_OK:
+ .ifdef CONFIG_CBM_ALL
+ .byte CR,LF,"READY.",CR,LF
+ .else
+ .ifdef APPLE
+ ; binary patch!
+ .byte CR,0,0,"K",CR,LF
+ .else
+ .byte CR,LF,"OK",CR,LF
+ .endif
+ .endif
+ .byte 0
+ .endif
+.endif
+QT_BREAK:
+
+.ifdef KBD
+ .byte CR,LF," Brk"
+ .byte 0
+ .byte $54,$D0 ; ???
+.elseif .def(MICROTAN) || .def(AIM65)
+ .byte CR,LF," BREAK"
+ .byte 0
+.else
+ .byte CR,LF,"BREAK"
+ .byte 0
+.endif
diff --git a/msbasic/microtan.cfg b/msbasic/microtan.cfg
new file mode 100644
index 0000000..537b9a9
--- /dev/null
+++ b/msbasic/microtan.cfg
@@ -0,0 +1,19 @@
+MEMORY {
+ ZP: start = $0000, size = $0100, type = rw;
+ BASROM: start = $C000, size = $3F00, fill = no, file = %O;
+ DUMMY: start = $0000, size = $00FF, file = "";
+}
+
+SEGMENTS {
+ ZEROPAGE: load = ZP, type = zp;
+ HEADER: load = BASROM, type = ro;
+ VECTORS: load = BASROM, type = ro;
+ KEYWORDS: load = BASROM, type = ro;
+ ERROR: load = BASROM, type = ro;
+ CODE: load = BASROM, type = ro;
+ CHRGET: load = BASROM, type = ro;
+ INIT: load = BASROM, type = ro;
+ EXTRA: load = BASROM, type = ro;
+ DUMMY: load = DUMMY; # don't include
+}
+
diff --git a/msbasic/microtan_extra.s b/msbasic/microtan_extra.s
new file mode 100644
index 0000000..8ea3d5c
--- /dev/null
+++ b/msbasic/microtan_extra.s
@@ -0,0 +1,923 @@
+ .byte 0,0,0,0,0,0,0,0,0
+LE210:
+ jmp LE34A
+LE213:
+ jmp LE34A
+LE216:
+ jmp LE33C
+LE219:
+ jmp LE252
+LE21C:
+ jmp LE6AD
+LE21F:
+ jmp LE6B9
+LE222:
+ pla
+ tay
+ sta $5E
+ pla
+ sta $5F
+ pha
+ tya
+ pha
+ ldy #$03
+LE22E:
+ lda ($5E),y
+ beq LE238
+ jsr LFE75
+ iny
+ bne LE22E
+LE238:
+ jsr LFDFA
+ lda $01
+ cmp #$03
+ beq LE24C
+ cmp #$0D
+ beq LE24B
+ jsr LFE75
+ jmp LE238
+LE24B:
+ rts
+LE24C:
+ pla
+ pla
+ pla
+ jmp LE2D6
+LE252:
+ tya
+ pha
+ jsr LE222
+ bcs LE260
+ .byte "FAST?"
+ .byte $0D,$00
+LE260:
+ ldy #$00
+ sty $50
+ sty $31
+ lda $03E0
+ cmp #$59
+ beq LE26F
+ inc $50
+LE26F:
+ pla
+ pha
+ beq LE28C
+ jsr LE222
+ bcs LE280
+ ora $5845
+ .byte "AM?"
+ .byte $0D,$00
+LE280:
+ lda $03E0
+ cmp #$59
+ beq LE28C
+ pla
+ clc
+ adc #$01
+ pha
+LE28C:
+ jsr LE222
+ bcs LE29D
+ ora $4946
+ .byte "LENAME?"
+ .byte $0D,$00
+LE29D:
+ ldy #$FF
+ jsr LF006
+ bcs LE28C
+ cmp #$FF
+ bne LE28C
+ lda #$00
+ lda #$42
+ jsr LF003
+ jsr LF000
+ pla
+ bne LE2C3
+ ldy #$20
+ jsr LF009
+ jsr LF00C
+ jsr LF01E
+ jmp LE2D6
+LE2C3:
+ pha
+ jsr LF01B
+ pla
+ clc
+ sbc #$00
+ jsr LF021
+ lda $1E
+ sta $9C
+ lda $1F
+ sta $9D
+LE2D6:
+ jsr LFE73
+ cli
+ lda #$00
+ sta $BFCB
+ sta $BFC2
+ ldx #$00
+LE2E4:
+ pla
+ sta $13,x
+ inx
+ cpx #$4D
+ bne LE2E4
+ rts
+ lda #$0F
+ sta $0C
+ lda #$00
+ sta $BFC2
+ sta $15
+ sta $16
+ jmp COLD_START
+LE2FD:
+ pha
+ txa
+ pha
+ lda #$02
+ sta $14
+ lda #$00
+LE306:
+ dex
+ bmi LE312
+ clc
+ adc #$20
+ bcc LE306
+ inc $14
+ bne LE306
+LE312:
+ sta $13
+ pla
+ tax
+ pla
+ rts
+LE318:
+ jsr LE2FD
+ sta ($13),y
+ rts
+LE31E:
+ pha
+ txa
+ pha
+ ldx #$00
+LE323:
+ lda $0220,x
+ sta $0200,x
+ inx
+ cpx #$A0
+ bne LE323
+ lda #$20
+ ldx #$1F
+LE332:
+ sta $0280,x
+ dex
+ bpl LE332
+ pla
+ tax
+LE33A:
+ pla
+ rts
+LE33C:
+ pha
+ lda $16
+ beq LE346
+ bpl LE33A
+ jmp LE714
+LE346:
+ pla
+ jmp LC7A5
+LE34A:
+ lda $16
+ beq LE357
+ bmi LE353
+ jmp LE778
+LE353:
+ lda #$00
+ sta $16
+LE357:
+ lda $15
+ beq LE35E
+ jmp LE660
+LE35E:
+ jsr LC764
+ cmp #$05
+ beq LE366
+ rts
+LE366:
+ stx $0E
+ lda #$00
+ sta $33
+ sta $34
+ ldx #$FF
+LE370:
+ inx
+ cpx $0E
+ beq LE3C8
+ lda $34
+ cmp #$19
+ bcs LE3A7
+ pha
+ lda $33
+ asl a
+ rol $34
+ asl a
+ rol $34
+ adc $33
+ sta $33
+ pla
+ adc $34
+ sta $34
+ asl $33
+ rol $34
+ lda $35,x
+ sec
+ sbc #$30
+ bmi LE3A7
+ cmp #$3A
+ bcs LE3A7
+ clc
+ adc $33
+ sta $33
+ bcc LE370
+ inc $34
+ bne LE370
+LE3A7:
+ ldx #$00
+LE3A9:
+ lda LE3B4,x
+ beq LE3C3
+ jsr LFE75
+ inx
+ bne LE3A9
+LE3B4:
+ ora $4F4E
+ .byte " SUCH LINE"
+
+ .byte $0D,$00
+LE3C3:
+ ldx #$00
+ lda #$0D
+ rts
+LE3C8:
+ ldx #$09
+LE3CA:
+ lda #$04
+ sta $45,x
+ dex
+ lda #$01
+ sta $45,x
+ dex
+ bpl LE3CA
+ sta $CE
+ lda #$04
+ sta $CF
+ stx $7D
+ stx $7B
+LE3E0:
+ ldy #$03
+ lda ($CE),y
+ pha
+ dey
+ lda ($CE),y
+ pha
+ dey
+ lda ($CE),y
+ tax
+ dey
+ lda ($CE),y
+ sta $CE
+ stx $CF
+ sta $4F
+ stx $50
+ pla
+ tax
+ pla
+ cmp $34
+ bne LE403
+ cpx $33
+ beq LE419
+LE403:
+ stx $7A
+ sta $7B
+ ldx #$00
+LE409:
+ lda $47,x
+ sta $45,x
+ inx
+ cpx #$0A
+ bne LE409
+ iny
+ lda ($CE),y
+ beq LE3A7
+ bne LE3E0
+LE419:
+ iny
+ lda ($CE),y
+ beq LE428
+ iny
+ lda ($CE),y
+ sta $7C
+ iny
+ lda ($CE),y
+ sta $7D
+LE428:
+ ldx #$03
+LE42A:
+ lda $7A,x
+ pha
+ dex
+ bpl LE42A
+ lda #$20
+ ldx #$0F
+LE434:
+ ldy #$1F
+LE436:
+ jsr LE318
+ dey
+ bpl LE436
+ dex
+ bpl LE434
+ ldx #$05
+LE441:
+ ldy #$1F
+ lda #$2D
+LE445:
+ jsr LE318
+ dey
+ bpl LE445
+ cpx #$09
+ beq LE453
+ ldx #$09
+ bne LE441
+LE453:
+ lda $45
+ sta $CE
+ lda $46
+ sta $CF
+LE45B:
+ txa
+ pha
+ lda #$00
+ sta $07
+ ldy #$02
+ lda ($CE),y
+ tax
+ iny
+ lda ($CE),y
+ cmp $34
+ beq LE473
+ bcc LE479
+LE46F:
+ dec $07
+ bmi LE47B
+LE473:
+ cpx $33
+ beq LE47B
+ bcs LE46F
+LE479:
+ inc $07
+LE47B:
+ sty $08
+ stx $D2
+ sta $D1
+ ldx #$90
+ sec
+ jsr FLOAT2
+ jsr FOUT
+ ldx #$00
+LE48C:
+ lda $0100,x
+ beq LE496
+ sta $35,x
+ inx
+ bne LE48C
+LE496:
+ lda #$20
+LE498:
+ ldy $08
+ and #$7F
+LE49C:
+ sta $35,x
+ beq LE4D0
+ inx
+ cpx #$4F
+ bcc LE4A9
+ lda #$00
+ beq LE49C
+LE4A9:
+ iny
+ lda ($CE),y
+ bpl LE49C
+ sec
+ sbc #$7F
+ stx $09
+ tax
+ sty $08
+ ldy #$FF
+LE4B8:
+ dex
+ beq LE4C3
+LE4BB:
+ iny
+ lda TOKEN_NAME_TABLE,y
+ bpl LE4BB
+ bmi LE4B8
+LE4C3:
+ ldx $09
+LE4C5:
+ iny
+ lda TOKEN_NAME_TABLE,y
+ bmi LE498
+ sta $35,x
+ inx
+ bne LE4C5
+LE4D0:
+ ldx #$00
+ stx $08
+ pla
+ tax
+ ldy #$00
+ lda $07
+ bne LE4E0
+ ldx #$06
+ bne LE4EE
+LE4E0:
+ bpl LE4E9
+LE4E2:
+ inx
+ cpx #$0E
+ beq LE529
+ bne LE4EE
+LE4E9:
+ jsr LE31E
+ ldx #$04
+LE4EE:
+ stx $09
+LE4F0:
+ ldx $08
+ lda $35,x
+ beq LE50D
+ inx
+ stx $08
+ ldx $09
+ jsr LE318
+ iny
+ cpy #$20
+ bne LE4F0
+ ldy #$00
+ lda $07
+ beq LE4E2
+ bpl LE4E9
+ bmi LE4E2
+LE50D:
+ ldy #$00
+ lda ($CE),y
+ pha
+ iny
+ lda ($CE),y
+ sta $CF
+ pla
+ sta $CE
+ lda ($CE),y
+ beq LE529
+ ldx $09
+ lda $07
+ bne LE526
+ ldx #$09
+LE526:
+ jmp LE45B
+LE529:
+ ldx #$00
+LE52B:
+ lda $02C1,x
+ cmp #$20
+ beq LE53A
+ sta $03E1,x
+ inx
+ stx $0E
+ bne LE52B
+LE53A:
+ ldx #$00
+LE53C:
+ pla
+ sta $7A,x
+ inx
+ cpx #$04
+ bne LE53C
+ ldx #$06
+ ldy #$00
+ sty $01
+LE54A:
+ jsr LE2FD
+ lda ($13),y
+ sta $82
+ lda #$FF
+ sta ($13),y
+LE555:
+ lda #$40
+ sta $80
+ sta $81
+LE55B:
+ lda $01
+ bne LE574
+ dec $80
+ bne LE55B
+ dec $81
+ bne LE55B
+ lda ($13),y
+ pha
+ lda $82
+ sta ($13),y
+ pla
+ sta $82
+ jmp LE555
+LE574:
+ lda $82
+ bmi LE57A
+ sta ($13),y
+LE57A:
+ lda $01
+ cmp #$18
+ bne LE584
+ dey
+ bpl LE584
+ iny
+LE584:
+ cmp #$06
+ bne LE58D
+ cpy #$1F
+ beq LE58D
+ iny
+LE58D:
+ cmp #$02
+ bne LE596
+ cpx #$06
+ beq LE596
+ dex
+LE596:
+ cmp #$04
+ bne LE59F
+ cpx #$08
+ beq LE59F
+ inx
+LE59F:
+ cmp #$7F
+ bne LE5B6
+ cpy #$00
+ bne LE5AB
+ cpx #$06
+ beq LE5B6
+LE5AB:
+ dey
+ bpl LE5BA
+ ldy #$1F
+ dex
+ jsr LE2FD
+ bne LE5BA
+LE5B6:
+ cmp #$05
+ bne LE5D5
+LE5BA:
+ pha
+ tya
+ pha
+LE5BD:
+ tya
+ clc
+ adc $13
+ cmp #$1F
+ beq LE5CE
+ iny
+ lda ($13),y
+ dey
+ sta ($13),y
+ iny
+ bne LE5BD
+LE5CE:
+ lda #$20
+ sta ($13),y
+ pla
+ tay
+ pla
+LE5D5:
+ cmp #$1B
+ beq LE641
+ cmp #$0D
+ beq LE657
+ cmp #$0A
+ beq LE631
+ cmp #$03
+ beq LE645
+ cmp #$0B
+ beq LE627
+ cmp #$09
+ beq LE63D
+ cmp #$20
+ bcc LE620
+ cmp #$7E
+ bcs LE620
+ pha
+ tya
+ pha
+ lda ($13),y
+LE5FA:
+ sta $80
+ tya
+ clc
+ adc $13
+ cmp #$1F
+ beq LE60F
+ iny
+ lda ($13),y
+ pha
+ lda $80
+ sta ($13),y
+ pla
+ bne LE5FA
+LE60F:
+ pla
+ tay
+ pla
+ sta ($13),y
+ cpy #$1F
+ bne LE61F
+ cpx #$08
+ beq LE620
+ inx
+ ldy #$FF
+LE61F:
+ iny
+LE620:
+ lda #$00
+ sta $01
+ jmp LE54A
+LE627:
+ ldx #$5F
+ lda #$20
+LE62B:
+ sta $02C0,x
+ dex
+ bpl LE62B
+LE631:
+ ldx #$02
+LE633:
+ lda $7A,x
+ sta $13
+ inx
+ lda $7A,x
+ jmp LE659
+LE63D:
+ ldx #$00
+ stx $0E
+LE641:
+ ldx #$00
+ beq LE633
+LE645:
+ jsr LFE73
+ ldx #$00
+ lda #$00
+ sta $16
+LE64E:
+ sta $15
+ ldy #$00
+ sty $03
+ lda #$0D
+ rts
+LE657:
+ lda #$FF
+LE659:
+ sta $14
+ lda #$01
+ pha
+ bne LE685
+LE660:
+ cmp #$03
+ beq LE69E
+ cmp #$02
+ beq LE681
+ ldx $03C0
+ cpx #$20
+ bne LE645
+ ldx #$FF
+LE671:
+ inx
+ cpx $0E
+ bne LE67A
+ lda #$02
+ bne LE64E
+LE67A:
+ lda $03E1,x
+ sta $35,x
+ bne LE671
+LE681:
+ tax
+ inx
+ txa
+ pha
+LE685:
+ ldx #$4F
+LE687:
+ lda $02C0,x
+ sta $35,x
+ dex
+ bpl LE687
+ ldx #$4F
+LE691:
+ lda $02BF,x
+ cmp #$20
+ bne LE69B
+ dex
+ bne LE691
+LE69B:
+ pla
+ bne LE64E
+LE69E:
+ ldx $14
+ cpx #$FF
+ beq LE645
+ stx $34
+ lda $13
+ sta $33
+ jmp LE3C8
+LE6AD:
+ pha
+ lda #$05
+ sta $0E
+ pla
+ jsr LINGET
+ jmp LC57E
+LE6B9:
+ lda $0E
+ bmi LE6D1
+ dec $0E
+ bne LE6D1
+ jsr LFDFA
+ lda #$82
+ sta $0E
+ lda $01
+ cmp #$0A
+ beq LE6D1
+ sec
+ rol $0E
+LE6D1:
+ jsr ISCNTC
+ jmp LC5A9
+LE6D7:
+ ldx #$FF
+LE6D9:
+ jsr LE6E2
+ dey
+ bne LE6D9
+ dex
+ bne LE6D9
+LE6E2:
+ rts
+LE6E3:
+ lda #$0C
+LE6E5:
+ ldx #$FF
+ tay
+ lda $01
+ cmp #$03
+ beq LE6E2
+ tya
+LE6EF:
+ pha
+ lda $BFC0
+LE6F3:
+ lda $BFCD
+ and #$08
+ beq LE6F3
+ lda $BFC9
+ pha
+ lda #$FF
+ sta $BFC9
+ pla
+ cmp #$FC
+ pla
+ bcc LE6E5
+ dex
+ bne LE6EF
+ dey
+ bne LE6EF
+ rts
+LE710:
+ lda #$06
+ bne LE6E5
+LE714:
+ stx $13
+ sty $14
+ lda $16
+ cmp #$FD
+ beq LE749
+ lda #$00
+ sta $BFCB
+ lda #$20
+ sta $BFC0
+ lda #$40
+ sta $BFC2
+ jsr LE6D7
+ jsr LF000
+ lda $16
+ cmp #$FF
+ bne LE740
+ ldy #$20
+ jsr LF009
+ dec $16
+LE740:
+ ldy #$10
+ ldx #$FF
+ jsr LF009
+ dec $16
+LE749:
+ pla
+ sei
+ pha
+ cmp #$0A
+ beq LE771
+ ldx $0E
+ stx $50
+ jsr LF00F
+ cli
+ lda $01
+ cmp #$03
+ beq LE771
+ pla
+ pha
+ cmp #$0D
+ bne LE771
+ lda #$00
+ sta $16
+ sta $BFCB
+ jsr LE6D7
+ sta $BFC2
+LE771:
+ ldx $13
+ ldy $14
+ cli
+ pla
+ rts
+LE778:
+ lda #$40
+ sta $BFC0
+ jsr LF000
+ cli
+ lda $16
+ cmp #$01
+ bne LE78A
+ jsr LE6E3
+LE78A:
+ jsr LE710
+ lda $01
+ cmp #$03
+ beq LE7CE
+LE793:
+ lda $50
+ pha
+ lda $51
+ pha
+ lda $0E
+ sta $50
+ sei
+ jsr LF018
+ cli
+ tay
+ pla
+ sta $51
+ pla
+ sta $50
+ bcs LE7BD
+ lda #$00
+ sta $16
+ ldx #$06
+LE7B1:
+ lda LE7DC,x ; "PARITY"
+ jsr LFE75
+ dex
+ bpl LE7B1
+ inx
+ beq LE7CE
+LE7BD:
+ lda $01
+ cmp #$03
+ beq LE7CE
+ cpy #$0D
+ beq LE7CE
+ sty $35,x
+ inx
+ cpx #$4F
+ bne LE793
+LE7CE:
+ lda #$00
+ sta $BFCB
+ sta $BFC2
+ sta $16
+ cli
+ lda #$0D
+ rts
+LE7DC:
+ .byte "YTIRAP"
+ .byte $0D,$FF,$FF,$FF,$FF,$FF,$FF,$FF
+ .byte $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
+ .byte $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
+ .byte $FF,$FF,$FF,$FF,$FF,$FF
diff --git a/msbasic/microtan_iscntc.s b/msbasic/microtan_iscntc.s
new file mode 100644
index 0000000..37b378b
--- /dev/null
+++ b/msbasic/microtan_iscntc.s
@@ -0,0 +1,12 @@
+.segment "CODE"
+ISCNTC:
+ lda $01
+ cmp #$03
+ beq LC6EF
+ lda #$01
+ rts
+LC6EF:
+ nop
+ nop
+ cmp #$03
+;!!! runs into "STOP"
\ No newline at end of file
diff --git a/msbasic/microtan_loadsave.s b/msbasic/microtan_loadsave.s
new file mode 100644
index 0000000..13693d5
--- /dev/null
+++ b/msbasic/microtan_loadsave.s
@@ -0,0 +1,75 @@
+.segment "CODE"
+
+SAVE:
+ ldy #$00
+ beq LC74D
+LC74B:
+ ldy #$01
+LC74D:
+ ldx #$4C
+LC74F:
+ lda $13,x
+ pha
+ dex
+ bpl LC74F
+ ldx #$03
+LC757:
+ lda TXTTAB,x
+ sta GOSTROUT+2,x
+ dex
+ bpl LC757
+ jmp LE219
+ nop
+ nop
+ nop
+LC764:
+ tya
+ pha
+ ldy $03
+ lda #$FF
+ sta ($0A),y
+ pla
+ tay
+ jsr LFDFA
+ lda $01
+ jsr LC7A5
+ rts
+ .byte "DED"
+ .byte $0D,$0A
+ .byte "OK"
+ .byte $0D,$0A,$00
+ .byte "SAVED"
+ .byte $0D,$0A,$00
+LOAD:
+ jsr LC74B
+ ldx #$FF
+ tsx
+ lda #$4F
+ jsr LFE75
+ lda #$4B
+ jsr LFE75
+ jsr LFE73
+ lda VARTAB
+ tax
+ ldy VARTAB+1
+ jmp FIX_LINKS
+ nop
+LC7A5:
+ pha
+ cmp #$0A
+ beq LC7AD
+ jsr LFE75
+LC7AD:
+ tya
+ pha
+ ldy $03
+ lda #$20
+ sta ($0A),y
+ pla
+ tay
+ pla
+ rts
+ inc $8A17
+ stx VARTAB
+ sty VARTAB+1
+ jmp FIX_LINKS
diff --git a/msbasic/misc1.s b/msbasic/misc1.s
new file mode 100644
index 0000000..8b03b9a
--- /dev/null
+++ b/msbasic/misc1.s
@@ -0,0 +1,233 @@
+.segment "CODE"
+
+; ----------------------------------------------------------------------------
+; CONVERT LINE NUMBER
+; ----------------------------------------------------------------------------
+LINGET:
+ ldx #$00
+ stx LINNUM
+ stx LINNUM+1
+L28BE:
+ bcs L28B7
+ sbc #$2F
+ sta CHARAC
+ lda LINNUM+1
+ sta INDEX
+ cmp #$19
+ bcs L28A0
+; <<<<>>>>
+; NOTE THAT IF (A) = $AB ON THE LINE ABOVE,
+; ON.1 WILL COMPARE = AND CAUSE A CATASTROPHIC
+; JUMP TO $22D9 (FOR GOTO), OR OTHER LOCATIONS
+; FOR OTHER CALLS TO LINGET.
+;
+; YOU CAN SEE THIS IS YOU FIRST PUT "BRK" IN $22D9,
+; THEN TYPE "GO TO 437761".
+;
+; ANY VALUE FROM 437760 THROUGH 440319 WILL CAUSE
+; THE PROBLEM. ($AB00 - $ABFF)
+; <<<<>>>>
+ lda LINNUM
+ asl a
+ rol INDEX
+ asl a
+ rol INDEX
+ adc LINNUM
+ sta LINNUM
+ lda INDEX
+ adc LINNUM+1
+ sta LINNUM+1
+ asl LINNUM
+ rol LINNUM+1
+ lda LINNUM
+ adc CHARAC
+ sta LINNUM
+ bcc L28EC
+ inc LINNUM+1
+L28EC:
+ jsr CHRGET
+ jmp L28BE
+
+; ----------------------------------------------------------------------------
+; "LET" STATEMENT
+;
+; LET =
+; =
+; ----------------------------------------------------------------------------
+LET:
+ jsr PTRGET
+ sta FORPNT
+ sty FORPNT+1
+ lda #TOKEN_EQUAL
+ jsr SYNCHR
+.ifndef CONFIG_SMALL
+ lda VALTYP+1
+ pha
+.endif
+ lda VALTYP
+ pha
+ jsr FRMEVL
+ pla
+ rol a
+ jsr CHKVAL
+ bne LETSTRING
+.ifndef CONFIG_SMALL
+ pla
+LET2:
+ bpl L2923
+ jsr ROUND_FAC
+ jsr AYINT
+ ldy #$00
+ lda FAC+3
+ sta (FORPNT),y
+ iny
+ lda FAC+4
+ sta (FORPNT),y
+ rts
+L2923:
+.endif
+
+; ----------------------------------------------------------------------------
+; REAL VARIABLE = EXPRESSION
+; ----------------------------------------------------------------------------
+ jmp SETFOR
+LETSTRING:
+.ifndef CONFIG_SMALL
+ pla
+.endif
+
+; ----------------------------------------------------------------------------
+; INSTALL STRING, DESCRIPTOR ADDRESS IS AT FAC+3,4
+; ----------------------------------------------------------------------------
+PUTSTR:
+.ifdef CONFIG_CBM_ALL
+ ldy FORPNT+1
+ .ifdef CBM1
+ cpy #$D0 ; TI$
+ .else
+ cpy #$DE
+ .endif
+ bne LC92B
+ jsr FREFAC
+ cmp #$06
+ .ifdef CBM2
+ bne IQERR1
+ .else
+ jne IQERR
+ .endif
+ ldy #$00
+ sty FAC
+ sty FACSIGN
+LC8E8:
+ sty STRNG2
+ jsr LC91C
+ jsr MUL10
+ inc STRNG2
+ ldy STRNG2
+ jsr LC91C
+ jsr COPY_FAC_TO_ARG_ROUNDED
+ tax
+ beq LC902
+ inx
+ txa
+ jsr LD9BF
+LC902:
+ ldy STRNG2
+ iny
+ cpy #$06
+ bne LC8E8
+ jsr MUL10
+ jsr QINT
+ ldx #$02
+ sei
+LC912:
+ lda FAC+2,x
+ sta TISTR,x
+ dex
+ bpl LC912
+ cli
+ rts
+LC91C:
+ lda (INDEX),y
+ jsr CHRGOT2
+ bcc LC926
+IQERR1:
+ jmp IQERR
+LC926:
+ sbc #$2F
+ jmp ADDACC
+LC92B:
+.endif
+ ldy #$02
+ lda (FAC_LAST-1),y
+ cmp FRETOP+1
+ bcc L2946
+ bne L2938
+ dey
+ lda (FAC_LAST-1),y
+ cmp FRETOP
+ bcc L2946
+L2938:
+ ldy FAC_LAST
+ cpy VARTAB+1
+ bcc L2946
+ bne L294D
+ lda FAC_LAST-1
+ cmp VARTAB
+ bcs L294D
+L2946:
+ lda FAC_LAST-1
+ ldy FAC_LAST
+ jmp L2963
+L294D:
+ ldy #$00
+ lda (FAC_LAST-1),y
+ jsr STRINI
+ lda DSCPTR
+ ldy DSCPTR+1
+ sta STRNG1
+ sty STRNG1+1
+ jsr MOVINS
+ lda #FAC
+ ldy #$00
+L2963:
+ sta DSCPTR
+ sty DSCPTR+1
+ jsr FRETMS
+ ldy #$00
+ lda (DSCPTR),y
+ sta (FORPNT),y
+ iny
+ lda (DSCPTR),y
+ sta (FORPNT),y
+ iny
+ lda (DSCPTR),y
+ sta (FORPNT),y
+RET5:
+ rts
+.ifdef AIM65
+LB89D:
+ cmp #$21
+ bne RET5
+ lda #$80
+ sta PRIFLG
+ jmp CHRGET
+.endif
+
+.ifdef CONFIG_FILE
+PRINTH:
+ jsr CMD
+ jmp LCAD6
+CMD:
+ jsr GETBYT
+ beq LC98F
+ lda #$2C
+ jsr SYNCHR
+LC98F:
+ php
+ jsr CHKOUT
+ stx CURDVC
+ plp
+ jmp PRINT
+.endif
+
diff --git a/msbasic/misc2.s b/msbasic/misc2.s
new file mode 100644
index 0000000..4f4a6c9
--- /dev/null
+++ b/msbasic/misc2.s
@@ -0,0 +1,174 @@
+.segment "CODE"
+
+; ----------------------------------------------------------------------------
+; "FRE" FUNCTION
+;
+; COLLECTS GARBAGE AND RETURNS # BYTES OF MEMORY LEFT
+; ----------------------------------------------------------------------------
+FRE:
+ lda VALTYP
+ beq L3188
+ jsr FREFAC
+L3188:
+ jsr GARBAG
+ sec
+ lda FRETOP
+ sbc STREND
+ tay
+ lda FRETOP+1
+ sbc STREND+1
+; FALL INTO GIVAYF TO FLOAT THE VALUE
+; NOTE THAT VALUES OVER 32767 WILL RETURN AS NEGATIVE
+
+; ----------------------------------------------------------------------------
+; FLOAT THE SIGNED INTEGER IN A,Y
+; ----------------------------------------------------------------------------
+GIVAYF:
+ ldx #$00
+ stx VALTYP
+ sta FAC+1
+ sty FAC+2
+ ldx #$90
+ jmp FLOAT1
+POS:
+ ldy POSX
+
+; ----------------------------------------------------------------------------
+; FLOAT (Y) INTO FAC, GIVING VALUE 0-255
+; ----------------------------------------------------------------------------
+SNGFLT:
+ lda #$00
+ beq GIVAYF
+
+; ----------------------------------------------------------------------------
+; CHECK FOR DIRECT OR RUNNING MODE
+; GIVING ERROR IF DIRECT MODE
+; ----------------------------------------------------------------------------
+ERRDIR:
+ ldx CURLIN+1
+ inx
+ bne RTS9
+ ldx #ERR_ILLDIR
+.ifdef CONFIG_2
+ .byte $2C
+LD288:
+ ldx #ERR_UNDEFFN
+.endif
+L31AF:
+ jmp ERROR
+DEF:
+ jsr FNC
+ jsr ERRDIR
+ jsr CHKOPN
+ lda #$80
+ sta SUBFLG
+ jsr PTRGET
+ jsr CHKNUM
+ jsr CHKCLS
+ lda #TOKEN_EQUAL
+ jsr SYNCHR
+.ifndef CONFIG_SMALL
+ pha
+.endif
+ lda VARPNT+1
+ pha
+ lda VARPNT
+ pha
+ lda TXTPTR+1
+ pha
+ lda TXTPTR
+ pha
+ jsr DATA
+ jmp L3250
+FNC:
+ lda #TOKEN_FN
+ jsr SYNCHR
+ ora #$80
+ sta SUBFLG
+ jsr PTRGET3
+ sta FNCNAM
+ sty FNCNAM+1
+ jmp CHKNUM
+L31F3:
+ jsr FNC
+ lda FNCNAM+1
+ pha
+ lda FNCNAM
+ pha
+ jsr PARCHK
+ jsr CHKNUM
+ pla
+ sta FNCNAM
+ pla
+ sta FNCNAM+1
+ ldy #$02
+.ifndef CONFIG_2
+ ldx #ERR_UNDEFFN
+.endif
+ lda (FNCNAM),y
+.ifndef CONFIG_2
+ beq L31AF
+.endif
+ sta VARPNT
+ tax
+ iny
+ lda (FNCNAM),y
+.ifdef CONFIG_2
+ beq LD288
+.endif
+ sta VARPNT+1
+.ifndef CONFIG_SMALL
+ iny
+.endif
+L3219:
+ lda (VARPNT),y
+ pha
+ dey
+ bpl L3219
+ ldy VARPNT+1
+ jsr STORE_FAC_AT_YX_ROUNDED
+ lda TXTPTR+1
+ pha
+ lda TXTPTR
+ pha
+ lda (FNCNAM),y
+ sta TXTPTR
+ iny
+ lda (FNCNAM),y
+ sta TXTPTR+1
+ lda VARPNT+1
+ pha
+ lda VARPNT
+ pha
+ jsr FRMNUM
+ pla
+ sta FNCNAM
+ pla
+ sta FNCNAM+1
+ jsr CHRGOT
+ beq L324A
+ jmp SYNERR
+L324A:
+ pla
+ sta TXTPTR
+ pla
+ sta TXTPTR+1
+L3250:
+ ldy #$00
+ pla
+ sta (FNCNAM),y
+ pla
+ iny
+ sta (FNCNAM),y
+ pla
+ iny
+ sta (FNCNAM),y
+ pla
+ iny
+ sta (FNCNAM),y
+.ifndef CONFIG_SMALL
+ pla
+ iny
+ sta (FNCNAM),y
+.endif
+ rts
diff --git a/msbasic/misc3.s b/msbasic/misc3.s
new file mode 100644
index 0000000..19b8c5b
--- /dev/null
+++ b/msbasic/misc3.s
@@ -0,0 +1,76 @@
+; KBD specific patches
+
+.segment "CODE"
+
+.ifdef KBD
+VARTAB_MINUS_2_TO_AY:
+ lda VARTAB
+ sec
+ sbc #$02
+ ldy VARTAB+1
+ bcs LF42C
+ dey
+LF42C:
+ rts
+
+; ----------------------------------------------------------------------------
+GET_UPPER:
+ lda INPUTBUFFERX,x
+LF430:
+ cmp #'a'
+ bcc LF43A
+ cmp #'z'+1
+ bcs LF43A
+LF438:
+ sbc #$1F
+LF43A:
+ rts
+
+; ----------------------------------------------------------------------------
+GETLN:
+ ldx #$5D
+LF43D:
+ txa
+ and #$7F
+ cmp $0340
+ beq LF44D
+ sta $0340
+ lda #$03
+ jsr LDE48
+LF44D:
+ jsr LDE7F
+ bne RTS4
+ cpx #$80
+ bcc LF44D
+RTS4:
+ rts
+
+; ----------------------------------------------------------------------------
+LF457:
+ lda TXTTAB
+ ldx TXTTAB+1
+LF45B:
+ sta JMPADRS+1
+ stx JMPADRS+2
+ ldy #$01
+ lda (JMPADRS+1),y
+ beq LF438
+ iny
+ iny
+ lda (JMPADRS+1),y
+ dey
+ cmp LINNUM+1
+ bne LF472
+ lda (JMPADRS+1),y
+ cmp LINNUM
+LF472:
+ bcs LF43A
+ dey
+ lda (JMPADRS+1),y
+ tax
+ dey
+ lda (JMPADRS+1),y
+ bcc LF45B
+LF47D:
+ jmp (JMPADRS+1)
+.endif
diff --git a/msbasic/msbasic.s b/msbasic/msbasic.s
new file mode 100644
index 0000000..e6a3348
--- /dev/null
+++ b/msbasic/msbasic.s
@@ -0,0 +1,34 @@
+.debuginfo +
+
+.setcpu "6502"
+.macpack longbranch
+
+.include "defines.s"
+.include "macros.s"
+.include "zeropage.s"
+
+.include "header.s"
+.include "token.s"
+.include "error.s"
+.include "message.s"
+.include "memory.s"
+.include "program.s"
+.include "flow1.s"
+.include "loadsave.s"
+.include "flow2.s"
+.include "misc1.s"
+.include "print.s"
+.include "input.s"
+.include "eval.s"
+.include "var.s"
+.include "array.s"
+.include "misc2.s"
+.include "string.s"
+.include "misc3.s"
+.include "poke.s"
+.include "float.s"
+.include "chrget.s"
+.include "rnd.s"
+.include "trig.s"
+.include "init.s"
+.include "extra.s"
diff --git a/msbasic/osi.cfg b/msbasic/osi.cfg
new file mode 100644
index 0000000..7665ff2
--- /dev/null
+++ b/msbasic/osi.cfg
@@ -0,0 +1,19 @@
+MEMORY {
+ ZP: start = $0000, size = $0100, type = rw;
+ BASROM: start = $A000, size = $3F00, fill = no, file = %O;
+ DUMMY: start = $0000, size = $00FF, file = "";
+}
+
+SEGMENTS {
+ ZEROPAGE: load = ZP, type = zp;
+ HEADER: load = BASROM, type = ro;
+ VECTORS: load = BASROM, type = ro;
+ KEYWORDS: load = BASROM, type = ro;
+ ERROR: load = BASROM, type = ro;
+ CODE: load = BASROM, type = ro;
+ CHRGET: load = BASROM, type = ro;
+ INIT: load = BASROM, type = ro;
+ EXTRA: load = BASROM, type = ro;
+ DUMMY: load = DUMMY; # don't include
+}
+
diff --git a/msbasic/osi_iscntc.s b/msbasic/osi_iscntc.s
new file mode 100644
index 0000000..7533281
--- /dev/null
+++ b/msbasic/osi_iscntc.s
@@ -0,0 +1,12 @@
+.segment "CODE"
+ISCNTC:
+ jmp MONISCNTC
+ nop
+ nop
+ nop
+ nop
+ lsr a
+ bcc RET2
+ jsr GETLN
+ cmp #$03
+;!!! *used*to* run into "STOP"
\ No newline at end of file
diff --git a/msbasic/poke.s b/msbasic/poke.s
new file mode 100644
index 0000000..e6e1c1e
--- /dev/null
+++ b/msbasic/poke.s
@@ -0,0 +1,118 @@
+.segment "CODE"
+
+.ifndef CONFIG_NO_POKE
+; ----------------------------------------------------------------------------
+; EVALUATE "EXP1,EXP2"
+;
+; CONVERT EXP1 TO 16-BIT NUMBER IN LINNUM
+; CONVERT EXP2 TO 8-BIT NUMBER IN X-REG
+; ----------------------------------------------------------------------------
+GTNUM:
+ jsr FRMNUM
+ jsr GETADR
+
+; ----------------------------------------------------------------------------
+; EVALUATE ",EXPRESSION"
+; CONVERT EXPRESSION TO SINGLE BYTE IN X-REG
+; ----------------------------------------------------------------------------
+COMBYTE:
+ jsr CHKCOM
+ jmp GETBYT
+
+; ----------------------------------------------------------------------------
+; CONVERT (FAC) TO A 16-BIT VALUE IN LINNUM
+; ----------------------------------------------------------------------------
+GETADR:
+ lda FACSIGN
+ .ifdef APPLE
+ nop ; PATCH
+ nop
+ .else
+ bmi GOIQ
+ .endif
+ lda FAC
+ cmp #$91
+ bcs GOIQ
+ jsr QINT
+ lda FAC_LAST-1
+ ldy FAC_LAST
+ sty LINNUM
+ sta LINNUM+1
+ rts
+
+; ----------------------------------------------------------------------------
+; "PEEK" FUNCTION
+; ----------------------------------------------------------------------------
+PEEK:
+.ifdef CONFIG_PEEK_SAVE_LINNUM
+ lda LINNUM+1
+ pha
+ lda LINNUM
+ pha
+.endif
+ jsr GETADR
+ ldy #$00
+.ifdef CBM1
+; disallow PEEK between $C000 and $DFFF
+ cmp #$C0
+ bcc LD6F3
+ cmp #$E1
+ bcc LD6F6
+LD6F3:
+.endif
+.ifdef CBM2
+ nop ; patch that disables the compares above
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+.endif
+ lda (LINNUM),y
+ tay
+.ifdef CONFIG_PEEK_SAVE_LINNUM
+ pla
+ sta LINNUM
+ pla
+ sta LINNUM+1
+.endif
+LD6F6:
+ jmp SNGFLT
+
+; ----------------------------------------------------------------------------
+; "POKE" STATEMENT
+; ----------------------------------------------------------------------------
+POKE:
+ jsr GTNUM
+ txa
+ ldy #$00
+ sta (LINNUM),y
+ rts
+
+; ----------------------------------------------------------------------------
+; "WAIT" STATEMENT
+; ----------------------------------------------------------------------------
+WAIT:
+ jsr GTNUM
+ stx FORPNT
+ ldx #$00
+ jsr CHRGOT
+.ifdef CONFIG_EASTER_EGG
+ beq EASTER_EGG
+.else
+ beq L3628
+.endif
+ jsr COMBYTE
+L3628:
+ stx FORPNT+1
+ ldy #$00
+L362C:
+ lda (LINNUM),y
+ eor FORPNT+1
+ and FORPNT
+ beq L362C
+RTS3:
+ rts
+.endif
diff --git a/msbasic/print.s b/msbasic/print.s
new file mode 100644
index 0000000..6561348
--- /dev/null
+++ b/msbasic/print.s
@@ -0,0 +1,410 @@
+.segment "CODE"
+
+.ifdef AIM65
+PRINT:
+ lda PRIFLG
+ sta ZBE
+ jsr L297E
+LB8B1:
+ lda ZBE
+ sta PRIFLG
+ rts
+.endif
+
+PRSTRING:
+ jsr STRPRT
+L297E:
+ jsr CHRGOT
+
+; ----------------------------------------------------------------------------
+; "PRINT" STATEMENT
+; ----------------------------------------------------------------------------
+.ifndef AIM65
+PRINT:
+.endif
+ beq CRDO
+PRINT2:
+ beq L29DD
+.ifdef AIM65
+ jsr LB89D
+ beq L29DD
+.endif
+ cmp #TOKEN_TAB
+ beq L29F5
+ cmp #TOKEN_SPC
+.ifdef CONFIG_2
+ clc ; also AppleSoft II
+.endif
+ beq L29F5
+ cmp #','
+; Pre-KIM had no CLC. KIM added the CLC
+; here. Post-KIM moved the CLC up...
+; (makes no sense on KIM, liveness = 0)
+.if .def(CONFIG_11A) && (!.def(CONFIG_2))
+ clc
+.endif
+ beq L29DE
+ cmp #$3B
+ beq L2A0D
+ jsr FRMEVL
+ bit VALTYP
+ bmi PRSTRING
+ jsr FOUT
+ jsr STRLIT
+.ifndef CONFIG_NO_CR
+ ldy #$00
+ lda (FAC_LAST-1),y
+ clc
+ adc POSX
+ .ifdef KBD
+ cmp #$28
+ .else
+ cmp Z17
+ .endif
+ bcc L29B1
+ jsr CRDO
+L29B1:
+.endif
+ jsr STRPRT
+.ifdef KBD
+ jmp L297E
+.else
+ jsr OUTSP
+ bne L297E ; branch always
+.endif
+
+.ifdef KBD
+; PATCHES
+LE86C:
+ pla
+ jmp CONTROL_C_TYPED
+LE870:
+ jsr GETBYT
+ txa
+LE874:
+ beq LE878
+ bpl LE8F2
+LE878:
+ jmp IQERR
+; PATCHES
+.endif
+
+
+
+.ifndef KBD
+L29B9:
+ .ifdef CBM2
+ lda #$00
+ sta INPUTBUFFER,x
+ ldx #<(INPUTBUFFER-1)
+ ldy #>(INPUTBUFFER-1)
+ .else
+ .ifndef APPLE
+ ldy #$00
+ sty INPUTBUFFER,x
+ ldx #LINNUM+1
+ .endif
+ .if .def(MICROTAN) || .def(SYM1)
+ bne CRDO2
+ .endif
+ .endif
+ .ifdef CONFIG_FILE
+ lda CURDVC
+ bne L29DD
+ .endif
+.endif
+
+
+CRDO:
+.if .def(CONFIG_PRINTNULLS) && .def(CONFIG_FILE)
+ lda CURDVC
+ bne LC9D8
+ sta POSX
+LC9D8:
+.endif
+ lda #CRLF_1
+.ifndef CONFIG_CBM_ALL
+ sta POSX
+.endif
+ jsr OUTDO
+CRDO2:
+ lda #CRLF_2
+ jsr OUTDO
+
+PRINTNULLS:
+.if .def(KBD) || .def(AIM65)
+ lda #$00
+ sta POSX
+ eor #$FF
+.else
+ .if .def(CONFIG_NULL) || .def(CONFIG_PRINTNULLS)
+ .ifdef CONFIG_FILE
+ ; Although there is no statement for it,
+ ; CBM1 had NULL support and ignores
+ ; it when not targeting the screen,
+ ; CBM2 dropped it completely.
+ lda CURDVC
+ bne L29DD
+ .endif
+ txa
+ pha
+ ldx Z15
+ beq L29D9
+ .ifdef SYM1
+ lda #$FF
+ .else
+ lda #$00
+ .endif
+L29D3:
+ jsr OUTDO
+ dex
+ bne L29D3
+L29D9:
+ stx POSX
+ pla
+ tax
+ .else
+ .ifndef CONFIG_2
+ lda #$00
+ sta POSX
+ .endif
+ eor #$FF
+ .endif
+.endif
+L29DD:
+ rts
+L29DE:
+ lda POSX
+.ifndef CONFIG_NO_CR
+ .ifdef KBD
+ cmp #$1A
+ .else
+ cmp Z18
+ .endif
+ bcc L29EA
+ jsr CRDO
+ jmp L2A0D
+L29EA:
+.endif
+ sec
+L29EB:
+.if .def(CONFIG_CBM_ALL) || .def(AIM65)
+ sbc #$0A
+.else
+ .ifdef KBD
+ sbc #$0D
+ .else
+ sbc #$0E
+ .endif
+.endif
+ bcs L29EB
+ eor #$FF
+ adc #$01
+ bne L2A08
+L29F5:
+.ifdef CONFIG_11A
+ php
+.else
+ pha
+.endif
+ jsr GTBYTC
+ cmp #')'
+.ifdef CONFIG_11A
+ .ifdef CONFIG_2
+ bne SYNERR4
+ .else
+ jne SYNERR
+ .endif
+ plp
+ bcc L2A09
+.else
+ .ifdef CONFIG_11
+ jne SYNERR
+ .else
+ bne SYNERR4
+ .endif
+ pla
+ cmp #TOKEN_TAB
+ .ifdef CONFIG_11
+ bne L2A09
+ .else
+ bne L2A0A
+ .endif
+.endif
+ txa
+ sbc POSX
+ bcc L2A0D
+.ifndef CONFIG_11
+ beq L2A0D
+.endif
+L2A08:
+ tax
+.ifdef CONFIG_11
+L2A09:
+ inx
+.endif
+L2A0A:
+.ifndef CONFIG_11
+ jsr OUTSP
+.endif
+ dex
+.ifndef CONFIG_11
+ bne L2A0A
+.else
+ bne L2A13
+.endif
+L2A0D:
+ jsr CHRGET
+ jmp PRINT2
+.ifdef CONFIG_11
+L2A13:
+ jsr OUTSP
+ bne L2A0A
+.endif
+
+; ----------------------------------------------------------------------------
+; PRINT STRING AT (Y,A)
+; ----------------------------------------------------------------------------
+STROUT:
+ jsr STRLIT
+
+; ----------------------------------------------------------------------------
+; PRINT STRING AT (FACMO,FACLO)
+; ----------------------------------------------------------------------------
+STRPRT:
+ jsr FREFAC
+ tax
+ ldy #$00
+ inx
+L2A22:
+ dex
+ beq L29DD
+ lda (INDEX),y
+ jsr OUTDO
+ iny
+ cmp #$0D
+ bne L2A22
+ jsr PRINTNULLS
+ jmp L2A22
+; ----------------------------------------------------------------------------
+OUTSP:
+.ifdef CONFIG_FILE
+ .ifndef CBM1
+; on non-screen devices, print SPACE
+; instead of CRSR RIGHT
+ lda CURDVC
+ beq LCA40
+ lda #$20
+ .byte $2C
+LCA40:
+ .endif
+ lda #$1D ; CRSR RIGHT
+.else
+ lda #$20
+.endif
+ .byte $2C
+OUTQUES:
+ lda #$3F
+
+; ----------------------------------------------------------------------------
+; PRINT CHAR FROM (A)
+; ----------------------------------------------------------------------------
+OUTDO:
+.ifndef KBD
+ bit Z14
+ bmi L2A56
+.endif
+.if .def(CONFIG_PRINT_CR) || .def(CBM1)
+; Commodore forgot to remove this in CBM1
+ pha
+.endif
+.ifdef CBM1
+ cmp #$1D ; CRSR RIGHT
+ beq LCA6A
+ cmp #$9D ; CRSR LEFT
+ beq LCA5A
+ cmp #$14 ; DEL
+ bne LCA64
+LCA5A:
+ lda POSX
+ beq L2A4E
+ lda CURDVC
+ bne L2A4E
+ dec POSX
+LCA64:
+ and #$7F
+.endif
+.ifndef CBM2
+ cmp #$20
+ bcc L2A4E
+.endif
+LCA6A:
+.ifdef CONFIG_CBM1_PATCHES
+ lda CURDVC
+ jsr PATCH6
+ nop
+.endif
+.ifdef CONFIG_PRINT_CR
+ lda POSX
+ cmp Z17
+ bne L2A4C
+ .ifdef AIM65
+ lda #$00
+ sta POSX
+ .elseif .def(APPLE)
+ nop ; PATCH!
+ nop ; don't print CR
+ nop
+ .else
+ jsr CRDO
+ .endif
+L2A4C:
+.endif
+.ifndef CONFIG_CBM_ALL
+ inc POSX
+.endif
+L2A4E:
+.if .def(CONFIG_PRINT_CR) || .def(CBM1)
+; Commodore forgot to remove this in CBM1
+ pla
+.endif
+.ifdef CONFIG_MONCOUT_DESTROYS_Y
+ sty DIMFLG
+.endif
+.ifdef CONFIG_IO_MSB
+ ora #$80
+.endif
+ jsr MONCOUT
+.ifdef CONFIG_IO_MSB
+ and #$7F
+.endif
+.ifdef CONFIG_MONCOUT_DESTROYS_Y
+ ldy DIMFLG
+.endif
+.ifdef OSI
+ nop
+ nop
+ nop
+ nop
+.endif
+L2A56:
+ and #$FF
+LE8F2:
+ rts
+
+; ----------------------------------------------------------------------------
+; ???
+; ----------------------------------------------------------------------------
+.ifdef KBD
+LE8F3:
+ pha
+ lda $047F
+ clc
+ beq LE900
+ lda #$00
+ sta $047F
+ sec
+LE900:
+ pla
+ rts
+.endif
diff --git a/msbasic/program.s b/msbasic/program.s
new file mode 100644
index 0000000..07511c7
--- /dev/null
+++ b/msbasic/program.s
@@ -0,0 +1,811 @@
+; error
+; line input, line editing
+; tokenize
+; detokenize
+; BASIC program memory management
+
+; MICROTAN has some nonstandard extension to LIST here
+
+.segment "CODE"
+
+MEMERR:
+ ldx #ERR_MEMFULL
+
+; ----------------------------------------------------------------------------
+; HANDLE AN ERROR
+;
+; (X)=OFFSET IN ERROR MESSAGE TABLE
+; (ERRFLG) > 128 IF "ON ERR" TURNED ON
+; (CURLIN+1) = $FF IF IN DIRECT MODE
+; ----------------------------------------------------------------------------
+ERROR:
+ lsr Z14
+.ifdef CONFIG_FILE
+ lda CURDVC ; output
+ beq LC366 ; is screen
+ jsr CLRCH ; otherwise redirect output back to screen
+ lda #$00
+ sta CURDVC
+LC366:
+.endif
+ jsr CRDO
+ jsr OUTQUES
+L2329:
+ lda ERROR_MESSAGES,x
+.ifndef CONFIG_SMALL_ERROR
+ pha
+ and #$7F
+.endif
+ jsr OUTDO
+.ifdef CONFIG_SMALL_ERROR
+ lda ERROR_MESSAGES+1,x
+ .ifdef KBD
+ and #$7F
+ .endif
+ jsr OUTDO
+.else
+ inx
+ pla
+ bpl L2329
+.endif
+ jsr STKINI
+ lda #QT_ERROR
+
+; ----------------------------------------------------------------------------
+; PRINT STRING AT (Y,A)
+; PRINT CURRENT LINE # UNLESS IN DIRECT MODE
+; FALL INTO WARM RESTART
+; ----------------------------------------------------------------------------
+PRINT_ERROR_LINNUM:
+ jsr STROUT
+ ldy CURLIN+1
+ iny
+ beq RESTART
+ jsr INPRT
+
+; ----------------------------------------------------------------------------
+; WARM RESTART ENTRY
+; ----------------------------------------------------------------------------
+RESTART:
+.ifdef KBD
+ jsr CRDO
+ nop
+L2351X:
+ jsr OKPRT
+L2351:
+ jsr INLIN
+LE28E:
+ bpl RESTART
+.else
+ lsr Z14
+ .ifndef AIM65
+ lda #QT_OK
+ .ifdef CONFIG_CBM_ALL
+ jsr STROUT
+ .else
+ jsr GOSTROUT
+ .endif
+ .else
+ jsr GORESTART
+ .endif
+L2351:
+ jsr INLIN
+.endif
+ stx TXTPTR
+ sty TXTPTR+1
+ jsr CHRGET
+.ifdef CONFIG_11
+; bug in pre-1.1: CHRGET sets Z on '\0'
+; and ':' - a line starting with ':' in
+; direct mode gets ignored
+ tax
+.endif
+.ifdef KBD
+ beq L2351X
+.else
+ beq L2351
+.endif
+ ldx #$FF
+ stx CURLIN+1
+ bcc NUMBERED_LINE
+ jsr PARSE_INPUT_LINE
+ jmp NEWSTT2
+
+; ----------------------------------------------------------------------------
+; HANDLE NUMBERED LINE
+; ----------------------------------------------------------------------------
+NUMBERED_LINE:
+ jsr LINGET
+ jsr PARSE_INPUT_LINE
+ sty EOLPNTR
+.ifdef KBD
+ jsr FNDLIN2
+ lda JMPADRS+1
+ sta LOWTR
+ sta Z96
+ lda JMPADRS+2
+ sta LOWTR+1
+ sta Z96+1
+ lda LINNUM
+ sta L06FE
+ lda LINNUM+1
+ sta L06FE+1
+ inc LINNUM
+ bne LE2D2
+ inc LINNUM+1
+ bne LE2D2
+ jmp SYNERR
+LE2D2:
+ jsr LF457
+ ldx #Z96
+ jsr CMPJMPADRS
+ bcs LE2FD
+LE2DC:
+ ldx #$00
+ lda (JMPADRS+1,x)
+ sta (Z96,x)
+ inc JMPADRS+1
+ bne LE2E8
+ inc JMPADRS+2
+LE2E8:
+ inc Z96
+ bne LE2EE
+ inc Z96+1
+LE2EE:
+ ldx #VARTAB
+ jsr CMPJMPADRS
+ bne LE2DC
+ lda Z96
+ sta VARTAB
+ lda Z96+1
+ sta VARTAB+1
+LE2FD:
+ jsr SETPTRS
+ jsr LE33D
+ lda INPUTBUFFER
+LE306:
+ beq LE28E
+ cmp #$A5
+ beq LE306
+ clc
+.else
+ jsr FNDLIN
+ bcc PUT_NEW_LINE
+ ldy #$01
+ lda (LOWTR),y
+ sta INDEX+1
+ lda VARTAB
+ sta INDEX
+ lda LOWTR+1
+ sta DEST+1
+ lda LOWTR
+ dey
+ sbc (LOWTR),y
+ clc
+ adc VARTAB
+ sta VARTAB
+ sta DEST
+ lda VARTAB+1
+ adc #$FF
+ sta VARTAB+1
+ sbc LOWTR+1
+ tax
+ sec
+ lda LOWTR
+ sbc VARTAB
+ tay
+ bcs L23A5
+ inx
+ dec DEST+1
+L23A5:
+ clc
+ adc INDEX
+ bcc L23AD
+ dec INDEX+1
+ clc
+L23AD:
+ lda (INDEX),y
+ sta (DEST),y
+ iny
+ bne L23AD
+ inc INDEX+1
+ inc DEST+1
+ dex
+ bne L23AD
+.endif
+; ----------------------------------------------------------------------------
+PUT_NEW_LINE:
+.ifndef KBD
+ .ifdef CONFIG_2
+ jsr SETPTRS
+ jsr LE33D
+ lda INPUTBUFFER
+ beq L2351
+ clc
+ .else
+ lda INPUTBUFFER
+ beq FIX_LINKS
+ lda MEMSIZ
+ ldy MEMSIZ+1
+ sta FRETOP
+ sty FRETOP+1
+ .endif
+.endif
+ lda VARTAB
+ sta HIGHTR
+ adc EOLPNTR
+ sta HIGHDS
+ ldy VARTAB+1
+ sty HIGHTR+1
+ bcc L23D6
+ iny
+L23D6:
+ sty HIGHDS+1
+ jsr BLTU
+.ifdef CONFIG_INPUTBUFFER_0200
+ lda LINNUM
+ ldy LINNUM+1
+ sta INPUTBUFFER-2
+ sty INPUTBUFFER-1
+.endif
+ lda STREND
+ ldy STREND+1
+ sta VARTAB
+ sty VARTAB+1
+ ldy EOLPNTR
+ dey
+; ---COPY LINE INTO PROGRAM-------
+L23E6:
+ lda INPUTBUFFER-4,y
+ sta (LOWTR),y
+ dey
+ bpl L23E6
+
+; ----------------------------------------------------------------------------
+; CLEAR ALL VARIABLES
+; RE-ESTABLISH ALL FORWARD LINKS
+; ----------------------------------------------------------------------------
+FIX_LINKS:
+ jsr SETPTRS
+.ifdef CONFIG_2
+ jsr LE33D
+ jmp L2351
+LE33D:
+.endif
+ lda TXTTAB
+ ldy TXTTAB+1
+ sta INDEX
+ sty INDEX+1
+ clc
+L23FA:
+ ldy #$01
+ lda (INDEX),y
+.ifdef CONFIG_2
+ beq RET3
+.else
+ jeq L2351
+.endif
+ ldy #$04
+L2405:
+ iny
+ lda (INDEX),y
+ bne L2405
+ iny
+ tya
+ adc INDEX
+ tax
+ ldy #$00
+ sta (INDEX),y
+ lda INDEX+1
+ adc #$00
+ iny
+ sta (INDEX),y
+ stx INDEX
+ sta INDEX+1
+ bcc L23FA ; always
+
+; ----------------------------------------------------------------------------
+.ifdef KBD
+.include "kbd_loadsave.s"
+.endif
+
+.ifdef CONFIG_2
+; !!! kbd_loadsave.s requires an RTS here!
+RET3:
+ rts
+.endif
+
+.include "inline.s"
+
+; ----------------------------------------------------------------------------
+; TOKENIZE THE INPUT LINE
+; ----------------------------------------------------------------------------
+PARSE_INPUT_LINE:
+ ldx TXTPTR
+ ldy #$04
+ sty DATAFLG
+L246C:
+ lda INPUTBUFFERX,x
+.ifdef CONFIG_CBM_ALL
+ bpl LC49E
+ cmp #$FF
+ beq L24AC
+ inx
+ bne L246C
+LC49E:
+.endif
+ cmp #$20
+ beq L24AC
+ sta ENDCHR
+ cmp #$22
+ beq L24D0
+ bit DATAFLG
+ bvs L24AC
+ cmp #$3F
+ bne L2484
+ lda #TOKEN_PRINT
+ bne L24AC
+L2484:
+ cmp #$30
+ bcc L248C
+ cmp #$3C
+ bcc L24AC
+; ----------------------------------------------------------------------------
+; SEARCH TOKEN NAME TABLE FOR MATCH STARTING
+; WITH CURRENT CHAR FROM INPUT LINE
+; ----------------------------------------------------------------------------
+L248C:
+ sty STRNG2
+ ldy #$00
+ sty EOLPNTR
+ dey
+ stx TXTPTR
+ dex
+L2496:
+ iny
+L2497:
+ inx
+L2498:
+.ifdef KBD
+ jsr GET_UPPER
+.else
+ lda INPUTBUFFERX,x
+ .ifndef CONFIG_2
+ cmp #$20
+ beq L2497
+ .endif
+.endif
+ sec
+ sbc TOKEN_NAME_TABLE,y
+ beq L2496
+ cmp #$80
+ bne L24D7
+ ora EOLPNTR
+; ----------------------------------------------------------------------------
+; STORE CHARACTER OR TOKEN IN OUTPUT LINE
+; ----------------------------------------------------------------------------
+L24AA:
+ ldy STRNG2
+L24AC:
+ inx
+ iny
+ sta INPUTBUFFER-5,y
+ lda INPUTBUFFER-5,y
+ beq L24EA
+ sec
+ sbc #$3A
+ beq L24BF
+ cmp #$49
+ bne L24C1
+L24BF:
+ sta DATAFLG
+L24C1:
+ sec
+ sbc #TOKEN_REM-':'
+ bne L246C
+ sta ENDCHR
+; ----------------------------------------------------------------------------
+; HANDLE LITERAL (BETWEEN QUOTES) OR REMARK,
+; BY COPYING CHARS UP TO ENDCHR.
+; ----------------------------------------------------------------------------
+L24C8:
+ lda INPUTBUFFERX,x
+ beq L24AC
+ cmp ENDCHR
+ beq L24AC
+L24D0:
+ iny
+ sta INPUTBUFFER-5,y
+ inx
+ bne L24C8
+; ----------------------------------------------------------------------------
+; ADVANCE POINTER TO NEXT TOKEN NAME
+; ----------------------------------------------------------------------------
+L24D7:
+ ldx TXTPTR
+ inc EOLPNTR
+L24DB:
+ iny
+ lda MATHTBL+28+1,y
+ bpl L24DB
+ lda TOKEN_NAME_TABLE,y
+ bne L2498
+ lda INPUTBUFFERX,x
+ bpl L24AA
+; ---END OF LINE------------------
+L24EA:
+ sta INPUTBUFFER-3,y
+.ifdef CONFIG_NO_INPUTBUFFER_ZP
+ dec TXTPTR+1
+.endif
+ lda #<(INPUTBUFFER-1)
+ sta TXTPTR
+ rts
+
+; ----------------------------------------------------------------------------
+; SEARCH FOR LINE
+;
+; (LINNUM) = LINE # TO FIND
+; IF NOT FOUND: CARRY = 0
+; LOWTR POINTS AT NEXT LINE
+; IF FOUND: CARRY = 1
+; LOWTR POINTS AT LINE
+; ----------------------------------------------------------------------------
+FNDLIN:
+.ifdef KBD
+ jsr CHRGET
+ jmp LE444
+LE440:
+ php
+ jsr LINGET
+LE444:
+ jsr LF457
+ ldx #$FF
+ plp
+ beq LE464
+ jsr CHRGOT
+ beq L2520
+ cmp #$A5
+ bne L2520
+ jsr CHRGET
+ beq LE464
+ bcs LE461
+ jsr LINGET
+ beq L2520
+LE461:
+ jmp SYNERR
+LE464:
+ stx LINNUM
+ stx LINNUM+1
+.else
+ lda TXTTAB
+ ldx TXTTAB+1
+FL1:
+ ldy #$01
+ sta LOWTR
+ stx LOWTR+1
+ lda (LOWTR),y
+ beq L251F
+ iny
+ iny
+ lda LINNUM+1
+ cmp (LOWTR),y
+ bcc L2520
+ beq L250D
+ dey
+ bne L2516
+L250D:
+ lda LINNUM
+ dey
+ cmp (LOWTR),y
+ bcc L2520
+ beq L2520
+L2516:
+ dey
+ lda (LOWTR),y
+ tax
+ dey
+ lda (LOWTR),y
+ bcs FL1
+L251F:
+ clc
+.endif
+L2520:
+ rts
+
+; ----------------------------------------------------------------------------
+; "NEW" STATEMENT
+; ----------------------------------------------------------------------------
+NEW:
+ bne L2520
+SCRTCH:
+ lda #$00
+ tay
+ sta (TXTTAB),y
+ iny
+ sta (TXTTAB),y
+ lda TXTTAB
+.ifdef CONFIG_2
+ clc
+.endif
+ adc #$02
+ sta VARTAB
+ lda TXTTAB+1
+ adc #$00
+ sta VARTAB+1
+; ----------------------------------------------------------------------------
+SETPTRS:
+ jsr STXTPT
+.ifdef CONFIG_11A
+ lda #$00
+
+; ----------------------------------------------------------------------------
+; "CLEAR" STATEMENT
+; ----------------------------------------------------------------------------
+CLEAR:
+ bne L256A
+.endif
+CLEARC:
+.ifdef KBD
+ lda #CONST_MEMSIZ
+.else
+ lda MEMSIZ
+ ldy MEMSIZ+1
+.endif
+ sta FRETOP
+ sty FRETOP+1
+.ifdef CONFIG_CBM_ALL
+ jsr CLALL
+.endif
+ lda VARTAB
+ ldy VARTAB+1
+ sta ARYTAB
+ sty ARYTAB+1
+ sta STREND
+ sty STREND+1
+ jsr RESTORE
+; ----------------------------------------------------------------------------
+STKINI:
+ ldx #TEMPST
+ stx TEMPPT
+ pla
+.ifdef CONFIG_2
+ tay
+.else
+ sta STACK+STACK_TOP+1
+.endif
+ pla
+.ifndef CONFIG_2
+ sta STACK+STACK_TOP+2
+.endif
+ ldx #STACK_TOP
+ txs
+.ifdef CONFIG_2
+ pha
+ tya
+ pha
+.endif
+ lda #$00
+ sta OLDTEXT+1
+ sta SUBFLG
+L256A:
+ rts
+
+; ----------------------------------------------------------------------------
+; SET TXTPTR TO BEGINNING OF PROGRAM
+; ----------------------------------------------------------------------------
+STXTPT:
+ clc
+ lda TXTTAB
+ adc #$FF
+ sta TXTPTR
+ lda TXTTAB+1
+ adc #$FF
+ sta TXTPTR+1
+ rts
+
+; ----------------------------------------------------------------------------
+.ifdef KBD
+LE4C0:
+ ldy #LE444
+LE4C4:
+ jsr LFFD6
+ jsr LFFED
+ lda $0504
+ clc
+ adc #$08
+ sta $0504
+ rts
+
+CMPJMPADRS:
+ lda 1,x
+ cmp JMPADRS+2
+ bne LE4DE
+ lda 0,x
+ cmp JMPADRS+1
+LE4DE:
+ rts
+.endif
+
+; ----------------------------------------------------------------------------
+; "LIST" STATEMENT
+; ----------------------------------------------------------------------------
+LIST:
+.ifdef KBD
+ jsr LE440
+ bne LE4DE
+ pla
+ pla
+L25A6:
+ jsr CRDO
+.else
+ .ifdef AIM65
+ pha
+ lda #$00
+LB4BF:
+ sta INPUTFLG
+ pla
+ .endif
+ .ifdef MICROTAN
+ php
+ jmp LE21C ; patch
+LC57E:
+ .elseif .def(AIM65) || .def(SYM1)
+ php
+ jsr LINGET
+LC57E:
+ .else
+ bcc L2581
+ beq L2581
+ cmp #TOKEN_MINUS
+ bne L256A
+L2581:
+ jsr LINGET
+ .endif
+ jsr FNDLIN
+ .if .def(MICROTAN) || .def(AIM65) || .def(SYM1)
+ plp
+ beq L2598
+ .endif
+ jsr CHRGOT
+ .if .def(MICROTAN) || .def(AIM65) || .def(SYM1)
+ beq L25A6
+ .else
+ beq L2598
+ .endif
+ cmp #TOKEN_MINUS
+ bne L2520
+ jsr CHRGET
+ .if .def(MICROTAN) || .def(AIM65) || .def(SYM1)
+ beq L2598
+ jsr LINGET
+ beq L25A6
+ rts
+ .else
+ jsr LINGET
+ bne L2520
+ .endif
+L2598:
+ .if !(.def(MICROTAN) || .def(AIM65) || .def(SYM1))
+ pla
+ pla
+ lda LINNUM
+ ora LINNUM+1
+ bne L25A6
+ .endif
+ lda #$FF
+ sta LINNUM
+ sta LINNUM+1
+L25A6:
+ .if .def(MICROTAN) || .def(AIM65) || .def(SYM1)
+ pla
+ pla
+ .endif
+L25A6X:
+.endif
+ ldy #$01
+.ifdef CONFIG_DATAFLG
+ sty DATAFLG
+.endif
+ lda (LOWTRX),y
+ beq L25E5
+.ifdef MICROTAN
+ jmp LE21F
+LC5A9:
+.else
+ jsr ISCNTC
+.endif
+.ifndef KBD
+ jsr CRDO
+.endif
+ iny
+ lda (LOWTRX),y
+ tax
+ iny
+ lda (LOWTRX),y
+ cmp LINNUM+1
+ bne L25C1
+ cpx LINNUM
+ beq L25C3
+L25C1:
+ bcs L25E5
+; ---LIST ONE LINE----------------
+L25C3:
+ sty FORPNT
+ jsr LINPRT
+ lda #$20
+L25CA:
+ ldy FORPNT
+ and #$7F
+L25CE:
+ jsr OUTDO
+.ifdef CONFIG_DATAFLG
+ cmp #$22
+ bne LA519
+ lda DATAFLG
+ eor #$FF
+ sta DATAFLG
+LA519:
+.endif
+ iny
+.ifdef CONFIG_11
+ beq L25E5
+.endif
+ lda (LOWTRX),y
+ bne L25E8
+ tay
+ lda (LOWTRX),y
+ tax
+ iny
+ lda (LOWTRX),y
+ stx LOWTRX
+ sta LOWTRX+1
+.if .def(MICROTAN) || .def(AIM65) || .def(SYM1)
+ bne L25A6X
+.else
+ bne L25A6
+.endif
+L25E5:
+.ifdef AIM65
+ lda INPUTFLG
+ beq L25E5a
+ jsr CRDO
+ jsr CRDO
+ lda #$1a
+ jsr OUTDO
+ jsr $e50a
+L25E5a:
+.endif
+ jmp RESTART
+L25E8:
+ bpl L25CE
+.ifdef CONFIG_DATAFLG
+ cmp #$FF
+ beq L25CE
+ bit DATAFLG
+ bmi L25CE
+.endif
+ sec
+ sbc #$7F
+ tax
+ sty FORPNT
+ ldy #$FF
+L25F2:
+ dex
+ beq L25FD
+L25F5:
+ iny
+ lda TOKEN_NAME_TABLE,y
+ bpl L25F5
+ bmi L25F2
+L25FD:
+ iny
+ lda TOKEN_NAME_TABLE,y
+ bmi L25CA
+ jsr OUTDO
+ bne L25FD ; always
+
diff --git a/msbasic/rnd.s b/msbasic/rnd.s
new file mode 100644
index 0000000..7603444
--- /dev/null
+++ b/msbasic/rnd.s
@@ -0,0 +1,135 @@
+.segment "CODE"
+
+; ----------------------------------------------------------------------------
+; "RND" FUNCTION
+; ----------------------------------------------------------------------------
+
+.ifdef KBD
+RND:
+ ldx #$10
+ jsr SIGN
+ beq LFC26
+ bmi LFC10
+ lda RNDSEED
+ ldy RNDSEED+1
+LFBFA:
+ sta FAC+2
+ sty FAC+1
+LFBFE:
+ asl a
+ asl a
+ eor FAC+2
+ asl a
+ eor FAC+1
+ asl a
+ asl a
+ asl a
+ asl a
+ eor FAC+1
+ asl a
+ rol FAC+2
+ rol FAC+1
+LFC10:
+ lda FAC+2
+ dex
+ bne LFBFE
+ sta RNDSEED
+ sta FAC+3
+ lda FAC+1
+ sta RNDSEED+1
+ lda #$80
+ sta FAC
+ stx FACSIGN
+ jmp NORMALIZE_FAC2
+LFC26:
+ ldy $03CA
+ lda $03C7
+ ora #$01
+GOMOVMF:
+ bne LFBFA
+ .byte $F0
+.else
+; <<< THESE ARE MISSING ONE BYTE FOR FP VALUES >>>
+; (non CONFIG_SMALL)
+CONRND1:
+ .byte $98,$35,$44,$7A
+CONRND2:
+ .byte $68,$28,$B1,$46
+RND:
+ jsr SIGN
+.ifdef CONFIG_CBM_ALL
+ bmi L3F01
+ bne LDF63
+ lda ENTROPY
+ sta FAC+1
+ lda ENTROPY+4
+ sta FAC+2
+ lda ENTROPY+1
+ sta FAC+3
+ lda ENTROPY+5
+ sta FAC+4
+ jmp LDF88
+LDF63:
+.else
+ tax
+ bmi L3F01
+.endif
+ lda #RNDSEED
+ jsr LOAD_FAC_FROM_YA
+.ifndef CONFIG_CBM_ALL
+ txa
+ beq RTS19
+.endif
+ lda #CONRND1
+ jsr FMULT
+ lda #CONRND2
+ jsr FADD
+L3F01:
+ ldx FAC_LAST
+ lda FAC+1
+ sta FAC_LAST
+ stx FAC+1
+.ifdef CONFIG_CBM_ALL
+ ldx FAC+2
+ lda FAC+3
+ sta FAC+2
+ stx FAC+3
+LDF88:
+.endif
+ lda #$00
+ sta FACSIGN
+ lda FAC
+ sta FACEXTENSION
+ lda #$80
+ sta FAC
+ jsr NORMALIZE_FAC2
+ ldx #RNDSEED
+GOMOVMF:
+ jmp STORE_FAC_AT_YX_ROUNDED
+.endif
+
+.segment "CHRGET"
+; ----------------------------------------------------------------------------
+; INITIAL VALUE FOR RANDOM NUMBER, ALSO COPIED
+; IN ALONG WITH CHRGET, BUT ERRONEOUSLY:
+; <<< THE LAST BYTE IS NOT COPIED >>>
+; (on all non-CONFIG_SMALL)
+; ----------------------------------------------------------------------------
+GENERIC_RNDSEED:
+.ifndef KBD
+; random number seed
+ .ifdef CONFIG_SMALL
+ .byte $80,$4F,$C7,$52
+ .else
+ .ifdef CONFIG_11
+ .byte $80,$4F,$C7,$52,$58
+ .else
+ .byte $80,$4F,$C7,$52,$59
+ .endif
+ .endif
+.endif
+GENERIC_CHRGET_END:
diff --git a/msbasic/string.s b/msbasic/string.s
new file mode 100644
index 0000000..1f02458
--- /dev/null
+++ b/msbasic/string.s
@@ -0,0 +1,786 @@
+.segment "CODE"
+; ----------------------------------------------------------------------------
+; "STR$" FUNCTION
+; ----------------------------------------------------------------------------
+STR:
+ jsr CHKNUM
+ ldy #$00
+ jsr FOUT1
+ pla
+ pla
+LD353:
+ lda #<(STACK2-1)
+ ldy #>(STACK2-1)
+.if STACK2 > $0100
+ bne STRLIT
+.else
+ beq STRLIT
+.endif
+
+; ----------------------------------------------------------------------------
+; GET SPACE AND MAKE DESCRIPTOR FOR STRING WHOSE
+; ADDRESS IS IN FAC+3,4 AND WHOSE LENGTH IS IN A-REG
+; ----------------------------------------------------------------------------
+STRINI:
+ ldx FAC_LAST-1
+ ldy FAC_LAST
+ stx DSCPTR
+ sty DSCPTR+1
+
+; ----------------------------------------------------------------------------
+; GET SPACE AND MAKE DESCRIPTOR FOR STRING WHOSE
+; ADDRESS IS IN Y,X AND WHOSE LENGTH IS IN A-REG
+; ----------------------------------------------------------------------------
+STRSPA:
+ jsr GETSPA
+ stx FAC+1
+ sty FAC+2
+ sta FAC
+ rts
+
+; ----------------------------------------------------------------------------
+; BUILD A DESCRIPTOR FOR STRING STARTING AT Y,A
+; AND TERMINATED BY $00 OR QUOTATION MARK
+; RETURN WITH DESCRIPTOR IN A TEMPORARY
+; AND ADDRESS OF DESCRIPTOR IN FAC+3,4
+; ----------------------------------------------------------------------------
+STRLIT:
+ ldx #$22
+ stx CHARAC
+ stx ENDCHR
+
+; ----------------------------------------------------------------------------
+; BUILD A DESCRIPTOR FOR STRING STARTING AT Y,A
+; AND TERMINATED BY $00, (CHARAC), OR (ENDCHR)
+;
+; RETURN WITH DESCRIPTOR IN A TEMPORARY
+; AND ADDRESS OF DESCRIPTOR IN FAC+3,4
+; ----------------------------------------------------------------------------
+STRLT2:
+ sta STRNG1
+ sty STRNG1+1
+ sta FAC+1
+ sty FAC+2
+ ldy #$FF
+L3298:
+ iny
+ lda (STRNG1),y
+ beq L32A9
+ cmp CHARAC
+ beq L32A5
+ cmp ENDCHR
+ bne L3298
+L32A5:
+ cmp #$22
+ beq L32AA
+L32A9:
+ clc
+L32AA:
+ sty FAC
+ tya
+ adc STRNG1
+ sta STRNG2
+ ldx STRNG1+1
+ bcc L32B6
+ inx
+L32B6:
+ stx STRNG2+1
+ lda STRNG1+1
+.ifdef CONFIG_NO_INPUTBUFFER_ZP
+ beq LD399
+ cmp #>INPUTBUFFER
+.elseif .def(AIM65)
+ beq LD399
+ cmp #$01
+.endif
+ bne PUTNEW
+LD399:
+ tya
+ jsr STRINI
+ ldx STRNG1
+ ldy STRNG1+1
+ jsr MOVSTR
+
+; ----------------------------------------------------------------------------
+; STORE DESCRIPTOR IN TEMPORARY DESCRIPTOR STACK
+;
+; THE DESCRIPTOR IS NOW IN FAC, FAC+1, FAC+2
+; PUT ADDRESS OF TEMP DESCRIPTOR IN FAC+3,4
+; ----------------------------------------------------------------------------
+PUTNEW:
+ ldx TEMPPT
+ cpx #TEMPST+9
+ bne PUTEMP
+ ldx #ERR_FRMCPX
+JERR:
+ jmp ERROR
+PUTEMP:
+ lda FAC
+ sta 0,x
+ lda FAC+1
+ sta 1,x
+ lda FAC+2
+ sta 2,x
+ ldy #$00
+ stx FAC_LAST-1
+ sty FAC_LAST
+.ifdef CONFIG_2
+ sty FACEXTENSION
+.endif
+ dey
+ sty VALTYP
+ stx LASTPT
+ inx
+ inx
+ inx
+ stx TEMPPT
+ rts
+
+; ----------------------------------------------------------------------------
+; MAKE SPACE FOR STRING AT BOTTOM OF STRING SPACE
+; (A)=# BYTES SPACE TO MAKE
+;
+; RETURN WITH (A) SAME,
+; AND Y,X = ADDRESS OF SPACE ALLOCATED
+; ----------------------------------------------------------------------------
+GETSPA:
+ lsr DATAFLG
+L32F1:
+ pha
+ eor #$FF
+ sec
+ adc FRETOP
+ ldy FRETOP+1
+ bcs L32FC
+ dey
+L32FC:
+ cpy STREND+1
+ bcc L3311
+ bne L3306
+ cmp STREND
+ bcc L3311
+L3306:
+ sta FRETOP
+ sty FRETOP+1
+ sta FRESPC
+ sty FRESPC+1
+ tax
+ pla
+ rts
+L3311:
+ ldx #ERR_MEMFULL
+ lda DATAFLG
+ bmi JERR
+ jsr GARBAG
+ lda #$80
+ sta DATAFLG
+ pla
+ bne L32F1
+
+; ----------------------------------------------------------------------------
+; SHOVE ALL REFERENCED STRINGS AS HIGH AS POSSIBLE
+; IN MEMORY (AGAINST HIMEM), FREEING UP SPACE
+; BELOW STRING AREA DOWN TO STREND.
+; ----------------------------------------------------------------------------
+GARBAG:
+
+.ifdef CONST_MEMSIZ
+ ldx #CONST_MEMSIZ
+.else
+ ldx MEMSIZ
+ lda MEMSIZ+1
+.endif
+FINDHIGHESTSTRING:
+ stx FRETOP
+ sta FRETOP+1
+ ldy #$00
+ sty FNCNAM+1
+.ifdef CONFIG_2
+ sty FNCNAM ; GC bugfix!
+.endif
+ lda STREND
+ ldx STREND+1
+ sta LOWTR
+ stx LOWTR+1
+ lda #TEMPST
+ ldx #$00
+ sta INDEX
+ stx INDEX+1
+L333D:
+ cmp TEMPPT
+ beq L3346
+ jsr CHECK_VARIABLE
+ beq L333D
+L3346:
+ lda #BYTES_PER_VARIABLE
+ sta DSCLEN
+ lda VARTAB
+ ldx VARTAB+1
+ sta INDEX
+ stx INDEX+1
+L3352:
+ cpx ARYTAB+1
+ bne L335A
+ cmp ARYTAB
+ beq L335F
+L335A:
+ jsr CHECK_SIMPLE_VARIABLE
+ beq L3352
+L335F:
+ sta HIGHDS
+ stx HIGHDS+1
+ lda #$03 ; OSI GC bugfix -> $04 ???
+ sta DSCLEN
+L3367:
+ lda HIGHDS
+ ldx HIGHDS+1
+L336B:
+ cpx STREND+1
+ bne L3376
+ cmp STREND
+ bne L3376
+ jmp MOVE_HIGHEST_STRING_TO_TOP
+L3376:
+ sta INDEX
+ stx INDEX+1
+.ifdef CONFIG_SMALL
+ ldy #$01
+.else
+ ldy #$00
+ lda (INDEX),y
+ tax
+ iny
+.endif
+ lda (INDEX),y
+ php
+ iny
+ lda (INDEX),y
+ adc HIGHDS
+ sta HIGHDS
+ iny
+ lda (INDEX),y
+ adc HIGHDS+1
+ sta HIGHDS+1
+ plp
+ bpl L3367
+.ifndef CONFIG_SMALL
+ txa
+ bmi L3367
+.endif
+ iny
+ lda (INDEX),y
+.ifdef CONFIG_CBM1_PATCHES
+ jsr LE7F3 ; XXX patch, call into screen editor
+.else
+ .ifdef CONFIG_11
+ ldy #$00 ; GC bugfix
+ .endif
+ asl a
+ adc #$05
+.endif
+ adc INDEX
+ sta INDEX
+ bcc L33A7
+ inc INDEX+1
+L33A7:
+ ldx INDEX+1
+L33A9:
+ cpx HIGHDS+1
+ bne L33B1
+ cmp HIGHDS
+ beq L336B
+L33B1:
+ jsr CHECK_VARIABLE
+ beq L33A9
+
+; ----------------------------------------------------------------------------
+; PROCESS A SIMPLE VARIABLE
+; ----------------------------------------------------------------------------
+CHECK_SIMPLE_VARIABLE:
+.ifndef CONFIG_SMALL
+ lda (INDEX),y
+ bmi CHECK_BUMP
+.endif
+ iny
+ lda (INDEX),y
+ bpl CHECK_BUMP
+ iny
+
+; ----------------------------------------------------------------------------
+; IF STRING IS NOT EMPTY, CHECK IF IT IS HIGHEST
+; ----------------------------------------------------------------------------
+CHECK_VARIABLE:
+ lda (INDEX),y
+ beq CHECK_BUMP
+ iny
+ lda (INDEX),y
+ tax
+ iny
+ lda (INDEX),y
+ cmp FRETOP+1
+ bcc L33D5
+ bne CHECK_BUMP
+ cpx FRETOP
+ bcs CHECK_BUMP
+L33D5:
+ cmp LOWTR+1
+ bcc CHECK_BUMP
+ bne L33DF
+ cpx LOWTR
+ bcc CHECK_BUMP
+L33DF:
+ stx LOWTR
+ sta LOWTR+1
+ lda INDEX
+ ldx INDEX+1
+ sta FNCNAM
+ stx FNCNAM+1
+ lda DSCLEN
+ sta Z52
+
+; ----------------------------------------------------------------------------
+; ADD (DSCLEN) TO PNTR IN INDEX
+; RETURN WITH Y=0, PNTR ALSO IN X,A
+; ----------------------------------------------------------------------------
+CHECK_BUMP:
+ lda DSCLEN
+ clc
+ adc INDEX
+ sta INDEX
+ bcc L33FA
+ inc INDEX+1
+L33FA:
+ ldx INDEX+1
+ ldy #$00
+ rts
+
+; ----------------------------------------------------------------------------
+; FOUND HIGHEST NON-EMPTY STRING, SO MOVE IT
+; TO TOP AND GO BACK FOR ANOTHER
+; ----------------------------------------------------------------------------
+MOVE_HIGHEST_STRING_TO_TOP:
+.ifdef CONFIG_2
+ lda FNCNAM+1 ; GC bugfix
+ ora FNCNAM
+.else
+ ldx FNCNAM+1
+.endif
+ beq L33FA
+ lda Z52
+.ifndef CONFIG_10A
+ sbc #$03
+.else
+ and #$04
+.endif
+ lsr a
+ tay
+ sta Z52
+ lda (FNCNAM),y
+ adc LOWTR
+ sta HIGHTR
+ lda LOWTR+1
+ adc #$00
+ sta HIGHTR+1
+ lda FRETOP
+ ldx FRETOP+1
+ sta HIGHDS
+ stx HIGHDS+1
+ jsr BLTU2
+ ldy Z52
+ iny
+ lda HIGHDS
+ sta (FNCNAM),y
+ tax
+ inc HIGHDS+1
+ lda HIGHDS+1
+ iny
+ sta (FNCNAM),y
+ jmp FINDHIGHESTSTRING
+
+; ----------------------------------------------------------------------------
+; CONCATENATE TWO STRINGS
+; ----------------------------------------------------------------------------
+CAT:
+ lda FAC_LAST
+ pha
+ lda FAC_LAST-1
+ pha
+ jsr FRM_ELEMENT
+ jsr CHKSTR
+ pla
+ sta STRNG1
+ pla
+ sta STRNG1+1
+ ldy #$00
+ lda (STRNG1),y
+ clc
+ adc (FAC_LAST-1),y
+ bcc L3454
+ ldx #ERR_STRLONG
+ jmp ERROR
+L3454:
+ jsr STRINI
+ jsr MOVINS
+ lda DSCPTR
+ ldy DSCPTR+1
+ jsr FRETMP
+ jsr MOVSTR1
+ lda STRNG1
+ ldy STRNG1+1
+ jsr FRETMP
+ jsr PUTNEW
+ jmp FRMEVL2
+
+; ----------------------------------------------------------------------------
+; GET STRING DESCRIPTOR POINTED AT BY (STRNG1)
+; AND MOVE DESCRIBED STRING TO (FRESPC)
+; ----------------------------------------------------------------------------
+MOVINS:
+ ldy #$00
+ lda (STRNG1),y
+ pha
+ iny
+ lda (STRNG1),y
+ tax
+ iny
+ lda (STRNG1),y
+ tay
+ pla
+
+; ----------------------------------------------------------------------------
+; MOVE STRING AT (Y,X) WITH LENGTH (A)
+; TO DESTINATION WHOSE ADDRESS IS IN FRESPC,FRESPC+1
+; ----------------------------------------------------------------------------
+MOVSTR:
+ stx INDEX
+ sty INDEX+1
+MOVSTR1:
+ tay
+ beq L3490
+ pha
+L3487:
+ dey
+ lda (INDEX),y
+ sta (FRESPC),y
+ tya
+ bne L3487
+ pla
+L3490:
+ clc
+ adc FRESPC
+ sta FRESPC
+ bcc L3499
+ inc FRESPC+1
+L3499:
+ rts
+
+; ----------------------------------------------------------------------------
+; IF (FAC) IS A TEMPORARY STRING, RELEASE DESCRIPTOR
+; ----------------------------------------------------------------------------
+FRESTR:
+ jsr CHKSTR
+
+; ----------------------------------------------------------------------------
+; IF STRING DESCRIPTOR POINTED TO BY FAC+3,4 IS
+; A TEMPORARY STRING, RELEASE IT.
+; ----------------------------------------------------------------------------
+FREFAC:
+ lda FAC_LAST-1
+ ldy FAC_LAST
+
+; ----------------------------------------------------------------------------
+; IF STRING DESCRIPTOR WHOSE ADDRESS IS IN Y,A IS
+; A TEMPORARY STRING, RELEASE IT.
+; ----------------------------------------------------------------------------
+FRETMP:
+ sta INDEX
+ sty INDEX+1
+ jsr FRETMS
+ php
+ ldy #$00
+ lda (INDEX),y
+ pha
+ iny
+ lda (INDEX),y
+ tax
+ iny
+ lda (INDEX),y
+ tay
+ pla
+ plp
+ bne L34CD
+ cpy FRETOP+1
+ bne L34CD
+ cpx FRETOP
+ bne L34CD
+ pha
+ clc
+ adc FRETOP
+ sta FRETOP
+ bcc L34CC
+ inc FRETOP+1
+L34CC:
+ pla
+L34CD:
+ stx INDEX
+ sty INDEX+1
+ rts
+
+; ----------------------------------------------------------------------------
+; RELEASE TEMPORARY DESCRIPTOR IF Y,A = LASTPT
+; ----------------------------------------------------------------------------
+FRETMS:
+.ifdef KBD
+ cpy #$00
+.else
+ cpy LASTPT+1
+.endif
+ bne L34E2
+ cmp LASTPT
+ bne L34E2
+ sta TEMPPT
+ sbc #$03
+ sta LASTPT
+ ldy #$00
+L34E2:
+ rts
+
+; ----------------------------------------------------------------------------
+; "CHR$" FUNCTION
+; ----------------------------------------------------------------------------
+CHRSTR:
+ jsr CONINT
+ txa
+ pha
+ lda #$01
+ jsr STRSPA
+ pla
+ ldy #$00
+ sta (FAC+1),y
+ pla
+ pla
+ jmp PUTNEW
+
+; ----------------------------------------------------------------------------
+; "LEFT$" FUNCTION
+; ----------------------------------------------------------------------------
+LEFTSTR:
+ jsr SUBSTRING_SETUP
+ cmp (DSCPTR),y
+ tya
+SUBSTRING1:
+ bcc L3503
+ lda (DSCPTR),y
+ tax
+ tya
+L3503:
+ pha
+SUBSTRING2:
+ txa
+SUBSTRING3:
+ pha
+ jsr STRSPA
+ lda DSCPTR
+ ldy DSCPTR+1
+ jsr FRETMP
+ pla
+ tay
+ pla
+ clc
+ adc INDEX
+ sta INDEX
+ bcc L351C
+ inc INDEX+1
+L351C:
+ tya
+ jsr MOVSTR1
+ jmp PUTNEW
+
+; ----------------------------------------------------------------------------
+; "RIGHT$" FUNCTION
+; ----------------------------------------------------------------------------
+RIGHTSTR:
+ jsr SUBSTRING_SETUP
+ clc
+ sbc (DSCPTR),y
+ eor #$FF
+ jmp SUBSTRING1
+
+; ----------------------------------------------------------------------------
+; "MID$" FUNCTION
+; ----------------------------------------------------------------------------
+MIDSTR:
+ lda #$FF
+ sta FAC_LAST
+ jsr CHRGOT
+ cmp #$29
+ beq L353F
+ jsr CHKCOM
+ jsr GETBYT
+L353F:
+ jsr SUBSTRING_SETUP
+.ifdef CONFIG_2
+ beq GOIQ
+.endif
+ dex
+ txa
+ pha
+ clc
+ ldx #$00
+ sbc (DSCPTR),y
+ bcs SUBSTRING2
+ eor #$FF
+ cmp FAC_LAST
+ bcc SUBSTRING3
+ lda FAC_LAST
+ bcs SUBSTRING3
+
+; ----------------------------------------------------------------------------
+; COMMON SETUP ROUTINE FOR LEFT$, RIGHT$, MID$:
+; REQUIRE ")"; POP RETURN ADRS, GET DESCRIPTOR
+; ADDRESS, GET 1ST PARAMETER OF COMMAND
+; ----------------------------------------------------------------------------
+SUBSTRING_SETUP:
+ jsr CHKCLS
+ pla
+.ifndef CONFIG_11
+ sta JMPADRS+1
+ pla
+ sta JMPADRS+2
+.else
+ tay
+ pla
+ sta Z52
+.endif
+ pla
+ pla
+ pla
+ tax
+ pla
+ sta DSCPTR
+ pla
+ sta DSCPTR+1
+.ifdef CONFIG_11
+ lda Z52
+ pha
+ tya
+ pha
+.endif
+ ldy #$00
+ txa
+.ifndef CONFIG_2
+ beq GOIQ
+.endif
+.ifndef CONFIG_11
+ inc JMPADRS+1
+ jmp (JMPADRS+1)
+.else
+ rts
+.endif
+
+; ----------------------------------------------------------------------------
+; "LEN" FUNCTION
+; ----------------------------------------------------------------------------
+LEN:
+ jsr GETSTR
+SNGFLT1:
+ jmp SNGFLT
+
+; ----------------------------------------------------------------------------
+; IF LAST RESULT IS A TEMPORARY STRING, FREE IT
+; MAKE VALTYP NUMERIC, RETURN LENGTH IN Y-REG
+; ----------------------------------------------------------------------------
+GETSTR:
+ jsr FRESTR
+ ldx #$00
+ stx VALTYP
+ tay
+ rts
+
+; ----------------------------------------------------------------------------
+; "ASC" FUNCTION
+; ----------------------------------------------------------------------------
+ASC:
+ jsr GETSTR
+ beq GOIQ
+ ldy #$00
+ lda (INDEX),y
+ tay
+.ifndef CONFIG_11A
+ jmp SNGFLT1
+.else
+ jmp SNGFLT
+.endif
+; ----------------------------------------------------------------------------
+GOIQ:
+ jmp IQERR
+
+; ----------------------------------------------------------------------------
+; SCAN TO NEXT CHARACTER AND CONVERT EXPRESSION
+; TO SINGLE BYTE IN X-REG
+; ----------------------------------------------------------------------------
+GTBYTC:
+ jsr CHRGET
+
+; ----------------------------------------------------------------------------
+; EVALUATE EXPRESSION AT TXTPTR, AND
+; CONVERT IT TO SINGLE BYTE IN X-REG
+; ----------------------------------------------------------------------------
+GETBYT:
+ jsr FRMNUM
+
+; ----------------------------------------------------------------------------
+; CONVERT (FAC) TO SINGLE BYTE INTEGER IN X-REG
+; ----------------------------------------------------------------------------
+CONINT:
+ jsr MKINT
+ ldx FAC_LAST-1
+ bne GOIQ
+ ldx FAC_LAST
+ jmp CHRGOT
+
+; ----------------------------------------------------------------------------
+; "VAL" FUNCTION
+; ----------------------------------------------------------------------------
+VAL:
+ jsr GETSTR
+ bne L35AC
+ jmp ZERO_FAC
+L35AC:
+ ldx TXTPTR
+ ldy TXTPTR+1
+ stx STRNG2
+ sty STRNG2+1
+ ldx INDEX
+ stx TXTPTR
+ clc
+ adc INDEX
+ sta DEST
+ ldx INDEX+1
+ stx TXTPTR+1
+ bcc L35C4
+ inx
+L35C4:
+ stx DEST+1
+ ldy #$00
+ lda (DEST),y
+ pha
+ lda #$00
+ sta (DEST),y
+ jsr CHRGOT
+ jsr FIN
+ pla
+ ldy #$00
+ sta (DEST),y
+
+; ----------------------------------------------------------------------------
+; COPY STRNG2 INTO TXTPTR
+; ----------------------------------------------------------------------------
+POINT:
+ ldx STRNG2
+ ldy STRNG2+1
+ stx TXTPTR
+ sty TXTPTR+1
+ rts
+
diff --git a/msbasic/sym1.cfg b/msbasic/sym1.cfg
new file mode 100644
index 0000000..650ddb7
--- /dev/null
+++ b/msbasic/sym1.cfg
@@ -0,0 +1,19 @@
+MEMORY {
+ ZP: start = $0000, size = $0100, type = rw;
+ BASROM: start = $C000, size = $2000, fill = no, file = %O;
+ DUMMY: start = $0000, size = $00FF, file = "";
+}
+
+SEGMENTS {
+ ZEROPAGE: load = ZP, type = zp;
+ HEADER: load = BASROM, type = ro;
+ VECTORS: load = BASROM, type = ro;
+ KEYWORDS: load = BASROM, type = ro;
+ ERROR: load = BASROM, type = ro;
+ CODE: load = BASROM, type = ro;
+ CHRGET: load = BASROM, type = ro;
+ INIT: load = BASROM, type = ro;
+ EXTRA: load = BASROM, type = ro;
+ DUMMY: load = DUMMY; # don't include
+}
+
diff --git a/msbasic/sym1_iscntc.s b/msbasic/sym1_iscntc.s
new file mode 100644
index 0000000..8183b94
--- /dev/null
+++ b/msbasic/sym1_iscntc.s
@@ -0,0 +1,8 @@
+.segment "CODE"
+ISCNTC:
+ jsr INSTAT
+ bcc RET1
+
+ lda #$03
+ cmp #$03
+;!!! runs into "STOP"
\ No newline at end of file
diff --git a/msbasic/sym1_loadsave.s b/msbasic/sym1_loadsave.s
new file mode 100644
index 0000000..56b247f
--- /dev/null
+++ b/msbasic/sym1_loadsave.s
@@ -0,0 +1,70 @@
+.segment "CODE"
+
+SAVE:
+ beq L2739
+ sta P1L
+ jsr CHRGET
+ bne NULL-1
+
+ lda TXTTAB
+ ldy TXTTAB+1
+ sta P2L
+ sty P2H
+
+ lda VARTAB
+ ldy VARTAB+1
+ sta P3L
+ sty P3H
+
+ ldy #$80
+ jsr USR2
+ bcs LC6DD
+ lda #SAVED
+ jmp STROUT
+
+LOADED:
+ .byte "LOADED",CR,LF
+ .byte "OK",CR,LF,0
+
+SAVED:
+ .byte "SAVED",CR,LF,0
+
+LOAD:
+ beq L2739
+ sta $A64E
+ jsr CHRGET
+ bne L2738
+ ldy #$80
+ jsr USR3
+ bcs LC6EF
+
+ lda #LOADED
+ jsr STROUT
+
+ ldx P3L
+ ldy P3H
+ txa
+ stx VARTAB
+ sty VARTAB+1
+ jmp FIX_LINKS
+
+LC6DD:
+ lda #BAD_SAVE
+ jmp STROUT
+
+BAD_SAVE:
+ htasc "BAD SAVE"
+ .byte CR,LF,0
+LC6EF:
+ lda #BAD_LOAD
+ jsr STROUT
+ jsr SCRTCH
+ jmp RESTART
+
+BAD_LOAD:
+ htasc "BAD LOAD"
+ .byte CR,LF,0
diff --git a/msbasic/token.s b/msbasic/token.s
new file mode 100644
index 0000000..30b2397
--- /dev/null
+++ b/msbasic/token.s
@@ -0,0 +1,181 @@
+ init_token_tables
+
+ keyword_rts "END", END
+ keyword_rts "FOR", FOR
+ keyword_rts "NEXT", NEXT
+ keyword_rts "DATA", DATA
+.ifdef CONFIG_FILE
+ keyword_rts "INPUT#", INPUTH
+.endif
+ keyword_rts "INPUT", INPUT
+ keyword_rts "DIM", DIM
+ keyword_rts "READ", READ
+.ifdef APPLE
+ keyword_rts "PLT", PLT
+.else
+ keyword_rts "LET", LET
+.endif
+ keyword_rts "GOTO", GOTO, TOKEN_GOTO
+ keyword_rts "RUN", RUN
+ keyword_rts "IF", IF
+ keyword_rts "RESTORE", RESTORE
+ keyword_rts "GOSUB", GOSUB, TOKEN_GOSUB
+ keyword_rts "RETURN", POP
+.ifdef APPLE
+ keyword_rts "TEX", TEX, TOKEN_REM
+.else
+ keyword_rts "REM", REM, TOKEN_REM
+.endif
+ keyword_rts "STOP", STOP
+ keyword_rts "ON", ON
+.ifdef CONFIG_NULL
+ keyword_rts "NULL", NULL
+.endif
+.ifdef KBD
+ keyword_rts "PLOD", PLOD
+ keyword_rts "PSAV", PSAV
+ keyword_rts "VLOD", VLOD
+ keyword_rts "VSAV", VSAV
+.endif
+.ifndef CONFIG_NO_POKE
+ keyword_rts "WAIT", WAIT
+.endif
+.ifndef KBD
+ keyword_rts "LOAD", LOAD
+ keyword_rts "SAVE", SAVE
+.endif
+.ifdef CONFIG_CBM_ALL
+ keyword_rts "VERIFY", VERIFY
+.endif
+ keyword_rts "DEF", DEF
+.ifdef KBD
+ keyword_rts "SLOD", SLOD
+.endif
+.ifndef CONFIG_NO_POKE
+ keyword_rts "POKE", POKE
+.endif
+.ifdef CONFIG_FILE
+ keyword_rts "PRINT#", PRINTH
+.endif
+ keyword_rts "PRINT", PRINT, TOKEN_PRINT
+ keyword_rts "CONT", CONT
+ keyword_rts "LIST", LIST
+.ifdef CONFIG_CBM_ALL
+ keyword_rts "CLR", CLEAR
+.else
+ keyword_rts "CLEAR", CLEAR
+.endif
+.ifdef CONFIG_FILE
+ keyword_rts "CMD", CMD
+ keyword_rts "SYS", SYS
+ keyword_rts "OPEN", OPEN
+ keyword_rts "CLOSE", CLOSE
+.endif
+.ifndef CONFIG_SMALL
+ keyword_rts "GET", GET
+.endif
+.ifdef KBD
+ keyword_rts "PRT", PRT
+.endif
+ keyword_rts "NEW", NEW
+
+ count_tokens
+
+ keyword "TAB(", TOKEN_TAB
+ keyword "TO", TOKEN_TO
+ keyword "FN", TOKEN_FN
+ keyword "SPC(", TOKEN_SPC
+ keyword "THEN", TOKEN_THEN
+ keyword "NOT", TOKEN_NOT
+ keyword "STEP", TOKEN_STEP
+ keyword "+", TOKEN_PLUS
+ keyword "-", TOKEN_MINUS
+ keyword "*"
+ keyword "/"
+.ifdef KBD
+ keyword "#"
+.else
+ keyword "^"
+.endif
+ keyword "AND"
+ keyword "OR"
+ keyword ">", TOKEN_GREATER
+ keyword "=", TOKEN_EQUAL
+ keyword "<"
+
+ .segment "VECTORS"
+UNFNC:
+
+ keyword_addr "SGN", SGN, TOKEN_SGN
+ keyword_addr "INT", INT
+ keyword_addr "ABS", ABS
+.ifdef KBD
+ keyword_addr "VER", VER
+.endif
+.ifndef CONFIG_NO_POKE
+ .ifdef CONFIG_RAM
+ keyword_addr "USR", IQERR
+ .else
+ keyword_addr "USR", USR, TOKEN_USR
+ .endif
+.endif
+ keyword_addr "FRE", FRE
+ keyword_addr "POS", POS
+ keyword_addr "SQR", SQR
+ keyword_addr "RND", RND
+ keyword_addr "LOG", LOG
+ keyword_addr "EXP", EXP
+.segment "VECTORS"
+UNFNC_COS:
+ keyword_addr "COS", COS
+.segment "VECTORS"
+UNFNC_SIN:
+ keyword_addr "SIN", SIN
+.segment "VECTORS"
+UNFNC_TAN:
+ keyword_addr "TAN", TAN
+.segment "VECTORS"
+UNFNC_ATN:
+ keyword_addr "ATN", ATN
+.ifdef KBD
+ keyword_addr "GETC", GETC
+.endif
+.ifndef CONFIG_NO_POKE
+ keyword_addr "PEEK", PEEK
+.endif
+ keyword_addr "LEN", LEN
+ keyword_addr "STR$", STR
+ keyword_addr "VAL", VAL
+ keyword_addr "ASC", ASC
+ keyword_addr "CHR$", CHRSTR
+ keyword_addr "LEFT$", LEFTSTR, TOKEN_LEFTSTR
+ keyword_addr "RIGHT$", RIGHTSTR
+ keyword_addr "MID$", MIDSTR
+.ifdef CONFIG_2
+ keyword "GO", TOKEN_GO
+.endif
+ .segment "KEYWORDS"
+ .byte 0
+
+ .segment "VECTORS"
+MATHTBL:
+ .byte $79
+ .word FADDT-1
+ .byte $79
+ .word FSUBT-1
+ .byte $7B
+ .word FMULTT-1
+ .byte $7B
+ .word FDIVT-1
+ .byte $7F
+ .word FPWRT-1
+ .byte $50
+ .word TAND-1
+ .byte $46
+ .word OR-1
+ .byte $7D
+ .word NEGOP-1
+ .byte $5A
+ .word EQUOP-1
+ .byte $64
+ .word RELOPS-1
diff --git a/msbasic/trig.s b/msbasic/trig.s
new file mode 100644
index 0000000..e3e2f85
--- /dev/null
+++ b/msbasic/trig.s
@@ -0,0 +1,205 @@
+.segment "CODE"
+
+.ifndef SYM1
+SIN_COS_TAN_ATN:
+; ----------------------------------------------------------------------------
+; "COS" FUNCTION
+; ----------------------------------------------------------------------------
+COS:
+ lda #CON_PI_HALF
+ jsr FADD
+
+; ----------------------------------------------------------------------------
+; "SIN" FUNCTION
+; ----------------------------------------------------------------------------
+SIN:
+ jsr COPY_FAC_TO_ARG_ROUNDED
+ lda #CON_PI_DOUB
+ ldx ARGSIGN
+ jsr DIV
+ jsr COPY_FAC_TO_ARG_ROUNDED
+ jsr INT
+ lda #$00
+ sta STRNG1
+ jsr FSUBT
+; ----------------------------------------------------------------------------
+; (FAC) = ANGLE AS A FRACTION OF A FULL CIRCLE
+;
+; NOW FOLD THE RANGE INTO A QUARTER CIRCLE
+;
+; <<< THERE ARE MUCH SIMPLER WAYS TO DO THIS >>>
+; ----------------------------------------------------------------------------
+ lda #QUARTER
+ jsr FSUB
+ lda FACSIGN
+ pha
+ bpl SIN1
+ jsr FADDH
+ lda FACSIGN
+ bmi L3F5B
+ lda CPRMASK
+ eor #$FF
+ sta CPRMASK
+; ----------------------------------------------------------------------------
+; IF FALL THRU, RANGE IS 0...1/2
+; IF BRANCH HERE, RANGE IS 0...1/4
+; ----------------------------------------------------------------------------
+SIN1:
+ jsr NEGOP
+; ----------------------------------------------------------------------------
+; IF FALL THRU, RANGE IS -1/2...0
+; IF BRANCH HERE, RANGE IS -1/4...0
+; ----------------------------------------------------------------------------
+L3F5B:
+ lda #QUARTER
+ jsr FADD
+ pla
+ bpl L3F68
+ jsr NEGOP
+L3F68:
+ lda #POLY_SIN
+ jmp POLYNOMIAL_ODD
+
+; ----------------------------------------------------------------------------
+; "TAN" FUNCTION
+;
+; COMPUTE TAN(X) = SIN(X) / COS(X)
+; ----------------------------------------------------------------------------
+TAN:
+ jsr STORE_FAC_IN_TEMP1_ROUNDED
+ lda #$00
+ sta CPRMASK
+ jsr SIN
+ ldx #TEMP3
+ ldy #$00
+ jsr GOMOVMF
+ lda #TEMP1+(5-BYTES_FP)
+ ldy #$00
+ jsr LOAD_FAC_FROM_YA
+ lda #$00
+ sta FACSIGN
+ lda CPRMASK
+ jsr TAN1
+ lda #TEMP3
+ ldy #$00
+ jmp FDIV
+TAN1:
+ pha
+ jmp SIN1
+
+; ----------------------------------------------------------------------------
+.ifdef CONFIG_SMALL
+CON_PI_HALF:
+ .byte $81,$49,$0F,$DB
+CON_PI_DOUB:
+ .byte $83,$49,$0F,$DB
+QUARTER:
+ .byte $7F,$00,$00,$00
+POLY_SIN:
+ .byte $04,$86,$1E,$D7,$FB,$87,$99,$26
+ .byte $65,$87,$23,$34,$58,$86,$A5,$5D
+ .byte $E1,$83,$49,$0F,$DB
+.else
+CON_PI_HALF:
+ .byte $81,$49,$0F,$DA,$A2
+CON_PI_DOUB:
+ .byte $83,$49,$0F,$DA,$A2
+QUARTER:
+ .byte $7F,$00,$00,$00,$00
+POLY_SIN:
+ .byte $05,$84,$E6,$1A,$2D,$1B,$86,$28
+ .byte $07,$FB,$F8,$87,$99,$68,$89,$01
+ .byte $87,$23,$35,$DF,$E1,$86,$A5,$5D
+ .byte $E7,$28,$83,$49,$0F,$DA,$A2
+ .ifndef CONFIG_11
+; no easter egg text before BASIC 1.1
+ .elseif !.def(CONFIG_2A)
+; ASCII encoded easter egg
+MICROSOFT:
+ .byte $A6,$D3,$C1,$C8,$D4,$C8,$D5,$C4
+ .byte $CE,$CA
+ .else
+; PET encoded easter egg text since CBM2
+MICROSOFT:
+ .byte $A1,$54,$46,$8F,$13,$8F,$52,$43
+ .byte $89,$CD
+ .endif
+.endif
+
+.ifndef AIM65
+; ----------------------------------------------------------------------------
+; "ATN" FUNCTION
+; ----------------------------------------------------------------------------
+ATN:
+ lda FACSIGN
+ pha
+ bpl L3FDB
+ jsr NEGOP
+L3FDB:
+ lda FAC
+ pha
+ cmp #$81
+ bcc L3FE9
+ lda #CON_ONE
+ jsr FDIV
+; ----------------------------------------------------------------------------
+; 0 <= X <= 1
+; 0 <= ATN(X) <= PI/8
+; ----------------------------------------------------------------------------
+L3FE9:
+ lda #POLY_ATN
+ jsr POLYNOMIAL_ODD
+ pla
+ cmp #$81
+ bcc L3FFC
+ lda #CON_PI_HALF
+ jsr FSUB
+L3FFC:
+ pla
+ bpl L4002
+ jmp NEGOP
+L4002:
+ rts
+
+; ----------------------------------------------------------------------------
+POLY_ATN:
+.ifdef CONFIG_SMALL
+ .byte $08
+ .byte $78,$3A,$C5,$37
+ .byte $7B,$83,$A2,$5C
+ .byte $7C,$2E,$DD,$4D
+ .byte $7D,$99,$B0,$1E
+ .byte $7D,$59,$ED,$24
+ .byte $7E,$91,$72,$00
+ .byte $7E,$4C,$B9,$73
+ .byte $7F,$AA,$AA,$53
+ .byte $81,$00,$00,$00
+.else
+ .byte $0B
+ .byte $76,$B3,$83,$BD,$D3
+ .byte $79,$1E,$F4,$A6,$F5
+ .byte $7B,$83,$FC,$B0,$10
+ .byte $7C,$0C,$1F,$67,$CA
+ .byte $7C,$DE,$53,$CB,$C1
+ .byte $7D,$14,$64,$70,$4C
+ .byte $7D,$B7,$EA,$51,$7A
+ .byte $7D,$63,$30,$88,$7E
+ .byte $7E,$92,$44,$99,$3A
+ .byte $7E,$4C,$CC,$91,$C7
+ .byte $7F,$AA,$AA,$AA,$13
+ .byte $81,$00,$00,$00,$00
+.endif
+
+.if .def(CONFIG_11A) && (!.def(CONFIG_2))
+ .byte $00 ; XXX
+.endif
+.endif
+.endif
\ No newline at end of file
diff --git a/msbasic/var.s b/msbasic/var.s
new file mode 100644
index 0000000..cc7e269
--- /dev/null
+++ b/msbasic/var.s
@@ -0,0 +1,242 @@
+.segment "CODE"
+
+; ----------------------------------------------------------------------------
+; "DIM" STATEMENT
+; ----------------------------------------------------------------------------
+NXDIM:
+ jsr CHKCOM
+DIM:
+ tax
+ jsr PTRGET2
+ jsr CHRGOT
+ bne NXDIM
+ rts
+
+; ----------------------------------------------------------------------------
+; PTRGET -- GENERAL VARIABLE SCAN
+;
+; SCANS VARIABLE NAME AT TXTPTR, AND SEARCHES THE
+; VARTAB AND ARYTAB FOR THE NAME.
+; IF NOT FOUND, CREATE VARIABLE OF APPROPRIATE TYPE.
+; RETURN WITH ADDRESS IN VARPNT AND Y,A
+;
+; ACTUAL ACTIVITY CONTROLLED SOMEWHAT BY TWO FLAGS:
+; DIMFLG -- NONZERO IF CALLED FROM "DIM"
+; ELSE = 0
+;
+; SUBFLG -- = $00
+; = $40 IF CALLED FROM "GETARYPT"
+; ----------------------------------------------------------------------------
+PTRGET:
+ ldx #$00
+ jsr CHRGOT
+PTRGET2:
+ stx DIMFLG
+PTRGET3:
+ sta VARNAM
+ jsr CHRGOT
+ jsr ISLETC
+ bcs NAMOK
+SYNERR3:
+ jmp SYNERR
+NAMOK:
+ ldx #$00
+ stx VALTYP
+.ifndef CONFIG_SMALL
+ stx VALTYP+1
+.endif
+ jsr CHRGET
+ bcc L2ECD
+ jsr ISLETC
+ bcc L2ED8
+L2ECD:
+ tax
+L2ECE:
+ jsr CHRGET
+ bcc L2ECE
+ jsr ISLETC
+ bcs L2ECE
+L2ED8:
+ cmp #$24
+.ifdef CONFIG_SMALL
+ bne L2EF9
+.else
+ bne L2EE2
+.endif
+ lda #$FF
+ sta VALTYP
+.ifndef CONFIG_SMALL
+ bne L2EF2
+L2EE2:
+ cmp #$25
+ bne L2EF9
+ lda SUBFLG
+ bne SYNERR3
+ lda #$80
+ sta VALTYP+1
+ ora VARNAM
+ sta VARNAM
+L2EF2:
+.endif
+ txa
+ ora #$80
+ tax
+ jsr CHRGET
+L2EF9:
+ stx VARNAM+1
+ sec
+ ora SUBFLG
+ sbc #$28
+ bne L2F05
+ jmp ARRAY
+L2F05:
+ lda #$00
+ sta SUBFLG
+ lda VARTAB
+ ldx VARTAB+1
+ ldy #$00
+L2F0F:
+ stx LOWTR+1
+L2F11:
+ sta LOWTR
+ cpx ARYTAB+1
+ bne L2F1B
+ cmp ARYTAB
+ beq NAMENOTFOUND
+L2F1B:
+ lda VARNAM
+ cmp (LOWTR),y
+ bne L2F29
+ lda VARNAM+1
+ iny
+ cmp (LOWTR),y
+ beq SET_VARPNT_AND_YA
+ dey
+L2F29:
+ clc
+ lda LOWTR
+ adc #BYTES_PER_VARIABLE
+ bcc L2F11
+ inx
+ bne L2F0F
+
+; ----------------------------------------------------------------------------
+; CHECK IF (A) IS ASCII LETTER A-Z
+;
+; RETURN CARRY = 1 IF A-Z
+; = 0 IF NOT
+; ----------------------------------------------------------------------------
+ISLETC:
+ cmp #$41
+ bcc L2F3C
+ sbc #$5B
+ sec
+ sbc #$A5
+L2F3C:
+ rts
+
+; ----------------------------------------------------------------------------
+; VARIABLE NOT FOUND, SO MAKE ONE
+; ----------------------------------------------------------------------------
+NAMENOTFOUND:
+ pla
+ pha
+ cmp #FRM_VARIABLE_CALL
+ bne MAKENEWVARIABLE
+.endif
+LD015:
+ lda #C_ZERO
+ rts
+
+; ----------------------------------------------------------------------------
+.ifndef CONFIG_2
+C_ZERO:
+ .byte $00,$00
+.endif
+
+; ----------------------------------------------------------------------------
+; MAKE A NEW SIMPLE VARIABLE
+;
+; MOVE ARRAYS UP 7 BYTES TO MAKE ROOM FOR NEW VARIABLE
+; ENTER 7-BYTE VARIABLE DATA IN THE HOLE
+; ----------------------------------------------------------------------------
+MAKENEWVARIABLE:
+.ifdef CONFIG_CBM_ALL
+ lda VARNAM
+ ldy VARNAM+1
+ cmp #$54
+ bne LD02F
+ cpy #$C9
+ beq LD015
+ cpy #$49
+ bne LD02F
+LD02C:
+ jmp SYNERR
+LD02F:
+ cmp #$53
+ bne LD037
+ cpy #$54
+ beq LD02C
+LD037:
+.endif
+ lda ARYTAB
+ ldy ARYTAB+1
+ sta LOWTR
+ sty LOWTR+1
+ lda STREND
+ ldy STREND+1
+ sta HIGHTR
+ sty HIGHTR+1
+ clc
+ adc #BYTES_PER_VARIABLE
+ bcc L2F68
+ iny
+L2F68:
+ sta HIGHDS
+ sty HIGHDS+1
+ jsr BLTU
+ lda HIGHDS
+ ldy HIGHDS+1
+ iny
+ sta ARYTAB
+ sty ARYTAB+1
+ ldy #$00
+ lda VARNAM
+ sta (LOWTR),y
+ iny
+ lda VARNAM+1
+ sta (LOWTR),y
+ lda #$00
+ iny
+ sta (LOWTR),y
+ iny
+ sta (LOWTR),y
+ iny
+ sta (LOWTR),y
+ iny
+ sta (LOWTR),y
+.ifndef CONFIG_SMALL
+ iny
+ sta (LOWTR),y
+.endif
+
+; ----------------------------------------------------------------------------
+; PUT ADDRESS OF VALUE OF VARIABLE IN VARPNT AND Y,A
+; ----------------------------------------------------------------------------
+SET_VARPNT_AND_YA:
+ lda LOWTR
+ clc
+ adc #$02
+ ldy LOWTR+1
+ bcc L2F9E
+ iny
+L2F9E:
+ sta VARPNT
+ sty VARPNT+1
+ rts
diff --git a/msbasic/w65c816sxb.cfg b/msbasic/w65c816sxb.cfg
new file mode 100644
index 0000000..733e9d3
--- /dev/null
+++ b/msbasic/w65c816sxb.cfg
@@ -0,0 +1,19 @@
+MEMORY {
+ ZP: start = $0000, size = $0100, type = rw;
+ BASROM: start = $1000, size = $3F00, fill = no, file = %O;
+ DUMMY: start = $0000, size = $00FF, file = "";
+}
+
+SEGMENTS {
+ ZEROPAGE: load = ZP, type = zp;
+ HEADER: load = BASROM, type = ro;
+ VECTORS: load = BASROM, type = ro;
+ KEYWORDS: load = BASROM, type = ro;
+ ERROR: load = BASROM, type = ro;
+ CODE: load = BASROM, type = ro;
+ CHRGET: load = BASROM, type = ro;
+ INIT: load = BASROM, type = ro;
+ EXTRA: load = BASROM, type = ro;
+ DUMMY: load = DUMMY; # don't include
+}
+
diff --git a/msbasic/w65c816sxb_extra.s b/msbasic/w65c816sxb_extra.s
new file mode 100644
index 0000000..89bd113
--- /dev/null
+++ b/msbasic/w65c816sxb_extra.s
@@ -0,0 +1,92 @@
+.segment "EXTRA"
+.export MONRDKEY_NB, MONRDKEY, MONCOUT, INITUSBSERIAL
+
+VIA_USB_REG_DDRB := $7FE2
+VIA_USB_REG_DDRA := $7FE3
+VIA_USB_REG_PORTB := $7FE0
+VIA_USB_REG_PORTA := $7FE1
+VIA_USB_NRD := %00001000 ; make RD# high to not output data from FTDI
+VIA_USB_WR := %00000100 ; make WR high to output data from FTDI
+VIA_USB_nRXF := %00000010
+VIA_USB_DDRB_INIT := (VIA_USB_NRD+VIA_USB_WR)
+
+; INIT: Set up outputs and block reading characters from FTDI
+INITUSBSERIAL:
+ lda #(VIA_USB_NRD+VIA_USB_WR) ; Make these outputs
+ sta VIA_USB_REG_DDRB ; to DDRB
+ lda #VIA_USB_NRD ; Block RD, no WR
+ sta VIA_USB_REG_PORTB ; to REGB
+ rts
+
+MONRDKEY_NB:
+READCHAR:
+ lda VIA_USB_REG_PORTB
+ and #VIA_USB_nRXF
+
+ bne READCHAR_NOTHINGTOREAD ; Z=0 -> had no result
+
+ ; Reset DDRA as input
+ lda #$00 ; 0x00
+ sta VIA_USB_REG_DDRA ; to Directory Data (all in)
+
+ lda #0 ; DO RD, no WR
+ sta VIA_USB_REG_PORTB ; to REGB
+
+
+ lda VIA_USB_REG_PORTA
+
+ ; Save on stack temporrily
+ pha
+
+ lda #VIA_USB_NRD ; Block RD, no WR
+ sta VIA_USB_REG_PORTB ; to REGB
+
+ ; Get character back
+ pla
+ sec
+ rts
+
+READCHAR_NOTHINGTOREAD:
+ clc
+ rts
+
+MONRDKEY:
+ php
+@MONRDKEYREREAD:
+ jsr MONRDKEY_NB
+ bcc @MONRDKEYREREAD
+ ; Enable to echo back
+ ; jsr SENDCHAR
+ plp
+ rts
+
+MONCOUT:
+ ; TXE SHOULD be read before sending, but since the USB connection is
+ ; running full speed this buffer has not been seen filling up.
+
+ ; Save A for when returning
+ pha
+
+ ; Output character
+ sta VIA_USB_REG_PORTA ; to data
+
+ lda #VIA_USB_NRD ; Block RD, no WR
+ sta VIA_USB_REG_PORTB ; to REGB
+
+ lda #$FF
+ sta VIA_USB_REG_DDRA ; (all out)
+
+ ; Pulse WR
+ lda #(VIA_USB_NRD+VIA_USB_WR) ; Block RD, DO WR
+ sta VIA_USB_REG_PORTB ; to REGB
+ lda #VIA_USB_NRD ; Block RD, no WR
+ sta VIA_USB_REG_PORTB ; to REGB
+
+ ; Reset DDRA as input
+ lda #$00
+ sta VIA_USB_REG_DDRA ; to Directory Data (all in)
+
+ ; Restore Accumulator
+ pla
+ rts
+
diff --git a/msbasic/w65c816sxb_iscntc.s b/msbasic/w65c816sxb_iscntc.s
new file mode 100644
index 0000000..5ae49a3
--- /dev/null
+++ b/msbasic/w65c816sxb_iscntc.s
@@ -0,0 +1,10 @@
+.segment "CODE"
+ISCNTC:
+ jsr MONRDKEY_NB
+ bcc @NOTHING
+ cmp #$03
+ beq @STOPIT
+@NOTHING:
+ rts
+@STOPIT:
+;!!! runs into "STOP"
diff --git a/msbasic/zeropage.s b/msbasic/zeropage.s
new file mode 100644
index 0000000..0c787e4
--- /dev/null
+++ b/msbasic/zeropage.s
@@ -0,0 +1,203 @@
+
+.feature org_per_seg
+.zeropage
+
+.org ZP_START1
+
+GORESTART:
+ .res 3
+GOSTROUT:
+ .res 3
+GOAYINT:
+ .res 2
+GOGIVEAYF:
+ .res 2
+
+.org ZP_START2
+Z15:
+ .res 1
+.ifndef POSX; allow override
+POSX:
+.endif
+ .res 1
+.ifndef Z17; allow override
+Z17:
+.endif
+ .res 1
+.ifndef Z18; allow override
+Z18:
+.endif
+ .res 1
+LINNUM:
+.ifndef TXPSV; allow override
+TXPSV:
+.endif
+ .res 2
+.ifndef INPUTBUFFER; allow override
+INPUTBUFFER:
+.endif
+
+.org ZP_START3
+
+CHARAC:
+ .res 1
+ENDCHR:
+ .res 1
+EOLPNTR:
+ .res 1
+DIMFLG:
+ .res 1
+VALTYP:
+.ifdef CONFIG_SMALL
+ .res 1
+.else
+ .res 2
+.endif
+DATAFLG:
+ .res 1
+SUBFLG:
+ .res 1
+INPUTFLG:
+ .res 1
+CPRMASK:
+ .res 1
+Z14:
+ .res 1
+
+.org ZP_START4
+
+TEMPPT:
+ .res 1
+LASTPT:
+ .res 2
+TEMPST:
+ .res 9
+INDEX:
+ .res 2
+DEST:
+ .res 2
+RESULT:
+ .res BYTES_FP
+RESULT_LAST = RESULT + BYTES_FP-1
+TXTTAB:
+ .res 2
+VARTAB:
+ .res 2
+ARYTAB:
+ .res 2
+STREND:
+ .res 2
+FRETOP:
+ .res 2
+FRESPC:
+ .res 2
+MEMSIZ:
+ .res 2
+CURLIN:
+ .res 2
+OLDLIN:
+ .res 2
+OLDTEXT:
+ .res 2
+Z8C:
+ .res 2
+DATPTR:
+ .res 2
+INPTR:
+ .res 2
+VARNAM:
+ .res 2
+VARPNT:
+ .res 2
+FORPNT:
+ .res 2
+LASTOP:
+ .res 2
+CPRTYP:
+ .res 1
+FNCNAM:
+TEMP3:
+ .res 2
+DSCPTR:
+.ifdef CONFIG_SMALL
+ .res 2
+.else
+ .res 3
+.endif
+DSCLEN:
+ .res 2
+.ifndef JMPADRS ; allow override
+JMPADRS := DSCLEN + 1
+.endif
+Z52:
+ .res 1
+ARGEXTENSION:
+.ifndef CONFIG_SMALL
+ .res 1
+.endif
+TEMP1:
+ .res 1
+HIGHDS:
+ .res 2
+HIGHTR:
+ .res 2
+.ifndef CONFIG_SMALL
+TEMP2:
+ .res 1
+.endif
+INDX:
+TMPEXP:
+.ifdef CONFIG_SMALL
+TEMP2:
+.endif
+ .res 1
+EXPON:
+ .res 1
+LOWTR:
+.ifndef LOWTRX ; allow override
+LOWTRX:
+.endif
+ .res 1
+EXPSGN:
+ .res 1
+FAC:
+ .res BYTES_FP
+FAC_LAST = FAC + BYTES_FP-1
+FACSIGN:
+ .res 1
+SERLEN:
+ .res 1
+SHIFTSIGNEXT:
+ .res 1
+ARG:
+ .res BYTES_FP
+ARG_LAST = ARG + BYTES_FP-1
+ARGSIGN:
+ .res 1
+STRNG1:
+ .res 2
+SGNCPR = STRNG1
+FACEXTENSION = STRNG1+1
+STRNG2:
+ .res 2
+.ifdef AIM65
+ATN:
+ .res 3
+ZBE:
+ .res 1
+.endif
+.ifdef SYM1
+USR1:
+ .res 3
+USR2:
+ .res 3
+USR3:
+ .res 3
+.endif
+CHRGET:
+TXTPTR = <(GENERIC_TXTPTR-GENERIC_CHRGET + CHRGET)
+CHRGOT = <(GENERIC_CHRGOT-GENERIC_CHRGET + CHRGET)
+CHRGOT2 = <(GENERIC_CHRGOT2-GENERIC_CHRGET + CHRGET)
+RNDSEED = <(GENERIC_RNDSEED-GENERIC_CHRGET + CHRGET)
+
+
diff --git a/src/cpu.c b/src/cpu.c
index 3fda804..54bbced 100644
--- a/src/cpu.c
+++ b/src/cpu.c
@@ -1,1961 +1,1961 @@
-#include "cpu.h"
-
-#include "memoryMap.h"
-#include "opcodes.h"
-
-#define COMBINE(H, L) ((H << 8) | L)
-#define PAGE_CROSSED(addr1, addr2) (((addr1) ^ (addr2)) & 0xFF00)
-#define LO_BYTE(x) ((uint8_t)((x) & 0xFF))
-#define HI_BYTE(x) ((uint8_t)(((x) >> 8) & 0xFF))
-
-static void doADC(CPU *cpu, uint8_t value) {
- if (cpu->Flags.DecimalMode == 1) {
- uint16_t al = (cpu->Accumulator & 0x0F) + (value & 0x0F) + cpu->Flags.CarryFlag;
- if (al >= 0x0A) al = ((al + 0x06) & 0x0F) + 0x10;
-
- uint16_t sum = (cpu->Accumulator & 0xF0) + (value & 0xF0) + al;
- if (sum >= 0xA0) sum += 0x60;
-
- // N/V/Z are hardware-quirky in decimal mode; derive from the binary sum
- uint16_t binSum = cpu->Accumulator + value + cpu->Flags.CarryFlag;
- cpu->Flags.OverflowFlag = ((cpu->Accumulator ^ binSum) & (value ^ binSum) & 0x80) != 0;
- cpu->Flags.NegativeFlag = (sum & 0x80) != 0;
- cpu->Flags.ZeroFlag = (uint8_t)binSum == 0;
-
- cpu->Flags.CarryFlag = sum >= 0x100;
- cpu->Accumulator = (uint8_t)sum;
- } else {
- uint16_t result = cpu->Accumulator + value + cpu->Flags.CarryFlag;
- cpu->Flags.CarryFlag = result > 0xFF;
- cpu->Flags.ZeroFlag = (uint8_t)result == 0;
- cpu->Flags.OverflowFlag = ((cpu->Accumulator ^ result) & (value ^ result) & 0x80) != 0;
- cpu->Flags.NegativeFlag = (result & 0x80) != 0;
- cpu->Accumulator = (uint8_t)result;
- }
-}
-
-static void doSBC(CPU *cpu, uint8_t value) {
- uint8_t carryIn = cpu->Flags.CarryFlag;
- uint8_t inverted = value ^ 0xFF;
-
- uint16_t binResult = cpu->Accumulator + inverted + carryIn;
- cpu->Flags.CarryFlag = binResult > 0xFF;
- cpu->Flags.ZeroFlag = (uint8_t)binResult == 0;
- cpu->Flags.OverflowFlag = ((cpu->Accumulator ^ binResult) & (inverted ^ binResult) & 0x80) != 0;
- cpu->Flags.NegativeFlag = (binResult & 0x80) != 0;
-
- if (cpu->Flags.DecimalMode == 1) {
- int16_t al = (cpu->Accumulator & 0x0F) - (value & 0x0F) - (1 - carryIn);
- if (al < 0) al = ((al - 0x06) & 0x0F) - 0x10;
-
- int16_t sum = (cpu->Accumulator & 0xF0) - (value & 0xF0) + al;
- if (sum < 0) sum -= 0x60;
-
- cpu->Accumulator = (uint8_t)sum;
- } else {
- cpu->Accumulator = (uint8_t)binResult;
- }
-}
-
-void initCPU(CPU *cpu) {
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wmissing-field-initializers"
- *cpu = (CPU){0x0000, 0xFF};
-#pragma clang diagnostic pop
-}
-
-void resetCPU(CPU *cpu, uint8_t *rom) {
- uint8_t low = rom[0xFFFC - ROM_BASE];
- uint8_t high = rom[0xFFFD - ROM_BASE];
- cpu->ProgrammeCounter = COMBINE(high, low);
-}
-
-uint8_t runCycle(CPU *cpu, uint8_t *ram, uint8_t *rom) {
- // Fetch opcode
- uint8_t opcode = readMemory(cpu->ProgrammeCounter++, ram, rom);
-
- // Decode opcode, fetch operands, execute
- switch (opcode) {
- case BRK: {
- // Store return address on stack
- uint16_t retAddr = cpu->ProgrammeCounter + 1;
- writeStack(cpu->StackPointer--, HI_BYTE(retAddr), ram);
- writeStack(cpu->StackPointer--, LO_BYTE(retAddr), ram);
- // Set Break flag, Store flags on stack, including HW unused bit quirk
- cpu->Flags.BreakCommand = 1;
- writeStack(cpu->StackPointer--, cpu->FlagsByte | 0x30, ram);
- // Set PC and remaining flags
- uint8_t low = readMemory(0xFFFE, ram, rom);
- uint8_t high = readMemory(0xFFFF, ram, rom);
- cpu->ProgrammeCounter = COMBINE(high, low);
- cpu->Flags.InterruptDisable = 1;
-
- return 7;
- }
- case ORA_XZi: {
- // Get offset
- uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get indirect address, discard carry
- uint8_t _address = (uint8_t)(cpu->X + offset);
- // Get final address, wrap around page
- uint8_t low = readMemory(_address, ram, rom);
- uint8_t high = readMemory((uint8_t)(_address + 1), ram, rom);
- // Get value
- uint8_t value = readMemory(COMBINE(high, low), ram, rom);
- // Perform OR, set flags
- cpu->Accumulator |= value;
- cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
- cpu->Flags.NegativeFlag = (cpu->Accumulator & 0x80) != 0;
-
- return 6;
- }
- case ORA_Z: {
- // Get offset
- uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory(offset, ram, rom);
- // Perform OR, set flags
- cpu->Accumulator |= value;
- cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
- cpu->Flags.NegativeFlag = (cpu->Accumulator & 0x80) != 0;
-
- return 3;
- }
- case ASL_Z: {
- // Get offset
- uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory(offset, ram, rom);
- // Perform shift
- cpu->Flags.CarryFlag = (value & 0x80) != 0;
- value = (uint8_t)(value << 1);
- // Set flags and write to memory
- cpu->Flags.ZeroFlag = value == 0;
- cpu->Flags.NegativeFlag = (value & 0x80) != 0;
- writeMemory(offset, value, ram);
-
- return 5;
- }
- case PHP: {
- // Push to stack, force Break and unused to 1 (HW idiosyncrasy)
- writeStack(cpu->StackPointer--, cpu->FlagsByte | 0x30, ram);
-
- return 3;
- }
- case ORA_I: {
- // Get value
- uint8_t value = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Perform OR, set flags
- cpu->Accumulator |= value;
- cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
- cpu->Flags.NegativeFlag = (cpu->Accumulator & 0x80) != 0;
-
- return 2;
- }
- case ASL: {
- // Perform shift
- cpu->Flags.CarryFlag = (cpu->Accumulator & 0x80) != 0;
- cpu->Accumulator = (uint8_t)(cpu->Accumulator << 1);
- // Set flags
- cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
- cpu->Flags.NegativeFlag = (cpu->Accumulator & 0x80) != 0;
-
- return 2;
- }
- case ORA_A: {
- // Load address
- uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
- uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory(COMBINE(high, low), ram, rom);
- // Perform OR, set flags
- cpu->Accumulator |= value;
- cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
- cpu->Flags.NegativeFlag = (cpu->Accumulator & 0x80) != 0;
-
- return 4;
- }
- case ASL_A: {
- // Load address
- uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
- uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory(COMBINE(high, low), ram, rom);
- // Perform shift
- cpu->Flags.CarryFlag = (value & 0x80) != 0;
- value = (uint8_t)(value << 1);
- // Set flags and write to memory
- cpu->Flags.ZeroFlag = value == 0;
- cpu->Flags.NegativeFlag = (value & 0x80) != 0;
- writeMemory(COMBINE(high, low), value, ram);
-
- return 6;
- }
-
- case BPL: {
- uint8_t cycles = 2;
-
- // Get offset
- int8_t offset = (int8_t)readMemory(cpu->ProgrammeCounter++, ram, rom);
-
- // Check flag
- if (cpu->Flags.NegativeFlag == 0) {
- uint16_t oldPC = cpu->ProgrammeCounter;
- // Modify PC
- cpu->ProgrammeCounter += offset;
- // Calculate cycles
- cycles++;
- cycles += PAGE_CROSSED(oldPC, cpu->ProgrammeCounter) ? 1 : 0;
- }
-
- return cycles;
- }
- case ORA_ZiY: {
- // Get _address
- uint8_t _address = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get offset
- uint8_t low = readMemory(_address, ram, rom);
- uint8_t high = readMemory((uint8_t)(_address + 1), ram, rom);
- // Get address
- uint16_t address = cpu->Y + COMBINE(high, low);
- // Get value
- uint8_t value = readMemory(address, ram, rom);
- // Perform OR, set flags
- cpu->Accumulator |= value;
- cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
- cpu->Flags.NegativeFlag = (cpu->Accumulator & 0x80) != 0;
-
- return 5 + (((uint16_t)low + cpu->Y) > 0xFF);
- }
- case ORA_XZ: {
- // Get offset
- uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory((uint8_t)(cpu->X + offset), ram, rom);
- // Perform OR, set flags
- cpu->Accumulator |= value;
- cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
- cpu->Flags.NegativeFlag = (cpu->Accumulator & 0x80) != 0;
-
- return 4;
- }
- case ASL_XZ: {
- // Get offset
- uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory((uint8_t)(cpu->X + offset), ram, rom);
- // Perform shift
- cpu->Flags.CarryFlag = (value & 0x80) != 0;
- value = (uint8_t)(value << 1);
- // Set flags and write to memory
- cpu->Flags.ZeroFlag = value == 0;
- cpu->Flags.NegativeFlag = (value & 0x80) != 0;
- writeMemory((uint8_t)(cpu->X + offset), value, ram);
-
- return 6;
- }
- case CLC: {
- cpu->Flags.CarryFlag = 0;
-
- return 2;
- }
- case ORA_YA: {
- // Get address
- uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
- uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory(cpu->Y + COMBINE(high, low), ram, rom);
- // Perform OR, set flags
- cpu->Accumulator |= value;
- cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
- cpu->Flags.NegativeFlag = (cpu->Accumulator & 0x80) != 0;
-
- return 4 + (((uint16_t)low + cpu->Y) > 0xFF);
- }
- case ORA_XA: {
- // Get address
- uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
- uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory(cpu->X + COMBINE(high, low), ram, rom);
- // Perform OR, set flags
- cpu->Accumulator |= value;
- cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
- cpu->Flags.NegativeFlag = (cpu->Accumulator & 0x80) != 0;
-
- return 4 + (((uint16_t)low + cpu->X) > 0xFF);
- }
- case ASL_XA: {
- // Get address
- uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
- uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory(cpu->X + COMBINE(high, low), ram, rom);
- // Perform shift
- cpu->Flags.CarryFlag = (value & 0x80) != 0;
- value = (uint8_t)(value << 1);
- // Set flags and write to memory
- cpu->Flags.ZeroFlag = value == 0;
- cpu->Flags.NegativeFlag = (value & 0x80) != 0;
- writeMemory(cpu->X + COMBINE(high, low), value, ram);
-
- return 7;
- }
-
- case JSR: {
- // Get address
- uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
- uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Write return address
- writeStack(cpu->StackPointer--, HI_BYTE(cpu->ProgrammeCounter - 1), ram);
- writeStack(cpu->StackPointer--, LO_BYTE(cpu->ProgrammeCounter - 1), ram);
- // Set PC
- cpu->ProgrammeCounter = COMBINE(high, low);
-
- return 6;
- }
- case AND_XZi: {
- // Get offset
- uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get indirect address, discard carry
- uint8_t _address = (uint8_t)(cpu->X + offset);
- // Get final address, wrap around page
- uint8_t low = readMemory(_address, ram, rom);
- uint8_t high = readMemory((uint8_t)(_address + 1), ram, rom);
- // Get value
- uint8_t value = readMemory(COMBINE(high, low), ram, rom);
- // Perform AND, set flags
- cpu->Accumulator &= value;
- cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
- cpu->Flags.NegativeFlag = (cpu->Accumulator & 0x80) != 0;
-
- return 6;
- }
- case BIT_Z: {
- // Get offset
- uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory(offset, ram, rom);
- // Set flags
- cpu->Flags.ZeroFlag = (cpu->Accumulator & value) == 0;
- cpu->Flags.OverflowFlag = (value & 0x40) != 0;
- cpu->Flags.NegativeFlag = (value & 0x80) != 0;
-
- return 3;
- }
- case AND_Z: {
- // Get offset
- uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory(offset, ram, rom);
- // Perform AND, set flags
- cpu->Accumulator &= value;
- cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
- cpu->Flags.NegativeFlag = (cpu->Accumulator & 0x80) != 0;
-
- return 3;
- }
- case ROL_Z: {
- // Get offset
- uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory(offset, ram, rom);
- // Save bit 7, rotate, set bit 0
- uint8_t bit7 = value >> 7;
- value = value << 1;
- value |= cpu->Flags.CarryFlag;
- // Set flags
- cpu->Flags.CarryFlag = bit7 != 0;
- cpu->Flags.ZeroFlag = value == 0;
- cpu->Flags.NegativeFlag = (value & 0x80) != 0;
- // Write value
- writeMemory(offset, value, ram);
-
- return 5;
- }
- case PLP: {
- // Pull from stack
- cpu->FlagsByte = readStack(++cpu->StackPointer, ram);
-
- return 4;
- }
- case AND_I: {
- // Get value
- uint8_t value = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Perform AND, set flags
- cpu->Accumulator &= value;
- cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
- cpu->Flags.NegativeFlag = (cpu->Accumulator & 0x80) != 0;
-
- return 2;
- }
- case ROL: {
- // Save bit 7, rotate, set bit 0
- uint8_t bit7 = cpu->Accumulator >> 7;
- cpu->Accumulator = cpu->Accumulator << 1;
- cpu->Accumulator |= cpu->Flags.CarryFlag;
- // Set flags
- cpu->Flags.CarryFlag = bit7 != 0;
- cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
- cpu->Flags.NegativeFlag = (cpu->Accumulator & 0x80) != 0;
-
- return 2;
- }
- case BIT_A: {
- // Load address
- uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
- uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory(COMBINE(high, low), ram, rom);
- // Set flags
- cpu->Flags.ZeroFlag = (cpu->Accumulator & value) == 0;
- cpu->Flags.OverflowFlag = (value & 0x40) != 0;
- cpu->Flags.NegativeFlag = (value & 0x80) != 0;
-
- return 4;
- }
- case AND_A: {
- // Load address
- uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
- uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory(COMBINE(high, low), ram, rom);
- // Perform AND, set flags
- cpu->Accumulator &= value;
- cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
- cpu->Flags.NegativeFlag = (cpu->Accumulator & 0x80) != 0;
-
- return 4;
- }
- case ROL_A: {
- // Get address
- uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
- uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory(COMBINE(high, low), ram, rom);
- // Save bit 7, rotate, set bit 0
- uint8_t bit7 = value >> 7;
- value = value << 1;
- value |= cpu->Flags.CarryFlag;
- // Set flags
- cpu->Flags.CarryFlag = bit7 != 0;
- cpu->Flags.ZeroFlag = value == 0;
- cpu->Flags.NegativeFlag = (value & 0x80) != 0;
- // Write value
- writeMemory(COMBINE(high, low), value, ram);
-
- return 6;
- }
-
- case BMI: {
- uint8_t cycles = 2;
-
- // Get offset
- int8_t offset = (int8_t)readMemory(cpu->ProgrammeCounter++, ram, rom);
-
- // Check flag
- if (cpu->Flags.NegativeFlag == 1) {
- uint16_t oldPC = cpu->ProgrammeCounter;
- // Modify PC
- cpu->ProgrammeCounter += offset;
- // Calculate cycles
- cycles++;
- cycles += PAGE_CROSSED(oldPC, cpu->ProgrammeCounter) ? 1 : 0;
- }
-
- return cycles;
- }
- case AND_ZiY: {
- // Get _address
- uint8_t _address = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get offset
- uint8_t low = readMemory(_address, ram, rom);
- uint8_t high = readMemory((uint8_t)(_address + 1), ram, rom);
- // Get address
- uint16_t address = cpu->Y + COMBINE(high, low);
- // Get value
- uint8_t value = readMemory(address, ram, rom);
- // Perform AND, set flags
- cpu->Accumulator &= value;
- cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
- cpu->Flags.NegativeFlag = (cpu->Accumulator & 0x80) != 0;
-
- return 5 + (((uint16_t)low + cpu->Y) > 0xFF);
- }
- case AND_XZ: {
- // Get offset
- uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory((uint8_t)(cpu->X + offset), ram, rom);
- // Perform AND, set flags
- cpu->Accumulator &= value;
- cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
- cpu->Flags.NegativeFlag = (cpu->Accumulator & 0x80) != 0;
-
- return 4;
- }
- case ROL_XZ: {
- // Get offset
- uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory((uint8_t)(cpu->X + offset), ram, rom);
- // Save bit 7, rotate, set bit 0
- uint8_t bit7 = value >> 7;
- value = value << 1;
- value |= cpu->Flags.CarryFlag;
- // Set flags
- cpu->Flags.CarryFlag = bit7 != 0;
- cpu->Flags.ZeroFlag = value == 0;
- cpu->Flags.NegativeFlag = (value & 0x80) != 0;
- // Write value
- writeMemory((uint8_t)(cpu->X + offset), value, ram);
-
- return 6;
- }
- case SEC: {
- cpu->Flags.CarryFlag = 1;
-
- return 2;
- }
- case AND_YA: {
- // Get address
- uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
- uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory(cpu->Y + COMBINE(high, low), ram, rom);
- // Perform AND, set flags
- cpu->Accumulator &= value;
- cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
- cpu->Flags.NegativeFlag = (cpu->Accumulator & 0x80) != 0;
-
- return 4 + (((uint16_t)low + cpu->Y) > 0xFF);
- }
- case AND_XA: {
- // Get address
- uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
- uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory(cpu->X + COMBINE(high, low), ram, rom);
- // Perform AND, set flags
- cpu->Accumulator &= value;
- cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
- cpu->Flags.NegativeFlag = (cpu->Accumulator & 0x80) != 0;
-
- return 4 + (((uint16_t)low + cpu->X) > 0xFF);
- }
- case ROL_XA: {
- // Get address
- uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
- uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory(cpu->X + COMBINE(high, low), ram, rom);
- // Save bit 7, rotate, set bit 0
- uint8_t bit7 = value >> 7;
- value = value << 1;
- value |= cpu->Flags.CarryFlag;
- // Set flags
- cpu->Flags.CarryFlag = bit7 != 0;
- cpu->Flags.ZeroFlag = value == 0;
- cpu->Flags.NegativeFlag = (value & 0x80) != 0;
- // Write value
- writeMemory(cpu->X + COMBINE(high, low), value, ram);
-
- return 7;
- }
-
- case RTI: {
- // Pull flags
- cpu->FlagsByte = readStack(++cpu->StackPointer, ram);
- // Pull address
- uint8_t low = readStack(++cpu->StackPointer, ram);
- uint8_t high = readStack(++cpu->StackPointer, ram);
- // Set PC
- cpu->ProgrammeCounter = COMBINE(high, low);
-
- return 6;
- }
- case EOR_XZi: {
- // Get offset
- uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get indirect address, discard carry
- uint8_t _address = (uint8_t)(cpu->X + offset);
- // Get final address, wrap around page
- uint8_t low = readMemory(_address, ram, rom);
- uint8_t high = readMemory((uint8_t)(_address + 1), ram, rom);
- // Get value
- uint8_t value = readMemory(COMBINE(high, low), ram, rom);
- // Perform XOR, set flags
- cpu->Accumulator ^= value;
- cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
- cpu->Flags.NegativeFlag = (cpu->Accumulator & 0x80) != 0;
-
- return 6;
- }
- case EOR_Z: {
- // Get offset
- uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory(offset, ram, rom);
- // Perform XOR, set flags
- cpu->Accumulator ^= value;
- cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
- cpu->Flags.NegativeFlag = (cpu->Accumulator & 0x80) != 0;
-
- return 3;
- }
- case LSR_Z: {
- // Get offset
- uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory(offset, ram, rom);
- // Perform shift
- cpu->Flags.CarryFlag = (value & 0x01) != 0;
- value = (uint8_t)(value >> 1);
- // Set flags and write to memory
- cpu->Flags.ZeroFlag = value == 0;
- cpu->Flags.NegativeFlag = 0;
- writeMemory(offset, value, ram);
-
- return 5;
- }
- case PHA: {
- writeStack(cpu->StackPointer--, cpu->Accumulator, ram);
-
- return 3;
- }
- case EOR_I: {
- // Get value
- uint8_t value = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Perform XOR, set flags
- cpu->Accumulator ^= value;
- cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
- cpu->Flags.NegativeFlag = (cpu->Accumulator & 0x80) != 0;
-
- return 2;
- }
- case LSR: {
- // Perform shift
- cpu->Flags.CarryFlag = (cpu->Accumulator & 0x01) != 0;
- cpu->Accumulator = (uint8_t)(cpu->Accumulator >> 1);
- // Set flags
- cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
- cpu->Flags.NegativeFlag = 0;
-
- return 2;
- }
- case JMP_A: {
- // Load address
- uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
- uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Set PC
- cpu->ProgrammeCounter = COMBINE(high, low);
-
- return 3;
- }
- case EOR_A: {
- // Load address
- uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
- uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory(COMBINE(high, low), ram, rom);
- // Perform XOR, set flags
- cpu->Accumulator ^= value;
- cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
- cpu->Flags.NegativeFlag = (cpu->Accumulator & 0x80) != 0;
-
- return 4;
- }
- case LSR_A: {
- // Load address
- uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
- uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory(COMBINE(high, low), ram, rom);
- // Perform shift
- cpu->Flags.CarryFlag = (value & 0x01) != 0;
- value = (uint8_t)(value >> 1);
- // Set flags and write to memory
- cpu->Flags.ZeroFlag = value == 0;
- cpu->Flags.NegativeFlag = 0;
- writeMemory(COMBINE(high, low), value, ram);
-
- return 6;
- }
-
- case BVC: {
- uint8_t cycles = 2;
-
- // Get offset
- int8_t offset = (int8_t)readMemory(cpu->ProgrammeCounter++, ram, rom);
-
- // Check flag
- if (cpu->Flags.OverflowFlag == 0) {
- uint16_t oldPC = cpu->ProgrammeCounter;
- // Modify PC
- cpu->ProgrammeCounter += offset;
- // Calculate cycles
- cycles++;
- cycles += PAGE_CROSSED(oldPC, cpu->ProgrammeCounter) ? 1 : 0;
- }
-
- return cycles;
- }
- case EOR_ZiY: {
- // Get _address
- uint8_t _address = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get offset
- uint8_t low = readMemory(_address, ram, rom);
- uint8_t high = readMemory((uint8_t)(_address + 1), ram, rom);
- // Get address
- uint16_t address = cpu->Y + COMBINE(high, low);
- // Get value
- uint8_t value = readMemory(address, ram, rom);
- // Perform XOR, set flags
- cpu->Accumulator ^= value;
- cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
- cpu->Flags.NegativeFlag = (cpu->Accumulator & 0x80) != 0;
-
- return 5 + (((uint16_t)low + cpu->Y) > 0xFF);
- }
- case EOR_XZ: {
- // Get offset
- uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory((uint8_t)(cpu->X + offset), ram, rom);
- // Perform XOR, set flags
- cpu->Accumulator ^= value;
- cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
- cpu->Flags.NegativeFlag = (cpu->Accumulator & 0x80) != 0;
-
- return 4;
- }
- case LSR_XZ: {
- // Get offset
- uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory((uint8_t)(cpu->X + offset), ram, rom);
- // Perform shift
- cpu->Flags.CarryFlag = (value & 0x01) != 0;
- value = (uint8_t)(value >> 1);
- // Set flags and write to memory
- cpu->Flags.ZeroFlag = value == 0;
- cpu->Flags.NegativeFlag = 0;
- writeMemory((uint8_t)(cpu->X + offset), value, ram);
-
- return 6;
- }
- case CLI: {
- cpu->Flags.InterruptDisable = 0;
-
- return 2;
- }
- case EOR_YA: {
- // Get address
- uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
- uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory(cpu->Y + COMBINE(high, low), ram, rom);
- // Perform XOR, set flags
- cpu->Accumulator ^= value;
- cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
- cpu->Flags.NegativeFlag = (cpu->Accumulator & 0x80) != 0;
-
- return 4 + (((uint16_t)low + cpu->Y) > 0xFF);
- }
- case EOR_XA: {
- // Get address
- uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
- uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory(cpu->X + COMBINE(high, low), ram, rom);
- // Perform XOR, set flags
- cpu->Accumulator ^= value;
- cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
- cpu->Flags.NegativeFlag = (cpu->Accumulator & 0x80) != 0;
-
- return 4 + (((uint16_t)low + cpu->X) > 0xFF);
- }
- case LSR_XA: {
- // Get address
- uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
- uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory(cpu->X + COMBINE(high, low), ram, rom);
- // Perform shift
- cpu->Flags.CarryFlag = (value & 0x01) != 0;
- value = (uint8_t)(value >> 1);
- // Set flags and write to memory
- cpu->Flags.ZeroFlag = value == 0;
- cpu->Flags.NegativeFlag = 0;
- writeMemory(cpu->X + COMBINE(high, low), value, ram);
-
- return 7;
- }
-
- case RTS: {
- // Pull address
- uint8_t low = readStack(++cpu->StackPointer, ram);
- uint8_t high = readStack(++cpu->StackPointer, ram);
- // Set PC
- cpu->ProgrammeCounter = COMBINE(high, low) + 1;
-
- return 6;
- }
- case ADC_XZi: {
- // Get offset
- uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get indirect address, discard carry
- uint8_t _address = (uint8_t)(cpu->X + offset);
- // Get final address, wrap around page
- uint8_t low = readMemory(_address, ram, rom);
- uint8_t high = readMemory((uint8_t)(_address + 1), ram, rom);
- // Get value
- uint8_t value = readMemory(COMBINE(high, low), ram, rom);
-
- doADC(cpu, value);
-
- return 6;
- }
- case ADC_Z: {
- // Get offset
- uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory(offset, ram, rom);
-
- doADC(cpu, value);
-
- return 3;
- }
- case ROR_Z: {
- // Get offset
- uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory(offset, ram, rom);
- // Save bit 0, rotate, set bit 0
- uint8_t bit0 = value & 0x1;
- value = value >> 1;
- value |= (cpu->Flags.CarryFlag << 7);
- // Set flags
- cpu->Flags.CarryFlag = bit0 != 0;
- cpu->Flags.ZeroFlag = value == 0;
- cpu->Flags.NegativeFlag = (value & 0x80) != 0;
- // Write value
- writeMemory(offset, value, ram);
-
- return 5;
- }
- case PLA: {
- // Pull from stack
- cpu->Accumulator = readStack(++cpu->StackPointer, ram);
- cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
- cpu->Flags.NegativeFlag = (cpu->Accumulator & 0x80) != 0;
-
- return 4;
- }
- case ADC_I: {
- // Get value
- uint8_t value = readMemory(cpu->ProgrammeCounter++, ram, rom);
-
- doADC(cpu, value);
-
- return 2;
- }
- case ROR: {
- // Save bit 0, rotate, set bit 0
- uint8_t bit0 = cpu->Accumulator & 0x1;
- cpu->Accumulator = cpu->Accumulator >> 1;
- cpu->Accumulator |= (cpu->Flags.CarryFlag << 7);
- // Set flags
- cpu->Flags.CarryFlag = bit0 != 0;
- cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
- cpu->Flags.NegativeFlag = (cpu->Accumulator & 0x80) != 0;
-
- return 2;
- }
- case JMP_Ai: {
- // Load pointer address
- uint8_t _low = readMemory(cpu->ProgrammeCounter++, ram, rom);
- uint8_t _high = readMemory(cpu->ProgrammeCounter++, ram, rom);
- uint16_t address = COMBINE(_high, _low);
- // Get address, replicating page-wrap hardware bug
- uint8_t low = readMemory(address, ram, rom);
- uint8_t high = readMemory((address & 0xFF00) | ((address + 1) & 0x00FF), ram, rom);
- // Set PC
- cpu->ProgrammeCounter = COMBINE(high, low);
-
- return 5;
- }
- case ADC_A: {
- // Load address
- uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
- uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory(COMBINE(high, low), ram, rom);
-
- doADC(cpu, value);
-
- return 4;
- }
- case ROR_A: {
- // Get address
- uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
- uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory(COMBINE(high, low), ram, rom);
- // Save bit 7, rotate, set bit 0
- uint8_t bit0 = value & 0x1;
- value = value >> 1;
- value |= (cpu->Flags.CarryFlag << 7);
- // Set flags
- cpu->Flags.CarryFlag = bit0 != 0;
- cpu->Flags.ZeroFlag = value == 0;
- cpu->Flags.NegativeFlag = (value & 0x80) != 0;
- // Write value
- writeMemory(COMBINE(high, low), value, ram);
-
- return 6;
- }
-
- case BVS: {
- uint8_t cycles = 2;
-
- // Get offset
- int8_t offset = (int8_t)readMemory(cpu->ProgrammeCounter++, ram, rom);
-
- // Check flag
- if (cpu->Flags.OverflowFlag == 1) {
- uint16_t oldPC = cpu->ProgrammeCounter;
- // Modify PC
- cpu->ProgrammeCounter += offset;
- // Calculate cycles
- cycles++;
- cycles += PAGE_CROSSED(oldPC, cpu->ProgrammeCounter) ? 1 : 0;
- }
-
- return cycles;
- }
- case ADC_ZiY: {
- // Get _address
- uint8_t _address = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get offset
- uint8_t low = readMemory(_address, ram, rom);
- uint8_t high = readMemory((uint8_t)(_address + 1), ram, rom);
- // Get address
- uint16_t address = cpu->Y + COMBINE(high, low);
- // Get value
- uint8_t value = readMemory(address, ram, rom);
-
- doADC(cpu, value);
-
- return 5 + (((uint16_t)low + cpu->Y) > 0xFF);
- }
- case ADC_XZ: {
- // Get offset
- uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory((uint8_t)(cpu->X + offset), ram, rom);
-
- doADC(cpu, value);
-
- return 4;
- }
- case ROR_XZ: {
- // Get offset
- uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory((uint8_t)(cpu->X + offset), ram, rom);
- // Save bit 0, rotate, set bit 0
- uint8_t bit0 = value & 0x1;
- value = value >> 1;
- value |= (cpu->Flags.CarryFlag << 7);
- // Set flags
- cpu->Flags.CarryFlag = bit0 != 0;
- cpu->Flags.ZeroFlag = value == 0;
- cpu->Flags.NegativeFlag = (value & 0x80) != 0;
- // Write value
- writeMemory((uint8_t)(cpu->X + offset), value, ram);
-
- return 6;
- }
- case SEI: {
- cpu->Flags.InterruptDisable = 1;
-
- return 2;
- }
- case ADC_YA: {
- // Get address
- uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
- uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory(cpu->Y + COMBINE(high, low), ram, rom);
-
- doADC(cpu, value);
-
- return 4 + (((uint16_t)low + cpu->Y) > 0xFF);
- }
- case ADC_XA: {
- // Get address
- uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
- uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory(cpu->X + COMBINE(high, low), ram, rom);
-
- doADC(cpu, value);
-
- return 4 + (((uint16_t)low + cpu->X) > 0xFF);
- }
- case ROR_XA: {
- // Get address
- uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
- uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory(cpu->X + COMBINE(high, low), ram, rom);
- // Save bit 0, rotate, set bit 0
- uint8_t bit0 = value & 0x1;
- value = value >> 1;
- value |= (cpu->Flags.CarryFlag << 7);
- // Set flags
- cpu->Flags.CarryFlag = bit0 != 0;
- cpu->Flags.ZeroFlag = value == 0;
- cpu->Flags.NegativeFlag = (value & 0x80) != 0;
- // Write value
- writeMemory(cpu->X + COMBINE(high, low), value, ram);
-
- return 7;
- }
-
- case STA_XZi: {
- // Get offset
- uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get indirect address, discard carry
- uint8_t _address = (uint8_t)(cpu->X + offset);
- // Get final address, wrap around page
- uint8_t low = readMemory(_address, ram, rom);
- uint8_t high = readMemory((uint8_t)(_address + 1), ram, rom);
- // Store accumulator at address
- writeMemory(COMBINE(high, low), cpu->Accumulator, ram);
-
- return 6;
- }
- case STY_Z: {
- // Get offset
- uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Store Y at address
- writeMemory(offset, cpu->Y, ram);
-
- return 3;
- }
- case STA_Z: {
- // Get offset
- uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Store accumulator at address
- writeMemory(offset, cpu->Accumulator, ram);
-
- return 3;
- }
- case STX_Z: {
- // Get offset
- uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Store X at address
- writeMemory(offset, cpu->X, ram);
-
- return 3;
- }
- case DEY: {
- // Decrement, set flags
- cpu->Y--;
- cpu->Flags.ZeroFlag = cpu->Y == 0;
- cpu->Flags.NegativeFlag = (cpu->Y & 0x80) != 0;
-
- return 2;
- }
- case TXA: {
- cpu->Accumulator = cpu->X;
- // Set flags
- cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
- cpu->Flags.NegativeFlag = (cpu->Accumulator & 0x80) != 0;
-
- return 2;
- }
- case STY_A: {
- // Load address
- uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
- uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Store Y at address
- writeMemory(COMBINE(high, low), cpu->Y, ram);
-
- return 4;
- }
- case STA_A: {
- // Load address
- uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
- uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Store accumulator at address
- writeMemory(COMBINE(high, low), cpu->Accumulator, ram);
-
- return 4;
- }
- case STX_A: {
- // Load address
- uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
- uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Store X at address
- writeMemory(COMBINE(high, low), cpu->X, ram);
-
- return 4;
- }
-
- case BCC: {
- uint8_t cycles = 2;
-
- // Get offset
- int8_t offset = (int8_t)readMemory(cpu->ProgrammeCounter++, ram, rom);
-
- // Check flag
- if (cpu->Flags.CarryFlag == 0) {
- uint16_t oldPC = cpu->ProgrammeCounter;
- // Modify PC
- cpu->ProgrammeCounter += offset;
- // Calculate cycles
- cycles++;
- cycles += PAGE_CROSSED(oldPC, cpu->ProgrammeCounter) ? 1 : 0;
- }
-
- return cycles;
- }
- case STA_ZiY: {
- // Get _address
- uint8_t _address = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get offset
- uint8_t low = readMemory(_address, ram, rom);
- uint8_t high = readMemory((uint8_t)(_address + 1), ram, rom);
- // Get address
- uint16_t address = cpu->Y + COMBINE(high, low);
- // Store accumulator at address
- writeMemory(address, cpu->Accumulator, ram);
-
- return 6;
- }
- case STY_XZ: {
- // Get offset
- uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Store accumulator at address
- writeMemory((uint8_t)(cpu->X + offset), cpu->Y, ram);
-
- return 4;
- }
- case STA_XZ: {
- // Get offset
- uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Store accumulator at address
- writeMemory((uint8_t)(cpu->X + offset), cpu->Accumulator, ram);
-
- return 4;
- }
- case STX_YZ: {
- // Get offset
- uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Store accumulator at address
- writeMemory((uint8_t)(cpu->Y + offset), cpu->X, ram);
-
- return 4;
- }
- case TYA: {
- cpu->Accumulator = cpu->Y;
- // Set flags
- cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
- cpu->Flags.NegativeFlag = (cpu->Accumulator & 0x80) != 0;
-
- return 2;
- }
- case STA_YA: {
- // Get address
- uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
- uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Store accumulator at address
- writeMemory(cpu->Y + COMBINE(high, low), cpu->Accumulator, ram);
-
- return 5;
- }
- case TXS: {
- cpu->StackPointer = cpu->X;
-
- return 2;
- }
- case STA_XA: {
- // Get address
- uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
- uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Store accumulator at address
- writeMemory(cpu->X + COMBINE(high, low), cpu->Accumulator, ram);
-
- return 5;
- }
-
- case LDY_I: {
- // Load value
- uint8_t value = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Store in accumulator, set flags
- cpu->Y = value;
- cpu->Flags.ZeroFlag = value == 0;
- cpu->Flags.NegativeFlag = (value & 0x80) != 0;
-
- return 2;
- }
- case LDA_XZi: {
- // Get offset
- uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get indirect address, discard carry
- uint8_t _address = (uint8_t)(cpu->X + offset);
- // Get final address, wrap around page
- uint8_t low = readMemory(_address, ram, rom);
- uint8_t high = readMemory((uint8_t)(_address + 1), ram, rom);
- // Get value
- uint8_t value = readMemory(COMBINE(high, low), ram, rom);
- // Store in accumulator, set flags
- cpu->Accumulator = value;
- cpu->Flags.ZeroFlag = value == 0;
- cpu->Flags.NegativeFlag = (value & 0x80) != 0;
-
- return 6;
- }
- case LDX_I: {
- // Load value
- uint8_t value = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Store in X, set flags
- cpu->X = value;
- cpu->Flags.ZeroFlag = value == 0;
- cpu->Flags.NegativeFlag = (value & 0x80) != 0;
-
- return 2;
- }
- case LDY_Z: {
- // Get offset
- uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory(offset, ram, rom);
- // Store in Y, set flags
- cpu->Y = value;
- cpu->Flags.ZeroFlag = value == 0;
- cpu->Flags.NegativeFlag = (value & 0x80) != 0;
-
- return 3;
- }
- case LDA_Z: {
- // Get offset
- uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory(offset, ram, rom);
- // Store in accumulator set flags
- cpu->Accumulator = value;
- cpu->Flags.ZeroFlag = value == 0;
- cpu->Flags.NegativeFlag = (value & 0x80) != 0;
-
- return 3;
- }
- case LDX_Z: {
- // Get offset
- uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory(offset, ram, rom);
- // Store in X, set flags
- cpu->X = value;
- cpu->Flags.ZeroFlag = value == 0;
- cpu->Flags.NegativeFlag = (value & 0x80) != 0;
-
- return 3;
- }
- case TAY: {
- cpu->Y = cpu->Accumulator;
- // Set flags
- cpu->Flags.ZeroFlag = cpu->Y == 0;
- cpu->Flags.NegativeFlag = (cpu->Y & 0x80) != 0;
-
- return 2;
- }
- case LDA_I: {
- // Load value
- uint8_t value = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Store in accumulator, set flags
- cpu->Accumulator = value;
- cpu->Flags.ZeroFlag = value == 0;
- cpu->Flags.NegativeFlag = (value & 0x80) != 0;
-
- return 2;
- }
- case TAX: {
- cpu->X = cpu->Accumulator;
- // Set flags
- cpu->Flags.ZeroFlag = cpu->X == 0;
- cpu->Flags.NegativeFlag = (cpu->X & 0x80) != 0;
-
- return 2;
- }
- case LDY_A: {
- // Load address
- uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
- uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory(COMBINE(high, low), ram, rom);
- // Store in Y, set flags
- cpu->Y = value;
- cpu->Flags.ZeroFlag = value == 0;
- cpu->Flags.NegativeFlag = (value & 0x80) != 0;
-
- return 4;
- }
- case LDA_A: {
- // Load address
- uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
- uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory(COMBINE(high, low), ram, rom);
- // Store in accumulator, set flags
- cpu->Accumulator = value;
- cpu->Flags.ZeroFlag = value == 0;
- cpu->Flags.NegativeFlag = (value & 0x80) != 0;
-
- return 4;
- }
- case LDX_A: {
- // Load address
- uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
- uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory(COMBINE(high, low), ram, rom);
- // Store in X, set flags
- cpu->X = value;
- cpu->Flags.ZeroFlag = value == 0;
- cpu->Flags.NegativeFlag = (value & 0x80) != 0;
-
- return 4;
- }
-
- case BCS: {
- uint8_t cycles = 2;
-
- // Get offset
- int8_t offset = (int8_t)readMemory(cpu->ProgrammeCounter++, ram, rom);
-
- // Check flag
- if (cpu->Flags.CarryFlag == 1) {
- uint16_t oldPC = cpu->ProgrammeCounter;
- // Modify PC
- cpu->ProgrammeCounter += offset;
- // Calculate cycles
- cycles++;
- cycles += PAGE_CROSSED(oldPC, cpu->ProgrammeCounter) ? 1 : 0;
- }
-
- return cycles;
- }
- case LDA_ZiY: {
- // Get _address
- uint8_t _address = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get offset
- uint8_t low = readMemory(_address, ram, rom);
- uint8_t high = readMemory((uint8_t)(_address + 1), ram, rom);
- // Get address
- uint16_t address = cpu->Y + COMBINE(high, low);
- // Get value
- uint8_t value = readMemory(address, ram, rom);
- // Store in accumulator, set flags
- cpu->Accumulator = value;
- cpu->Flags.ZeroFlag = value == 0;
- cpu->Flags.NegativeFlag = (value & 0x80) != 0;
-
- return 5 + (((uint16_t)low + cpu->Y) > 0xFF);
- }
- case LDY_XZ: {
- // Get offset
- uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory((uint8_t)(cpu->X + offset), ram, rom);
- // Store in Y, set flags
- cpu->Y = value;
- cpu->Flags.ZeroFlag = value == 0;
- cpu->Flags.NegativeFlag = (value & 0x80) != 0;
-
- return 4;
- }
- case LDA_XZ: {
- // Get offset
- uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory((uint8_t)(cpu->X + offset), ram, rom);
- // Store in accumulator, set flags
- cpu->Accumulator = value;
- cpu->Flags.ZeroFlag = value == 0;
- cpu->Flags.NegativeFlag = (value & 0x80) != 0;
-
- return 4;
- }
- case LDX_YZ: {
- // Get offset
- uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory((uint8_t)(cpu->Y + offset), ram, rom);
- // Store in X, set flags
- cpu->X = value;
- cpu->Flags.ZeroFlag = value == 0;
- cpu->Flags.NegativeFlag = (value & 0x80) != 0;
-
- return 4;
- }
- case CLV: {
- cpu->Flags.OverflowFlag = 0;
-
- return 2;
- }
- case LDA_YA: {
- // Get address
- uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
- uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Store in Y, set flags
- uint8_t value = readMemory(cpu->Y + COMBINE(high, low), ram, rom);
- cpu->Accumulator = value;
- cpu->Flags.ZeroFlag = value == 0;
- cpu->Flags.NegativeFlag = (value & 0x80) != 0;
-
- return 4 + (((uint16_t)low + cpu->Y) > 0xFF);
- }
- case TSX: {
- cpu->X = cpu->StackPointer;
- // Set flags
- cpu->Flags.ZeroFlag = cpu->X == 0;
- cpu->Flags.NegativeFlag = (cpu->X & 0x80) != 0;
-
- return 2;
- }
- case LDY_XA: {
- // Get address
- uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
- uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Store in Y, set flags
- uint8_t value = readMemory(cpu->X + COMBINE(high, low), ram, rom);
- cpu->Y = value;
- cpu->Flags.ZeroFlag = value == 0;
- cpu->Flags.NegativeFlag = (value & 0x80) != 0;
-
- return 4 + (((uint16_t)low + cpu->X) > 0xFF);
- }
- case LDA_XA: {
- // Get address
- uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
- uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Store in Y, set flags
- uint8_t value = readMemory(cpu->X + COMBINE(high, low), ram, rom);
- cpu->Accumulator = value;
- cpu->Flags.ZeroFlag = value == 0;
- cpu->Flags.NegativeFlag = (value & 0x80) != 0;
-
- return 4 + (((uint16_t)low + cpu->X) > 0xFF);
- }
- case LDX_YA: {
- // Get address
- uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
- uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Store in Y, set flags
- uint8_t value = readMemory(cpu->Y + COMBINE(high, low), ram, rom);
- cpu->X = value;
- cpu->Flags.ZeroFlag = value == 0;
- cpu->Flags.NegativeFlag = (value & 0x80) != 0;
-
- return 4 + (((uint16_t)low + cpu->Y) > 0xFF);
- }
-
- case CPY_I: {
- // Get value
- uint8_t value = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Compare
- uint8_t cmp = cpu->Y - value;
- // Set flags
- cpu->Flags.CarryFlag = value <= cpu->Y;
- cpu->Flags.ZeroFlag = cmp == 0;
- cpu->Flags.NegativeFlag = (cmp & 0x80) != 0;
-
- return 2;
- }
- case CMP_XZi: {
- // Get offset
- uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get indirect address, discard carry
- uint8_t _address = (uint8_t)(cpu->X + offset);
- // Get final address, wrap around page
- uint8_t low = readMemory(_address, ram, rom);
- uint8_t high = readMemory((uint8_t)(_address + 1), ram, rom);
- // Get value
- uint8_t value = readMemory(COMBINE(high, low), ram, rom);
- // Compare
- uint8_t cmp = cpu->Accumulator - value;
- // Set flags
- cpu->Flags.CarryFlag = value <= cpu->Accumulator;
- cpu->Flags.ZeroFlag = cmp == 0;
- cpu->Flags.NegativeFlag = (cmp & 0x80) != 0;
-
- return 6;
- }
- case CPY_Z: {
- // Get offset
- uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory(offset, ram, rom);
- // Compare
- uint8_t cmp = cpu->Y - value;
- // Set flags
- cpu->Flags.CarryFlag = value <= cpu->Y;
- cpu->Flags.ZeroFlag = cmp == 0;
- cpu->Flags.NegativeFlag = (cmp & 0x80) != 0;
-
- return 3;
- }
- case CMP_Z: {
- // Get offset
- uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory(offset, ram, rom);
- // Compare
- uint8_t cmp = cpu->Accumulator - value;
- // Set flags
- cpu->Flags.CarryFlag = value <= cpu->Accumulator;
- cpu->Flags.ZeroFlag = cmp == 0;
- cpu->Flags.NegativeFlag = (cmp & 0x80) != 0;
-
- return 3;
- }
- case DEC_Z: {
- // Get offset
- uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory(offset, ram, rom);
- // Decrement, set flags
- value--;
- cpu->Flags.ZeroFlag = value == 0;
- cpu->Flags.NegativeFlag = (value & 0x80) != 0;
- // Store at address
- writeMemory(offset, value, ram);
-
- return 5;
- }
- case INY: {
- // Increment, set flags
- cpu->Y++;
- cpu->Flags.ZeroFlag = cpu->Y == 0;
- cpu->Flags.NegativeFlag = (cpu->Y & 0x80) != 0;
-
- return 2;
- }
- case CMP_I: {
- // Get value
- uint8_t value = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Compare
- uint8_t cmp = cpu->Accumulator - value;
- // Set flags
- cpu->Flags.CarryFlag = value <= cpu->Accumulator;
- cpu->Flags.ZeroFlag = cmp == 0;
- cpu->Flags.NegativeFlag = (cmp & 0x80) != 0;
-
- return 2;
- }
- case DEX: {
- // Decrement, set flags
- cpu->X--;
- cpu->Flags.ZeroFlag = cpu->X == 0;
- cpu->Flags.NegativeFlag = (cpu->X & 0x80) != 0;
-
- return 2;
- }
- case CPY_A: {
- // Load address
- uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
- uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory(COMBINE(high, low), ram, rom);
- // Compare
- uint8_t cmp = cpu->Y - value;
- // Set flags
- cpu->Flags.CarryFlag = value <= cpu->Y;
- cpu->Flags.ZeroFlag = cmp == 0;
- cpu->Flags.NegativeFlag = (cmp & 0x80) != 0;
-
- return 4;
- }
- case CMP_A: {
- // Load address
- uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
- uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory(COMBINE(high, low), ram, rom);
- // Compare
- uint8_t cmp = cpu->Accumulator - value;
- // Set flags
- cpu->Flags.CarryFlag = value <= cpu->Accumulator;
- cpu->Flags.ZeroFlag = cmp == 0;
- cpu->Flags.NegativeFlag = (cmp & 0x80) != 0;
-
- return 4;
- }
- case DEC_A: {
- // Load address
- uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
- uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory(COMBINE(high, low), ram, rom);
- // Decrement, set flags
- value--;
- cpu->Flags.ZeroFlag = value == 0;
- cpu->Flags.NegativeFlag = (value & 0x80) != 0;
- // Store at address
- writeMemory(COMBINE(high, low), value, ram);
-
- return 6;
- }
-
- case BNE: {
- uint8_t cycles = 2;
-
- // Get offset
- int8_t offset = (int8_t)readMemory(cpu->ProgrammeCounter++, ram, rom);
-
- // Check flag
- if (cpu->Flags.ZeroFlag == 0) {
- uint16_t oldPC = cpu->ProgrammeCounter;
- // Modify PC
- cpu->ProgrammeCounter += offset;
- // Calculate cycles
- cycles++;
- cycles += PAGE_CROSSED(oldPC, cpu->ProgrammeCounter) ? 1 : 0;
- }
-
- return cycles;
- }
- case CMP_ZiY: {
- // Get _address
- uint8_t _address = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get offset
- uint8_t low = readMemory(_address, ram, rom);
- uint8_t high = readMemory((uint8_t)(_address + 1), ram, rom);
- // Get address
- uint16_t address = cpu->Y + COMBINE(high, low);
- // Get value
- uint8_t value = readMemory(address, ram, rom);
- // Compare
- uint8_t cmp = cpu->Accumulator - value;
- // Set flags
- cpu->Flags.CarryFlag = value <= cpu->Accumulator;
- cpu->Flags.ZeroFlag = cmp == 0;
- cpu->Flags.NegativeFlag = (cmp & 0x80) != 0;
-
- return 5 + (((uint16_t)low + cpu->Y) > 0xFF);
- }
- case CMP_XZ: {
- // Get offset
- uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory((uint8_t)(cpu->X + offset), ram, rom);
- // Compare
- uint8_t cmp = cpu->Accumulator - value;
- // Set flags
- cpu->Flags.CarryFlag = value <= cpu->Accumulator;
- cpu->Flags.ZeroFlag = cmp == 0;
- cpu->Flags.NegativeFlag = (cmp & 0x80) != 0;
-
- return 4;
- }
- case DEC_XZ: {
- // Get offset
- uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory((uint8_t)(cpu->X + offset), ram, rom);
- // Decrement, set flags
- value--;
- cpu->Flags.ZeroFlag = value == 0;
- cpu->Flags.NegativeFlag = (value & 0x80) != 0;
- // Store at address
- writeMemory((uint8_t)(cpu->X + offset), value, ram);
-
- return 6;
- }
- case CLD: {
- cpu->Flags.DecimalMode = 0;
-
- return 2;
- }
- case CMP_YA: {
- // Get address
- uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
- uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory(cpu->Y + COMBINE(high, low), ram, rom);
- // Compare
- uint8_t cmp = cpu->Accumulator - value;
- // Set flags
- cpu->Flags.CarryFlag = value <= cpu->Accumulator;
- cpu->Flags.ZeroFlag = cmp == 0;
- cpu->Flags.NegativeFlag = (cmp & 0x80) != 0;
-
- return 4 + (((uint16_t)low + cpu->Y) > 0xFF);
- }
- case CMP_XA: {
- // Get address
- uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
- uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory(cpu->X + COMBINE(high, low), ram, rom);
- // Compare
- uint8_t cmp = cpu->Accumulator - value;
- // Set flags
- cpu->Flags.CarryFlag = value <= cpu->Accumulator;
- cpu->Flags.ZeroFlag = cmp == 0;
- cpu->Flags.NegativeFlag = (cmp & 0x80) != 0;
-
- return 4 + (((uint16_t)low + cpu->X) > 0xFF);
- }
- case DEC_XA: {
- // Get address
- uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
- uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory(cpu->X + COMBINE(high, low), ram, rom);
- // Decrement, set flags
- value--;
- cpu->Flags.ZeroFlag = value == 0;
- cpu->Flags.NegativeFlag = (value & 0x80) != 0;
- // Store at address
- writeMemory(cpu->X + COMBINE(high, low), value, ram);
-
- return 7;
- }
-
- case CPX_I: {
- // Get value
- uint8_t value = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Compare
- uint8_t cmp = cpu->X - value;
- // Set flags
- cpu->Flags.CarryFlag = value <= cpu->X;
- cpu->Flags.ZeroFlag = cmp == 0;
- cpu->Flags.NegativeFlag = (cmp & 0x80) != 0;
-
- return 2;
- }
- case SBC_XZi: {
- // Get offset
- uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get indirect address, discard carry
- uint8_t _address = (uint8_t)(cpu->X + offset);
- // Get final address, wrap around page
- uint8_t low = readMemory(_address, ram, rom);
- uint8_t high = readMemory((uint8_t)(_address + 1), ram, rom);
- // Get value
- uint8_t value = readMemory(COMBINE(high, low), ram, rom);
-
- doSBC(cpu, value);
-
- return 6;
- }
- case CPX_Z: {
- // Get offset
- uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory(offset, ram, rom);
- // Compare
- uint8_t cmp = cpu->X - value;
- // Set flags
- cpu->Flags.CarryFlag = value <= cpu->X;
- cpu->Flags.ZeroFlag = cmp == 0;
- cpu->Flags.NegativeFlag = (cmp & 0x80) != 0;
-
- return 3;
- }
- case SBC_Z: {
- // Get offset
- uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory(offset, ram, rom);
-
- doSBC(cpu, value);
-
- return 3;
- }
- case INC_Z: {
- // Get offset
- uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory(offset, ram, rom);
- // Increment, set flags
- value++;
- cpu->Flags.ZeroFlag = value == 0;
- cpu->Flags.NegativeFlag = (value & 0x80) != 0;
- // Store at address
- writeMemory(offset, value, ram);
-
- return 5;
- }
- case INX: {
- // Increment, set flags
- cpu->X++;
- cpu->Flags.ZeroFlag = cpu->X == 0;
- cpu->Flags.NegativeFlag = (cpu->X & 0x80) != 0;
-
- return 2;
- }
- case SBC_I: {
- // Get value
- uint8_t value = readMemory(cpu->ProgrammeCounter++, ram, rom);
-
- doSBC(cpu, value);
-
- return 2;
- }
- case NOP: {
- return 2;
- }
- case CPX_A: {
- // Load address
- uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
- uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory(COMBINE(high, low), ram, rom);
- // Compare
- uint8_t cmp = cpu->X - value;
- // Set flags
- cpu->Flags.CarryFlag = value <= cpu->X;
- cpu->Flags.ZeroFlag = cmp == 0;
- cpu->Flags.NegativeFlag = (cmp & 0x80) != 0;
-
- return 4;
- }
- case SBC_A: {
- // Load address
- uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
- uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory(COMBINE(high, low), ram, rom);
-
- doSBC(cpu, value);
-
- return 4;
- }
- case INC_A: {
- // Load address
- uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
- uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory(COMBINE(high, low), ram, rom);
- // Increment, set flags
- value++;
- cpu->Flags.ZeroFlag = value == 0;
- cpu->Flags.NegativeFlag = (value & 0x80) != 0;
- // Store at address
- writeMemory(COMBINE(high, low), value, ram);
-
- return 6;
- }
-
- case BEQ: {
- uint8_t cycles = 2;
-
- // Get offset
- int8_t offset = (int8_t)readMemory(cpu->ProgrammeCounter++, ram, rom);
-
- // Check flag
- if (cpu->Flags.ZeroFlag == 1) {
- uint16_t oldPC = cpu->ProgrammeCounter;
- // Modify PC
- cpu->ProgrammeCounter += offset;
- // Calculate cycles
- cycles++;
- cycles += PAGE_CROSSED(oldPC, cpu->ProgrammeCounter) ? 1 : 0;
- }
-
- return cycles;
- }
- case SBC_ZiY: {
- // Get _address
- uint8_t _address = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get offset
- uint8_t low = readMemory(_address, ram, rom);
- uint8_t high = readMemory((uint8_t)(_address + 1), ram, rom);
- // Get address
- uint16_t address = cpu->Y + COMBINE(high, low);
- // Get value
- uint8_t value = readMemory(address, ram, rom);
-
- doSBC(cpu, value);
-
- return 5 + (((uint16_t)low + cpu->Y) > 0xFF);
- }
- case SBC_XZ: {
- // Get offset
- uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory((uint8_t)(cpu->X + offset), ram, rom);
-
- doSBC(cpu, value);
-
- return 4;
- }
- case INC_XZ: {
- // Get offset
- uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory((uint8_t)(cpu->X + offset), ram, rom);
- // Increment, set flags
- value++;
- cpu->Flags.ZeroFlag = value == 0;
- cpu->Flags.NegativeFlag = (value & 0x80) != 0;
- // Store at address
- writeMemory((uint8_t)(cpu->X + offset), value, ram);
-
- return 6;
- }
- case SED: {
- cpu->Flags.DecimalMode = 1;
-
- return 2;
- }
- case SBC_YA: {
- // Get address
- uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
- uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory(cpu->Y + COMBINE(high, low), ram, rom);
-
- doSBC(cpu, value);
-
- return 4 + (((uint16_t)low + cpu->Y) > 0xFF);
- }
- case SBC_XA: {
- // Get address
- uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
- uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory(cpu->X + COMBINE(high, low), ram, rom);
-
- doSBC(cpu, value);
-
- return 4 + (((uint16_t)low + cpu->X) > 0xFF);
- }
- case INC_XA: {
- // Get address
- uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
- uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
- // Get value
- uint8_t value = readMemory(cpu->X + COMBINE(high, low), ram, rom);
- // Increment, set flags
- value++;
- cpu->Flags.ZeroFlag = value == 0;
- cpu->Flags.NegativeFlag = (value & 0x80) != 0;
- // Store at address
- writeMemory(cpu->X + COMBINE(high, low), value, ram);
-
- return 7;
- }
-
- default:
- break;
- }
-
- return 1;
+#include "cpu.h"
+
+#include "memoryMap.h"
+#include "opcodes.h"
+
+#define COMBINE(H, L) ((H << 8) | L)
+#define PAGE_CROSSED(addr1, addr2) (((addr1) ^ (addr2)) & 0xFF00)
+#define LO_BYTE(x) ((uint8_t)((x) & 0xFF))
+#define HI_BYTE(x) ((uint8_t)(((x) >> 8) & 0xFF))
+
+static void doADC(CPU *cpu, uint8_t value) {
+ if (cpu->Flags.DecimalMode == 1) {
+ uint16_t al = (cpu->Accumulator & 0x0F) + (value & 0x0F) + cpu->Flags.CarryFlag;
+ if (al >= 0x0A) al = ((al + 0x06) & 0x0F) + 0x10;
+
+ uint16_t sum = (cpu->Accumulator & 0xF0) + (value & 0xF0) + al;
+ if (sum >= 0xA0) sum += 0x60;
+
+ // N/V/Z are hardware-quirky in decimal mode; derive from the binary sum
+ uint16_t binSum = cpu->Accumulator + value + cpu->Flags.CarryFlag;
+ cpu->Flags.OverflowFlag = ((cpu->Accumulator ^ binSum) & (value ^ binSum) & 0x80) != 0;
+ cpu->Flags.NegativeFlag = (sum & 0x80) != 0;
+ cpu->Flags.ZeroFlag = (uint8_t)binSum == 0;
+
+ cpu->Flags.CarryFlag = sum >= 0x100;
+ cpu->Accumulator = (uint8_t)sum;
+ } else {
+ uint16_t result = cpu->Accumulator + value + cpu->Flags.CarryFlag;
+ cpu->Flags.CarryFlag = result > 0xFF;
+ cpu->Flags.ZeroFlag = (uint8_t)result == 0;
+ cpu->Flags.OverflowFlag = ((cpu->Accumulator ^ result) & (value ^ result) & 0x80) != 0;
+ cpu->Flags.NegativeFlag = (result & 0x80) != 0;
+ cpu->Accumulator = (uint8_t)result;
+ }
+}
+
+static void doSBC(CPU *cpu, uint8_t value) {
+ uint8_t carryIn = cpu->Flags.CarryFlag;
+ uint8_t inverted = value ^ 0xFF;
+
+ uint16_t binResult = cpu->Accumulator + inverted + carryIn;
+ cpu->Flags.CarryFlag = binResult > 0xFF;
+ cpu->Flags.ZeroFlag = (uint8_t)binResult == 0;
+ cpu->Flags.OverflowFlag = ((cpu->Accumulator ^ binResult) & (inverted ^ binResult) & 0x80) != 0;
+ cpu->Flags.NegativeFlag = (binResult & 0x80) != 0;
+
+ if (cpu->Flags.DecimalMode == 1) {
+ int16_t al = (cpu->Accumulator & 0x0F) - (value & 0x0F) - (1 - carryIn);
+ if (al < 0) al = ((al - 0x06) & 0x0F) - 0x10;
+
+ int16_t sum = (cpu->Accumulator & 0xF0) - (value & 0xF0) + al;
+ if (sum < 0) sum -= 0x60;
+
+ cpu->Accumulator = (uint8_t)sum;
+ } else {
+ cpu->Accumulator = (uint8_t)binResult;
+ }
+}
+
+void initCPU(CPU *cpu) {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wmissing-field-initializers"
+ *cpu = (CPU){0x0000, 0xFF};
+#pragma clang diagnostic pop
+}
+
+void resetCPU(CPU *cpu, uint8_t *rom) {
+ uint8_t low = rom[0xFFFC - ROM_BASE];
+ uint8_t high = rom[0xFFFD - ROM_BASE];
+ cpu->ProgrammeCounter = COMBINE(high, low);
+}
+
+uint8_t runCycle(CPU *cpu, uint8_t *ram, uint8_t *rom) {
+ // Fetch opcode
+ uint8_t opcode = readMemory(cpu->ProgrammeCounter++, ram, rom);
+
+ // Decode opcode, fetch operands, execute
+ switch (opcode) {
+ case BRK: {
+ // Store return address on stack
+ uint16_t retAddr = cpu->ProgrammeCounter + 1;
+ writeStack(cpu->StackPointer--, HI_BYTE(retAddr), ram);
+ writeStack(cpu->StackPointer--, LO_BYTE(retAddr), ram);
+ // Set Break flag, Store flags on stack, including HW unused bit quirk
+ cpu->Flags.BreakCommand = 1;
+ writeStack(cpu->StackPointer--, cpu->FlagsByte | 0x30, ram);
+ // Set PC and remaining flags
+ uint8_t low = readMemory(0xFFFE, ram, rom);
+ uint8_t high = readMemory(0xFFFF, ram, rom);
+ cpu->ProgrammeCounter = COMBINE(high, low);
+ cpu->Flags.InterruptDisable = 1;
+
+ return 7;
+ }
+ case ORA_XZi: {
+ // Get offset
+ uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get indirect address, discard carry
+ uint8_t _address = (uint8_t)(cpu->X + offset);
+ // Get final address, wrap around page
+ uint8_t low = readMemory(_address, ram, rom);
+ uint8_t high = readMemory((uint8_t)(_address + 1), ram, rom);
+ // Get value
+ uint8_t value = readMemory(COMBINE(high, low), ram, rom);
+ // Perform OR, set flags
+ cpu->Accumulator |= value;
+ cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
+ cpu->Flags.NegativeFlag = (cpu->Accumulator & 0x80) != 0;
+
+ return 6;
+ }
+ case ORA_Z: {
+ // Get offset
+ uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory(offset, ram, rom);
+ // Perform OR, set flags
+ cpu->Accumulator |= value;
+ cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
+ cpu->Flags.NegativeFlag = (cpu->Accumulator & 0x80) != 0;
+
+ return 3;
+ }
+ case ASL_Z: {
+ // Get offset
+ uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory(offset, ram, rom);
+ // Perform shift
+ cpu->Flags.CarryFlag = (value & 0x80) != 0;
+ value = (uint8_t)(value << 1);
+ // Set flags and write to memory
+ cpu->Flags.ZeroFlag = value == 0;
+ cpu->Flags.NegativeFlag = (value & 0x80) != 0;
+ writeMemory(offset, value, ram);
+
+ return 5;
+ }
+ case PHP: {
+ // Push to stack, force Break and unused to 1 (HW idiosyncrasy)
+ writeStack(cpu->StackPointer--, cpu->FlagsByte | 0x30, ram);
+
+ return 3;
+ }
+ case ORA_I: {
+ // Get value
+ uint8_t value = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Perform OR, set flags
+ cpu->Accumulator |= value;
+ cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
+ cpu->Flags.NegativeFlag = (cpu->Accumulator & 0x80) != 0;
+
+ return 2;
+ }
+ case ASL: {
+ // Perform shift
+ cpu->Flags.CarryFlag = (cpu->Accumulator & 0x80) != 0;
+ cpu->Accumulator = (uint8_t)(cpu->Accumulator << 1);
+ // Set flags
+ cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
+ cpu->Flags.NegativeFlag = (cpu->Accumulator & 0x80) != 0;
+
+ return 2;
+ }
+ case ORA_A: {
+ // Load address
+ uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory(COMBINE(high, low), ram, rom);
+ // Perform OR, set flags
+ cpu->Accumulator |= value;
+ cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
+ cpu->Flags.NegativeFlag = (cpu->Accumulator & 0x80) != 0;
+
+ return 4;
+ }
+ case ASL_A: {
+ // Load address
+ uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory(COMBINE(high, low), ram, rom);
+ // Perform shift
+ cpu->Flags.CarryFlag = (value & 0x80) != 0;
+ value = (uint8_t)(value << 1);
+ // Set flags and write to memory
+ cpu->Flags.ZeroFlag = value == 0;
+ cpu->Flags.NegativeFlag = (value & 0x80) != 0;
+ writeMemory(COMBINE(high, low), value, ram);
+
+ return 6;
+ }
+
+ case BPL: {
+ uint8_t cycles = 2;
+
+ // Get offset
+ int8_t offset = (int8_t)readMemory(cpu->ProgrammeCounter++, ram, rom);
+
+ // Check flag
+ if (cpu->Flags.NegativeFlag == 0) {
+ uint16_t oldPC = cpu->ProgrammeCounter;
+ // Modify PC
+ cpu->ProgrammeCounter += offset;
+ // Calculate cycles
+ cycles++;
+ cycles += PAGE_CROSSED(oldPC, cpu->ProgrammeCounter) ? 1 : 0;
+ }
+
+ return cycles;
+ }
+ case ORA_ZiY: {
+ // Get _address
+ uint8_t _address = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get offset
+ uint8_t low = readMemory(_address, ram, rom);
+ uint8_t high = readMemory((uint8_t)(_address + 1), ram, rom);
+ // Get address
+ uint16_t address = cpu->Y + COMBINE(high, low);
+ // Get value
+ uint8_t value = readMemory(address, ram, rom);
+ // Perform OR, set flags
+ cpu->Accumulator |= value;
+ cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
+ cpu->Flags.NegativeFlag = (cpu->Accumulator & 0x80) != 0;
+
+ return 5 + (((uint16_t)low + cpu->Y) > 0xFF);
+ }
+ case ORA_XZ: {
+ // Get offset
+ uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory((uint8_t)(cpu->X + offset), ram, rom);
+ // Perform OR, set flags
+ cpu->Accumulator |= value;
+ cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
+ cpu->Flags.NegativeFlag = (cpu->Accumulator & 0x80) != 0;
+
+ return 4;
+ }
+ case ASL_XZ: {
+ // Get offset
+ uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory((uint8_t)(cpu->X + offset), ram, rom);
+ // Perform shift
+ cpu->Flags.CarryFlag = (value & 0x80) != 0;
+ value = (uint8_t)(value << 1);
+ // Set flags and write to memory
+ cpu->Flags.ZeroFlag = value == 0;
+ cpu->Flags.NegativeFlag = (value & 0x80) != 0;
+ writeMemory((uint8_t)(cpu->X + offset), value, ram);
+
+ return 6;
+ }
+ case CLC: {
+ cpu->Flags.CarryFlag = 0;
+
+ return 2;
+ }
+ case ORA_YA: {
+ // Get address
+ uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory(cpu->Y + COMBINE(high, low), ram, rom);
+ // Perform OR, set flags
+ cpu->Accumulator |= value;
+ cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
+ cpu->Flags.NegativeFlag = (cpu->Accumulator & 0x80) != 0;
+
+ return 4 + (((uint16_t)low + cpu->Y) > 0xFF);
+ }
+ case ORA_XA: {
+ // Get address
+ uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory(cpu->X + COMBINE(high, low), ram, rom);
+ // Perform OR, set flags
+ cpu->Accumulator |= value;
+ cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
+ cpu->Flags.NegativeFlag = (cpu->Accumulator & 0x80) != 0;
+
+ return 4 + (((uint16_t)low + cpu->X) > 0xFF);
+ }
+ case ASL_XA: {
+ // Get address
+ uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory(cpu->X + COMBINE(high, low), ram, rom);
+ // Perform shift
+ cpu->Flags.CarryFlag = (value & 0x80) != 0;
+ value = (uint8_t)(value << 1);
+ // Set flags and write to memory
+ cpu->Flags.ZeroFlag = value == 0;
+ cpu->Flags.NegativeFlag = (value & 0x80) != 0;
+ writeMemory(cpu->X + COMBINE(high, low), value, ram);
+
+ return 7;
+ }
+
+ case JSR: {
+ // Get address
+ uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Write return address
+ writeStack(cpu->StackPointer--, HI_BYTE(cpu->ProgrammeCounter - 1), ram);
+ writeStack(cpu->StackPointer--, LO_BYTE(cpu->ProgrammeCounter - 1), ram);
+ // Set PC
+ cpu->ProgrammeCounter = COMBINE(high, low);
+
+ return 6;
+ }
+ case AND_XZi: {
+ // Get offset
+ uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get indirect address, discard carry
+ uint8_t _address = (uint8_t)(cpu->X + offset);
+ // Get final address, wrap around page
+ uint8_t low = readMemory(_address, ram, rom);
+ uint8_t high = readMemory((uint8_t)(_address + 1), ram, rom);
+ // Get value
+ uint8_t value = readMemory(COMBINE(high, low), ram, rom);
+ // Perform AND, set flags
+ cpu->Accumulator &= value;
+ cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
+ cpu->Flags.NegativeFlag = (cpu->Accumulator & 0x80) != 0;
+
+ return 6;
+ }
+ case BIT_Z: {
+ // Get offset
+ uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory(offset, ram, rom);
+ // Set flags
+ cpu->Flags.ZeroFlag = (cpu->Accumulator & value) == 0;
+ cpu->Flags.OverflowFlag = (value & 0x40) != 0;
+ cpu->Flags.NegativeFlag = (value & 0x80) != 0;
+
+ return 3;
+ }
+ case AND_Z: {
+ // Get offset
+ uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory(offset, ram, rom);
+ // Perform AND, set flags
+ cpu->Accumulator &= value;
+ cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
+ cpu->Flags.NegativeFlag = (cpu->Accumulator & 0x80) != 0;
+
+ return 3;
+ }
+ case ROL_Z: {
+ // Get offset
+ uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory(offset, ram, rom);
+ // Save bit 7, rotate, set bit 0
+ uint8_t bit7 = value >> 7;
+ value = value << 1;
+ value |= cpu->Flags.CarryFlag;
+ // Set flags
+ cpu->Flags.CarryFlag = bit7 != 0;
+ cpu->Flags.ZeroFlag = value == 0;
+ cpu->Flags.NegativeFlag = (value & 0x80) != 0;
+ // Write value
+ writeMemory(offset, value, ram);
+
+ return 5;
+ }
+ case PLP: {
+ // Pull from stack
+ cpu->FlagsByte = readStack(++cpu->StackPointer, ram);
+
+ return 4;
+ }
+ case AND_I: {
+ // Get value
+ uint8_t value = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Perform AND, set flags
+ cpu->Accumulator &= value;
+ cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
+ cpu->Flags.NegativeFlag = (cpu->Accumulator & 0x80) != 0;
+
+ return 2;
+ }
+ case ROL: {
+ // Save bit 7, rotate, set bit 0
+ uint8_t bit7 = cpu->Accumulator >> 7;
+ cpu->Accumulator = cpu->Accumulator << 1;
+ cpu->Accumulator |= cpu->Flags.CarryFlag;
+ // Set flags
+ cpu->Flags.CarryFlag = bit7 != 0;
+ cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
+ cpu->Flags.NegativeFlag = (cpu->Accumulator & 0x80) != 0;
+
+ return 2;
+ }
+ case BIT_A: {
+ // Load address
+ uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory(COMBINE(high, low), ram, rom);
+ // Set flags
+ cpu->Flags.ZeroFlag = (cpu->Accumulator & value) == 0;
+ cpu->Flags.OverflowFlag = (value & 0x40) != 0;
+ cpu->Flags.NegativeFlag = (value & 0x80) != 0;
+
+ return 4;
+ }
+ case AND_A: {
+ // Load address
+ uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory(COMBINE(high, low), ram, rom);
+ // Perform AND, set flags
+ cpu->Accumulator &= value;
+ cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
+ cpu->Flags.NegativeFlag = (cpu->Accumulator & 0x80) != 0;
+
+ return 4;
+ }
+ case ROL_A: {
+ // Get address
+ uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory(COMBINE(high, low), ram, rom);
+ // Save bit 7, rotate, set bit 0
+ uint8_t bit7 = value >> 7;
+ value = value << 1;
+ value |= cpu->Flags.CarryFlag;
+ // Set flags
+ cpu->Flags.CarryFlag = bit7 != 0;
+ cpu->Flags.ZeroFlag = value == 0;
+ cpu->Flags.NegativeFlag = (value & 0x80) != 0;
+ // Write value
+ writeMemory(COMBINE(high, low), value, ram);
+
+ return 6;
+ }
+
+ case BMI: {
+ uint8_t cycles = 2;
+
+ // Get offset
+ int8_t offset = (int8_t)readMemory(cpu->ProgrammeCounter++, ram, rom);
+
+ // Check flag
+ if (cpu->Flags.NegativeFlag == 1) {
+ uint16_t oldPC = cpu->ProgrammeCounter;
+ // Modify PC
+ cpu->ProgrammeCounter += offset;
+ // Calculate cycles
+ cycles++;
+ cycles += PAGE_CROSSED(oldPC, cpu->ProgrammeCounter) ? 1 : 0;
+ }
+
+ return cycles;
+ }
+ case AND_ZiY: {
+ // Get _address
+ uint8_t _address = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get offset
+ uint8_t low = readMemory(_address, ram, rom);
+ uint8_t high = readMemory((uint8_t)(_address + 1), ram, rom);
+ // Get address
+ uint16_t address = cpu->Y + COMBINE(high, low);
+ // Get value
+ uint8_t value = readMemory(address, ram, rom);
+ // Perform AND, set flags
+ cpu->Accumulator &= value;
+ cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
+ cpu->Flags.NegativeFlag = (cpu->Accumulator & 0x80) != 0;
+
+ return 5 + (((uint16_t)low + cpu->Y) > 0xFF);
+ }
+ case AND_XZ: {
+ // Get offset
+ uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory((uint8_t)(cpu->X + offset), ram, rom);
+ // Perform AND, set flags
+ cpu->Accumulator &= value;
+ cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
+ cpu->Flags.NegativeFlag = (cpu->Accumulator & 0x80) != 0;
+
+ return 4;
+ }
+ case ROL_XZ: {
+ // Get offset
+ uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory((uint8_t)(cpu->X + offset), ram, rom);
+ // Save bit 7, rotate, set bit 0
+ uint8_t bit7 = value >> 7;
+ value = value << 1;
+ value |= cpu->Flags.CarryFlag;
+ // Set flags
+ cpu->Flags.CarryFlag = bit7 != 0;
+ cpu->Flags.ZeroFlag = value == 0;
+ cpu->Flags.NegativeFlag = (value & 0x80) != 0;
+ // Write value
+ writeMemory((uint8_t)(cpu->X + offset), value, ram);
+
+ return 6;
+ }
+ case SEC: {
+ cpu->Flags.CarryFlag = 1;
+
+ return 2;
+ }
+ case AND_YA: {
+ // Get address
+ uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory(cpu->Y + COMBINE(high, low), ram, rom);
+ // Perform AND, set flags
+ cpu->Accumulator &= value;
+ cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
+ cpu->Flags.NegativeFlag = (cpu->Accumulator & 0x80) != 0;
+
+ return 4 + (((uint16_t)low + cpu->Y) > 0xFF);
+ }
+ case AND_XA: {
+ // Get address
+ uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory(cpu->X + COMBINE(high, low), ram, rom);
+ // Perform AND, set flags
+ cpu->Accumulator &= value;
+ cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
+ cpu->Flags.NegativeFlag = (cpu->Accumulator & 0x80) != 0;
+
+ return 4 + (((uint16_t)low + cpu->X) > 0xFF);
+ }
+ case ROL_XA: {
+ // Get address
+ uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory(cpu->X + COMBINE(high, low), ram, rom);
+ // Save bit 7, rotate, set bit 0
+ uint8_t bit7 = value >> 7;
+ value = value << 1;
+ value |= cpu->Flags.CarryFlag;
+ // Set flags
+ cpu->Flags.CarryFlag = bit7 != 0;
+ cpu->Flags.ZeroFlag = value == 0;
+ cpu->Flags.NegativeFlag = (value & 0x80) != 0;
+ // Write value
+ writeMemory(cpu->X + COMBINE(high, low), value, ram);
+
+ return 7;
+ }
+
+ case RTI: {
+ // Pull flags
+ cpu->FlagsByte = readStack(++cpu->StackPointer, ram);
+ // Pull address
+ uint8_t low = readStack(++cpu->StackPointer, ram);
+ uint8_t high = readStack(++cpu->StackPointer, ram);
+ // Set PC
+ cpu->ProgrammeCounter = COMBINE(high, low);
+
+ return 6;
+ }
+ case EOR_XZi: {
+ // Get offset
+ uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get indirect address, discard carry
+ uint8_t _address = (uint8_t)(cpu->X + offset);
+ // Get final address, wrap around page
+ uint8_t low = readMemory(_address, ram, rom);
+ uint8_t high = readMemory((uint8_t)(_address + 1), ram, rom);
+ // Get value
+ uint8_t value = readMemory(COMBINE(high, low), ram, rom);
+ // Perform XOR, set flags
+ cpu->Accumulator ^= value;
+ cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
+ cpu->Flags.NegativeFlag = (cpu->Accumulator & 0x80) != 0;
+
+ return 6;
+ }
+ case EOR_Z: {
+ // Get offset
+ uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory(offset, ram, rom);
+ // Perform XOR, set flags
+ cpu->Accumulator ^= value;
+ cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
+ cpu->Flags.NegativeFlag = (cpu->Accumulator & 0x80) != 0;
+
+ return 3;
+ }
+ case LSR_Z: {
+ // Get offset
+ uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory(offset, ram, rom);
+ // Perform shift
+ cpu->Flags.CarryFlag = (value & 0x01) != 0;
+ value = (uint8_t)(value >> 1);
+ // Set flags and write to memory
+ cpu->Flags.ZeroFlag = value == 0;
+ cpu->Flags.NegativeFlag = 0;
+ writeMemory(offset, value, ram);
+
+ return 5;
+ }
+ case PHA: {
+ writeStack(cpu->StackPointer--, cpu->Accumulator, ram);
+
+ return 3;
+ }
+ case EOR_I: {
+ // Get value
+ uint8_t value = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Perform XOR, set flags
+ cpu->Accumulator ^= value;
+ cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
+ cpu->Flags.NegativeFlag = (cpu->Accumulator & 0x80) != 0;
+
+ return 2;
+ }
+ case LSR: {
+ // Perform shift
+ cpu->Flags.CarryFlag = (cpu->Accumulator & 0x01) != 0;
+ cpu->Accumulator = (uint8_t)(cpu->Accumulator >> 1);
+ // Set flags
+ cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
+ cpu->Flags.NegativeFlag = 0;
+
+ return 2;
+ }
+ case JMP_A: {
+ // Load address
+ uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Set PC
+ cpu->ProgrammeCounter = COMBINE(high, low);
+
+ return 3;
+ }
+ case EOR_A: {
+ // Load address
+ uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory(COMBINE(high, low), ram, rom);
+ // Perform XOR, set flags
+ cpu->Accumulator ^= value;
+ cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
+ cpu->Flags.NegativeFlag = (cpu->Accumulator & 0x80) != 0;
+
+ return 4;
+ }
+ case LSR_A: {
+ // Load address
+ uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory(COMBINE(high, low), ram, rom);
+ // Perform shift
+ cpu->Flags.CarryFlag = (value & 0x01) != 0;
+ value = (uint8_t)(value >> 1);
+ // Set flags and write to memory
+ cpu->Flags.ZeroFlag = value == 0;
+ cpu->Flags.NegativeFlag = 0;
+ writeMemory(COMBINE(high, low), value, ram);
+
+ return 6;
+ }
+
+ case BVC: {
+ uint8_t cycles = 2;
+
+ // Get offset
+ int8_t offset = (int8_t)readMemory(cpu->ProgrammeCounter++, ram, rom);
+
+ // Check flag
+ if (cpu->Flags.OverflowFlag == 0) {
+ uint16_t oldPC = cpu->ProgrammeCounter;
+ // Modify PC
+ cpu->ProgrammeCounter += offset;
+ // Calculate cycles
+ cycles++;
+ cycles += PAGE_CROSSED(oldPC, cpu->ProgrammeCounter) ? 1 : 0;
+ }
+
+ return cycles;
+ }
+ case EOR_ZiY: {
+ // Get _address
+ uint8_t _address = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get offset
+ uint8_t low = readMemory(_address, ram, rom);
+ uint8_t high = readMemory((uint8_t)(_address + 1), ram, rom);
+ // Get address
+ uint16_t address = cpu->Y + COMBINE(high, low);
+ // Get value
+ uint8_t value = readMemory(address, ram, rom);
+ // Perform XOR, set flags
+ cpu->Accumulator ^= value;
+ cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
+ cpu->Flags.NegativeFlag = (cpu->Accumulator & 0x80) != 0;
+
+ return 5 + (((uint16_t)low + cpu->Y) > 0xFF);
+ }
+ case EOR_XZ: {
+ // Get offset
+ uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory((uint8_t)(cpu->X + offset), ram, rom);
+ // Perform XOR, set flags
+ cpu->Accumulator ^= value;
+ cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
+ cpu->Flags.NegativeFlag = (cpu->Accumulator & 0x80) != 0;
+
+ return 4;
+ }
+ case LSR_XZ: {
+ // Get offset
+ uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory((uint8_t)(cpu->X + offset), ram, rom);
+ // Perform shift
+ cpu->Flags.CarryFlag = (value & 0x01) != 0;
+ value = (uint8_t)(value >> 1);
+ // Set flags and write to memory
+ cpu->Flags.ZeroFlag = value == 0;
+ cpu->Flags.NegativeFlag = 0;
+ writeMemory((uint8_t)(cpu->X + offset), value, ram);
+
+ return 6;
+ }
+ case CLI: {
+ cpu->Flags.InterruptDisable = 0;
+
+ return 2;
+ }
+ case EOR_YA: {
+ // Get address
+ uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory(cpu->Y + COMBINE(high, low), ram, rom);
+ // Perform XOR, set flags
+ cpu->Accumulator ^= value;
+ cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
+ cpu->Flags.NegativeFlag = (cpu->Accumulator & 0x80) != 0;
+
+ return 4 + (((uint16_t)low + cpu->Y) > 0xFF);
+ }
+ case EOR_XA: {
+ // Get address
+ uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory(cpu->X + COMBINE(high, low), ram, rom);
+ // Perform XOR, set flags
+ cpu->Accumulator ^= value;
+ cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
+ cpu->Flags.NegativeFlag = (cpu->Accumulator & 0x80) != 0;
+
+ return 4 + (((uint16_t)low + cpu->X) > 0xFF);
+ }
+ case LSR_XA: {
+ // Get address
+ uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory(cpu->X + COMBINE(high, low), ram, rom);
+ // Perform shift
+ cpu->Flags.CarryFlag = (value & 0x01) != 0;
+ value = (uint8_t)(value >> 1);
+ // Set flags and write to memory
+ cpu->Flags.ZeroFlag = value == 0;
+ cpu->Flags.NegativeFlag = 0;
+ writeMemory(cpu->X + COMBINE(high, low), value, ram);
+
+ return 7;
+ }
+
+ case RTS: {
+ // Pull address
+ uint8_t low = readStack(++cpu->StackPointer, ram);
+ uint8_t high = readStack(++cpu->StackPointer, ram);
+ // Set PC
+ cpu->ProgrammeCounter = COMBINE(high, low) + 1;
+
+ return 6;
+ }
+ case ADC_XZi: {
+ // Get offset
+ uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get indirect address, discard carry
+ uint8_t _address = (uint8_t)(cpu->X + offset);
+ // Get final address, wrap around page
+ uint8_t low = readMemory(_address, ram, rom);
+ uint8_t high = readMemory((uint8_t)(_address + 1), ram, rom);
+ // Get value
+ uint8_t value = readMemory(COMBINE(high, low), ram, rom);
+
+ doADC(cpu, value);
+
+ return 6;
+ }
+ case ADC_Z: {
+ // Get offset
+ uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory(offset, ram, rom);
+
+ doADC(cpu, value);
+
+ return 3;
+ }
+ case ROR_Z: {
+ // Get offset
+ uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory(offset, ram, rom);
+ // Save bit 0, rotate, set bit 0
+ uint8_t bit0 = value & 0x1;
+ value = value >> 1;
+ value |= (cpu->Flags.CarryFlag << 7);
+ // Set flags
+ cpu->Flags.CarryFlag = bit0 != 0;
+ cpu->Flags.ZeroFlag = value == 0;
+ cpu->Flags.NegativeFlag = (value & 0x80) != 0;
+ // Write value
+ writeMemory(offset, value, ram);
+
+ return 5;
+ }
+ case PLA: {
+ // Pull from stack
+ cpu->Accumulator = readStack(++cpu->StackPointer, ram);
+ cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
+ cpu->Flags.NegativeFlag = (cpu->Accumulator & 0x80) != 0;
+
+ return 4;
+ }
+ case ADC_I: {
+ // Get value
+ uint8_t value = readMemory(cpu->ProgrammeCounter++, ram, rom);
+
+ doADC(cpu, value);
+
+ return 2;
+ }
+ case ROR: {
+ // Save bit 0, rotate, set bit 0
+ uint8_t bit0 = cpu->Accumulator & 0x1;
+ cpu->Accumulator = cpu->Accumulator >> 1;
+ cpu->Accumulator |= (cpu->Flags.CarryFlag << 7);
+ // Set flags
+ cpu->Flags.CarryFlag = bit0 != 0;
+ cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
+ cpu->Flags.NegativeFlag = (cpu->Accumulator & 0x80) != 0;
+
+ return 2;
+ }
+ case JMP_Ai: {
+ // Load pointer address
+ uint8_t _low = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ uint8_t _high = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ uint16_t address = COMBINE(_high, _low);
+ // Get address, replicating page-wrap hardware bug
+ uint8_t low = readMemory(address, ram, rom);
+ uint8_t high = readMemory((address & 0xFF00) | ((address + 1) & 0x00FF), ram, rom);
+ // Set PC
+ cpu->ProgrammeCounter = COMBINE(high, low);
+
+ return 5;
+ }
+ case ADC_A: {
+ // Load address
+ uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory(COMBINE(high, low), ram, rom);
+
+ doADC(cpu, value);
+
+ return 4;
+ }
+ case ROR_A: {
+ // Get address
+ uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory(COMBINE(high, low), ram, rom);
+ // Save bit 7, rotate, set bit 0
+ uint8_t bit0 = value & 0x1;
+ value = value >> 1;
+ value |= (cpu->Flags.CarryFlag << 7);
+ // Set flags
+ cpu->Flags.CarryFlag = bit0 != 0;
+ cpu->Flags.ZeroFlag = value == 0;
+ cpu->Flags.NegativeFlag = (value & 0x80) != 0;
+ // Write value
+ writeMemory(COMBINE(high, low), value, ram);
+
+ return 6;
+ }
+
+ case BVS: {
+ uint8_t cycles = 2;
+
+ // Get offset
+ int8_t offset = (int8_t)readMemory(cpu->ProgrammeCounter++, ram, rom);
+
+ // Check flag
+ if (cpu->Flags.OverflowFlag == 1) {
+ uint16_t oldPC = cpu->ProgrammeCounter;
+ // Modify PC
+ cpu->ProgrammeCounter += offset;
+ // Calculate cycles
+ cycles++;
+ cycles += PAGE_CROSSED(oldPC, cpu->ProgrammeCounter) ? 1 : 0;
+ }
+
+ return cycles;
+ }
+ case ADC_ZiY: {
+ // Get _address
+ uint8_t _address = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get offset
+ uint8_t low = readMemory(_address, ram, rom);
+ uint8_t high = readMemory((uint8_t)(_address + 1), ram, rom);
+ // Get address
+ uint16_t address = cpu->Y + COMBINE(high, low);
+ // Get value
+ uint8_t value = readMemory(address, ram, rom);
+
+ doADC(cpu, value);
+
+ return 5 + (((uint16_t)low + cpu->Y) > 0xFF);
+ }
+ case ADC_XZ: {
+ // Get offset
+ uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory((uint8_t)(cpu->X + offset), ram, rom);
+
+ doADC(cpu, value);
+
+ return 4;
+ }
+ case ROR_XZ: {
+ // Get offset
+ uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory((uint8_t)(cpu->X + offset), ram, rom);
+ // Save bit 0, rotate, set bit 0
+ uint8_t bit0 = value & 0x1;
+ value = value >> 1;
+ value |= (cpu->Flags.CarryFlag << 7);
+ // Set flags
+ cpu->Flags.CarryFlag = bit0 != 0;
+ cpu->Flags.ZeroFlag = value == 0;
+ cpu->Flags.NegativeFlag = (value & 0x80) != 0;
+ // Write value
+ writeMemory((uint8_t)(cpu->X + offset), value, ram);
+
+ return 6;
+ }
+ case SEI: {
+ cpu->Flags.InterruptDisable = 1;
+
+ return 2;
+ }
+ case ADC_YA: {
+ // Get address
+ uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory(cpu->Y + COMBINE(high, low), ram, rom);
+
+ doADC(cpu, value);
+
+ return 4 + (((uint16_t)low + cpu->Y) > 0xFF);
+ }
+ case ADC_XA: {
+ // Get address
+ uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory(cpu->X + COMBINE(high, low), ram, rom);
+
+ doADC(cpu, value);
+
+ return 4 + (((uint16_t)low + cpu->X) > 0xFF);
+ }
+ case ROR_XA: {
+ // Get address
+ uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory(cpu->X + COMBINE(high, low), ram, rom);
+ // Save bit 0, rotate, set bit 0
+ uint8_t bit0 = value & 0x1;
+ value = value >> 1;
+ value |= (cpu->Flags.CarryFlag << 7);
+ // Set flags
+ cpu->Flags.CarryFlag = bit0 != 0;
+ cpu->Flags.ZeroFlag = value == 0;
+ cpu->Flags.NegativeFlag = (value & 0x80) != 0;
+ // Write value
+ writeMemory(cpu->X + COMBINE(high, low), value, ram);
+
+ return 7;
+ }
+
+ case STA_XZi: {
+ // Get offset
+ uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get indirect address, discard carry
+ uint8_t _address = (uint8_t)(cpu->X + offset);
+ // Get final address, wrap around page
+ uint8_t low = readMemory(_address, ram, rom);
+ uint8_t high = readMemory((uint8_t)(_address + 1), ram, rom);
+ // Store accumulator at address
+ writeMemory(COMBINE(high, low), cpu->Accumulator, ram);
+
+ return 6;
+ }
+ case STY_Z: {
+ // Get offset
+ uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Store Y at address
+ writeMemory(offset, cpu->Y, ram);
+
+ return 3;
+ }
+ case STA_Z: {
+ // Get offset
+ uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Store accumulator at address
+ writeMemory(offset, cpu->Accumulator, ram);
+
+ return 3;
+ }
+ case STX_Z: {
+ // Get offset
+ uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Store X at address
+ writeMemory(offset, cpu->X, ram);
+
+ return 3;
+ }
+ case DEY: {
+ // Decrement, set flags
+ cpu->Y--;
+ cpu->Flags.ZeroFlag = cpu->Y == 0;
+ cpu->Flags.NegativeFlag = (cpu->Y & 0x80) != 0;
+
+ return 2;
+ }
+ case TXA: {
+ cpu->Accumulator = cpu->X;
+ // Set flags
+ cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
+ cpu->Flags.NegativeFlag = (cpu->Accumulator & 0x80) != 0;
+
+ return 2;
+ }
+ case STY_A: {
+ // Load address
+ uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Store Y at address
+ writeMemory(COMBINE(high, low), cpu->Y, ram);
+
+ return 4;
+ }
+ case STA_A: {
+ // Load address
+ uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Store accumulator at address
+ writeMemory(COMBINE(high, low), cpu->Accumulator, ram);
+
+ return 4;
+ }
+ case STX_A: {
+ // Load address
+ uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Store X at address
+ writeMemory(COMBINE(high, low), cpu->X, ram);
+
+ return 4;
+ }
+
+ case BCC: {
+ uint8_t cycles = 2;
+
+ // Get offset
+ int8_t offset = (int8_t)readMemory(cpu->ProgrammeCounter++, ram, rom);
+
+ // Check flag
+ if (cpu->Flags.CarryFlag == 0) {
+ uint16_t oldPC = cpu->ProgrammeCounter;
+ // Modify PC
+ cpu->ProgrammeCounter += offset;
+ // Calculate cycles
+ cycles++;
+ cycles += PAGE_CROSSED(oldPC, cpu->ProgrammeCounter) ? 1 : 0;
+ }
+
+ return cycles;
+ }
+ case STA_ZiY: {
+ // Get _address
+ uint8_t _address = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get offset
+ uint8_t low = readMemory(_address, ram, rom);
+ uint8_t high = readMemory((uint8_t)(_address + 1), ram, rom);
+ // Get address
+ uint16_t address = cpu->Y + COMBINE(high, low);
+ // Store accumulator at address
+ writeMemory(address, cpu->Accumulator, ram);
+
+ return 6;
+ }
+ case STY_XZ: {
+ // Get offset
+ uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Store accumulator at address
+ writeMemory((uint8_t)(cpu->X + offset), cpu->Y, ram);
+
+ return 4;
+ }
+ case STA_XZ: {
+ // Get offset
+ uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Store accumulator at address
+ writeMemory((uint8_t)(cpu->X + offset), cpu->Accumulator, ram);
+
+ return 4;
+ }
+ case STX_YZ: {
+ // Get offset
+ uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Store accumulator at address
+ writeMemory((uint8_t)(cpu->Y + offset), cpu->X, ram);
+
+ return 4;
+ }
+ case TYA: {
+ cpu->Accumulator = cpu->Y;
+ // Set flags
+ cpu->Flags.ZeroFlag = cpu->Accumulator == 0;
+ cpu->Flags.NegativeFlag = (cpu->Accumulator & 0x80) != 0;
+
+ return 2;
+ }
+ case STA_YA: {
+ // Get address
+ uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Store accumulator at address
+ writeMemory(cpu->Y + COMBINE(high, low), cpu->Accumulator, ram);
+
+ return 5;
+ }
+ case TXS: {
+ cpu->StackPointer = cpu->X;
+
+ return 2;
+ }
+ case STA_XA: {
+ // Get address
+ uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Store accumulator at address
+ writeMemory(cpu->X + COMBINE(high, low), cpu->Accumulator, ram);
+
+ return 5;
+ }
+
+ case LDY_I: {
+ // Load value
+ uint8_t value = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Store in accumulator, set flags
+ cpu->Y = value;
+ cpu->Flags.ZeroFlag = value == 0;
+ cpu->Flags.NegativeFlag = (value & 0x80) != 0;
+
+ return 2;
+ }
+ case LDA_XZi: {
+ // Get offset
+ uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get indirect address, discard carry
+ uint8_t _address = (uint8_t)(cpu->X + offset);
+ // Get final address, wrap around page
+ uint8_t low = readMemory(_address, ram, rom);
+ uint8_t high = readMemory((uint8_t)(_address + 1), ram, rom);
+ // Get value
+ uint8_t value = readMemory(COMBINE(high, low), ram, rom);
+ // Store in accumulator, set flags
+ cpu->Accumulator = value;
+ cpu->Flags.ZeroFlag = value == 0;
+ cpu->Flags.NegativeFlag = (value & 0x80) != 0;
+
+ return 6;
+ }
+ case LDX_I: {
+ // Load value
+ uint8_t value = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Store in X, set flags
+ cpu->X = value;
+ cpu->Flags.ZeroFlag = value == 0;
+ cpu->Flags.NegativeFlag = (value & 0x80) != 0;
+
+ return 2;
+ }
+ case LDY_Z: {
+ // Get offset
+ uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory(offset, ram, rom);
+ // Store in Y, set flags
+ cpu->Y = value;
+ cpu->Flags.ZeroFlag = value == 0;
+ cpu->Flags.NegativeFlag = (value & 0x80) != 0;
+
+ return 3;
+ }
+ case LDA_Z: {
+ // Get offset
+ uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory(offset, ram, rom);
+ // Store in accumulator set flags
+ cpu->Accumulator = value;
+ cpu->Flags.ZeroFlag = value == 0;
+ cpu->Flags.NegativeFlag = (value & 0x80) != 0;
+
+ return 3;
+ }
+ case LDX_Z: {
+ // Get offset
+ uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory(offset, ram, rom);
+ // Store in X, set flags
+ cpu->X = value;
+ cpu->Flags.ZeroFlag = value == 0;
+ cpu->Flags.NegativeFlag = (value & 0x80) != 0;
+
+ return 3;
+ }
+ case TAY: {
+ cpu->Y = cpu->Accumulator;
+ // Set flags
+ cpu->Flags.ZeroFlag = cpu->Y == 0;
+ cpu->Flags.NegativeFlag = (cpu->Y & 0x80) != 0;
+
+ return 2;
+ }
+ case LDA_I: {
+ // Load value
+ uint8_t value = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Store in accumulator, set flags
+ cpu->Accumulator = value;
+ cpu->Flags.ZeroFlag = value == 0;
+ cpu->Flags.NegativeFlag = (value & 0x80) != 0;
+
+ return 2;
+ }
+ case TAX: {
+ cpu->X = cpu->Accumulator;
+ // Set flags
+ cpu->Flags.ZeroFlag = cpu->X == 0;
+ cpu->Flags.NegativeFlag = (cpu->X & 0x80) != 0;
+
+ return 2;
+ }
+ case LDY_A: {
+ // Load address
+ uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory(COMBINE(high, low), ram, rom);
+ // Store in Y, set flags
+ cpu->Y = value;
+ cpu->Flags.ZeroFlag = value == 0;
+ cpu->Flags.NegativeFlag = (value & 0x80) != 0;
+
+ return 4;
+ }
+ case LDA_A: {
+ // Load address
+ uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory(COMBINE(high, low), ram, rom);
+ // Store in accumulator, set flags
+ cpu->Accumulator = value;
+ cpu->Flags.ZeroFlag = value == 0;
+ cpu->Flags.NegativeFlag = (value & 0x80) != 0;
+
+ return 4;
+ }
+ case LDX_A: {
+ // Load address
+ uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory(COMBINE(high, low), ram, rom);
+ // Store in X, set flags
+ cpu->X = value;
+ cpu->Flags.ZeroFlag = value == 0;
+ cpu->Flags.NegativeFlag = (value & 0x80) != 0;
+
+ return 4;
+ }
+
+ case BCS: {
+ uint8_t cycles = 2;
+
+ // Get offset
+ int8_t offset = (int8_t)readMemory(cpu->ProgrammeCounter++, ram, rom);
+
+ // Check flag
+ if (cpu->Flags.CarryFlag == 1) {
+ uint16_t oldPC = cpu->ProgrammeCounter;
+ // Modify PC
+ cpu->ProgrammeCounter += offset;
+ // Calculate cycles
+ cycles++;
+ cycles += PAGE_CROSSED(oldPC, cpu->ProgrammeCounter) ? 1 : 0;
+ }
+
+ return cycles;
+ }
+ case LDA_ZiY: {
+ // Get _address
+ uint8_t _address = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get offset
+ uint8_t low = readMemory(_address, ram, rom);
+ uint8_t high = readMemory((uint8_t)(_address + 1), ram, rom);
+ // Get address
+ uint16_t address = cpu->Y + COMBINE(high, low);
+ // Get value
+ uint8_t value = readMemory(address, ram, rom);
+ // Store in accumulator, set flags
+ cpu->Accumulator = value;
+ cpu->Flags.ZeroFlag = value == 0;
+ cpu->Flags.NegativeFlag = (value & 0x80) != 0;
+
+ return 5 + (((uint16_t)low + cpu->Y) > 0xFF);
+ }
+ case LDY_XZ: {
+ // Get offset
+ uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory((uint8_t)(cpu->X + offset), ram, rom);
+ // Store in Y, set flags
+ cpu->Y = value;
+ cpu->Flags.ZeroFlag = value == 0;
+ cpu->Flags.NegativeFlag = (value & 0x80) != 0;
+
+ return 4;
+ }
+ case LDA_XZ: {
+ // Get offset
+ uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory((uint8_t)(cpu->X + offset), ram, rom);
+ // Store in accumulator, set flags
+ cpu->Accumulator = value;
+ cpu->Flags.ZeroFlag = value == 0;
+ cpu->Flags.NegativeFlag = (value & 0x80) != 0;
+
+ return 4;
+ }
+ case LDX_YZ: {
+ // Get offset
+ uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory((uint8_t)(cpu->Y + offset), ram, rom);
+ // Store in X, set flags
+ cpu->X = value;
+ cpu->Flags.ZeroFlag = value == 0;
+ cpu->Flags.NegativeFlag = (value & 0x80) != 0;
+
+ return 4;
+ }
+ case CLV: {
+ cpu->Flags.OverflowFlag = 0;
+
+ return 2;
+ }
+ case LDA_YA: {
+ // Get address
+ uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Store in Y, set flags
+ uint8_t value = readMemory(cpu->Y + COMBINE(high, low), ram, rom);
+ cpu->Accumulator = value;
+ cpu->Flags.ZeroFlag = value == 0;
+ cpu->Flags.NegativeFlag = (value & 0x80) != 0;
+
+ return 4 + (((uint16_t)low + cpu->Y) > 0xFF);
+ }
+ case TSX: {
+ cpu->X = cpu->StackPointer;
+ // Set flags
+ cpu->Flags.ZeroFlag = cpu->X == 0;
+ cpu->Flags.NegativeFlag = (cpu->X & 0x80) != 0;
+
+ return 2;
+ }
+ case LDY_XA: {
+ // Get address
+ uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Store in Y, set flags
+ uint8_t value = readMemory(cpu->X + COMBINE(high, low), ram, rom);
+ cpu->Y = value;
+ cpu->Flags.ZeroFlag = value == 0;
+ cpu->Flags.NegativeFlag = (value & 0x80) != 0;
+
+ return 4 + (((uint16_t)low + cpu->X) > 0xFF);
+ }
+ case LDA_XA: {
+ // Get address
+ uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Store in Y, set flags
+ uint8_t value = readMemory(cpu->X + COMBINE(high, low), ram, rom);
+ cpu->Accumulator = value;
+ cpu->Flags.ZeroFlag = value == 0;
+ cpu->Flags.NegativeFlag = (value & 0x80) != 0;
+
+ return 4 + (((uint16_t)low + cpu->X) > 0xFF);
+ }
+ case LDX_YA: {
+ // Get address
+ uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Store in Y, set flags
+ uint8_t value = readMemory(cpu->Y + COMBINE(high, low), ram, rom);
+ cpu->X = value;
+ cpu->Flags.ZeroFlag = value == 0;
+ cpu->Flags.NegativeFlag = (value & 0x80) != 0;
+
+ return 4 + (((uint16_t)low + cpu->Y) > 0xFF);
+ }
+
+ case CPY_I: {
+ // Get value
+ uint8_t value = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Compare
+ uint8_t cmp = cpu->Y - value;
+ // Set flags
+ cpu->Flags.CarryFlag = value <= cpu->Y;
+ cpu->Flags.ZeroFlag = cmp == 0;
+ cpu->Flags.NegativeFlag = (cmp & 0x80) != 0;
+
+ return 2;
+ }
+ case CMP_XZi: {
+ // Get offset
+ uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get indirect address, discard carry
+ uint8_t _address = (uint8_t)(cpu->X + offset);
+ // Get final address, wrap around page
+ uint8_t low = readMemory(_address, ram, rom);
+ uint8_t high = readMemory((uint8_t)(_address + 1), ram, rom);
+ // Get value
+ uint8_t value = readMemory(COMBINE(high, low), ram, rom);
+ // Compare
+ uint8_t cmp = cpu->Accumulator - value;
+ // Set flags
+ cpu->Flags.CarryFlag = value <= cpu->Accumulator;
+ cpu->Flags.ZeroFlag = cmp == 0;
+ cpu->Flags.NegativeFlag = (cmp & 0x80) != 0;
+
+ return 6;
+ }
+ case CPY_Z: {
+ // Get offset
+ uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory(offset, ram, rom);
+ // Compare
+ uint8_t cmp = cpu->Y - value;
+ // Set flags
+ cpu->Flags.CarryFlag = value <= cpu->Y;
+ cpu->Flags.ZeroFlag = cmp == 0;
+ cpu->Flags.NegativeFlag = (cmp & 0x80) != 0;
+
+ return 3;
+ }
+ case CMP_Z: {
+ // Get offset
+ uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory(offset, ram, rom);
+ // Compare
+ uint8_t cmp = cpu->Accumulator - value;
+ // Set flags
+ cpu->Flags.CarryFlag = value <= cpu->Accumulator;
+ cpu->Flags.ZeroFlag = cmp == 0;
+ cpu->Flags.NegativeFlag = (cmp & 0x80) != 0;
+
+ return 3;
+ }
+ case DEC_Z: {
+ // Get offset
+ uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory(offset, ram, rom);
+ // Decrement, set flags
+ value--;
+ cpu->Flags.ZeroFlag = value == 0;
+ cpu->Flags.NegativeFlag = (value & 0x80) != 0;
+ // Store at address
+ writeMemory(offset, value, ram);
+
+ return 5;
+ }
+ case INY: {
+ // Increment, set flags
+ cpu->Y++;
+ cpu->Flags.ZeroFlag = cpu->Y == 0;
+ cpu->Flags.NegativeFlag = (cpu->Y & 0x80) != 0;
+
+ return 2;
+ }
+ case CMP_I: {
+ // Get value
+ uint8_t value = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Compare
+ uint8_t cmp = cpu->Accumulator - value;
+ // Set flags
+ cpu->Flags.CarryFlag = value <= cpu->Accumulator;
+ cpu->Flags.ZeroFlag = cmp == 0;
+ cpu->Flags.NegativeFlag = (cmp & 0x80) != 0;
+
+ return 2;
+ }
+ case DEX: {
+ // Decrement, set flags
+ cpu->X--;
+ cpu->Flags.ZeroFlag = cpu->X == 0;
+ cpu->Flags.NegativeFlag = (cpu->X & 0x80) != 0;
+
+ return 2;
+ }
+ case CPY_A: {
+ // Load address
+ uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory(COMBINE(high, low), ram, rom);
+ // Compare
+ uint8_t cmp = cpu->Y - value;
+ // Set flags
+ cpu->Flags.CarryFlag = value <= cpu->Y;
+ cpu->Flags.ZeroFlag = cmp == 0;
+ cpu->Flags.NegativeFlag = (cmp & 0x80) != 0;
+
+ return 4;
+ }
+ case CMP_A: {
+ // Load address
+ uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory(COMBINE(high, low), ram, rom);
+ // Compare
+ uint8_t cmp = cpu->Accumulator - value;
+ // Set flags
+ cpu->Flags.CarryFlag = value <= cpu->Accumulator;
+ cpu->Flags.ZeroFlag = cmp == 0;
+ cpu->Flags.NegativeFlag = (cmp & 0x80) != 0;
+
+ return 4;
+ }
+ case DEC_A: {
+ // Load address
+ uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory(COMBINE(high, low), ram, rom);
+ // Decrement, set flags
+ value--;
+ cpu->Flags.ZeroFlag = value == 0;
+ cpu->Flags.NegativeFlag = (value & 0x80) != 0;
+ // Store at address
+ writeMemory(COMBINE(high, low), value, ram);
+
+ return 6;
+ }
+
+ case BNE: {
+ uint8_t cycles = 2;
+
+ // Get offset
+ int8_t offset = (int8_t)readMemory(cpu->ProgrammeCounter++, ram, rom);
+
+ // Check flag
+ if (cpu->Flags.ZeroFlag == 0) {
+ uint16_t oldPC = cpu->ProgrammeCounter;
+ // Modify PC
+ cpu->ProgrammeCounter += offset;
+ // Calculate cycles
+ cycles++;
+ cycles += PAGE_CROSSED(oldPC, cpu->ProgrammeCounter) ? 1 : 0;
+ }
+
+ return cycles;
+ }
+ case CMP_ZiY: {
+ // Get _address
+ uint8_t _address = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get offset
+ uint8_t low = readMemory(_address, ram, rom);
+ uint8_t high = readMemory((uint8_t)(_address + 1), ram, rom);
+ // Get address
+ uint16_t address = cpu->Y + COMBINE(high, low);
+ // Get value
+ uint8_t value = readMemory(address, ram, rom);
+ // Compare
+ uint8_t cmp = cpu->Accumulator - value;
+ // Set flags
+ cpu->Flags.CarryFlag = value <= cpu->Accumulator;
+ cpu->Flags.ZeroFlag = cmp == 0;
+ cpu->Flags.NegativeFlag = (cmp & 0x80) != 0;
+
+ return 5 + (((uint16_t)low + cpu->Y) > 0xFF);
+ }
+ case CMP_XZ: {
+ // Get offset
+ uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory((uint8_t)(cpu->X + offset), ram, rom);
+ // Compare
+ uint8_t cmp = cpu->Accumulator - value;
+ // Set flags
+ cpu->Flags.CarryFlag = value <= cpu->Accumulator;
+ cpu->Flags.ZeroFlag = cmp == 0;
+ cpu->Flags.NegativeFlag = (cmp & 0x80) != 0;
+
+ return 4;
+ }
+ case DEC_XZ: {
+ // Get offset
+ uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory((uint8_t)(cpu->X + offset), ram, rom);
+ // Decrement, set flags
+ value--;
+ cpu->Flags.ZeroFlag = value == 0;
+ cpu->Flags.NegativeFlag = (value & 0x80) != 0;
+ // Store at address
+ writeMemory((uint8_t)(cpu->X + offset), value, ram);
+
+ return 6;
+ }
+ case CLD: {
+ cpu->Flags.DecimalMode = 0;
+
+ return 2;
+ }
+ case CMP_YA: {
+ // Get address
+ uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory(cpu->Y + COMBINE(high, low), ram, rom);
+ // Compare
+ uint8_t cmp = cpu->Accumulator - value;
+ // Set flags
+ cpu->Flags.CarryFlag = value <= cpu->Accumulator;
+ cpu->Flags.ZeroFlag = cmp == 0;
+ cpu->Flags.NegativeFlag = (cmp & 0x80) != 0;
+
+ return 4 + (((uint16_t)low + cpu->Y) > 0xFF);
+ }
+ case CMP_XA: {
+ // Get address
+ uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory(cpu->X + COMBINE(high, low), ram, rom);
+ // Compare
+ uint8_t cmp = cpu->Accumulator - value;
+ // Set flags
+ cpu->Flags.CarryFlag = value <= cpu->Accumulator;
+ cpu->Flags.ZeroFlag = cmp == 0;
+ cpu->Flags.NegativeFlag = (cmp & 0x80) != 0;
+
+ return 4 + (((uint16_t)low + cpu->X) > 0xFF);
+ }
+ case DEC_XA: {
+ // Get address
+ uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory(cpu->X + COMBINE(high, low), ram, rom);
+ // Decrement, set flags
+ value--;
+ cpu->Flags.ZeroFlag = value == 0;
+ cpu->Flags.NegativeFlag = (value & 0x80) != 0;
+ // Store at address
+ writeMemory(cpu->X + COMBINE(high, low), value, ram);
+
+ return 7;
+ }
+
+ case CPX_I: {
+ // Get value
+ uint8_t value = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Compare
+ uint8_t cmp = cpu->X - value;
+ // Set flags
+ cpu->Flags.CarryFlag = value <= cpu->X;
+ cpu->Flags.ZeroFlag = cmp == 0;
+ cpu->Flags.NegativeFlag = (cmp & 0x80) != 0;
+
+ return 2;
+ }
+ case SBC_XZi: {
+ // Get offset
+ uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get indirect address, discard carry
+ uint8_t _address = (uint8_t)(cpu->X + offset);
+ // Get final address, wrap around page
+ uint8_t low = readMemory(_address, ram, rom);
+ uint8_t high = readMemory((uint8_t)(_address + 1), ram, rom);
+ // Get value
+ uint8_t value = readMemory(COMBINE(high, low), ram, rom);
+
+ doSBC(cpu, value);
+
+ return 6;
+ }
+ case CPX_Z: {
+ // Get offset
+ uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory(offset, ram, rom);
+ // Compare
+ uint8_t cmp = cpu->X - value;
+ // Set flags
+ cpu->Flags.CarryFlag = value <= cpu->X;
+ cpu->Flags.ZeroFlag = cmp == 0;
+ cpu->Flags.NegativeFlag = (cmp & 0x80) != 0;
+
+ return 3;
+ }
+ case SBC_Z: {
+ // Get offset
+ uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory(offset, ram, rom);
+
+ doSBC(cpu, value);
+
+ return 3;
+ }
+ case INC_Z: {
+ // Get offset
+ uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory(offset, ram, rom);
+ // Increment, set flags
+ value++;
+ cpu->Flags.ZeroFlag = value == 0;
+ cpu->Flags.NegativeFlag = (value & 0x80) != 0;
+ // Store at address
+ writeMemory(offset, value, ram);
+
+ return 5;
+ }
+ case INX: {
+ // Increment, set flags
+ cpu->X++;
+ cpu->Flags.ZeroFlag = cpu->X == 0;
+ cpu->Flags.NegativeFlag = (cpu->X & 0x80) != 0;
+
+ return 2;
+ }
+ case SBC_I: {
+ // Get value
+ uint8_t value = readMemory(cpu->ProgrammeCounter++, ram, rom);
+
+ doSBC(cpu, value);
+
+ return 2;
+ }
+ case NOP: {
+ return 2;
+ }
+ case CPX_A: {
+ // Load address
+ uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory(COMBINE(high, low), ram, rom);
+ // Compare
+ uint8_t cmp = cpu->X - value;
+ // Set flags
+ cpu->Flags.CarryFlag = value <= cpu->X;
+ cpu->Flags.ZeroFlag = cmp == 0;
+ cpu->Flags.NegativeFlag = (cmp & 0x80) != 0;
+
+ return 4;
+ }
+ case SBC_A: {
+ // Load address
+ uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory(COMBINE(high, low), ram, rom);
+
+ doSBC(cpu, value);
+
+ return 4;
+ }
+ case INC_A: {
+ // Load address
+ uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory(COMBINE(high, low), ram, rom);
+ // Increment, set flags
+ value++;
+ cpu->Flags.ZeroFlag = value == 0;
+ cpu->Flags.NegativeFlag = (value & 0x80) != 0;
+ // Store at address
+ writeMemory(COMBINE(high, low), value, ram);
+
+ return 6;
+ }
+
+ case BEQ: {
+ uint8_t cycles = 2;
+
+ // Get offset
+ int8_t offset = (int8_t)readMemory(cpu->ProgrammeCounter++, ram, rom);
+
+ // Check flag
+ if (cpu->Flags.ZeroFlag == 1) {
+ uint16_t oldPC = cpu->ProgrammeCounter;
+ // Modify PC
+ cpu->ProgrammeCounter += offset;
+ // Calculate cycles
+ cycles++;
+ cycles += PAGE_CROSSED(oldPC, cpu->ProgrammeCounter) ? 1 : 0;
+ }
+
+ return cycles;
+ }
+ case SBC_ZiY: {
+ // Get _address
+ uint8_t _address = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get offset
+ uint8_t low = readMemory(_address, ram, rom);
+ uint8_t high = readMemory((uint8_t)(_address + 1), ram, rom);
+ // Get address
+ uint16_t address = cpu->Y + COMBINE(high, low);
+ // Get value
+ uint8_t value = readMemory(address, ram, rom);
+
+ doSBC(cpu, value);
+
+ return 5 + (((uint16_t)low + cpu->Y) > 0xFF);
+ }
+ case SBC_XZ: {
+ // Get offset
+ uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory((uint8_t)(cpu->X + offset), ram, rom);
+
+ doSBC(cpu, value);
+
+ return 4;
+ }
+ case INC_XZ: {
+ // Get offset
+ uint8_t offset = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory((uint8_t)(cpu->X + offset), ram, rom);
+ // Increment, set flags
+ value++;
+ cpu->Flags.ZeroFlag = value == 0;
+ cpu->Flags.NegativeFlag = (value & 0x80) != 0;
+ // Store at address
+ writeMemory((uint8_t)(cpu->X + offset), value, ram);
+
+ return 6;
+ }
+ case SED: {
+ cpu->Flags.DecimalMode = 1;
+
+ return 2;
+ }
+ case SBC_YA: {
+ // Get address
+ uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory(cpu->Y + COMBINE(high, low), ram, rom);
+
+ doSBC(cpu, value);
+
+ return 4 + (((uint16_t)low + cpu->Y) > 0xFF);
+ }
+ case SBC_XA: {
+ // Get address
+ uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory(cpu->X + COMBINE(high, low), ram, rom);
+
+ doSBC(cpu, value);
+
+ return 4 + (((uint16_t)low + cpu->X) > 0xFF);
+ }
+ case INC_XA: {
+ // Get address
+ uint8_t low = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ uint8_t high = readMemory(cpu->ProgrammeCounter++, ram, rom);
+ // Get value
+ uint8_t value = readMemory(cpu->X + COMBINE(high, low), ram, rom);
+ // Increment, set flags
+ value++;
+ cpu->Flags.ZeroFlag = value == 0;
+ cpu->Flags.NegativeFlag = (value & 0x80) != 0;
+ // Store at address
+ writeMemory(cpu->X + COMBINE(high, low), value, ram);
+
+ return 7;
+ }
+
+ default:
+ break;
+ }
+
+ return 1;
}
\ No newline at end of file
diff --git a/src/io.c b/src/io.c
index d42dccf..1cf8616 100644
--- a/src/io.c
+++ b/src/io.c
@@ -1,14 +1,17 @@
-#include "io.h"
-
-#include
-
-int putChar(uint8_t c) {
- int _c = putchar(c);
- fflush(stdout);
- return _c;
-}
-
-int getChar(void) {
- clearerr(stdin);
- return getchar();
+#include "io.h"
+
+#include
+
+int putChar(uint8_t c) {
+ int _c = putchar(c);
+ fflush(stdout);
+ return _c;
+}
+
+int getChar(void) {
+ clearerr(stdin);
+
+ int c = getchar();
+
+ return c;
}
\ No newline at end of file
diff --git a/src/main.c b/src/main.c
index 96ff6f1..48ff9b0 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1,88 +1,90 @@
-#include "cpu.h"
-#include "ram.h"
-#include "rom.h"
-
-#include
-#include
-#include
-#include
-#include
-#include
-
-#define MACHINE_SPEED_HZ 1e6 // 1 MHz;
-
-static struct termios orig_termios;
-static struct timespec sleepTime;
-
-void restore_terminal(void) { tcsetattr(STDIN_FILENO, TCSANOW, &orig_termios); }
-
-void set_nonblocking_input(void) {
- struct termios raw;
-
- tcgetattr(STDIN_FILENO, &orig_termios);
- atexit(restore_terminal);
-
- raw = orig_termios;
- raw.c_lflag &= ~(ICANON | ECHO); // disable line buffering and echo
- raw.c_cc[VMIN] = 0; // don't block waiting for input
- raw.c_cc[VTIME] = 0;
- tcsetattr(STDIN_FILENO, TCSANOW, &raw);
-
- // make stdin reads non-blocking too
- int flags = fcntl(STDIN_FILENO, F_GETFL, 0);
- fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK);
-}
-
-int main(void) {
- uint8_t *ram = NULL;
- CPU cpu;
-
- set_nonblocking_input();
-
- initRom(rom);
-
- if (createRAM(&ram) != 0) {
- printf("Could not create RAM\n");
- return 1;
- }
-
- /* DEBUG */
-
- //FILE *fp = fopen("/Users/Kili2/Documents/Projekte/6502pc/6502_65C02_functional_tests/6502_functional_test.bin", "rb");
- //FILE *fp = fopen("/Users/Kili2/Documents/Projekte/6502pc/6502_65C02_functional_tests/6502_decimal_test.bin", "rb");
- FILE *fp = fopen("/mnt/c/Users/llego/source/repos/6502PC/6502_65C02_functional_tests/6502_functional_test.bin", "rb");
- //FILE *fp = fopen("/mnt/c/Users/llego/source/repos/6502PC/6502_65C02_functional_tests/6502_decimal_test.bin", "rb");
- if (!fp) {
- perror("fopen");
- return 1;
- }
-
- fread(ram, 1, RAM_SIZE, fp);
- if (ferror(fp)) {
- perror("fread");
- fclose(fp);
- return 1;
- }
-
- fclose(fp);
-
- /* DEBUG END*/
-
- initCPU(&cpu);
- resetCPU(&cpu, rom);
-
- while (1) {
- uint8_t sleep = runCycle(&cpu, ram, rom);
- if (sleep == 1) {
- printf("opcode missing: 0x%X\n", ram[cpu.ProgrammeCounter - 1]);
- return 1;
- }
- sleepTime.tv_sec = 0;
- sleepTime.tv_nsec = sleep * (1000 / MACHINE_SPEED_HZ);
- nanosleep(&sleepTime, NULL);
- }
-
- destroyRAM(ram);
-
- return 0;
+#include "cpu.h"
+#include "ram.h"
+#include "rom.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define MACHINE_SPEED_HZ 1e6 // 1 MHz;
+
+static struct termios orig_termios;
+static struct timespec sleepTime;
+
+void restore_terminal(void) { tcsetattr(STDIN_FILENO, TCSANOW, &orig_termios); }
+
+void set_nonblocking_input(void) {
+ struct termios raw;
+
+ tcgetattr(STDIN_FILENO, &orig_termios);
+ atexit(restore_terminal);
+
+ raw = orig_termios;
+ raw.c_lflag &= ~(ICANON | ECHO); // disable line buffering and echo
+ raw.c_cc[VMIN] = 0; // don't block waiting for input
+ raw.c_cc[VTIME] = 0;
+ tcsetattr(STDIN_FILENO, TCSANOW, &raw);
+
+ // make stdin reads non-blocking too
+ int flags = fcntl(STDIN_FILENO, F_GETFL, 0);
+ fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK);
+}
+
+int main(void) {
+ uint8_t *ram = NULL;
+ CPU cpu;
+
+ set_nonblocking_input();
+
+ initRom(rom);
+
+ if (createRAM(&ram) != 0) {
+ printf("Could not create RAM\n");
+ return 1;
+ }
+
+ /* DEBUG */
+
+ //FILE *fp = fopen("/Users/Kili2/Documents/Projekte/6502pc/6502_65C02_functional_tests/6502_functional_test.bin", "rb");
+ //FILE *fp = fopen("/Users/Kili2/Documents/Projekte/6502pc/6502_65C02_functional_tests/6502_decimal_test.bin", "rb");
+ //FILE *fp = fopen("/mnt/c/Users/llego/source/repos/6502PC/6502_65C02_functional_tests/6502_functional_test.bin", "rb");
+ //FILE *fp = fopen("/mnt/c/Users/llego/source/repos/6502PC/6502_65C02_functional_tests/6502_decimal_test.bin", "rb");
+ /*
+ if (!fp) {
+ perror("fopen");
+ return 1;
+ }
+
+ fread(ram, 1, RAM_SIZE, fp);
+ if (ferror(fp)) {
+ perror("fread");
+ fclose(fp);
+ return 1;
+ }
+
+ fclose(fp);
+ */
+
+ /* DEBUG END*/
+
+ initCPU(&cpu);
+ resetCPU(&cpu, rom);
+
+ while (1) {
+ uint8_t sleep = runCycle(&cpu, ram, rom);
+ if (sleep == 1) {
+ printf("opcode missing: 0x%X\n", ram[cpu.ProgrammeCounter - 1]);
+ return 1;
+ }
+ sleepTime.tv_sec = 0;
+ sleepTime.tv_nsec = sleep * (1000 / MACHINE_SPEED_HZ);
+ nanosleep(&sleepTime, NULL);
+ }
+
+ destroyRAM(ram);
+
+ return 0;
}
\ No newline at end of file
diff --git a/src/memoryMap.c b/src/memoryMap.c
index 70917e6..3f7de6c 100644
--- a/src/memoryMap.c
+++ b/src/memoryMap.c
@@ -1,53 +1,53 @@
-#include "memoryMap.h"
-
-uint8_t readMemory(uint16_t address, uint8_t *ram, uint8_t *rom) {
- if ((address < RAM_SIZE && address < IO_BASE) || address >= ROM_BASE) {
- if (address >= ROM_BASE && ram[IO_BASE + ROM_BANKED_OUT] == 0) {
- return rom[address - ROM_BASE];
- }
-
- return ram[address];
- } else {
- uint16_t _address = address - IO_BASE;
- switch (_address) {
- case KEYBOARD_ADDRESS: {
- return getChar();
- }
- case ROM_BANKED_OUT: {
- return ram[IO_BASE + ROM_BANKED_OUT];
- }
-
- default:
- break;
- }
-
- return 0;
- }
-}
-
-void writeMemory(uint16_t address, uint8_t value, uint8_t *ram) {
- if ((address < RAM_SIZE && address < IO_BASE) || address >= ROM_BASE) {
- if (address < ROM_BASE && ram[IO_BASE + ROM_BANKED_OUT] != 0) {
- ram[address] = value;
- }
- } else {
- uint16_t _address = address - IO_BASE;
- switch (_address) {
- case SCREEN_ADDRESS: {
- putChar(value);
- break;
- }
- case ROM_BANKED_OUT: {
- ram[IO_BASE + ROM_BANKED_OUT] = value;
- break;
- }
-
- default:
- break;
- }
- }
-}
-
-uint8_t readStack(uint8_t address, uint8_t *ram) { return ram[0x100 + address]; }
-
+#include "memoryMap.h"
+
+uint8_t readMemory(uint16_t address, uint8_t *ram, uint8_t *rom) {
+ if ((address < RAM_SIZE && address < IO_BASE) || address >= ROM_BASE) {
+ if (address >= ROM_BASE && ram[IO_BASE + ROM_BANKED_OUT] == 0) {
+ return rom[address - ROM_BASE];
+ }
+
+ return ram[address];
+ } else {
+ uint16_t _address = address - IO_BASE;
+ switch (_address) {
+ case KEYBOARD_ADDRESS: {
+ return getChar();
+ }
+ case ROM_BANKED_OUT: {
+ return ram[IO_BASE + ROM_BANKED_OUT];
+ }
+
+ default:
+ break;
+ }
+
+ return 0;
+ }
+}
+
+void writeMemory(uint16_t address, uint8_t value, uint8_t *ram) {
+ if ((address < RAM_SIZE && address < IO_BASE) || address >= ROM_BASE) {
+ if (address < ROM_BASE && ram[IO_BASE + ROM_BANKED_OUT] != 0) {
+ ram[address] = value;
+ }
+ } else {
+ uint16_t _address = address - IO_BASE;
+ switch (_address) {
+ case SCREEN_ADDRESS: {
+ putChar(value);
+ break;
+ }
+ case ROM_BANKED_OUT: {
+ ram[IO_BASE + ROM_BANKED_OUT] = value;
+ break;
+ }
+
+ default:
+ break;
+ }
+ }
+}
+
+uint8_t readStack(uint8_t address, uint8_t *ram) { return ram[0x100 + address]; }
+
void writeStack(uint8_t address, uint8_t value, uint8_t *ram) { ram[0x100 + address] = value; }
\ No newline at end of file
diff --git a/src/ram.c b/src/ram.c
index c147d00..cdd4e93 100644
--- a/src/ram.c
+++ b/src/ram.c
@@ -1,20 +1,20 @@
-#include "ram.h"
-
-#include "io.h"
-
-#include
-
-int createRAM(uint8_t **ram) {
- *ram = (uint8_t *)malloc(RAM_SIZE);
-
- if (*ram == NULL) return -1;
-
- // Zero IO
- for (size_t i = IO_BASE; i < IO_SIZE; i++) {
- ram[i] = 0;
- }
-
- return 0;
-}
-
+#include "ram.h"
+
+#include "io.h"
+
+#include
+
+int createRAM(uint8_t **ram) {
+ *ram = (uint8_t *)malloc(RAM_SIZE);
+
+ if (*ram == NULL) return -1;
+
+ // Zero IO
+ for (size_t i = IO_BASE; i < IO_SIZE; i++) {
+ ram[i] = 0;
+ }
+
+ return 0;
+}
+
void destroyRAM(uint8_t *ram) { free(ram); }
\ No newline at end of file
diff --git a/src/rom.c b/src/rom.c
index 0fea814..79a529a 100644
--- a/src/rom.c
+++ b/src/rom.c
@@ -1,11 +1,29 @@
-#include "rom.h"
-
-#include "io.h"
-
-uint8_t rom[ROM_SIZE] = {0};
-
-void initRom(uint8_t *rom) {
- /* Reset Vector */
- rom[0xFFFC - ROM_BASE] = 0x00; // Lower byte base of ROM
- rom[0xFFFD - ROM_BASE] = 0x04; // Upper byte of base of ROM
+#include "rom.h"
+
+#include "io.h"
+
+#include
+
+uint8_t rom[ROM_SIZE] = {0};
+
+void initRom(uint8_t *rom) {
+ FILE *fp = fopen("/mnt/c/Users/llego/source/repos/6502PC/msbasic/tmp/kilian.bin", "rb");
+
+ if (!fp) {
+ perror("fopen");
+ return;
+ }
+
+ fread(rom, 1, ROM_SIZE, fp);
+ if (ferror(fp)) {
+ perror("fread");
+ fclose(fp);
+ return;
+ }
+
+ fclose(fp);
+
+ /* Reset Vector, BASIC at DF02 */
+ //rom[0xFFFC - ROM_BASE] = 0x02; // Lower byte base of ROM
+ //rom[0xFFFD - ROM_BASE] = 0xDF; // Upper byte of base of ROM
}
\ No newline at end of file