apple2_printm/printm.s

923 lines
20 KiB
ArmAsm
Raw Normal View History

2016-02-17 20:35:00 +00:00
; ca65
.feature c_comments
2016-02-18 20:34:00 +00:00
2016-02-19 01:32:00 +00:00
/* Version 15
2016-02-18 21:45:00 +00:00
printm - a printf replacement for 65C02
2016-02-19 01:32:00 +00:00
Michael Pohoreski
2016-02-18 20:48:00 +00:00
2016-02-18 20:34:00 +00:00
Problem:
2016-02-19 01:32:00 +00:00
Ideally we want to print a single line that includes literal and variables
in MIXED ASCII case -- high bit characters would be output "as is"
and ASCII characters would be interpreted as a variable output.
While originally this gives us a nice 1:1 mapping for input:output ...
2016-02-18 20:34:00 +00:00
.byte "X=## Y=### $=####:@@ %%%%%%%%~????????"
2016-02-19 01:32:00 +00:00
... it has 2 problems:
a) it has to be constructed in pieces
b) and it is bloated.
Is there we can use a more compact printf-style format string
where we don't waste storing the escape character, and
toggle the high bit on characters on/off as needed?
Yes, if we use a macro!
2016-02-18 20:34:00 +00:00
2016-02-19 01:32:00 +00:00
PRINTM "X=%# Y=%d $=%x:%@ %%~%?"
Thisis why printf() on the 6502 sucks:
2016-02-18 20:34:00 +00:00
- is bloated by using a meta-character '%' instead of the high bit
- doesn't provide a standard way to print binary *facepalm*
- doesn't provide a standard way to print a deferenced pointer
- 2 digit, 3 digit and 5 digit decimals requiring wasting "width" characters
e.g. %2d, %3d, %5d
When a single character would work instead.
Solution:
Here is a micro replacement, printm()
* Literals have the high byte set (APPLE text)
* Meta characters have the high bit cleared (ASCII)
x Hex - print 2 Byte
$ Hex - print 4 Byte
@ Ptr - print hex byte at 16-bit pointer
& Ptr - print hex word at 16-bit pointer
# Dec - Print 1 Byte in decimal (max 2 digits)
d Dec - Print 2 Byte in decimal (max 3 digits)
u Dec - Print 2 Byte in decimal (max 5 digits)
b Dec - Print signed byte
% Bin 1 Byte
? Bin 1 Byte but 1's are printed in inverse
a Str - APPLE text (high bit set), last char is ASCII
s Str - C string, zero terminated
p Str - Pascal string, first character is string length
Note: The dummy address $C0DE is to force the assembler
to generate a 16-bit address instead of optimizing a ZP operand
2016-02-19 01:32:00 +00:00
The printm with everything enabled takes up 472 bytes
2016-02-18 21:45:00 +00:00
Demo + Library text dump:
4000:20 58 FC A9 D5 A2 45 A0
4008:23 8E BE 40 8C BF 40 8E
4010:C0 40 8C C1 40 8E 1C 40
4018:8C 1D 40 8D DE C0 8D C2
4020:40 20 5C 40 8D C4 40 A0
4028:00 20 67 40 A2 B8 A0 40
4030:20 00 42 A0 02 20 67 40
4038:A2 E1 A0 40 20 00 42 A0
4040:04 20 67 40 A2 FE A0 40
4048:20 00 42 A0 06 20 67 40
4050:A2 2E A0 41 20 00 42 A9
4058:08 4C 5B FB A2 08 85 FF
4060:06 FF 6A CA D0 FA 60 B9
2016-02-19 01:32:00 +00:00
4068:76 40 8D 8C 43 B9 8E 40
4070:09 04 8D 8D 43 60 00 80
2016-02-18 21:45:00 +00:00
4078:00 80 00 80 00 80 28 A8
4080:28 A8 28 A8 28 A8 50 D0
4088:50 D0 50 D0 50 D0 00 00
4090:01 01 02 02 03 03 00 00
4098:01 01 02 02 03 03 00 00
40A0:01 01 02 02 03 03 D8 BD
40A8:23 A0 D9 BD 64 A0 A4 BD
40B0:78 BA 40 A0 25 FE 3F 00
40B8:A6 40 27 00 BF 00 DE C0
40C0:DE C0 1A DA 1A DA C2 F9
40C8:F4 E5 BD 62 A0 62 A0 62
40D0:A0 62 A0 62 00 C8 C5 CC
40D8:CC CF 00 D7 CF D2 CC C4
40E0:00 C6 40 80 00 FF 00 00
40E8:00 01 00 7F 00 D3 F4 F2
40F0:E9 EE E7 F3 BA A0 A7 73
40F8:A7 AC A7 73 A7 00 ED 40
4100:D5 40 DB 40 C8 CF CD 45
4108:0D D3 F4 F2 E9 EE E7 A0
4110:CC E5 EE A0 B1 B3 C1 F0
4118:F0 EC E5 BA A0 A7 61 A7
4120:A0 A0 D0 E1 F3 E3 E1 EC
4128:BA A0 A7 70 A7 00 16 41
4130:04 41 08 41 00 00 00 00
4138:00 00 00 00 00 00 00 00
4140:00 00 00 00 00 00 00 00
4148:00 00 00 00 00 00 00 00
4150:00 00 00 00 00 00 00 00
4158:00 00 00 00 00 00 00 00
4160:00 00 00 00 00 00 00 00
4168:00 00 00 00 00 00 00 00
4170:00 00 00 00 00 00 00 00
4178:00 00 00 00 00 00 00 00
4180:00 00 00 00 00 00 00 00
4188:00 00 00 00 00 00 00 00
4190:00 00 00 00 00 00 00 00
4198:00 00 00 00 00 00 00 00
41A0:00 00 00 00 00 00 00 00
41A8:00 00 00 00 00 00 00 00
41B0:00 00 00 00 00 00 00 00
41B8:00 00 00 00 00 00 00 00
41C0:00 00 00 00 00 00 00 00
41C8:00 00 00 00 00 00 00 00
41D0:00 00 00 00 00 00 00 00
41D8:00 00 00 00 00 00 00 00
41E0:00 00 00 00 00 00 00 00
41E8:00 00 00 00 00 00 00 00
41F0:00 00 00 00 00 00 00 00
41F8:00 00 00 00 00 00 00 00
2016-02-19 01:32:00 +00:00
4200:8E 99 43 8C 9A 43 9C 97
4208:43 20 92 43 8E 83 42 8C
2016-02-18 21:45:00 +00:00
4210:84 42 80 6E A9 04 D0 02
2016-02-19 01:32:00 +00:00
4218:A9 02 8D 52 42 20 92 43
4220:8E AF 43 8C B0 43 A2 00
4228:AD AF 43 29 0F C9 0A 90
4230:02 69 06 69 B0 9D A9 43
4238:4E B0 43 6E AF 43 4E B0
4240:43 6E AF 43 4E B0 43 6E
4248:AF 43 4E B0 43 6E AF 43
2016-02-18 21:45:00 +00:00
4250:E8 E0 00 D0 D3 CA 30 22
2016-02-19 01:32:00 +00:00
4258:BD A9 43 20 8B 43 80 F5
2016-02-18 21:45:00 +00:00
4260:A9 04 D0 02 A9 02 8D 52
2016-02-19 01:32:00 +00:00
4268:42 20 92 43 A0 00 B1 FE
2016-02-18 21:45:00 +00:00
4270:AA C8 B1 FE A8 80 A9 20
2016-02-19 01:32:00 +00:00
4278:8B 43 EE 83 42 D0 03 EE
2016-02-18 21:45:00 +00:00
4280:84 42 AD DE C0 F0 14 30
2016-02-19 01:32:00 +00:00
4288:EE A2 0C DD B1 43 F0 05
2016-02-18 21:45:00 +00:00
4290:CA 10 F8 30 E5 8A 0A AA
2016-02-19 01:32:00 +00:00
4298:7C BE 43 60 A9 05 D0 06
2016-02-18 21:45:00 +00:00
42A0:A9 03 D0 02 A9 02 8D 05
2016-02-19 01:32:00 +00:00
42A8:43 20 92 43 8E AF 43 8C
42B0:B0 43 9C A9 43 9C AA 43
42B8:9C AB 43 A2 10 F8 0E AF
42C0:43 2E B0 43 AD A9 43 6D
42C8:A9 43 8D A9 43 AD AA 43
42D0:6D AA 43 8D AA 43 AD AB
42D8:43 6D AB 43 8D AB 43 CA
2016-02-18 21:45:00 +00:00
42E0:D0 DC D8 A2 02 A0 05 BD
2016-02-19 01:32:00 +00:00
42E8:A9 43 4A 4A 4A 4A 18 69
42F0:B0 99 A9 43 88 BD A9 43
42F8:29 0F 18 69 B0 99 A9 43
2016-02-18 21:45:00 +00:00
4300:88 CA 10 E3 A2 00 4C 55
4308:42 A9 81 D0 02 A9 01 8D
2016-02-19 01:32:00 +00:00
4310:21 43 20 92 43 A0 08 8A
2016-02-18 21:45:00 +00:00
4318:C9 80 2A AA 29 01 F0 02
2016-02-19 01:32:00 +00:00
4320:A9 81 49 B0 20 8B 43 88
4328:D0 ED 4C 7A 42 20 92 43
4330:8A 10 0D A9 AD 20 8B 43
2016-02-18 21:45:00 +00:00
4338:8A 49 FF 29 7F 18 69 01
4340:AA A0 00 A9 03 8D 05 43
2016-02-19 01:32:00 +00:00
4348:4C AC 42 20 92 43 A0 00
4350:B1 FE 10 0A 20 8B 43 C8
4358:D0 F6 E6 FF 80 F2 09 80
4360:4C 77 42 20 92 43 A0 00
4368:B1 FE F0 BE 20 8B 43 C8
4370:D0 F6 E6 FF 80 F2 20 92
4378:43 A0 00 B1 FE F0 AB AA
4380:C8 B1 FE 20 8B 43 CA D0
4388:F7 F0 9F 8D DE C0 EE 8C
4390:43 60 20 96 43 AA A0 00
4398:B9 DE C0 EE 97 43 D0 03
43A0:EE 9A 43 A8 86 FE 84 FF
43A8:60 00 00 00 00 00 00 00
43B0:00 3F 25 62 75 64 23 78
43B8:24 26 40 70 73 61 09 43
43C0:0D 43 2D 43 9C 42 A0 42
43C8:A4 42 14 42 18 42 60 42
43D0:64 42 76 43 63 43 4B 43
2016-02-18 21:45:00 +00:00
2016-02-18 20:34:00 +00:00
To toggle features on / off:
*/
2016-02-18 21:45:00 +00:00
ENABLE_BIN = 1
ENABLE_DEC = 1
ENABLE_BYTE = 1 ; requires ENABLE_DEC
ENABLE_HEX = 1
2016-02-18 20:34:00 +00:00
ENABLE_PTR = 1 ; requires ENABLE_HEX
ENABLE_STR = 1
2016-02-19 01:32:00 +00:00
; more ca65
2016-02-17 20:35:00 +00:00
.feature labels_without_colons
.feature leading_dot_in_identifiers
; 65C02
.PC02
2016-02-19 01:32:00 +00:00
; This will take a printf-style string and compact it
; % is the escape character to output the next byte in ASCII (high bit clear)
; othersise the remaining chars will default to have their high bit set
.macro PRINTM text
.local h
h .set $80
.repeat .strlen(text), I
.if (.strat(text , I) = '%')
; handle special case of last char was %
.if( h = $00 )
.byte .strat(text, I) | h
h .set $80
.else
h .set $00
.endif
.else
.byte .strat(text, I) | h
h .set $80
.endif
.endrep
.byte 0
.endmacro
2016-02-17 20:35:00 +00:00
; 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
2016-02-18 20:19:00 +00:00
; Force APPLE 'text' with high bit on but last character has high bit off
; Will display as NORMAL characters (last character will appear FLASHING)
; Merlin: Macro Assembler -- Dextral Character Inverted
.macro DCI text
.repeat .strlen(text)-1, I
.byte .strat(text, I) | $80
.endrep
.byte .strat(text, .strlen(text)-1) & $7F
.endmacro
2016-02-17 20:35:00 +00:00
; 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
2016-02-18 20:19:00 +00:00
.macro PASCAL text
.byte .strlen(text)
APPLE text
.endmacro
2016-02-17 20:35:00 +00:00
.macro db val
.byte val
.endmacro
.macro dw val
.word val
.endmacro
.macro ds bytes
.res bytes
.endmacro
2016-02-18 20:19:00 +00:00
HOME = $FC58
TABV = $FB5B
2016-02-17 20:35:00 +00:00
2016-02-18 20:19:00 +00:00
; printm pointer for PrintPtr2, PrintPtr4, PrintStrA, PrintStrC, PrintStrP
_temp = $FE
__MAIN = $4000
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 20:19:00 +00:00
/*
Output:
X=39 Y=191 $=2345:D5 11010101~10101011
Byte=-128 -001 000 001 127
2016-02-17 20:35:00 +00:00
2016-02-18 20:19:00 +00:00
Strings: 'HELLO','WORLD'
2016-02-17 20:35:00 +00:00
2016-02-18 20:19:00 +00:00
Apple: 'HOME' Pascal: 'String Len 13'
*/
.org __MAIN ; .org must come after header else offsets are wrong
; Demo printm
2016-02-17 23:02:00 +00:00
JSR HOME
LDA #$D5
2016-02-18 20:19:00 +00:00
LDX #$45
LDY #$23
STX DATA+6
STY DATA+7
STX DATA+8
STY DATA+9
STX _HgrAddr+1
STY _HgrAddr+2
_HgrAddr
STA $C0DE
STA DATA+10
2016-02-17 23:02:00 +00:00
JSR ReverseByte
2016-02-18 20:19:00 +00:00
STA DATA+12
2016-02-17 23:02:00 +00:00
2016-02-18 20:48:00 +00:00
.if ENABLE_BIN || ENABLE_DEC || ENABLE_HEX
2016-02-18 20:19:00 +00:00
LDY #0
JSR VTABY
2016-02-17 23:02:00 +00:00
LDX #<DATA ; Low Byte of Address
LDY #>DATA ; High Byte of Address
JSR PrintM
2016-02-18 20:48:00 +00:00
.endif
2016-02-18 17:56:00 +00:00
2016-02-18 20:48:00 +00:00
.if ENABLE_BYTE
2016-02-18 20:19:00 +00:00
LDY #2
JSR VTABY
2016-02-18 17:56:00 +00:00
LDX #<DATA2
LDY #>DATA2
JSR PrintM
2016-02-18 20:48:00 +00:00
.endif ; ENABLE_BYTE
2016-02-18 17:56:00 +00:00
2016-02-18 20:48:00 +00:00
.if ENABLE_STR
2016-02-18 20:19:00 +00:00
LDY #4
JSR VTABY
LDX #<DATA3
LDY #>DATA3
JSR PrintM
LDY #6
JSR VTABY
LDX #<DATA4
LDY #>DATA4
JSR PrintM
2016-02-18 20:48:00 +00:00
.endif ; ENABLE_STR
2016-02-18 20:19:00 +00:00
LDA #8
JMP TABV
2016-02-17 23:02:00 +00:00
ReverseByte
LDX #8
2016-02-18 20:19:00 +00:00
STA $FF ; temp working byte
2016-02-17 23:02:00 +00:00
ReverseBit
2016-02-18 20:19:00 +00:00
ASL $FF ; temp working byte
2016-02-17 23:02:00 +00:00
ROR
DEX
BNE ReverseBit
RTS
2016-02-17 20:35:00 +00:00
2016-02-18 20:19:00 +00:00
VTABY
LDA SCREEN_LO,Y
STA PutChar+1
LDA SCREEN_HI,Y
ORA #$04 ; TXT page 1
STA PutChar+2
RTS
; Y Lookup Table for 40x24 Text Screen
SCREEN_LO
.byte $00, $80, $00, $80
.byte $00, $80, $00, $80
.byte $28, $A8, $28, $A8
.byte $28, $A8, $28, $A8
.byte $50, $D0, $50, $D0
.byte $50, $D0, $50, $D0
SCREEN_HI
.byte $00, $00, $01, $01
.byte $02, $02, $03, $03
.byte $00, $00, $01, $01
.byte $02, $02, $03, $03
.byte $00, $00, $01, $01
.byte $02, $02, $03, $03
2016-02-17 20:35:00 +00:00
TEXT
2016-02-18 17:56:00 +00:00
;byte "X=## Y=ddd $=xxxx:@@ %%%%%%%%~????????"
2016-02-19 01:32:00 +00:00
PRINTM "X=%# Y=%d $=%x:%@ %%~%?"
2016-02-17 20:35:00 +00:00
DATA
dw TEXT ; aArg[ 0] text
2016-02-17 23:02:00 +00:00
dw 39 ; aArg[ 1] x
dw 191 ; aArg[ 2] y
2016-02-18 20:19:00 +00:00
dw $C0DE ; aArg[ 3] addr ScreenAddr
dw $C0DE ; aArg[ 4] byte ScreenAddr pointer
dw $DA1A ; aArg[ 5] bits ScreenByte
dw $DA1A ; aArg[ 6] bits ScreenByte reversed
2016-02-17 20:35:00 +00:00
2016-02-18 17:56:00 +00:00
TEXT2
2016-02-19 01:32:00 +00:00
PRINTM "Byte=%b %b %b %b %b"
2016-02-18 17:56:00 +00:00
TEXT_HELLO
2016-02-18 20:19:00 +00:00
APPLE "HELLO"
2016-02-18 17:56:00 +00:00
db 0
TEXT_WORLD
2016-02-18 20:19:00 +00:00
APPLE "WORLD"
2016-02-18 17:56:00 +00:00
db 0
2016-02-18 20:19:00 +00:00
2016-02-18 17:56:00 +00:00
DATA2
dw TEXT2
dw $80 ; -128
dw $FF ; -1
dw $00 ; 0
2016-02-18 20:19:00 +00:00
dw $01 ; +1
2016-02-18 17:56:00 +00:00
dw $7F ; +127
2016-02-18 20:19:00 +00:00
TEXT3
2016-02-19 01:32:00 +00:00
PRINTM "Strings: '%s','%s'"
2016-02-18 20:19:00 +00:00
DATA3
dw TEXT3
2016-02-18 17:56:00 +00:00
dw TEXT_HELLO
dw TEXT_WORLD
2016-02-18 20:19:00 +00:00
TEXT_DCI
DCI "HOME"
2016-02-17 20:35:00 +00:00
2016-02-18 20:19:00 +00:00
TEXT_PASCAL
PASCAL "String Len 13"
2016-02-18 17:56:00 +00:00
2016-02-18 20:19:00 +00:00
TEXT4
2016-02-19 01:32:00 +00:00
PRINTM "Apple: '%a' Pascal: '%p'"
2016-02-18 20:19:00 +00:00
DATA4
dw TEXT4
dw TEXT_DCI
dw TEXT_PASCAL
; Pad until end of page so PrintM starts on new page
ds 256 - <*
2016-02-18 15:48:00 +00:00
2016-02-17 20:35:00 +00:00
2016-02-18 20:48:00 +00:00
; self-modifying variable aliases
2016-02-17 20:35:00 +00:00
_pScreen = PutChar +1
_pFormat = GetFormat +1
_iArg = NxtArgByte+1
_pArg = IncArg +1
2016-02-18 20:34:00 +00:00
.if ENABLE_HEX
2016-02-18 00:47:00 +00:00
_nHexWidth = HexWidth +1
2016-02-18 20:34:00 +00:00
.endif
.if ENABLE_DEC
2016-02-18 00:47:00 +00:00
_nDecWidth = DecWidth +1
2016-02-18 20:34:00 +00:00
.endif ; ENABLE_DEC
2016-02-17 20:35:00 +00:00
2016-02-18 21:45:00 +00:00
; ======================================================================
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
2016-02-18 20:48:00 +00:00
STZ _iArg
2016-02-17 20:35:00 +00:00
NextArg
2016-02-18 17:56:00 +00:00
JSR NxtArgYX
2016-02-17 20:35:00 +00:00
STX _pFormat+0 ; lo
STY _pFormat+1 ; hi
BRA GetFormat ; always
2016-02-17 23:02:00 +00:00
2016-02-18 20:34:00 +00:00
.if ENABLE_HEX
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-18 17:56:00 +00:00
JSR NxtArgYX
2016-02-18 15:48:00 +00:00
; Print 16-bit Y,X in hex
; Uses _nHexWidth to limit output width
2016-02-18 20:19:00 +00:00
PrintHexYX
STX _val+0 ; may be tempting to move this to NxtArgYX
STY _val+1 ; as XYtoVal but others call us
2016-02-17 23:17:00 +00:00
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-18 20:34:00 +00:00
.if ENABLE_PTR
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-18 20:19:00 +00:00
JSR NxtArgToTemp
2016-02-17 23:02:00 +00:00
2016-02-18 20:19:00 +00:00
; JSR NxtArgYX
2016-02-18 20:48:00 +00:00
; 13 bytes: zero page version
2016-02-18 20:19:00 +00:00
; STX _temp+0 ; zero-page for (ZP),Y
; STY _temp+1
2016-02-17 23:02:00 +00:00
LDY #$0
2016-02-18 20:19:00 +00:00
LDA (_temp),Y
2016-02-17 23:02:00 +00:00
TAX
INY
2016-02-18 20:19:00 +00:00
LDA (_temp),Y
2016-02-17 23:02:00 +00:00
TAY
2016-02-18 00:47:00 +00:00
2016-02-18 20:48:00 +00:00
; 20 bytes: self-modifying code version if zero-page not available
2016-02-18 00:47:00 +00:00
; 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 20:19:00 +00:00
BRA PrintHexYX ; needs XYtoVal setup
2016-02-18 20:34:00 +00:00
.endif ; ENABLE_PTR
.endif ; ENABLE_HEX
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-19 01:32:00 +00:00
NextFormat ; Adjust pointer to next char in format
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!
2016-02-19 01:32:00 +00:00
BEQ _Done ; zero-terminated
2016-02-17 20:35:00 +00:00
BMI Print ; neg = literal
2016-02-18 20:48:00 +00:00
; NOTE: If all features are turned off, will get a ca65 Range Error
2016-02-17 20:35:00 +00:00
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-18 20:34:00 +00:00
.if ENABLE_DEC
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-18 17:56:00 +00:00
JSR NxtArgYX
2016-02-18 15:48:00 +00:00
PrintDecYX
2016-02-18 20:19:00 +00:00
STX _val+0 ; may be tempting to move this to NxtArgYX
STY _val+1 ; as XYtoVal but others call us
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-18 17:56:00 +00:00
LDA _bcd,X ; __c??? _b_?XX a_YYXX
2016-02-17 23:02:00 +00:00
LSR
LSR
LSR
LSR
CLC
2016-02-18 17:56:00 +00:00
ADC #'0'+$80
STA _bcd,Y ; __c??X _b_YXX aZYYXX
2016-02-17 23:02:00 +00:00
DEY
2016-02-18 17:56:00 +00:00
LDA _bcd,X ; __c??X _b_YXX aZYYXX
2016-02-17 23:02:00 +00:00
AND #$F
CLC
2016-02-18 17:56:00 +00:00
ADC #'0'+$80
STA _bcd,Y ; __c?XX _bYYXX ZZYYXX
2016-02-17 23:02:00 +00:00
DEY
DEX
2016-02-17 23:17:00 +00:00
BPL _BCD2Char
2016-02-18 00:47:00 +00:00
DecWidth
2016-02-18 20:48:00 +00:00
LDX #0 ; _nDecDigits NOTE: self-modifying!
2016-02-17 23:42:00 +00:00
JMP PrintReverseBCD
2016-02-18 20:34:00 +00:00
.endif ; ENABLE_DEC
2016-02-17 23:02:00 +00:00
2016-02-18 20:19:00 +00:00
.if ENABLE_BIN
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 17:56:00 +00:00
JSR NxtArgYX ; 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-18 20:48:00 +00:00
AND #$01 ; 0 -> B0
2016-02-17 23:02:00 +00:00
BEQ _FlipBit
_PrintBit
2016-02-18 20:48:00 +00:00
LDA #$81 ; 1 -> 31 NOTE: self-modifying!
2016-02-17 23:02:00 +00:00
_FlipBit
EOR #$B0
JSR PutChar
DEY
BNE _Bit2Asc
2016-02-18 20:34:00 +00:00
.endif ; ENABLE_BIN
2016-02-17 23:42:00 +00:00
_JumpNextFormat
; BRA NextFormat ; always
JMP NextFormat ; JMP :-(
2016-02-17 23:54:00 +00:00
2016-02-18 20:19:00 +00:00
; b Print a signed byte in decimal
2016-02-18 17:56:00 +00:00
; ======================================================================
2016-02-18 20:34:00 +00:00
.if ENABLE_DEC
.if ENABLE_BYTE
2016-02-18 17:56:00 +00:00
PrintByte
JSR NxtArgYX ; X = low byte
TXA
BPL PrintBytePos
LDA #'-' + $80 ; X >= $80 --> $80 (-128) .. $FF (-1)
JSR PutChar
TXA
EOR #$FF ; 2's complement
AND #$7F
CLC
ADC #$01
PrintBytePos
TAX
LDY #00 ; 00XX
LDA #3 ; 3 digits max
STA _nDecWidth
2016-02-18 20:19:00 +00:00
JMP PrintDecYX ; needs XYtoVal setup
2016-02-18 20:34:00 +00:00
.endif ; ENABLE_BYTE
.endif ; ENABLE_DEC
2016-02-18 20:19:00 +00:00
2016-02-18 17:56:00 +00:00
2016-02-18 20:34:00 +00:00
.if ENABLE_STR
2016-02-18 20:19:00 +00:00
; a String (APPLE text, last byte ASCII)
; See: DCI
; ======================================================================
PrintStrA
JSR NxtArgToTemp
LDY #$0
_PrintStrA
LDA (_temp),Y
BPL @_LastChar
JSR PutChar
INY
BNE _PrintStrA
INC _temp+1
BRA _PrintStrA
@_LastChar
2016-02-19 01:32:00 +00:00
; 6 byte:
; LDX #1
; ORA #$80
; BRA _PrintCharA
; 5 byte:
2016-02-18 20:19:00 +00:00
ORA #$80
2016-02-19 01:32:00 +00:00
JMP Print
2016-02-18 20:19:00 +00:00
; s String (C,ASCIIZ)
; ======================================================================
PrintStrC
JSR NxtArgToTemp
LDY #$0
@_NextByte
LDA (_temp),Y
BEQ _JumpNextFormat
JSR PutChar
INY
BNE @_NextByte
INC _temp+1
BRA @_NextByte
; p String (Pascal)
2016-02-18 17:56:00 +00:00
; ======================================================================
PrintStrP
2016-02-18 20:19:00 +00:00
JSR NxtArgToTemp
2016-02-18 17:56:00 +00:00
LDY #$0
2016-02-18 20:19:00 +00:00
LDA (_temp),Y
BEQ _JumpNextFormat
2016-02-18 17:56:00 +00:00
TAX
_PrintStrP
2016-02-17 20:35:00 +00:00
INY
2016-02-18 20:19:00 +00:00
LDA (_temp),Y
_PrintCharA
2016-02-18 17:56:00 +00:00
JSR PutChar
DEX
BNE _PrintStrP
BEQ _JumpNextFormat ; always
2016-02-18 20:34:00 +00:00
.endif ; ENABLE_STR
2016-02-18 17:56:00 +00:00
; __________ Utility __________
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
2016-02-18 20:48:00 +00:00
STA $C0DE ; _pScreen NOTE: self-modifying!
2016-02-17 20:35:00 +00:00
INC PutChar+1 ; inc lo
RTS
2016-02-18 00:47:00 +00:00
; ======================================================================
2016-02-18 17:56:00 +00:00
; @return next arg as 16-bit arg value in Y,X
2016-02-18 20:19:00 +00:00
NxtArgToTemp
2016-02-18 17:56:00 +00:00
NxtArgYX
JSR NxtArgByte
TAX
2016-02-17 20:35:00 +00:00
; @return _Arg[ _Num ]
NxtArgByte
2016-02-18 20:48:00 +00:00
LDY #00 ; _iArg NOTE: self-modifying!
2016-02-17 20:35:00 +00:00
IncArg
LDA $C0DE,Y ; _pArg NOTE: self-modifying!
2016-02-18 20:48:00 +00:00
INC _iArg ;
2016-02-17 20:35:00 +00:00
BNE @_SamePage
INC _pArg+1 ;
@_SamePage
TAY
2016-02-18 20:19:00 +00:00
; Callers of NxtToArgYX don't use _temp
_NxtArgToTemp
STX _temp+0 ; zero-page for (ZP),Y
STY _temp+1
;XYtoVal
; STX _val+0 ; may be tempting to move this to NxtArgYX
; STY _val+1 ;
2016-02-17 20:35:00 +00:00
RTS
2016-02-18 20:48:00 +00:00
;
2016-02-18 20:19:00 +00:00
; ======================================================================
2016-02-17 23:02:00 +00:00
_bcd ds 6 ; 6 chars for printing dec
2016-02-18 20:34:00 +00:00
_val dw 0 ; PrintHex2 PrintHex4 temp
2016-02-17 20:35:00 +00:00
MetaChar
2016-02-18 20:19:00 +00:00
.if ENABLE_BIN
db '?' ; PrintBinInv NOTE: 1's printed in inverse
2016-02-17 20:35:00 +00:00
db '%' ; PrintBinAsc
2016-02-18 20:19:00 +00:00
.endif
.if ENABLE_DEC
.if ENABLE_BYTE
db 'b' ; PrintByte NOTE: Signed -128 .. +127
.endif
2016-02-17 23:54:00 +00:00
db 'u' ; PrintDec5
db 'd' ; PrintDec3
2016-02-17 20:35:00 +00:00
db '#' ; PrintDec2
2016-02-18 20:19:00 +00:00
.endif
.if ENABLE_HEX
2016-02-17 23:02:00 +00:00
db 'x' ; PrintHex4
2016-02-18 20:19:00 +00:00
db '$' ; PrintHex2
2016-02-18 21:45:00 +00:00
.if ENABLE_PTR
2016-02-18 20:19:00 +00:00
db '&' ; PrintPtr4
db '@' ; PrintPtr2
2016-02-18 21:45:00 +00:00
.endif
2016-02-18 20:19:00 +00:00
.endif
.if ENABLE_STR
db 'p' ; PrintStrP NOTE: Pascal string; C printf 'p' is pointer!
db 's' ; PrintStrC NOTE: C string, zero terminated
db 'a' ; PrintStrA NOTE: Last byte is ASCII
.endif
2016-02-17 20:35:00 +00:00
_MetaCharEnd
NumMeta = _MetaCharEnd - MetaChar
MetaFunc
2016-02-18 20:19:00 +00:00
.if ENABLE_BIN
2016-02-17 20:35:00 +00:00
dw PrintBinInv
dw PrintBinAsc
2016-02-18 20:19:00 +00:00
.endif
.if ENABLE_DEC
.if ENABLE_BYTE
2016-02-18 17:56:00 +00:00
dw PrintByte
2016-02-18 20:19:00 +00:00
.endif
2016-02-17 23:54:00 +00:00
dw PrintDec5
dw PrintDec3
2016-02-17 20:35:00 +00:00
dw PrintDec2
2016-02-18 20:19:00 +00:00
.endif
.if ENABLE_HEX
2016-02-17 20:35:00 +00:00
dw PrintHex4
2016-02-18 20:19:00 +00:00
dw PrintHex2
2016-02-18 20:34:00 +00:00
.if ENABLE_PTR
2016-02-18 20:19:00 +00:00
dw PrintPtr4
dw PrintPtr2
2016-02-18 20:34:00 +00:00
.endif
2016-02-18 20:19:00 +00:00
.endif
.if ENABLE_STR
dw PrintStrP
dw PrintStrC
dw PrintStrA
.endif
2016-02-17 20:35:00 +00:00
__END