apple2_printm/printm.s

1568 lines
38 KiB
ArmAsm
Raw Normal View History

2016-02-17 20:35:00 +00:00
; ca65
.feature c_comments
2016-02-20 16:01:00 +00:00
.linecont +
.feature labels_without_colons
.feature leading_dot_in_identifiers
.PC02 ; 65C02
2016-02-18 20:34:00 +00:00
2016-02-21 23:54:00 +00:00
/* Version 37
2016-02-19 21:07:00 +00:00
printm - a modular micro printf replacement for 65C02
2016-02-19 01:32:00 +00:00
Michael Pohoreski
2016-02-19 21:07:00 +00:00
Copyleft {c} Feb, 2016
2016-02-20 07:47:00 +00:00
Special Thanks: Sheldon for his 65C02 printf() source, qkumba optimizations
2016-02-18 20:34:00 +00:00
Problem:
2016-02-19 01:32:00 +00:00
2016-02-19 21:07:00 +00:00
Ideally we want to print an 1:1 mapping of input:output text that includes
literal and variables. We could do this by using mixed ASCII case:
- high bit characters would be output "as is"
- ASCII characters would be interpreted as a variable output.
2016-02-19 01:32:00 +00:00
2016-02-19 05:58:00 +00:00
__ ___ ____ __ ________ ________
.byte "X=## Y=### $=$$$$:@@ %%%%%%%%~????????"
Legend:
2016-02-18 20:34:00 +00:00
2016-02-19 05:58:00 +00:00
# Print Dec Num
$ Print Hex Num
% Print Bin Num
? Print Bin Num but with 1's in inverse
@ Print Ptr Val
_ Chars with underscore represents ASCII characters
While originally this gives us a nice 1:1 mapping for input:output ...
2016-02-18 20:34:00 +00:00
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.
2016-02-19 21:07:00 +00:00
Can we fix (a) ?
2016-02-19 05:58:00 +00:00
Can we use a more compact printf-style format string
where we don't waste storing the escape character AND
2016-02-19 01:32:00 +00:00
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:%@ %%~%?"
2016-02-19 21:07:00 +00:00
Can we fix (b) ?
Yes, by using an unique meta character that has the width associated with it.
This is why the cannonical 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*
2016-02-19 05:58:00 +00:00
- doesn't provide a standard way to print a dereferenced pointer
2016-02-18 20:34:00 +00:00
- 2 digit, 3 digit and 5 digit decimals requiring wasting "width" characters
e.g. %2d, %3d, %5d
When a single character would work instead.
2016-02-19 21:07:00 +00:00
- printf() is notorious for being bloated. If you don't use
features you can't turn them off to reclaim the memory used
by the code (or data)
2016-02-18 20:34:00 +00:00
Solution:
2016-02-19 21:07:00 +00:00
Here is a *modular* _micro_ replacement: printm()
2016-02-18 20:34:00 +00:00
* Literals have the high byte set (APPLE text)
* Meta characters have the high bit cleared (ASCII)
2016-02-19 05:58:00 +00:00
$ Hex - print 2 Byte
x Hex - print 4 Byte
2016-02-18 20:34:00 +00:00
@ 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)
2016-02-19 05:58:00 +00:00
b Dec - Print signed byte in decimal
2016-02-18 20:34:00 +00:00
2016-02-19 05:58:00 +00:00
% Bin - Print 8 bits
? Bin - Print 8 bits but 1's in inverse
2016-02-18 20:34:00 +00:00
2016-02-19 21:07:00 +00:00
o Oct - Print 1 Byte in octal (max 3 digits)
O Oct - Print 2 Byte in octal (max 6 digits)
2016-02-18 20:34:00 +00:00
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
2016-02-20 17:17:00 +00:00
2016-02-19 21:07:00 +00:00
Each option can individually be enabled / disabled
to control the memory footprint since you probably
don't need "every" feature. Seriously, when was the last time
you _needed_ octal? :-)
2016-02-19 05:58:00 +00:00
2016-02-20 17:17:00 +00:00
printm() has manually been optimized for size. In gcc parlance, `-Os`.
2016-02-21 23:54:00 +00:00
With everything enabled printm() takes up $1BA = 442 bytes
2016-02-19 05:58:00 +00:00
(Plus 2 bytes in zero page.)
2016-02-19 21:07:00 +00:00
Whoa! I thought you said this was micro!?
2016-02-21 02:51:00 +00:00
Believe me it is. Here are some of the optimization tricks used:
1) Using BIT to skip instructions in common entry point
EntryPointA SEC
db BIT_ZP ; skip over next instruction
EntryPointB
CLC
...common set up code...
BCC _CodeForA
_CodeForB
_CodeForA
_CodeForAll
2) Self-modifying code for dynamic width
EntryPointA LDA n1
db BIT_ABS ; skip next instruction
EntryPointB LDA n2 ; intentional fall into common code
_SetWidth STA _DynamicWidth+1
LDX #0
...code...
_DynamicWidth
CPX #n
3) No CMPs to preserve the Carry flag for common entry points
4) Jump table is 3 bytes/entry, using 65C02: JUMP (FUNCS+1,X)
char, word_ptr_to_func
5) A negative buffer offset so that a register will reach zero
and we can test for end of processing without using a CMP
which would trash the carry:
LDY #$FD ; $00-$FD=-3 bcd[0] bcd[1] bcd[2] bcd[3]
@DoubleDabble: ; Y=FD Y=FE Y=FF Y=00
LDA _bcd-$FD,Y
ADC _bcd-$FD,Y
STA _bcd-$FD,Y
INY
BNE @DoubleDabble
; When Y=0, we'll be at _bcd[3]
2016-02-21 23:51:00 +00:00
With all 15 features turned OFF the core routines use $49 = 73 bytes.
2016-02-19 05:58:00 +00:00
2016-02-20 21:08:00 +00:00
With the common setting (default) features:
2016-02-19 21:07:00 +00:00
BinAsc, Dec2, Dec3, Dec5, Hex2, Hex4, and StrA
2016-02-21 23:54:00 +00:00
the size is $11A = 282 bytes
2016-02-18 20:34:00 +00:00
2016-02-19 21:07:00 +00:00
To toggle features on / off change USE_* to 0 or 1:
2016-02-19 05:58:00 +00:00
*/
; NOTE: The Size *also* includes the core routines
; so the actual implementation size for each feature
; is actually smaller the size leads you to believe.
2016-02-19 21:07:00 +00:00
; Also, "common functionality" is also included in the count..
; core _PrintDec routine.
2016-02-19 05:58:00 +00:00
;
2016-02-20 16:01:00 +00:00
; Feature Size Bytes Total Notes
2016-02-21 23:54:00 +00:00
USE_BIN_ASC = 1 ; $78 120 \. $7E (126 bytes)
USE_BIN_INV = 0 ; $78 119 /
USE_DEC_2 = 1 ; $C5 197 \
USE_DEC_3 = 1 ; $C5 197 \.$EF (239 bytes)
USE_DEC_5 = 1 ; $C5 197 /
USE_DEC_BYTE = 0 ; $DE 222 / sets ENABLE_DEC
USE_HEX_2 = 1 ; $93 147 \. $98 (152 bytes)
USE_HEX_4 = 1 ; $93 147 /
USE_OCT_3 = 0 ; $8C 140 \. $92 (146 bytes)
USE_OCT_6 = 0 ; $8C 140 /
USE_PTR_2 = 0 ; $A2 162 \. $A7 (167 bytes) sets ENABLE_HEX
USE_PTR_4 = 0 ; $A2 162 /
USE_STR_A = 1 ; $72 114 \
USE_STR_C = 0 ; $72 114 > $9F (159 bytes)
USE_STR_PASCAL = 0 ; $74 116 /
2016-02-19 05:58:00 +00:00
/*
2016-02-18 21:45:00 +00:00
2016-02-21 07:21:00 +00:00
Demo (All features) + Library text dump:
2016-02-18 21:45:00 +00:00
2016-02-20 21:08:00 +00:00
4000:20 58 FC A9 20 85 E6 A9
4008:D5 8D 00 20 A9 AA 8D 01
2016-02-21 23:51:00 +00:00
4010:20 AD D4 41 A2 00 A0 00
4018:20 11 F4 18 A5 26 6D D2
4020:41 85 26 AA A4 27 8E D6
4028:41 8C D7 41 8E D8 41 8C
4030:D9 41 AD 00 20 A0 00 91
4038:26 8D DA 41 9C DB 41 8D
4040:F6 41 8D FA 41 20 9F 41
4048:8D DC 41 9C DD 41 A0 00
4050:20 AF 41 A2 D0 A0 41 20
4058:0E 43 A0 01 20 AF 41 A2
4060:F4 A0 41 20 0E 43 A0 02
4068:20 AF 41 A2 F8 A0 41 20
4070:0E 43 A0 03 20 AF 41 A2
4078:23 A0 42 20 0E 43 A0 04
4080:20 AF 41 A2 27 A0 42 20
4088:0E 43 A0 05 20 AF 41 A2
4090:2B A0 42 20 0E 43 A0 06
4098:20 AF 41 A2 2F A0 42 20
40A0:0E 43 A0 07 20 AF 41 A2
40A8:5F A0 42 20 0E 43 A0 08
40B0:20 AF 41 A2 63 A0 42 20
40B8:0E 43 A0 09 20 AF 41 A2
40C0:67 A0 42 20 0E 43 A0 0A
40C8:20 AF 41 A2 6D A0 42 20
40D0:0E 43 A0 0B 20 AF 41 A2
40D8:83 A0 42 20 0E 43 A0 0C
40E0:20 AF 41 A2 87 A0 42 20
40E8:0E 43 A0 0D 20 AF 41 A2
40F0:D7 A0 42 20 0E 43 A0 0E
40F8:20 AF 41 A2 D1 A0 42 20
4100:0E 43 A0 0F 20 AF 41 A2
4108:DB A0 42 20 0E 43 A9 11
4110:20 5B FB A2 DF A0 42 20
4118:8E 41 AD 0D 43 85 FF 20
4120:DA FD AD 0C 43 85 FE 20
4128:DA FD 20 AA 41 20 4C 41
4130:A2 F1 A0 42 20 8E 41 A2
4138:0F 86 FE 64 FF 8A 20 DA
4140:FD 20 AA 41 20 4C 41 A9
2016-02-21 23:54:00 +00:00
4148:8D 4C ED FD 9C 93 44 9C
4150:94 44 9C 95 44 A2 10 F8
4158:06 FE 26 FF A0 FD B9 96
4160:43 79 96 43 99 96 43 C8
2016-02-21 23:51:00 +00:00
4168:D0 F4 CA D0 EB D8 A2 05
2016-02-21 23:54:00 +00:00
4170:88 B9 96 43 4A 4A 4A 4A
2016-02-21 23:51:00 +00:00
4178:18 69 B0 20 ED FD CA B9
2016-02-21 23:54:00 +00:00
4180:96 43 29 0F 18 69 B0 20
2016-02-21 23:51:00 +00:00
4188:ED FD CA 10 E3 60 86 FC
4190:84 FD A0 00 B1 FC F0 06
4198:20 ED FD C8 D0 F6 60 A2
41A0:08 85 FE 06 FE 6A CA D0
41A8:FA 60 A9 A0 4C ED FD 98
41B0:20 C1 FB A6 28 A4 29 8E
2016-02-21 23:54:00 +00:00
41B8:8D 44 8C 8E 44 60 D8 BD
2016-02-21 23:51:00 +00:00
41C0:23 A0 D9 BD 64 A0 A4 BD
41C8:78 BA 40 A0 25 FE 3F 00
41D0:BE 41 27 00 BF 00 DE C0
41D8:DE C0 1A DA 1A DA C2 E9
41E0:EE A0 C1 D3 C3 BA A0 25
41E8:00 C2 E9 EE A0 C9 CE D6
41F0:BA A0 3F 00 DE 41 1A DA
41F8:E9 41 1A DA C4 E5 E3 B2
4200:BA A0 23 00 C4 E5 E3 B3
4208:BA A0 64 00 C4 E5 E3 B5
4210:BA A0 75 00 C2 F9 F4 E5
4218:BD 62 A0 62 A0 62 A0 62
4220:A0 62 00 FC 41 63 00 04
4228:42 E7 03 0C 42 69 FF 14
4230:42 80 00 FF 00 00 00 01
4238:00 7F 00 C8 E5 F8 B2 BA
4240:A0 24 00 C8 E5 F8 B4 BA
4248:A0 78 00 D0 F4 F2 B2 BA
4250:A0 78 BA 40 00 D0 F4 F2
4258:B4 BA A0 78 BA 26 00 3B
4260:42 34 12 43 42 34 12 4B
4268:42 00 20 00 20 55 42 00
4270:20 00 20 CF E3 F4 B3 BA
4278:A0 6F 00 CF E3 F4 B6 BA
4280:A0 4F 00 73 42 B6 01 7B
4288:42 DF 32 C8 C5 CC CC CF
4290:00 D7 CF D2 CC C4 00 C8
4298:CF CD 45 0D D0 E1 F3 E3
42A0:E1 EC A0 CC E5 EE A0 B1
42A8:B3 C3 A0 A0 A0 A0 A0 BA
42B0:A0 A7 73 A7 AC A7 73 A7
42B8:00 C1 F0 F0 EC E5 A0 BA
42C0:A0 A7 61 A7 00 D0 E1 F3
42C8:E3 E1 EC BA A0 A7 70 A7
42D0:00 A9 42 8B 42 91 42 B9
42D8:42 97 42 C5 42 9B 42 F0
42E0:F2 E9 EE F4 ED A8 A9 AE
42E8:F3 E9 FA E5 A0 BD A0 A4
42F0:00 A0 E2 F9 F4 E5 F3 8D
42F8:A0 A0 A0 A0 AE E6 E5 E1
4300:F4 F5 F2 E5 F3 A0 BD A0
2016-02-21 23:54:00 +00:00
4308:A4 A0 A0 00 BA 01 8E 24
2016-02-21 23:51:00 +00:00
4310:43 8C 25 43 20 1F 43 8E
4318:78 43 8C 79 43 80 58 20
4320:23 43 AA AD DE C0 EE 24
4328:43 D0 03 EE 25 43 A8 86
4330:FE 84 FF 60 38 A9 18 20
2016-02-21 23:54:00 +00:00
4338:1F 43 90 03 20 67 44 8A
4340:20 67 44 80 2A 38 A9 18
2016-02-21 23:51:00 +00:00
4348:20 1F 43 A0 00 B1 FE 90
4350:EF AA C8 B1 FE 80 E5 20
4358:1F 43 A0 00 B1 FE 10 0A
2016-02-21 23:54:00 +00:00
4360:20 8C 44 C8 D0 F6 E6 FF
4368:80 F2 09 80 20 8C 44 EE
2016-02-21 23:51:00 +00:00
4370:78 43 D0 03 EE 79 43 AD
4378:DE C0 F0 B7 30 EE A2 2D
2016-02-21 23:54:00 +00:00
4380:CA CA CA 30 EA DD 9B 44
4388:D0 F6 7C 9C 44 A9 02 2C
2016-02-21 23:51:00 +00:00
4390:A9 01 2C A9 00 8D BE 43
2016-02-21 23:54:00 +00:00
4398:20 1F 43 9C 93 44 9C 94
43A0:44 9C 95 44 A2 10 F8 06
43A8:FE 26 FF A0 FD B9 96 43
43B0:79 96 43 99 96 43 C8 D0
2016-02-21 23:51:00 +00:00
43B8:F4 CA D0 EB D8 A0 03 F0
2016-02-21 23:54:00 +00:00
43C0:0A B9 93 44 20 74 44 20
43C8:8C 44 88 B9 93 44 20 67
43D0:44 88 10 F7 80 99 20 1F
43D8:43 8A 10 0A A9 AD 20 8C
43E0:44 8A 49 FF AA E8 86 FE
43E8:64 FF A9 01 8D BE 43 80
43F0:AA A9 31 2C A9 B1 8D 06
43F8:44 20 1F 43 A0 08 8A 0A
4400:AA A9 B0 90 02 A9 B1 20
4408:8C 44 88 D0 F1 80 C5 A9
4410:06 2C A9 03 8D 31 44 20
4418:1F 43 A2 00 A5 FE 29 07
4420:18 69 B0 9D 93 44 A0 03
4428:46 FF 66 FE 88 D0 F9 E8
4430:E0 06 D0 E8 CA 30 9D BD
4438:93 44 20 8C 44 80 F5 20
4440:1F 43 A0 00 B1 FE F0 8C
4448:20 8C 44 C8 D0 F6 E6 FF
4450:80 F2 20 1F 43 A0 00 B1
4458:FE F0 B2 AA C8 B1 FE 20
4460:8C 44 CA D0 F7 F0 A6 20
4468:74 44 A5 FE 20 8C 44 A5
4470:FF 4C 8C 44 48 4A 4A 4A
4478:4A 20 7F 44 85 FE 68 29
4480:0F C9 0A 90 02 69 06 69
4488:B0 85 FF 60 8D DE C0 EE
4490:8D 44 60 00 00 00 00 00
4498:00 00 00 3F F1 43 25 F4
44A0:43 62 D6 43 75 8D 43 64
44A8:90 43 23 93 43 78 34 43
44B0:24 36 43 26 45 43 40 47
44B8:43 4F 0F 44 6F 12 44 70
44C0:52 44 73 3F 44 61 57 43
2016-02-18 20:34:00 +00:00
*/
2016-02-19 05:58:00 +00:00
2016-02-17 20:35:00 +00:00
2016-02-19 21:07:00 +00:00
; Assemble-time diagnostic information
.macro DEBUG text
2016-02-20 16:10:00 +00:00
.if 0
2016-02-19 21:07:00 +00:00
.out text
.endif
.endmacro
2016-02-19 05:58:00 +00:00
; This will take a printf-style string and compact it. The '%' is the escape
; character to output the next byte in ASCII (high bit clear) and print a var.
; Otherwise the remaining chars will default to literals having their high bit
; set. To output a literal '%' you will need to manually add it
; as the %% outputs confusingly enough is a single ASCII '%' which is print binary
.macro PRINTM text, endbyte ; text2, text3, text4, text5, text6
2016-02-19 01:32:00 +00:00
.local h
h .set $80
.repeat .strlen(text), I
.if (.strat(text , I) = '%')
; handle special case of last char was %
.if( h = $00 )
2016-02-19 05:58:00 +00:00
.byte .strat(text, I) ; ASCII % = PrintBin
2016-02-19 01:32:00 +00:00
h .set $80
.else
h .set $00
.endif
.else
.byte .strat(text, I) | h
h .set $80
.endif
.endrep
2016-02-19 05:58:00 +00:00
.ifnblank endbyte
.byte endbyte
.endif
2016-02-19 01:32:00 +00:00
.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-19 21:07:00 +00:00
; Include necessary components based on features requested
ENABLE_BIN = USE_BIN_ASC || USE_BIN_INV
ENABLE_DEC = USE_DEC_2 || USE_DEC_3 || USE_DEC_5 || USE_DEC_BYTE
ENABLE_HEX = USE_HEX_2 || USE_HEX_4 || USE_PTR_2 || USE_PTR_4
ENABLE_OCT = USE_OCT_3 || USE_OCT_6
ENABLE_PTR = USE_PTR_2 || USE_PTR_4
ENABLE_STR = USE_STR_A || USE_STR_C || USE_STR_PASCAL
NumMeta = 0 + \
USE_BIN_ASC + \
USE_BIN_INV + \
USE_DEC_2 + \
USE_DEC_3 + \
USE_DEC_5 + \
USE_DEC_BYTE + \
USE_HEX_2 + \
USE_HEX_4 + \
USE_OCT_3 + \
USE_OCT_6 + \
USE_PTR_2 + \
USE_PTR_4 + \
USE_STR_A + \
USE_STR_C + \
USE_STR_PASCAL
DEBUG .sprintf( "Features enabled: %d", NumMeta )
; Only used by demo
BASL = $28 ; TXT pointer to cursor
BASH = $29
GBASL = $26 ; HGR pointer to cursor
2016-02-19 05:58:00 +00:00
GBASH = $27
2016-02-20 17:17:00 +00:00
HGRPAGE = $E6 ; used by HPOSN
2016-02-19 21:07:00 +00:00
HPOSN = $F411 ; A=row, X=col.lo,Y=col.hi, sets GBASL, GBASH
BASCALC = $FBC1 ; A=row, sets BASL, BASH
2016-02-18 20:19:00 +00:00
HOME = $FC58
TABV = $FB5B
2016-02-19 05:58:00 +00:00
COUT = $FDED
2016-02-19 21:07:00 +00:00
PRBYTE = $FDDA ; print A in hex
demoptr = $FC
demotmp = $FE
2016-02-18 20:19:00 +00:00
__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:
2016-02-19 21:07:00 +00:00
X=39 Y=191 $=3FF7:D5 11010101~10101011
Bin ASC: 11010101
Bin INV: 11010101
2016-02-19 05:58:00 +00:00
Dec2: 99
Dec3: 999
Dec5: 65385
2016-02-18 20:19:00 +00:00
Byte=-128 -001 000 001 127
2016-02-19 21:07:00 +00:00
Hex2: 34
Hex4: 1234
Ptr2: 2000:D5
Ptr4: 2000:AAD5
Oct3: 666
Oct6: 031337
2016-02-19 05:58:00 +00:00
Apple : 'HOME'
2016-02-19 21:07:00 +00:00
C : 'HELLO','WORLD'
2016-02-19 05:58:00 +00:00
Pascal: 'Pascal Len 13'
2016-02-18 20:19:00 +00:00
2016-02-19 21:07:00 +00:00
printm().size = $0209 000521 bytes
.features = $ 0F 000015
2016-02-18 20:19:00 +00:00
*/
2016-02-19 19:57:00 +00:00
.org __MAIN ; .org must come after header else offsets are wrong
2016-02-19 05:58:00 +00:00
2016-02-18 20:19:00 +00:00
; Demo printm
2016-02-17 23:02:00 +00:00
JSR HOME
2016-02-20 17:17:00 +00:00
LDA #$20
STA HGRPAGE
2016-02-17 23:02:00 +00:00
LDA #$D5
2016-02-19 05:58:00 +00:00
STA $2000
LDA #$AA
STA $2001
2016-02-19 19:57:00 +00:00
LDA ARGS_DEMO+4 ;HGR Y row
LDX #$00 ; HGR x.col_lo = 0
LDY #$00 ; x.col_hi = 0
2016-02-19 05:58:00 +00:00
JSR HPOSN
CLC
LDA GBASL
2016-02-19 19:57:00 +00:00
ADC ARGS_DEMO+2 ; HGR x col
2016-02-19 05:58:00 +00:00
STA GBASL
TAX
LDY GBASH
2016-02-18 20:19:00 +00:00
2016-02-19 19:57:00 +00:00
STX ARGS_DEMO+6 ; aArg[3]
STY ARGS_DEMO+7
STX ARGS_DEMO+8 ; aArg[4]
STY ARGS_DEMO+9
2016-02-18 20:19:00 +00:00
2016-02-19 05:58:00 +00:00
LDA $2000
LDY #0
STA (GBASL),Y
2016-02-19 19:57:00 +00:00
STA ARGS_DEMO+10 ; aArg[5]
STZ ARGS_DEMO+11
2016-02-19 21:07:00 +00:00
2016-02-19 19:57:00 +00:00
STA ARGS_BIN_ASC+2
2016-02-19 21:07:00 +00:00
STA ARGS_BIN_INV+2
2016-02-18 20:19:00 +00:00
2016-02-17 23:02:00 +00:00
JSR ReverseByte
2016-02-19 19:57:00 +00:00
STA ARGS_DEMO+12 ; aArg[6]
STZ ARGS_DEMO+13
2016-02-17 23:02:00 +00:00
2016-02-19 05:58:00 +00:00
.if ENABLE_BIN && ENABLE_DEC && ENABLE_HEX
2016-02-18 20:19:00 +00:00
LDY #0
JSR VTABY
2016-02-19 19:57:00 +00:00
LDX #<ARGS_DEMO ; Low Byte of Address
LDY #>ARGS_DEMO ; High Byte of Address
2016-02-17 23:02:00 +00:00
JSR PrintM
2016-02-18 20:48:00 +00:00
.endif
2016-02-18 17:56:00 +00:00
2016-02-19 05:58:00 +00:00
.if ENABLE_BIN
2016-02-19 21:07:00 +00:00
DEBUG "+BIN"
2016-02-19 05:58:00 +00:00
.if USE_BIN_ASC
2016-02-19 21:07:00 +00:00
DEBUG "____:ASC"
2016-02-19 05:58:00 +00:00
LDY #1
JSR VTABY
LDX #<ARGS_BIN_ASC
LDY #>ARGS_BIN_ASC
JSR PrintM
.endif
.if USE_BIN_INV
2016-02-19 21:07:00 +00:00
DEBUG "____:INV"
2016-02-18 20:19:00 +00:00
LDY #2
JSR VTABY
2016-02-19 05:58:00 +00:00
LDX #<ARGS_BIN_INV
LDY #>ARGS_BIN_INV
2016-02-18 17:56:00 +00:00
JSR PrintM
2016-02-19 05:58:00 +00:00
.endif
.endif
2016-02-18 17:56:00 +00:00
2016-02-19 05:58:00 +00:00
.if ENABLE_DEC
2016-02-19 21:07:00 +00:00
DEBUG "+DEC"
2016-02-19 05:58:00 +00:00
.if USE_DEC_2
2016-02-19 21:07:00 +00:00
DEBUG "____:Dec2"
2016-02-19 05:58:00 +00:00
LDY #3
JSR VTABY
LDX #<ARGS_DEC_2
LDY #>ARGS_DEC_2
JSR PrintM
.endif
.if USE_DEC_3
2016-02-19 21:07:00 +00:00
DEBUG "____:Dec3"
2016-02-18 20:19:00 +00:00
LDY #4
JSR VTABY
2016-02-19 05:58:00 +00:00
LDX #<ARGS_DEC_3
LDY #>ARGS_DEC_3
2016-02-18 20:19:00 +00:00
JSR PrintM
2016-02-19 05:58:00 +00:00
.endif
.if USE_DEC_5
2016-02-19 21:07:00 +00:00
DEBUG "____:Dec5"
2016-02-19 05:58:00 +00:00
LDY #5
JSR VTABY
LDX #<ARGS_DEC_5
LDY #>ARGS_DEC_5
JSR PrintM
.endif
.if USE_DEC_BYTE
2016-02-19 21:07:00 +00:00
DEBUG "____:DecB"
2016-02-18 20:19:00 +00:00
LDY #6
JSR VTABY
2016-02-19 05:58:00 +00:00
LDX #<ARGS_DEC_BYTE
LDY #>ARGS_DEC_BYTE
2016-02-18 20:19:00 +00:00
JSR PrintM
2016-02-19 05:58:00 +00:00
.endif ; USE_DEC_BYTE
.endif
.if ENABLE_HEX
2016-02-19 21:07:00 +00:00
DEBUG "+HEX"
2016-02-19 05:58:00 +00:00
.if USE_HEX_2
2016-02-19 21:07:00 +00:00
DEBUG "____:Hex2"
2016-02-19 05:58:00 +00:00
LDY #7
JSR VTABY
LDX #<ARGS_HEX_2
LDY #>ARGS_HEX_2
JSR PrintM
.endif
.if USE_HEX_4
2016-02-19 21:07:00 +00:00
DEBUG "____:Hex4"
2016-02-19 05:58:00 +00:00
LDY #8
JSR VTABY
LDX #<ARGS_HEX_4
LDY #>ARGS_HEX_4
JSR PrintM
.endif
.if USE_PTR_2
2016-02-19 21:07:00 +00:00
DEBUG "____:Ptr2"
2016-02-19 05:58:00 +00:00
LDY #9
JSR VTABY
LDX #<ARGS_PTR_2
LDY #>ARGS_PTR_2
JSR PrintM
.endif
.if USE_PTR_4
2016-02-19 21:07:00 +00:00
DEBUG "____:Ptr4"
2016-02-19 05:58:00 +00:00
LDY #10
JSR VTABY
LDX #<ARGS_PTR_4
LDY #>ARGS_PTR_4
JSR PrintM
.endif
.endif
2016-02-19 21:07:00 +00:00
.if ENABLE_OCT
DEBUG "+OCT"
.if USE_OCT_3
DEBUG "____:Oct3"
2016-02-19 05:58:00 +00:00
LDY #11
JSR VTABY
2016-02-19 21:07:00 +00:00
LDX #<ARGS_OCT_3
LDY #>ARGS_OCT_3
2016-02-19 05:58:00 +00:00
JSR PrintM
.endif
2016-02-19 21:07:00 +00:00
.if USE_OCT_6
DEBUG "____:Oct6"
LDY #12
JSR VTABY
LDX #<ARGS_OCT_6
LDY #>ARGS_OCT_6
JSR PrintM
.endif
.endif
.if ENABLE_STR
DEBUG "+STR"
2016-02-19 05:58:00 +00:00
.if USE_STR_A
2016-02-19 21:07:00 +00:00
DEBUG "____:StrA"
LDY #13
2016-02-19 05:58:00 +00:00
JSR VTABY
LDX #<ARGS_STR_A
LDY #>ARGS_STR_A
JSR PrintM
.endif
2016-02-19 21:07:00 +00:00
.if USE_STR_C
DEBUG "____:StrC"
LDY #14
JSR VTABY
LDX #<ARGS_STR_C
LDY #>ARGS_STR_C
JSR PrintM
.endif
2016-02-19 05:58:00 +00:00
.if USE_STR_PASCAL
2016-02-19 21:07:00 +00:00
DEBUG "____:StrP"
LDY #15
2016-02-19 05:58:00 +00:00
JSR VTABY
LDX #<ARGS_STR_PASCAL
LDY #>ARGS_STR_PASCAL
JSR PrintM
.endif
2016-02-18 20:48:00 +00:00
.endif ; ENABLE_STR
2016-02-18 20:19:00 +00:00
2016-02-19 21:07:00 +00:00
LDA #17
2016-02-19 05:58:00 +00:00
JSR TABV
2016-02-19 21:07:00 +00:00
; "old-skool" text/hex printing: use ROM funcs
LDX #<PRINTM_TEXT
LDY #>PRINTM_TEXT
JSR PrintStringZ
2016-02-19 05:58:00 +00:00
LDA PRINTM_SIZE+1
2016-02-19 21:07:00 +00:00
STA demotmp+1
2016-02-19 19:57:00 +00:00
JSR PRBYTE
2016-02-19 05:58:00 +00:00
LDA PRINTM_SIZE+0
2016-02-19 21:07:00 +00:00
STA demotmp+0
JSR PRBYTE
JSR PrintSpc
JSR PrintDec
LDX #<PRINTM_CMDS
LDY #>PRINTM_CMDS
JSR PrintStringZ
2016-02-21 23:51:00 +00:00
LDX #NumMeta
2016-02-19 21:07:00 +00:00
STX demotmp+0
STZ demotmp+1
TXA
2016-02-19 05:58:00 +00:00
JSR PRBYTE
2016-02-19 21:07:00 +00:00
JSR PrintSpc
JSR PrintDec
2016-02-19 05:58:00 +00:00
LDA #$8D
JMP COUT
2016-02-17 23:02:00 +00:00
2016-02-19 21:07:00 +00:00
; ======================================================================
; ds 256 - <*
; Print demotmp in Decimal
2016-02-20 16:02:00 +00:00
; NOTE: Can't use printm PrintDec5 as it may not be enabled/available
2016-02-19 21:07:00 +00:00
PrintDec
2016-02-20 16:02:00 +00:00
STZ _bcd+0
STZ _bcd+1
STZ _bcd+2
2016-02-19 21:07:00 +00:00
LDX #16 ; 16 bits
SED ; Double Dabble
2016-02-20 16:02:00 +00:00
@Dec2BCD:
2016-02-19 21:07:00 +00:00
ASL demotmp+0
ROL demotmp+1
2016-02-20 16:02:00 +00:00
LDY #$FD
@DoubleDabble:
LDA _bcd-$FD,Y
ADC _bcd-$FD,Y
STA _bcd-$FD,Y
2016-02-19 21:07:00 +00:00
INY
2016-02-20 16:02:00 +00:00
BNE @DoubleDabble
2016-02-19 21:07:00 +00:00
DEX
2016-02-20 16:02:00 +00:00
BNE @Dec2BCD
2016-02-19 21:07:00 +00:00
CLD
2016-02-20 16:02:00 +00:00
LDX #5 ; was Y
2016-02-20 17:05:00 +00:00
@BCD2Char: ; NOTE: Digits are reversed!
2016-02-20 21:08:00 +00:00
DEY ; $FF - $FD = 2
2016-02-20 16:02:00 +00:00
LDA _bcd-$FD,Y ; __c??? _b_?XX a_YYXX
2016-02-19 21:07:00 +00:00
LSR
LSR
LSR
LSR
CLC
ADC #'0'+$80
2016-02-20 21:08:00 +00:00
JSR COUT ; __c??X _b_YXX aZYYXX
2016-02-20 16:02:00 +00:00
DEX
LDA _bcd-$FD,Y ; __c??X _b_YXX aZYYXX
2016-02-19 21:07:00 +00:00
AND #$F
CLC
ADC #'0'+$80
2016-02-20 21:08:00 +00:00
JSR COUT ; __c?XX _bYYXX ZZYYXX
2016-02-19 21:07:00 +00:00
DEX
2016-02-20 17:05:00 +00:00
BPL @BCD2Char
2016-02-19 21:07:00 +00:00
RTS
2016-02-20 16:02:00 +00:00
; NOTE: Can't use printm PrintStr*() as it may not be enabled/available
2016-02-19 21:07:00 +00:00
PrintStringZ
STX demoptr+0
STY demoptr+1
LDY #0
@_Text
LDA (demoptr),Y
BEQ @_Done
JSR COUT
INY
BNE @_Text
@_Done
RTS
2016-02-17 23:02:00 +00:00
ReverseByte
LDX #8
2016-02-19 21:07:00 +00:00
STA demotmp ; temp working byte
2016-02-17 23:02:00 +00:00
ReverseBit
2016-02-19 21:07:00 +00:00
ASL demotmp ; 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-19 21:07:00 +00:00
PrintSpc
LDA #' '+$80
JMP COUT
2016-02-18 20:19:00 +00:00
2016-02-19 21:07:00 +00:00
VTABY TYA
JSR BASCALC
LDX BASL
LDY BASH
STX PutChar+1
STY PutChar+2
RTS
2016-02-18 20:19:00 +00:00
2016-02-19 05:58:00 +00:00
; ______________________________________________________________________
2016-02-19 19:57:00 +00:00
TEXT_DEMO
2016-02-18 17:56:00 +00:00
;byte "X=## Y=ddd $=xxxx:@@ %%%%%%%%~????????"
2016-02-19 05:58:00 +00:00
PRINTM "X=%# Y=%d $=%x:%@ %%~%?", 0
2016-02-17 20:35:00 +00:00
2016-02-19 19:57:00 +00:00
ARGS_DEMO
dw TEXT_DEMO; 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-19 05:58:00 +00:00
; ______________________________________________________________________
2016-02-18 17:56:00 +00:00
2016-02-19 05:58:00 +00:00
TEXT_BIN_ASC PRINTM "Bin ASC: %%", 0
TEXT_BIN_INV PRINTM "Bin INV: %?", 0
2016-02-18 17:56:00 +00:00
2016-02-19 05:58:00 +00:00
ARGS_BIN_ASC
dw TEXT_BIN_ASC
2016-02-19 19:57:00 +00:00
dw $DA1A
2016-02-19 05:58:00 +00:00
ARGS_BIN_INV
dw TEXT_BIN_INV
2016-02-19 19:57:00 +00:00
dw $DA1A
2016-02-19 05:58:00 +00:00
; ______________________________________________________________________
TEXT_DEC_2 PRINTM "Dec2: %#", 0
TEXT_DEC_3 PRINTM "Dec3: %d", 0
TEXT_DEC_5 PRINTM "Dec5: %u", 0
TEXT_DEC_BYTE PRINTM "Byte=%b %b %b %b %b", 0
2016-02-20 22:05:00 +00:00
;TEXT_DEC_BYTE PRINTM "%b",0
2016-02-19 05:58:00 +00:00
ARGS_DEC_2
dw TEXT_DEC_2
dw 99 ;
2016-02-18 20:19:00 +00:00
2016-02-19 05:58:00 +00:00
ARGS_DEC_3
dw TEXT_DEC_3
dw 999 ;
ARGS_DEC_5
dw TEXT_DEC_5
dw $FF69 ; $FF69 = 65385
ARGS_DEC_BYTE
dw TEXT_DEC_BYTE
2016-02-18 17:56:00 +00:00
dw $80 ; -128
2016-02-19 19:57:00 +00:00
dw $FF ; -001
dw $00 ; 000
dw $01 ; +001
2016-02-18 17:56:00 +00:00
dw $7F ; +127
2016-02-18 20:19:00 +00:00
2016-02-19 05:58:00 +00:00
; ______________________________________________________________________
2016-02-18 20:19:00 +00:00
2016-02-19 19:57:00 +00:00
TEXT_HEX_2 PRINTM "Hex2: %$", 0
TEXT_HEX_4 PRINTM "Hex4: %x", 0
TEXT_PTR_2 PRINTM "Ptr2: %x:%@", 0
TEXT_PTR_4 PRINTM "Ptr4: %x:%&", 0
2016-02-19 05:58:00 +00:00
ARGS_HEX_2
dw TEXT_HEX_2
dw $1234
ARGS_HEX_4
dw TEXT_HEX_4
dw $1234
ARGS_PTR_2
dw TEXT_PTR_2
dw $2000
dw $2000
ARGS_PTR_4
dw TEXT_PTR_4
dw $2000
dw $2000
; ______________________________________________________________________
2016-02-19 21:07:00 +00:00
TEXT_OCT_3 PRINTM "Oct3: %o", 0
TEXT_OCT_6 PRINTM "Oct6: %O", 0
ARGS_OCT_3
dw TEXT_OCT_3
dw 438
ARGS_OCT_6
dw TEXT_OCT_6
dw 13023
; ______________________________________________________________________
2016-02-19 05:58:00 +00:00
TEXT_HELLO
APPLE "HELLO"
db 0
TEXT_WORLD
APPLE "WORLD"
db 0
2016-02-18 17:56:00 +00:00
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
2016-02-19 05:58:00 +00:00
PASCAL "Pascal Len 13"
TEXT_STR_C
PRINTM "C : '%s','%s'", 0
TEXT_STR_A
PRINTM "Apple : '%a'", 0
TEXT_STR_PASCAL
PRINTM "Pascal: '%p'", 0
2016-02-18 17:56:00 +00:00
2016-02-19 05:58:00 +00:00
ARGS_STR_C
dw TEXT_STR_C
dw TEXT_HELLO
dw TEXT_WORLD
2016-02-18 20:19:00 +00:00
2016-02-19 05:58:00 +00:00
ARGS_STR_A
dw TEXT_STR_A
2016-02-18 20:19:00 +00:00
dw TEXT_DCI
2016-02-19 05:58:00 +00:00
ARGS_STR_PASCAL
dw TEXT_STR_PASCAL
2016-02-18 20:19:00 +00:00
dw TEXT_PASCAL
2016-02-19 05:58:00 +00:00
; ______________________________________________________________________
2016-02-19 19:57:00 +00:00
PRINTM_TEXT APPLE "printm().size = $"
2016-02-19 05:58:00 +00:00
db 0
2016-02-19 21:07:00 +00:00
PRINTM_CMDS APPLE " bytes"
db $8D
APPLE " .features = $ "
db 0
__LIB_SIZE = __END - __PRINTM
PRINTM_SIZE
dw __LIB_SIZE
2016-02-19 05:58:00 +00:00
2016-02-18 20:19:00 +00:00
; Pad until end of page so PrintM starts on new page
2016-02-19 21:07:00 +00:00
; ds (256 - <*) & 7
; ds (256 - <*) & 15
; ds (256 - <*)
2016-02-18 15:48:00 +00:00
2016-02-17 20:35:00 +00:00
2016-02-19 21:07:00 +00:00
; ----------------------------------------------------------------------
; ----------------------------------------------------------------------
;
; printm() library code starts here
;
; ----------------------------------------------------------------------
; ----------------------------------------------------------------------
__PRINTM
; pointer for PrintPtr2, PrintPtr4, PrintStrA, PrintStrC, PrintStrP
_temp = $FE
2016-02-17 20:35:00 +00:00
2016-02-19 21:07:00 +00:00
; self-modifying variable aliases
2016-02-17 20:35:00 +00:00
_pScreen = PutChar +1
_pFormat = GetFormat +1
2016-02-21 02:51:00 +00:00
_pArg = NxtArgByte+1
2016-02-18 20:34:00 +00:00
.if ENABLE_DEC
2016-02-18 00:47:00 +00:00
_nDecWidth = DecWidth +1
2016-02-19 21:07:00 +00:00
.endif
.if ENABLE_OCT
_nOctWidth = OctWidth +1
.endif
2016-02-19 05:58:00 +00:00
2016-02-19 21:07:00 +00:00
; Entry Point
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-21 02:51:00 +00:00
FirstArg
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-21 02:51:00 +00:00
; ======================================================================
; @return next arg as 16-bit arg value in Y,X
2016-02-21 23:51:00 +00:00
2016-02-21 02:51:00 +00:00
NxtArgToTemp
NxtArgYX
JSR NxtArgByte
TAX
; @return _Arg[ _Num ]
NxtArgByte
LDA $C0DE ; _pArg NOTE: self-modifying!
2016-02-21 23:51:00 +00:00
INC _pArg+0 ;
2016-02-21 02:51:00 +00:00
BNE @_SamePage
INC _pArg+1 ;
@_SamePage
TAY
; 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 ;
_Done
RTS
2016-02-18 20:34:00 +00:00
2016-02-19 05:58:00 +00:00
; $ Hex 2 Byte
; x Hex 4 Byte
2016-02-18 00:47:00 +00:00
; ======================================================================
2016-02-19 21:07:00 +00:00
.if ENABLE_HEX
2016-02-20 09:06:00 +00:00
.if USE_HEX_4
DEBUG .sprintf( "PrintHex4() @ %X", * )
PrintHex4:
2016-02-20 22:05:00 +00:00
SEC
2016-02-20 21:08:00 +00:00
.if USE_HEX_2
2016-02-20 22:05:00 +00:00
db $A9 ; LDA #imm skip next 1-byte instruction
2016-02-20 21:08:00 +00:00
.endif
2016-02-20 09:06:00 +00:00
.endif
2016-02-19 05:58:00 +00:00
.if USE_HEX_2
2016-02-19 21:07:00 +00:00
DEBUG .sprintf( "PrintHex2() @ %X", * )
2016-02-19 05:58:00 +00:00
PrintHex2:
2016-02-20 22:05:00 +00:00
CLC
2016-02-19 05:58:00 +00:00
.endif
2016-02-18 15:48:00 +00:00
2016-02-20 22:05:00 +00:00
; Print 16-bit Y,X in hex
2016-02-19 05:58:00 +00:00
_PrintHex:
2016-02-20 22:05:00 +00:00
JSR NxtArgYX ; A=Y= high byte
BCC _PrintHexX
PrintHexAX:
;TYA - optimization from NxtArgYX above
JSR PrintHexByte
_PrintHexX:
TXA
PrintHexA:
JSR PrintHexByte
BRA NextFormat
2016-02-19 05:58: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-19 21:07:00 +00:00
.if ENABLE_PTR
2016-02-20 09:06:00 +00:00
2016-02-19 05:58:00 +00:00
.if USE_PTR_4
2016-02-19 21:07:00 +00:00
DEBUG .sprintf( "PrintPtr4() @ %X", * )
2016-02-19 05:58:00 +00:00
PrintPtr4:
2016-02-20 22:05:00 +00:00
SEC
2016-02-20 21:08:00 +00:00
.if USE_PTR_2
2016-02-20 22:05:00 +00:00
db $A9 ; LDA #imm skip next 1-byte instruction
2016-02-20 21:08:00 +00:00
.endif
2016-02-19 05:58:00 +00:00
.endif
2016-02-18 00:47:00 +00:00
2016-02-19 05:58:00 +00:00
.if USE_PTR_2
2016-02-19 21:07:00 +00:00
DEBUG .sprintf( "PrintPtr2() @ %X", * )
2016-02-19 05:58:00 +00:00
PrintPtr2:
2016-02-20 22:05:00 +00:00
CLC
2016-02-19 05:58:00 +00:00
.endif
_PrintPtr:
JSR NxtArgToTemp
LDY #$0
LDA (_temp),Y
2016-02-20 22:05:00 +00:00
BCC PrintHexA
2016-02-19 05:58:00 +00:00
TAX
INY
LDA (_temp),Y
2016-02-20 22:05:00 +00:00
BRA PrintHexAX ; needs XYtoVal setup
2016-02-19 21:07:00 +00:00
.endif ; ENABLE_PTR
2016-02-21 23:51:00 +00:00
.endif ; ENABLE_HEX
2016-02-18 20:34:00 +00:00
2016-02-17 23:02:00 +00:00
2016-02-19 05:58:00 +00:00
; a String (APPLE text, last byte ASCII)
; See: DCI
2016-02-18 00:47:00 +00:00
; ======================================================================
2016-02-19 21:07:00 +00:00
.if ENABLE_STR
2016-02-19 05:58:00 +00:00
.if USE_STR_A
2016-02-19 21:07:00 +00:00
DEBUG .sprintf( "PrintStrA() @ %X", * )
2016-02-19 05:58:00 +00:00
PrintStrA:
JSR NxtArgToTemp
LDY #$0
_PrintStrA:
LDA (_temp),Y
BPL @_LastChar
JSR PutChar
INY
BNE _PrintStrA
INC _temp+1
BRA _PrintStrA
2016-02-21 23:54:00 +00:00
@_LastChar: ; intentional fall into ForceHighBit Print
2016-02-19 05:58:00 +00:00
.endif ; USE_STR_A
.endif ; ENABLE_STR
; ======================================================================
2016-02-19 21:07:00 +00:00
; Main Read/Eval/Print/Loop of printm()
; ======================================================================
; Note: The dummy address $C0DE is to force the assembler
; to generate a 16-bit address instead of optimizing a ZP operand
2016-02-21 23:54:00 +00:00
ForceHighBit
2016-02-19 19:57:00 +00:00
ORA #$80
2016-02-19 21:07:00 +00:00
Print ; print literal chars
2016-02-17 20:35:00 +00:00
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-19 05:58:00 +00:00
2016-02-19 19:57:00 +00:00
; NOTE: If all features are turned off LDX #-1 ca65 throws Range Error
; NumMeta = _MetaCharEnd - MetaChar
; LDX #NumMeta-1 ; pos = meta
; We can't use this equation since it is not const due to the assembler
; not having defined _MetaCharEnd yet
; Instead we count the number of features enabled
2016-02-19 21:07:00 +00:00
GetNumFeatures
2016-02-19 05:58:00 +00:00
.if (NumMeta > 0)
2016-02-21 02:51:00 +00:00
LDX #NumMeta*3 ; pos = meta
2016-02-19 05:58:00 +00:00
.else
.out "INFO: No meta commands, defaulting to text"
2016-02-21 23:54:00 +00:00
BRA ForceHighBit
2016-02-19 05:58:00 +00:00
.endif
2016-02-21 23:51:00 +00:00
.if NumMeta
2016-02-17 20:35:00 +00:00
FindMeta
2016-02-21 02:51:00 +00:00
DEX
DEX
2016-02-17 20:35:00 +00:00
DEX
2016-02-20 07:47:00 +00:00
BMI NextFormat
2016-02-21 02:51:00 +00:00
CMP MetaTable,X
2016-02-20 07:47:00 +00:00
BNE FindMeta
2016-02-17 20:35:00 +00:00
CallMeta
2016-02-21 02:51:00 +00:00
JMP (MetaTable+1,X)
2016-02-17 20:35:00 +00:00
2016-02-19 21:07:00 +00:00
; ______________________________________________________________________
2016-02-17 20:35:00 +00:00
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-19 21:07:00 +00:00
.if ENABLE_DEC
2016-02-20 22:05:00 +00:00
2016-02-19 05:58:00 +00:00
.if USE_DEC_5
2016-02-19 21:07:00 +00:00
DEBUG .sprintf( "PrintDec5() @ %X", * )
2016-02-19 05:58:00 +00:00
PrintDec5:
2016-02-20 22:05:00 +00:00
LDA #5/2 ; offset into _bcd buffer
2016-02-20 21:08:00 +00:00
.if USE_DEC_2 || USE_DEC_3
db $2C ; BIT $abs skip next instruction
.endif
2016-02-19 05:58:00 +00:00
.endif
2016-02-17 23:02:00 +00:00
2016-02-19 05:58:00 +00:00
.if USE_DEC_3
2016-02-19 21:07:00 +00:00
DEBUG .sprintf( "PrintDec3() @ %X", * )
2016-02-19 05:58:00 +00:00
PrintDec3:
2016-02-20 22:05:00 +00:00
LDA #3/2 ; offset into bcd buffer
2016-02-20 21:08:00 +00:00
.if USE_DEC_2
2016-02-20 17:12:00 +00:00
db $2C ; BIT $abs skip next instruction
2016-02-20 21:08:00 +00:00
.endif
2016-02-19 05:58:00 +00:00
.endif
2016-02-17 23:02:00 +00:00
2016-02-19 05:58:00 +00:00
.if USE_DEC_2
2016-02-19 21:07:00 +00:00
DEBUG .sprintf( "PrintDec2() @ %X", * )
2016-02-19 05:58:00 +00:00
PrintDec2:
2016-02-20 22:05:00 +00:00
LDA #0 ; special: print 2 digits
2016-02-19 05:58:00 +00:00
.endif
2016-02-17 23:17:00 +00:00
2016-02-19 21:07:00 +00:00
; no .if USE_DEC_BYTE here because ENABLE_DEC already covers that
2016-02-19 05:58:00 +00:00
_PrintDec:
STA _nDecWidth
JSR NxtArgYX
PrintDecYX:
STZ _bcd+0
STZ _bcd+1
STZ _bcd+2
Dec2BCD:
2016-02-19 21:07:00 +00:00
LDX #16 ; 16 bits
SED ; "Double Dabble"
2016-02-20 16:10:00 +00:00
@Dec2BCD: ; https://en.wikipedia.org/wiki/Double_dabble
2016-02-21 03:26:00 +00:00
ASL _temp+0
ROL _temp+1
2016-02-19 05:58:00 +00:00
2016-02-21 02:51:00 +00:00
LDY #$FD ; $00-$FD=-3 bcd[0] bcd[1] bcd[2] bcd[3]
@DoubleDabble: ; Y=FD Y=FE Y=FF Y=00
2016-02-20 09:06:00 +00:00
LDA _bcd-$FD,Y
ADC _bcd-$FD,Y
STA _bcd-$FD,Y
2016-02-20 08:05:00 +00:00
INY
BNE @DoubleDabble
2016-02-19 05:58:00 +00:00
DEX
2016-02-20 16:10:00 +00:00
BNE @Dec2BCD
2016-02-19 05:58:00 +00:00
CLD
2016-02-20 17:05:00 +00:00
DecWidth:
2016-02-21 07:21:00 +00:00
LDY #3 ; default to 6 digits
2016-02-21 02:51:00 +00:00
BEQ @EvenBCD ; special case 0 -> only 2 digits
2016-02-21 23:51:00 +00:00
; otherwise have odd digits,
2016-02-21 02:51:00 +00:00
; Print low nibble, skip high nibble
@OddBCD: ; Y = num digits/2 to print
2016-02-20 22:05:00 +00:00
LDA _bcd,Y ; __c??? _b_?XX a_YYXX
JSR HexA
JSR PutChar
2016-02-21 23:51:00 +00:00
DEY
2016-02-20 22:05:00 +00:00
@EvenBCD:
LDA _bcd,Y ; __c??? _b_?XX a_YYXX
JSR PrintHexByte
DEY
BPL @EvenBCD
2016-02-21 23:54:00 +00:00
.endif
_JumpNextFormat1
2016-02-20 22:05:00 +00:00
BRA NextFormat ; always
2016-02-21 23:54:00 +00:00
.if ENABLE_DEC
2016-02-17 23:02:00 +00:00
2016-02-21 23:54:00 +00:00
; b Print a signed byte in decimal
; ======================================================================
.if USE_DEC_BYTE
DEBUG .sprintf( "PrintDecB() @ %X", * )
PrintByte:
JSR NxtArgYX ; X = low byte, Y=A high byte
TXA
BPL PrintBytePos
LDA #'-' + $80 ; X >= $80 --> $80 (-128) .. $FF (-1)
JSR PutChar
TXA
EOR #$FF ; 2's complement
TAX
INX
PrintBytePos:
STX _temp+0 ; needs XYtoTemp setup
STZ _temp+1 ; 00XX
LDA #3/2 ; 3 digits max
STA _nDecWidth
BRA PrintDecYX
.endif ; USE_DEC_BYTE
.endif ; ENABLE_DEC
2016-02-20 22:05:00 +00:00
2016-02-19 05:58:00 +00:00
; ______________________________________________________________________
2016-02-17 23:02:00 +00:00
2016-02-19 05:58:00 +00:00
; % Bin 1 Byte normal ones, normal zeroes
; ? Bin 1 Byte inverse ones, normal zeroes
2016-02-18 00:47:00 +00:00
; ======================================================================
2016-02-19 21:07:00 +00:00
.if ENABLE_BIN
2016-02-19 05:58:00 +00:00
.if USE_BIN_INV
2016-02-19 21:07:00 +00:00
DEBUG .sprintf( "PrintBinI() @ %X", * )
2016-02-19 05:58:00 +00:00
PrintBinInv:
2016-02-20 07:55:00 +00:00
LDA #$31
2016-02-20 21:08:00 +00:00
.if USE_BIN_ASC
2016-02-20 17:12:00 +00:00
;BNE _PrintBin
db $2C ; BIT $abs skip next instruction
2016-02-20 21:08:00 +00:00
.endif
2016-02-19 05:58:00 +00:00
.endif ; USE_BIN_INV
.if USE_BIN_ASC
2016-02-19 21:07:00 +00:00
DEBUG .sprintf( "PrintBinA() @ %X", * )
2016-02-19 05:58:00 +00:00
PrintBinAsc:
2016-02-20 07:55:00 +00:00
LDA #$B1
2016-02-19 05:58:00 +00:00
.endif ; USE_BIN_ASC
_PrintBin:
STA _PrintBit+1
2016-02-21 03:26:00 +00:00
JSR NxtArgYX ; X = low byte, Y=A = high byte
2016-02-19 05:58:00 +00:00
LDY #8 ; print 8 bits
_Bit2Asc:
TXA
2016-02-20 07:55:00 +00:00
ASL ; C= A>=$80
2016-02-19 05:58:00 +00:00
TAX
2016-02-20 07:55:00 +00:00
LDA #$B0
BCC _FlipBit
2016-02-19 05:58:00 +00:00
_PrintBit:
2016-02-20 07:55:00 +00:00
LDA #$B1 ; 1 -> 31 NOTE: self-modifying!
2016-02-19 05:58:00 +00:00
_FlipBit:
JSR PutChar
DEY
BNE _Bit2Asc
2016-02-18 20:34:00 +00:00
.endif ; ENABLE_BIN
2016-02-19 21:07:00 +00:00
; Left as exercise for the reader to optimize the jump size :-)
2016-02-21 23:54:00 +00:00
; 2 bytes short of BRA NextFormat
_JumpNextFormat2
2016-02-17 23:42:00 +00:00
; BRA NextFormat ; always
2016-02-21 23:54:00 +00:00
; JMP NextFormat ; JMP :-(
BRA _JumpNextFormat1
2016-02-18 20:19:00 +00:00
2016-02-19 05:58:00 +00:00
; ______________________________________________________________________
2016-02-18 17:56:00 +00:00
2016-02-19 21:07:00 +00:00
; o Print byte in octal (max 3 digits)
; O Print word in octal (max 6 digits)
; ======================================================================
.if ENABLE_OCT
.if USE_OCT_6
DEBUG .sprintf( "PrintOct6() @ %X", * )
PrintOct6:
LDA #6
2016-02-20 21:08:00 +00:00
.if USE_OCT_3
2016-02-20 17:12:00 +00:00
db $2C ; BIT $abs skip next instruction
2016-02-20 21:08:00 +00:00
.endif
2016-02-19 21:07:00 +00:00
.endif
.if USE_OCT_3
DEBUG .sprintf( "PrintOct3() @ %X", * )
PrintOct3:
LDA #3
.endif
_PrintOct:
STA _nOctWidth
JSR NxtArgYX ; X = low byte
2016-02-18 20:19:00 +00:00
2016-02-19 21:07:00 +00:00
LDX #0
2016-02-20 22:13:00 +00:00
_Oct2Asc:
2016-02-19 21:07:00 +00:00
LDA _temp
AND #7
CLC
ADC #'0'+$80
STA _bcd,x ; NOTE: Digits are reversed!
2016-02-20 16:01:00 +00:00
LDY #3
2016-02-20 08:06:00 +00:00
@OctShr:
2016-02-19 21:07:00 +00:00
LSR _temp+1
ROR _temp+0
2016-02-20 08:06:00 +00:00
DEY
BNE @OctShr
2016-02-19 21:07:00 +00:00
INX
OctWidth:
2016-02-20 22:13:00 +00:00
CPX #6 ; _nOctDigits NOTE: self-modifying!
BNE _Oct2Asc ; Intentional fall into reverse BCD
2016-02-20 22:05:00 +00:00
; On Entry: X number of chars to print in buffer _bcd
; ======================================================================
PrintReverseBCD
DEX
2016-02-21 23:54:00 +00:00
BMI _JumpNextFormat1
2016-02-20 22:05:00 +00:00
LDA _bcd, X
JSR PutChar
BRA PrintReverseBCD
2016-02-21 23:51:00 +00:00
.endif ; ENABLE_OCT
2016-02-19 21:07:00 +00:00
; ______________________________________________________________________
2016-02-18 20:19:00 +00:00
; s String (C,ASCIIZ)
; ======================================================================
2016-02-19 21:07:00 +00:00
.if ENABLE_STR
2016-02-19 05:58:00 +00:00
.if USE_STR_C
2016-02-19 21:07:00 +00:00
DEBUG .sprintf( "PrintStrC() @ %X", * )
2016-02-19 05:58:00 +00:00
PrintStrC:
JSR NxtArgToTemp
LDY #$0
@_NextByte:
LDA (_temp),Y
2016-02-21 23:54:00 +00:00
BEQ _JumpNextFormat1
2016-02-19 05:58:00 +00:00
JSR PutChar
INY
BNE @_NextByte
2016-02-19 21:07:00 +00:00
INC _temp+1 ; support strings > 256 chars
2016-02-19 05:58:00 +00:00
BRA @_NextByte
.endif
2016-02-19 21:07:00 +00:00
.endif
2016-02-18 20:19:00 +00:00
; p String (Pascal)
2016-02-18 17:56:00 +00:00
; ======================================================================
2016-02-19 21:07:00 +00:00
.if ENABLE_STR
2016-02-19 05:58:00 +00:00
.if USE_STR_PASCAL
2016-02-19 21:07:00 +00:00
DEBUG .sprintf( "PrintStrP() @ %X", * )
2016-02-19 05:58:00 +00:00
PrintStrP:
JSR NxtArgToTemp
LDY #$0
LDA (_temp),Y
2016-02-21 23:54:00 +00:00
BEQ _JumpNextFormat2
2016-02-19 05:58:00 +00:00
TAX
_PrintStrP:
INY
LDA (_temp),Y
JSR PutChar
DEX
BNE _PrintStrP
2016-02-21 23:54:00 +00:00
BEQ _JumpNextFormat2 ; always
2016-02-19 05:58:00 +00:00
.endif
2016-02-18 20:34:00 +00:00
.endif ; ENABLE_STR
2016-02-18 17:56:00 +00:00
2016-02-19 21:07:00 +00:00
; ----------------------------------------------------------------------
; Utility
; ----------------------------------------------------------------------
2016-02-17 20:35:00 +00:00
2016-02-20 22:13:00 +00:00
.if ENABLE_HEX || ENABLE_DEC
2016-02-20 22:05:00 +00:00
; Converts A to Hex digits, prints them
PrintHexByte:
2016-02-21 07:21:00 +00:00
DEBUG .sprintf( "PrintHexByte @ %X", * )
2016-02-20 22:05:00 +00:00
JSR HexA
LDA _temp+0
JSR PutChar
PrintHexBotNib:
LDA _temp+1
JMP PutChar
; Converts A to Hex digits, stores two chars in _temp+0, _temp+1
; @return: A will be bottom nibble in ASCII
HexA:
PHA
LSR
LSR
LSR
LSR
JSR _HexNib
STA _temp+0
PLA
_HexNib:
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 _temp+1
RTS
2016-02-21 23:51:00 +00:00
.endif ; ENABLE_HEX || ENABLE_DEC
.endif ; NumMeta
2016-02-20 22:05:00 +00:00
2016-02-18 00:47:00 +00:00
; ======================================================================
2016-02-19 21:07:00 +00:00
;
2016-02-17 20:35:00 +00:00
PutChar
2016-02-19 21:07:00 +00:00
.if 1
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-19 21:07:00 +00:00
.else ; Alternatively use the monitor ROM char output
JMP COUT
.endif
2016-02-17 20:35:00 +00:00
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-21 23:51:00 +00:00
.if NumMeta
2016-02-18 20:34:00 +00:00
_val dw 0 ; PrintHex2 PrintHex4 temp
2016-02-17 20:35:00 +00:00
2016-02-21 02:51:00 +00:00
MetaTable
2016-02-18 20:19:00 +00:00
.if ENABLE_BIN
2016-02-19 05:58:00 +00:00
.if USE_BIN_INV
2016-02-18 20:19:00 +00:00
db '?' ; PrintBinInv NOTE: 1's printed in inverse
2016-02-17 20:35:00 +00:00
dw PrintBinInv
2016-02-19 05:58:00 +00:00
.endif
.if USE_BIN_ASC
2016-02-21 02:51:00 +00:00
db '%' ; PrintBinAsc
2016-02-17 20:35:00 +00:00
dw PrintBinAsc
2016-02-19 05:58:00 +00:00
.endif
2016-02-18 20:19:00 +00:00
.endif
2016-02-21 02:51:00 +00:00
2016-02-18 20:19:00 +00:00
.if ENABLE_DEC
2016-02-19 05:58:00 +00:00
.if USE_DEC_BYTE
2016-02-21 02:51:00 +00:00
db 'b' ; PrintByte NOTE: Signed -128 .. +127
2016-02-18 17:56:00 +00:00
dw PrintByte
2016-02-18 20:19:00 +00:00
.endif
2016-02-19 05:58:00 +00:00
.if USE_DEC_5
2016-02-21 02:51:00 +00:00
db 'u' ; PrintDec5
2016-02-17 23:54:00 +00:00
dw PrintDec5
2016-02-19 05:58:00 +00:00
.endif
.if USE_DEC_3
2016-02-21 02:51:00 +00:00
db 'd' ; PrintDec3
2016-02-17 23:54:00 +00:00
dw PrintDec3
2016-02-19 05:58:00 +00:00
.endif
.if USE_DEC_2
2016-02-21 02:51:00 +00:00
db '#' ; PrintDec2
2016-02-17 20:35:00 +00:00
dw PrintDec2
2016-02-19 05:58:00 +00:00
.endif
2016-02-18 20:19:00 +00:00
.endif
2016-02-21 02:51:00 +00:00
2016-02-18 20:19:00 +00:00
.if ENABLE_HEX
2016-02-19 05:58:00 +00:00
.if USE_HEX_4
2016-02-21 02:51:00 +00:00
db 'x' ; PrintHex4
2016-02-17 20:35:00 +00:00
dw PrintHex4
2016-02-19 05:58:00 +00:00
.endif
.if USE_HEX_2
2016-02-21 02:51:00 +00:00
db '$' ; PrintHex2
2016-02-18 20:19:00 +00:00
dw PrintHex2
2016-02-19 05:58:00 +00:00
.endif
.if USE_PTR_4
2016-02-21 02:51:00 +00:00
db '&' ; PrintPtr4
2016-02-18 20:19:00 +00:00
dw PrintPtr4
2016-02-19 05:58:00 +00:00
.endif
.if USE_PTR_2
2016-02-21 02:51:00 +00:00
db '@' ; PrintPtr2
2016-02-18 20:19:00 +00:00
dw PrintPtr2
2016-02-18 20:34:00 +00:00
.endif
2016-02-18 20:19:00 +00:00
.endif
2016-02-21 02:51:00 +00:00
2016-02-19 21:07:00 +00:00
.if ENABLE_OCT
.if USE_OCT_6
2016-02-21 02:51:00 +00:00
db 'O' ; PrintOct6
2016-02-19 21:07:00 +00:00
dw PrintOct6
.endif
.if USE_OCT_3
2016-02-21 02:51:00 +00:00
db 'o' ; PrintOct3
2016-02-19 21:07:00 +00:00
dw PrintOct3
.endif
.endif
2016-02-18 20:19:00 +00:00
.if ENABLE_STR
2016-02-19 05:58:00 +00:00
.if USE_STR_PASCAL
2016-02-21 02:51:00 +00:00
db 'p' ; PrintStrP NOTE: Pascal string; C printf 'p' is pointer!
2016-02-18 20:19:00 +00:00
dw PrintStrP
2016-02-19 05:58:00 +00:00
.endif
.if USE_STR_C
2016-02-21 02:51:00 +00:00
db 's' ; PrintStrC NOTE: C string, zero terminated
2016-02-18 20:19:00 +00:00
dw PrintStrC
2016-02-19 05:58:00 +00:00
.endif
.if USE_STR_A
2016-02-21 02:51:00 +00:00
db 'a' ; PrintStrA NOTE: Last byte is ASCII
2016-02-18 20:19:00 +00:00
dw PrintStrA
2016-02-19 05:58:00 +00:00
.endif
2016-02-18 20:19:00 +00:00
.endif
2016-02-21 23:51:00 +00:00
.endif ; NumMeta
2016-02-17 20:35:00 +00:00
__END
2016-02-21 07:21:00 +00:00
DEBUG .sprintf( "_bcd @ %X", _bcd )
2016-02-20 16:10:00 +00:00
DEBUG .sprintf( "Demo size: %X (%d bytes)", __PRINTM-__MAIN, __PRINTM-__MAIN)
2016-02-21 23:51:00 +00:00
DEBUG .sprintf( "Total size: %X (%d bytes)", __END -__MAIN, __END -__MAIN)
2016-02-21 02:51:00 +00:00
.out .sprintf( "printm size: %X (%d bytes)", __LIB_SIZE , __LIB_SIZE )
2016-02-20 07:47:00 +00:00