From f45c2b1ec37179bfd06654b8b8e240f6665cf62d Mon Sep 17 00:00:00 2001 From: Michaelangel007 Date: Thu, 18 Aug 2016 17:42:31 -0700 Subject: [PATCH] Assembly ca65 version --- ca65_fixes.inc | 100 ++++++++++++++ rpm_ca65.s | 346 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 446 insertions(+) create mode 100644 ca65_fixes.inc create mode 100644 rpm_ca65.s diff --git a/ca65_fixes.inc b/ca65_fixes.inc new file mode 100644 index 0000000..a3f6904 --- /dev/null +++ b/ca65_fixes.inc @@ -0,0 +1,100 @@ +; Version 2 +; DB -> DFB + +; ca65 +.feature c_comments +.linecont + +.feature labels_without_colons +.feature leading_dot_in_identifiers +.PC02 ; 65C02 + +; Fix ca65's crappy out-of-the-box support for old assembler directives -- which are completely missing! + +; Force APPLE 'text' to have high bit on +; Will display as NORMAL characters +.macro ASC text + .repeat .strlen(text), I + .byte .strat(text, I) | $80 + .endrep +.endmacro + + +; Define Double Byte -- Big Endian, high-byte first, low-byte second +.macro DDB words +.endmacro + + +; Define Byte +.macro DFB byte1,byte2,byte3,byte4,byte5,byte6,byte7,byte8,byte9,byte10 + .ifnblank byte1 + .byte byte1 + .endif + .ifnblank byte2 + .byte byte2 + .endif + .ifnblank byte3 + .byte byte3 + .endif + .ifnblank byte4 + .byte byte4 + .endif + .ifnblank byte5 + .byte byte5 + .endif + .ifnblank byte6 + .byte byte6 + .endif + .ifnblank byte7 + .byte byte7 + .endif + .ifnblank byte8 + .byte byte8 + .endif + .ifnblank byte9 + .byte byte9 + .endif + .ifnblank byte10 + .byte byte10 + .endif +.endmacro + + +.macro DW words + .word words +.endmacro + + +; DS 1 +; DS 30, $A0 +.macro DS length, fillval + .ifblank fillval + .res length + .else + .res length, fillval + .endif +.endmacro + + +; MAIN EQU * +.define equ = +.define EQU = + + +; ORG *+256 +; +; DATA EQU * +; ORG DATA+256 +.macro ORG address + ; work around that + ; .res address-* + ; doesn't work due to bogus "Error: Constant expression expected" + .local _pc_ +_pc_: +.if .const(_pc_) + .out .sprintf( "Current * = %04X, Reserving $%04X Bytes, New * = $%04X", _pc_, (address-_pc_), address ) + .res (address - _pc_),$EA +.else + .org address +.endif +.endmacro + diff --git a/rpm_ca65.s b/rpm_ca65.s new file mode 100644 index 0000000..e06119c --- /dev/null +++ b/rpm_ca65.s @@ -0,0 +1,346 @@ +; 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 ; hi byte + RTS +GetPtrB + LDX #DigitsB + RTS +GetPtrS + LDX #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 +pad EQU 256 - <* +page EQU *+pad + +DigitsA EQU page ; stupid assembler can't use variable 'a' +DigitsB EQU page+256 +DigitsS EQU page+512 +Buffer EQU page+768 +