apple2_printm/printm.s

500 lines
10 KiB
ArmAsm
Raw Normal View History

2016-02-18 15:48:00 +00:00
; Version 9
2016-02-17 20:35:00 +00:00
; ca65
.feature c_comments
.feature labels_without_colons
.feature leading_dot_in_identifiers
; 65C02
.PC02
; Force APPLE 'text' to have high bit on
; Will display as NORMAL characters
.macro APPLE text
.repeat .strlen(text), I
.byte .strat(text, I) | $80
.endrep
.endmacro
; Force ASCII 'text' to be control chars: $00..$1F
; Will display as INVERSE characters
.macro CTRL text
.repeat .strlen(text), I
.byte .strat(text, I) & $1F
.endrep
.endmacro
; Force ASCII 'text' to be control chars: $00..$3F
; Will display as INVERSE characters
.macro INV text
.repeat .strlen(text), I
.byte .strat(text, I) & $3F
.endrep
.endmacro
.macro db val
.byte val
.endmacro
.macro dw val
.word val
.endmacro
.macro ds bytes
.res bytes
.endmacro
2016-02-18 15:48:00 +00:00
__MAIN = $4000
2016-02-17 20:35:00 +00:00
2016-02-18 15:48:00 +00:00
; DOS3.3 meta -- remove these 2 if running under ProDOS
.word __MAIN ; 2 byte BLOAD address
.word __END - __MAIN ; 2 byte BLOAD size
2016-02-17 20:35:00 +00:00
2016-02-18 15:48:00 +00:00
.org __MAIN ; .org must come after header else offsets are wrong
2016-02-17 20:35:00 +00:00
HOME = $FC58
2016-02-18 00:47:00 +00:00
temp = $FE
2016-02-17 20:35:00 +00:00
2016-02-17 23:02:00 +00:00
JSR HOME
LDA #$D5
STA $2345
STA DATA + $0C
JSR ReverseByte
STA DATA + $0E
LDX #<DATA ; Low Byte of Address
LDY #>DATA ; High Byte of Address
JSR PrintM
RTS
ReverseByte
LDX #8
STA temp
ReverseBit
ASL temp
ROR
DEX
BNE ReverseBit
RTS
2016-02-17 20:35:00 +00:00
TEXT
APPLE "X="
2016-02-17 23:02:00 +00:00
.byte "#"
APPLE " Y="
2016-02-17 23:42:00 +00:00
.byte "d"
2016-02-17 23:02:00 +00:00
APPLE " $="
.byte "x"
APPLE ":"
.byte "@"
APPLE " "
.byte "%"
APPLE "~"
.byte "?"
2016-02-17 20:35:00 +00:00
.byte 0
DATA
dw $0400 ; aArg[-1] Screen Dst
dw TEXT ; aArg[ 0] text
2016-02-17 23:02:00 +00:00
dw 39 ; aArg[ 1] x
dw 191 ; aArg[ 2] y
dw $2345 ; aArg[ 3] addr
dw $2345 ; aArg[ 4] byte
dw $DA1A ; aArg[ 5] bits
dw $DA1A ; aArg[ 6] bits
2016-02-17 20:35:00 +00:00
2016-02-17 23:02:00 +00:00
ds 256 - <*
2016-02-17 20:35:00 +00:00
/*
2016-02-18 15:48:00 +00:00
/*
Problem:
We want to print this ...
.byte "X=## Y=### $=####:@@ %%%%%%%%~????????"
... without having to waste marking up literals with an escape character
2016-02-17 20:35:00 +00:00
printf() on the 6502
- is bloated by using a meta-character '%' instead of the high bit
2016-02-18 15:48:00 +00:00
- doesn't provide a standard way to print binary *facepalm*
2016-02-17 20:35:00 +00:00
- doesn't provide a standard way to print a deferenced pointer
2016-02-18 15:48:00 +00:00
- 2 digit, 3 digit and 5 digit decimals requiring wasting a "width" character
e.g. %2d, %3d, %5d
2016-02-17 20:35:00 +00:00
2016-02-18 15:48:00 +00:00
Solution:
Here is a micro replacement, printm()
2016-02-17 20:35:00 +00:00
* Literals have the high byte set (APPLE text)
* Meta characters have the high bit cleared (ASCII)
2016-02-18 15:48:00 +00:00
x Hex 2 Byte
$ Hex 4 Byte
@ Ptr 2 Byte
& Ptr 4 Byte
2016-02-17 20:35:00 +00:00
2016-02-18 15:48:00 +00:00
# Dec 1 Byte (max 2 digits)
d Dec 2 Byte (max 3 digits)
u Dec 2 Byte (max 5 digits)
% Bin 1 Byte normal one's and zeros
? Bin 1 Byte inverse one's, normal zeroes
s Str - Zero terminated
p Str - Pascall
Note: The dummy address $C0DE is to force the assembler
to generate a 16-bit address instead of optimizing a ZP operand
2016-02-17 20:35:00 +00:00
*/
; Self-Modifying variable aliases
_pScreen = PutChar +1
_pFormat = GetFormat +1
_iArg = NxtArgByte+1
_pArg = IncArg +1
2016-02-18 00:47:00 +00:00
_nHexWidth = HexWidth +1
_nDecWidth = DecWidth +1
2016-02-17 20:35:00 +00:00
; printm( format, args, ... )
2016-02-18 00:47:00 +00:00
; ======================================================================
2016-02-17 20:35:00 +00:00
PrintM
STX _pArg+0
STY _pArg+1
STZ _iArg
JSR NxtArgXY
STX _pScreen+0 ; lo
STY _pScreen+1 ; hi
NextArg
JSR NxtArgXY
STX _pFormat+0 ; lo
STY _pFormat+1 ; hi
BRA GetFormat ; always
2016-02-17 23:02:00 +00:00
; x Hex 2 Byte
; $ Hex 4 Byte
2016-02-18 00:47:00 +00:00
; ======================================================================
2016-02-17 23:02:00 +00:00
PrintHex4
LDA #4
BNE _PrintHex
PrintHex2
LDA #2
_PrintHex
2016-02-18 00:47:00 +00:00
STA _nHexWidth
2016-02-17 23:02:00 +00:00
JSR NxtArgXY
2016-02-18 15:48:00 +00:00
; Print 16-bit Y,X in hex
; Uses _nHexWidth to limit output width
_PrintHexYX
2016-02-17 23:17:00 +00:00
STX _val+0
STY _val+1
LDX #0
_HexDigit
LDA _val+0
AND #$F
CMP #$A ; n < 10 ?
BCC _Hex2Asc
ADC #6 ; n += 6 $A -> +6 + (C=1) = $11
_Hex2Asc
ADC #'0' + $80 ; inverse=remove #$80
STA _bcd, X ; NOTE: Digits are reversed!
LSR _val+1 ; 16-bit SHR nibble
ROR _val+0
LSR _val+1
ROR _val+0
LSR _val+1
ROR _val+0
LSR _val+1
ROR _val+0
INX
2016-02-18 00:47:00 +00:00
HexWidth
CPX #0 ; _nHexWidth NOTE: self-modifying!
2016-02-17 23:17:00 +00:00
BNE _HexDigit
2016-02-17 23:54:00 +00:00
; Intentional fall into reverse BCD
2016-02-17 23:17:00 +00:00
2016-02-18 00:47:00 +00:00
; On Entry: X number of chars to print in buffer _bcd
; ======================================================================
2016-02-17 23:42:00 +00:00
PrintReverseBCD
2016-02-17 23:17:00 +00:00
DEX
BMI NextFormat
LDA _bcd, X
JSR PutChar
2016-02-17 23:42:00 +00:00
BRA PrintReverseBCD
2016-02-17 23:02:00 +00:00
2016-02-18 00:47:00 +00:00
2016-02-17 23:02:00 +00:00
; @ Ptr 2 Byte
; & Ptr 4 Byte
2016-02-18 00:47:00 +00:00
; ======================================================================
2016-02-17 23:02:00 +00:00
PrintPtr4
LDA #4
BNE _PrintPtr
PrintPtr2
LDA #2
_PrintPtr
2016-02-18 00:47:00 +00:00
STA _nHexWidth
2016-02-17 23:02:00 +00:00
JSR NxtArgXY
2016-02-18 00:47:00 +00:00
; 13 bytes - zero page version
STX temp+0 ; zero-page for (ZP),Y
STY temp+1
2016-02-17 23:02:00 +00:00
LDY #$0
2016-02-18 00:47:00 +00:00
LDA (temp),Y
2016-02-17 23:02:00 +00:00
TAX
INY
2016-02-18 00:47:00 +00:00
LDA (temp),Y
2016-02-17 23:02:00 +00:00
TAY
2016-02-18 00:47:00 +00:00
; 20 bytes - self modifying code version if zero-page not available
; STX PtrVal+1
; STY PtrVal+2
; LDY #0 ; 0: A->X
;PrtVal
; TAX ; 1: A->Y
; LDA $C0DE, Y
; INY
; CPY #2
; BEQ _JumpPrintHexXY
; BNE _PtrVal
;_JumpPrintHexXY
; TAY
2016-02-18 15:48:00 +00:00
BRA _PrintHexYX ; always
2016-02-17 23:02:00 +00:00
2016-02-18 00:47:00 +00:00
; ======================================================================
2016-02-17 20:35:00 +00:00
Print
JSR PutChar
2016-02-17 23:42:00 +00:00
; Adjust pointer to next char in format
2016-02-17 20:35:00 +00:00
NextFormat
2016-02-17 23:42:00 +00:00
INC _pFormat+0
BNE GetFormat
INC _pFormat+1
2016-02-17 20:35:00 +00:00
GetFormat
LDA $C0DE ; _pFormat NOTE: self-modifying!
BEQ _Done
BMI Print ; neg = literal
LDX #NumMeta-1 ; pos = meta
FindMeta
CMP MetaChar,X
BEQ CallMeta
DEX
BPL FindMeta
BMI NextFormat ; always = invalid meta; ignore
CallMeta
TXA
ASL
TAX
JMP (MetaFunc,X)
_Done
RTS
; === Meta Ops ===
2016-02-17 23:42:00 +00:00
; # Dec 1 Byte (max 2 digits)
; d Dec 2 Byte (max 3 digits)
; u Dec 2 Byte (max 5 digits)
2016-02-18 00:47:00 +00:00
; ======================================================================
2016-02-17 23:54:00 +00:00
PrintDec5
LDA #5
BNE _PrintDec ; always
PrintDec3
LDA #3
BNE _PrintDec ; always
2016-02-17 23:02:00 +00:00
PrintDec2
2016-02-17 23:54:00 +00:00
LDA #2 ; 2 digits
2016-02-17 23:02:00 +00:00
_PrintDec
2016-02-18 00:47:00 +00:00
STA _nDecWidth
2016-02-17 23:02:00 +00:00
JSR NxtArgXY
2016-02-18 15:48:00 +00:00
PrintDecYX
2016-02-17 23:02:00 +00:00
STX _val+0
STY _val+1
2016-02-17 20:35:00 +00:00
2016-02-17 23:02:00 +00:00
STZ _bcd+0
STZ _bcd+1
STZ _bcd+2
2016-02-17 20:35:00 +00:00
2016-02-17 23:17:00 +00:00
Dec2BCD
2016-02-17 23:02:00 +00:00
LDX #16
SED
2016-02-17 23:17:00 +00:00
_Dec2BCD
2016-02-17 23:02:00 +00:00
ASL _val+0
ROl _val+1
LDA _bcd+0
ADC _bcd+0
STA _bcd+0
LDA _bcd+1
ADC _bcd+1
STA _bcd+1
LDA _bcd+2
ADC _bcd+2
STA _bcd+2
DEX
2016-02-17 23:17:00 +00:00
BNE _Dec2BCD
2016-02-17 23:02:00 +00:00
CLD
2016-02-17 23:17:00 +00:00
BCD2Char
2016-02-17 23:02:00 +00:00
LDX #2
LDY #5
2016-02-17 23:17:00 +00:00
_BCD2Char
2016-02-17 23:02:00 +00:00
LDA _bcd,X ; ab?def a?_dXX ?_YYXX
LSR
LSR
LSR
LSR
CLC
ADC #'0' + $80
STA _bcd,Y ; ab?deX a?_YXX ?ZYYXX
DEY
LDA _bcd,X ; ab?deX a?_YXX ?ZYYXX
AND #$F
CLC
ADC #'0' + $80
STA _bcd,Y ; ab?dXX a?YYXX ZZYYXX
DEY
DEX
2016-02-17 23:17:00 +00:00
BPL _BCD2Char
2016-02-18 00:47:00 +00:00
DecWidth
LDX #0 ; _nDecDigits NOTE: self modifying!
2016-02-17 23:42:00 +00:00
JMP PrintReverseBCD
2016-02-17 23:02:00 +00:00
2016-02-18 15:48:00 +00:00
; % Bin 1 Byte normal one's and zeros
; ? Bin 1 Byte inverse one's, normal zeroes
2016-02-18 00:47:00 +00:00
; ======================================================================
2016-02-17 23:02:00 +00:00
PrintBinInv
LDA #$81
BNE _PrintBin
2016-02-17 20:35:00 +00:00
PrintBinAsc
2016-02-17 23:02:00 +00:00
LDA #$01
_PrintBin
STA _PrintBit+1
2016-02-18 00:47:00 +00:00
JSR NxtArgXY ; X = low byte
2016-02-17 23:02:00 +00:00
LDY #8 ; print 8 bits
_Bit2Asc
2016-02-18 00:47:00 +00:00
TXA
CMP #$80 ; C= A>=$80
ROL ; C<-76543210<-C
TAX
2016-02-17 23:02:00 +00:00
AND #$01 ; 0 -> B0
BEQ _FlipBit
_PrintBit
LDA #$81 ; 1 -> 31 NOTE: self-modifying!
_FlipBit
EOR #$B0
JSR PutChar
DEY
BNE _Bit2Asc
2016-02-17 23:42:00 +00:00
_JumpNextFormat
; BRA NextFormat ; always
JMP NextFormat ; JMP :-(
2016-02-17 23:54:00 +00:00
; ___ Utility ___
2016-02-17 23:02:00 +00:00
/*
2016-02-17 20:35:00 +00:00
_CmpMeta = CmpMeta+1
GetWidth
STA _CmpMeta ; save last meta
LDA _pFormat+0 ; Src.Lo
LDY _pFormat+1 ; Src.Hi
STA IncWidth+1 ; Dst.Lo
STY IncWidth+2 ; Dst.Hi
LDY #0
IncWidth
LDA $C0DE,Y ; NOTE: self-modifying!
2016-02-18 00:47:00 +00:00
STY _nHexWidth
2016-02-17 20:35:00 +00:00
CmpMeta
CMP #$00 ; _CmpMeta NOTE: self-modifying!
BNE _Done ; optimization: re-use RTS
INY
BRA IncWidth
2016-02-17 23:02:00 +00:00
*/
2016-02-17 20:35:00 +00:00
2016-02-18 00:47:00 +00:00
; ======================================================================
2016-02-17 20:35:00 +00:00
PutChar
STA $400 ; NOTE: self-modifying!
INC PutChar+1 ; inc lo
RTS
; @return &aArg[ iArg ] -> XY
2016-02-18 00:47:00 +00:00
; ======================================================================
2016-02-17 20:35:00 +00:00
GetArgAddr
LDX _pArg+0 ; Low Byte
LDY _pArg+1 ; High Byte
RTS
2016-02-18 00:47:00 +00:00
; ======================================================================
2016-02-17 20:35:00 +00:00
; @return _Arg[ _Num ]
NxtArgByte
LDY #00 ; _iArg NOTE: self-modifying!
IncArg
LDA $C0DE,Y ; _pArg NOTE: self-modifying!
INC _iArg ;
BNE @_SamePage
INC _pArg+1 ;
@_SamePage
RTS
2016-02-18 00:47:00 +00:00
; ======================================================================
2016-02-17 20:35:00 +00:00
; @return X,Y 16-bit arg value
NxtArgXY
JSR NxtArgByte
TAX
JSR NxtArgByte
TAY
RTS
2016-02-17 23:54:00 +00:00
; Hex2/Hex4 temp
2016-02-17 23:02:00 +00:00
_bcd ds 6 ; 6 chars for printing dec
2016-02-17 20:35:00 +00:00
_val dw 0
MetaChar
2016-02-17 23:02:00 +00:00
db '&' ; PrintPtr4
db '@' ; PrintPtr2
2016-02-17 20:35:00 +00:00
db '?' ; PrintBinInv
db '%' ; PrintBinAsc
2016-02-17 23:54:00 +00:00
db 'u' ; PrintDec5
db 'd' ; PrintDec3
2016-02-17 20:35:00 +00:00
db '#' ; PrintDec2
db '$' ; PrintHex2
2016-02-17 23:02:00 +00:00
db 'x' ; PrintHex4
2016-02-17 20:35:00 +00:00
_MetaCharEnd
NumMeta = _MetaCharEnd - MetaChar
MetaFunc
2016-02-17 23:02:00 +00:00
dw PrintPtr4
dw PrintPtr2
2016-02-17 20:35:00 +00:00
dw PrintBinInv
dw PrintBinAsc
2016-02-17 23:54:00 +00:00
dw PrintDec5
dw PrintDec3
2016-02-17 20:35:00 +00:00
dw PrintDec2
2016-02-17 23:02:00 +00:00
dw PrintHex2
2016-02-17 20:35:00 +00:00
dw PrintHex4
__END