mirror of
https://github.com/Michaelangel007/apple2_russian_peasant_multiplication.git
synced 2024-10-31 19:05:19 +00:00
347 lines
7.5 KiB
ArmAsm
347 lines
7.5 KiB
ArmAsm
|
; ASC
|
||
|
; DFB
|
||
|
;.include "ca65_fixes.inc"
|
||
|
|
||
|
ZERO_LEAD EQU $00
|
||
|
|
||
|
KEY_CR EQU $8D
|
||
|
KEY_ESC EQU $9B
|
||
|
KEY_0 EQU $B0 ; '0' = $30
|
||
|
KEY_9 EQU $B9 ; '9' = $39
|
||
|
|
||
|
pDigits EQU $FA
|
||
|
Carry EQU $FC
|
||
|
Div EQU $FD
|
||
|
|
||
|
KEYBOARD EQU $C000
|
||
|
KEYSTROBE EQU $C010
|
||
|
|
||
|
TEXT EQU $FB2F ; Init text mode and window
|
||
|
HOME EQU $FC58
|
||
|
RDKEY EQU $FD0C
|
||
|
COUT EQU $FDED
|
||
|
|
||
|
__main = $2000
|
||
|
|
||
|
; Header for DOS 3.3 binary file; remove 2 lines for ProDOS
|
||
|
DW __main
|
||
|
DW __end - __main
|
||
|
|
||
|
; main()
|
||
|
ORG __main
|
||
|
|
||
|
LDA #7 ; Version
|
||
|
JSR TEXT ; Just in case we are in graphics mode
|
||
|
JSR HOME
|
||
|
JSR InitABS ; Init A,B,S
|
||
|
JSR IntroH
|
||
|
JSR InputA ; Input
|
||
|
JSR InputB
|
||
|
JSR IntroS
|
||
|
|
||
|
MulDigit ; Calc
|
||
|
JSR IsZeroB
|
||
|
BCS OutS
|
||
|
|
||
|
JSR IsOddB
|
||
|
BCC EvenS
|
||
|
JSR AddAToS
|
||
|
EvenS
|
||
|
JSR ShlA
|
||
|
JSR ShrB
|
||
|
CLC
|
||
|
BCC MulDigit ; ^ (always)
|
||
|
OutS
|
||
|
JSR PrintS ; output
|
||
|
;RTS ; NOTE: DOS3.3 BRUN bug doesn't exit, should JMP $3D0
|
||
|
JMP $0000
|
||
|
|
||
|
InputA
|
||
|
JSR IntroA
|
||
|
JSR GetPtrA
|
||
|
BNE GetString
|
||
|
InputB
|
||
|
JSR IntroB
|
||
|
JSR GetPtrB
|
||
|
; intentional fall int GetString
|
||
|
GetString ; common entry point
|
||
|
STX pDigits
|
||
|
STY pDigits+1
|
||
|
|
||
|
LDX #0 ; digits length
|
||
|
_linechar
|
||
|
JSR GetDigit ; C=1 enter, C=0 digit
|
||
|
BCS _linedone
|
||
|
JSR COUT ; preserves A,Y
|
||
|
AND #$F ; C=0 digit
|
||
|
STA Buffer,X
|
||
|
INX
|
||
|
BPL _linechar ; or BNE for 255 digits
|
||
|
BMI IntroE ; error if > 127 digits
|
||
|
_linedone ; Now move digits from $200 -> DigitsA, DigitsB, etc.
|
||
|
|
||
|
LDY #0 ; X = src, Y = dst offset
|
||
|
CPX #0 ; any digits?
|
||
|
BEQ _movedone ; No digits!
|
||
|
_moveline
|
||
|
DEX
|
||
|
LDA Buffer,X
|
||
|
STA (pDigits),Y ; digit[y] = char & 0xF
|
||
|
INY
|
||
|
CPX #0
|
||
|
BNE _moveline ; ^ max 256 digits
|
||
|
_movedone
|
||
|
BEQ PrintCR ; v (always)
|
||
|
|
||
|
GetDigit
|
||
|
; LDA KEYBOARD
|
||
|
; BPL GetDigit
|
||
|
; STA KEYSTROBE
|
||
|
JSR RDKEY
|
||
|
CMP #KEY_CR
|
||
|
BEQ _eol
|
||
|
CMP #KEY_ESC
|
||
|
BEQ _esc
|
||
|
CMP #KEY_0
|
||
|
BCC GetDigit
|
||
|
CMP #KEY_9+1
|
||
|
BCS GetDigit
|
||
|
RTS
|
||
|
_eol SEC ; C=1 enter
|
||
|
RTS
|
||
|
_esc ; Unwind stack of InputA/B
|
||
|
PLA
|
||
|
PLA
|
||
|
RTS ; Return to who originally called main()
|
||
|
|
||
|
GetPtrA
|
||
|
LDX #<DigitsA ; lo byte
|
||
|
LDY #>DigitsA ; hi byte
|
||
|
RTS
|
||
|
GetPtrB
|
||
|
LDX #<DigitsB
|
||
|
LDY #>DigitsB
|
||
|
RTS
|
||
|
GetPtrS
|
||
|
LDX #<DigitsS
|
||
|
LDY #>DigitsS
|
||
|
RTS
|
||
|
|
||
|
InitABS
|
||
|
LDA #$00
|
||
|
TAX
|
||
|
_zero
|
||
|
STA DigitsA,X
|
||
|
STA DigitsB,X
|
||
|
STA DigitsS,X
|
||
|
INX
|
||
|
BNE _zero ; zero digits[0..$FF]
|
||
|
RTS
|
||
|
|
||
|
|
||
|
IntroA LDY #OffsetA
|
||
|
BNE _intro
|
||
|
IntroB LDY #OffsetB
|
||
|
BNE _intro
|
||
|
IntroS LDY #OffsetS
|
||
|
BNE _intro
|
||
|
IntroE LDY #OffsetE
|
||
|
BNE _intro
|
||
|
IntroH
|
||
|
LDY #OffsetH
|
||
|
_intro
|
||
|
LDA _text,Y
|
||
|
BEQ _outro ; asciiz
|
||
|
JSR COUT
|
||
|
INY
|
||
|
BNE _intro
|
||
|
_outro
|
||
|
RTS
|
||
|
PrintCR
|
||
|
LDA #KEY_CR
|
||
|
JMP COUT
|
||
|
|
||
|
; ________________________________________________________________________
|
||
|
; Pseudo BCD - one byte per digit
|
||
|
; ________________________________________________________________________
|
||
|
|
||
|
; ========================================
|
||
|
PrintA
|
||
|
JSR GetPtrA
|
||
|
BNE _print
|
||
|
PrintB
|
||
|
JSR GetPtrB
|
||
|
BNE _print
|
||
|
PrintS
|
||
|
JSR GetPtrS
|
||
|
_print
|
||
|
STX _bcd+1
|
||
|
STY _bcd+2
|
||
|
LDX #ZERO_LEAD ; Default to leading zero ($0)
|
||
|
LDY #$FF ; start at digits[255]
|
||
|
_bcd
|
||
|
LDA $FFFF,Y ; NOTE: Self-Modified by _print
|
||
|
BNE _digit ; digits[i] == 0 && leadingzero
|
||
|
CPX #ZERO_LEAD ; X != 0
|
||
|
BEQ _skip
|
||
|
_digit
|
||
|
CLC
|
||
|
ADC #KEY_0 ; 0 -> $B0 .. 9 -> $B9
|
||
|
TAX ; If digit printed stop checking for leading zero
|
||
|
JSR COUT
|
||
|
_skip
|
||
|
DEY ;
|
||
|
CPY #$FF ; digits[255] ?
|
||
|
BNE _bcd ; ^
|
||
|
|
||
|
; Bug fix: If no digits were printed then number must be zero
|
||
|
LDA #0 ; print '0'
|
||
|
TAY ; no length
|
||
|
CPX #ZERO_LEAD
|
||
|
BEQ _digit
|
||
|
BNE PrintCR ; ^ (always) move to next line when done
|
||
|
|
||
|
; ========================================
|
||
|
AddAToS
|
||
|
LDY #0
|
||
|
CLC
|
||
|
_add
|
||
|
LDA DigitsS,Y
|
||
|
ADC DigitsA,Y
|
||
|
CMP #$A ; Base=10, C = (a+s+carry) >= 10
|
||
|
BCC _overflow
|
||
|
SBC #$A ; C=1, A = A - 9 - C
|
||
|
_overflow
|
||
|
STA DigitsS,Y
|
||
|
INY
|
||
|
BNE _add
|
||
|
RTS
|
||
|
|
||
|
; ========================================
|
||
|
IsOddB
|
||
|
LDY #0
|
||
|
LDA DigitsB,Y
|
||
|
AND #1
|
||
|
BEQ _not_zero ; Even -> C=0
|
||
|
BNE _is_zero ; Odd _> C=1
|
||
|
|
||
|
; ========================================
|
||
|
IsZeroB
|
||
|
LDY #0
|
||
|
_is_0
|
||
|
LDA DigitsB,Y
|
||
|
BNE _not_zero
|
||
|
INY
|
||
|
BNE _is_0
|
||
|
_is_zero
|
||
|
SEC
|
||
|
RTS
|
||
|
_not_zero
|
||
|
CLC
|
||
|
RTS
|
||
|
|
||
|
; ========================================
|
||
|
ShlA
|
||
|
LDY #0
|
||
|
CLC
|
||
|
_shl
|
||
|
LDA DigitsA,Y
|
||
|
TAX
|
||
|
LDA Mul2Digit,X
|
||
|
ADC #0
|
||
|
STA DigitsA,Y
|
||
|
LDA Mul2Carry,X
|
||
|
ROR
|
||
|
INY
|
||
|
BNE _shl
|
||
|
RTS
|
||
|
|
||
|
; ========================================
|
||
|
ShrB
|
||
|
LDY #$FF ; start at digits[255]
|
||
|
LDX #0 ; digits processed
|
||
|
STX Carry ; $00 .. 9*2 = $18
|
||
|
_shr
|
||
|
CLC ;
|
||
|
LDA DigitsB,Y ; sum = digit[i] + carry
|
||
|
ADC Carry ; A=0000_00xy C=0/1
|
||
|
ROR ; A=c000_000x, C=y
|
||
|
AND #$F ; A=0000_000x
|
||
|
STA DigitsB,Y ; digit[i] = (sum / 2)
|
||
|
LDA #0 ;
|
||
|
BCC _shr_next ; C=0 -> Carry = 0
|
||
|
LDA #10 ; C=1 -> Carry = 10 (base)
|
||
|
_shr_next
|
||
|
STA Carry ; carry = (sum & 1) ? BASE : 0
|
||
|
DEY
|
||
|
INX ; we need to compare y=$FF without disturbing carry
|
||
|
BNE _shr ; max 256 digits -- solution, use X reg :-)
|
||
|
RTS
|
||
|
|
||
|
Mul2Digit ; Digit
|
||
|
DFB 0 ; 0*2 = 0 0
|
||
|
DFB 2 ; 1*2 = 0 2
|
||
|
DFB 4 ; 2*2 = 0 4
|
||
|
DFB 6 ; 3*2 = 0 6
|
||
|
DFB 8 ; 4*2 = 0 8
|
||
|
DFB 0 ; 5*2 = 1 0
|
||
|
DFB 2 ; 6*2 = 1 2
|
||
|
DFB 4 ; 7*2 = 1 4
|
||
|
DFB 6 ; 8*2 = 1 6
|
||
|
DFB 8 ; 9*2 = 1 8
|
||
|
Mul2Carry ; Carry
|
||
|
DFB 0 ; 0*2 = 0 0
|
||
|
DFB 0 ; 1*2 = 0 2
|
||
|
DFB 0 ; 2*2 = 0 4
|
||
|
DFB 0 ; 3*2 = 0 6
|
||
|
DFB 0 ; 4*2 = 0 8
|
||
|
DFB 1 ; 5*2 = 1 0
|
||
|
DFB 1 ; 6*2 = 1 2
|
||
|
DFB 1 ; 7*2 = 1 4
|
||
|
DFB 1 ; 8*2 = 1 6
|
||
|
DFB 1 ; 9*2 = 1 8
|
||
|
|
||
|
_text
|
||
|
TextH ; Header
|
||
|
ASC "RUSSIAN PEASANT MULTIPLICATION"
|
||
|
DFB KEY_CR
|
||
|
DFB KEY_CR
|
||
|
DFB 0
|
||
|
TextA
|
||
|
ASC "INPUT A"
|
||
|
DFB KEY_CR
|
||
|
ASC "?"
|
||
|
DFB 0
|
||
|
TextB
|
||
|
ASC "INPUT B"
|
||
|
DFB KEY_CR
|
||
|
ASC "?"
|
||
|
DFB 0
|
||
|
TextE
|
||
|
DFB KEY_CR
|
||
|
ASC "WARNING"
|
||
|
ASC ": MORE THAN 127 CHARS"
|
||
|
DFB KEY_CR
|
||
|
DFB 0
|
||
|
TextS
|
||
|
ASC "= "
|
||
|
DFB 0
|
||
|
|
||
|
OffsetH EQU TextH - _text
|
||
|
OffsetA EQU TextA - _text
|
||
|
OffsetB EQU TextB - _text
|
||
|
OffsetE EQU TextE - _text
|
||
|
OffsetS EQU TextS - _text
|
||
|
|
||
|
__end
|
||
|
|
||
|
; Pad until end of page, these globals are not stored on disk
|
||
|
DUM *
|
||
|
DS \
|
||
|
DigitsA DS 256 ; stupid assembler can't use variable 'a'
|
||
|
DigitsB DS 256
|
||
|
DigitsS DS 256
|
||
|
Buffer DS 256
|
||
|
DEND
|
||
|
|