Skip to content

Commit

Permalink
Merge branch 'master' into feature/misc-c64-fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
highbyte committed Oct 20, 2023
2 parents acf25b1 + 016c19f commit 706ddbb
Show file tree
Hide file tree
Showing 12 changed files with 1,119 additions and 9 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,8 @@
- Several UI applications [```Highbyte.DotNet6502.Apps.*```](doc/APPS.md) that are the hosts for emulating the Systems above and their different rendering techniques.

# What's currently missing
Including but not limited to:
Missing features (but not limited to):
- 6502 CPU
- Decimal mode (Binary Coded Decimal) calculations
- Support for unofficial opcodes
- Systems
- C64: Emulation of graphics mode, cycle-exact rendering, etc.
Expand All @@ -54,6 +53,7 @@ For requirements and local development setup, see [here](doc/DEVELOP.md)
- https://www.c64-wiki.com/wiki/BRK
- http://www.emulator101.com/6502-addressing-modes.html
- https://www.pagetable.com/?p=410
- http://6502.org/tutorials/decimal_mode.html

## C64 specific references
- https://www.c64-wiki.com/wiki/Reset_(Process)
Expand Down
42 changes: 42 additions & 0 deletions samples/Assembler/Generic/Build/test_bcd_mode.labels
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@


al C:c1b6 .N2
al C:c1b3 .N1
al C:c000 .TEST
al C:c0f1 .SUB2
al C:c0d1 .SUB1
al C:c164 .A65C02
al C:c05b .ADD
al C:c05a .DONE
al C:c0ae .SUB
al C:c1b4 .N1H
al C:c1b5 .N1L
al C:c1b8 .NF
al C:c1ae .DA
al C:c1b1 .HA
al C:c1ba .ZF
al C:c1b9 .VF
al C:c188 .A65816
al C:c1af .DNVZC
al C:c0e3 .S11
al C:c0ed .S12
al C:c1b0 .ERROR
al C:c143 .C1
al C:c091 .A1
al C:c09e .A2
al C:c0a1 .A3
al C:c151 .S6502
al C:c115 .COMPARE
al C:c170 .S65C02
al C:c144 .A6502
al C:c1b2 .HNVZC
al C:c1bb .N2H
al C:c1b7 .N2L
al C:c022 .LOOP2
al C:c00d .LOOP1
al C:c1ad .CF
al C:c1ac .AR
al C:c101 .S21
al C:c111 .S23
al C:c10b .S22
al C:c194 .S65816
Binary file added samples/Assembler/Generic/Build/test_bcd_mode.prg
Binary file not shown.
296 changes: 296 additions & 0 deletions samples/Assembler/Generic/Build/test_bcd_mode.report

Large diffs are not rendered by default.

294 changes: 294 additions & 0 deletions samples/Assembler/Generic/test_bcd_mode.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,294 @@
; FROM http://www.6502.org/tutorials/decimal_mode.html
;
; Verify decimal mode behavior
; Written by Bruce Clark. This code is public domain.
;
; Returns:
; ERROR = 0 if the test passed
; ERROR = 1 if the test failed
;
; This routine requires 17 bytes of RAM -- 1 byte each for:
; AR, CF, DA, DNVZC, ERROR, HA, HNVZC, N1, N1H, N1L, N2, N2L, NF, VF, and ZF
; and 2 bytes for N2H
;
; Variables:
; N1 and N2 are the two numbers to be added or subtracted
; N1H, N1L, N2H, and N2L are the upper 4 bits and lower 4 bits of N1 and N2
; DA and DNVZC are the actual accumulator and flag results in decimal mode
; HA and HNVZC are the accumulator and flag results when N1 and N2 are
; added or subtracted using binary arithmetic
; AR, NF, VF, ZF, and CF are the predicted decimal mode accumulator and
; flag results, calculated using binary arithmetic
;
; This program takes approximately 1 minute at 1 MHz (a few seconds more on
; a 65C02 than a 6502 or 65816)
;

;ACME assembler
;!to "./test_bcd_mode.prg"

;code start address
* = $c000

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
STA N2L
LDA N2 ; N2H = N2 & $F0
AND #$F0 ; [2] see text
STA N2H
ORA #$0F ; N2H+1 = (N2 & $F0) + $0F
STA N2H+1
LOOP2 LDA N1 ; N1L = N1 & $0F
AND #$0F ; [3] see text
STA N1L
LDA N1 ; N1H = N1 & $F0
AND #$F0 ; [4] see text
STA N1H
JSR ADD
JSR A6502
JSR COMPARE
BNE DONE
JSR SUB
JSR S6502
JSR COMPARE
BNE DONE
INC N1 ; [5] see text
BNE LOOP2 ; loop through all 256 values of N1
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 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

; Calculate the predicted SBC accumulator result for the 6502 and 65816

;
SUB1 CPY #1 ; set carry if Y = 1, clear carry if Y = 0
LDA N1L
SBC N2L
LDX #0
BCS S11
INX
SBC #5 ; subtract 6 (carry is clear)
AND #$0F
CLC
S11 ORA N1H
;
; if N1L - N2L >= 0, then subtract N2 & $F0
; if N1L - N2L < 0, then subtract (N2 & $F0) + $0F + 1 (carry is clear)
;
SBC N2H,X
BCS S12
SBC #$5F ; subtract $60 (carry is clear)
S12 STA AR
RTS

; Calculate the predicted SBC accumulator result for the 6502 and 65C02

;
SUB2 CPY #1 ; set carry if Y = 1, clear carry if Y = 0
LDA N1L
SBC N2L
LDX #0
BCS S21
INX
AND #$0F
CLC
S21 ORA N1H
;
; if N1L - N2L >= 0, then subtract N2 & $F0
; if N1L - N2L < 0, then subtract (N2 & $F0) + $0F + 1 (carry is clear)
;
SBC N2H,X
BCS S22
SBC #$5F ; subtract $60 (carry is clear)
S22 CPX #0
BEQ S23
SBC #6
S23 STA AR ; predicted accumulator result
RTS

; Compare accumulator actual results to predicted results
;
; Return:
; Z flag = 1 (BEQ branch) if same
; Z flag = 0 (BNE branch) if different
;
COMPARE LDA DA
CMP AR
BNE C1
LDA DNVZC ; [7] see text
EOR NF
AND #$80 ; mask off N flag
BNE C1
LDA DNVZC ; [8] see text
EOR VF
AND #$40 ; mask off V flag
BNE C1 ; [9] see text
LDA DNVZC
EOR ZF ; mask off Z flag
AND #2
BNE C1 ; [10] see text
LDA DNVZC
EOR CF
AND #1 ; mask off C flag
C1 RTS

; These routines store the predicted values for ADC and SBC for the 6502,
; 65C02, and 65816 in AR, CF, NF, VF, and ZF

A6502 LDA VF
;
; since all 8 bits of the P register were stored in VF, bit 7 of VF contains
; the N flag for NF
;
STA NF
LDA HNVZC
STA ZF
RTS

S6502 JSR SUB1
LDA HNVZC
STA NF
STA VF
STA ZF
STA CF
RTS

A65C02 LDA AR
PHP
PLA
STA NF
STA ZF
RTS

S65C02 JSR SUB2
LDA AR
PHP
PLA
STA NF
STA ZF
LDA HNVZC
STA VF
STA CF
RTS

A65816 LDA AR
PHP
PLA
STA NF
STA ZF
RTS

S65816 JSR SUB1
LDA AR
PHP
PLA
STA NF
STA ZF
LDA HNVZC
STA VF
STA CF
RTS

AR !by 0
CF !by 0
DA !by 0
DNVZC !by 0
ERROR !by 0 ;ERROR should be at $C1B0 if code is loaded at $C000 and not changed
HA !by 0
HNVZC !by 0
N1 !by 0
N1H !by 0
N1L !by 0
N2 !by 0
N2L !by 0
NF !by 0
VF !by 0
ZF !by 0
N2H !by 0,0
Loading

0 comments on commit 706ddbb

Please sign in to comment.