Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.sys.apple2.programmer > #2219 > unrolled thread
| Started by | wssimms@gmail.com |
|---|---|
| First post | 2016-02-13 20:29 -0800 |
| Last post | 2016-02-18 13:37 -0800 |
| Articles | 18 on this page of 38 — 7 participants |
Back to article view | Back to comp.sys.apple2.programmer
printf for 65c02 wssimms@gmail.com - 2016-02-13 20:29 -0800
Re: printf for 65c02 wssimms@gmail.com - 2016-02-13 20:31 -0800
Re: printf for 65c02 wssimms@gmail.com - 2016-02-13 20:36 -0800
Re: printf for 65c02 Antoine Vignau <antoine.vignau@laposte.net> - 2016-02-13 23:22 -0800
Re: printf for 65c02 Michael Barry <barrym95838@yahoo.com> - 2016-02-15 22:57 -0800
Re: printf for 65c02 wssimms@gmail.com - 2016-02-16 01:54 -0800
Re: printf for 65c02 "Bill Garber" <willy46pa@comcast.net> - 2016-02-16 21:11 -0500
Re: printf for 65c02 Michael Pohoreski <michael.pohoreski@gmail.com> - 2016-02-18 16:03 -0800
Re: printf for 65c02 wssimms@gmail.com - 2016-02-18 18:07 -0800
Re: printf for 65c02 Michael J. Mahon <mjmahon@aol.com> - 2016-02-19 03:01 -0600
Re: printf for 65c02 Michael Pohoreski <michael.pohoreski@gmail.com> - 2016-02-19 08:04 -0800
Re: printf for 65c02 qkumba <peter.ferrie@gmail.com> - 2016-02-19 10:05 -0800
Re: printf for 65c02 Michael Pohoreski <michael.pohoreski@gmail.com> - 2016-02-20 00:37 -0800
Re: printf for 65c02 qkumba <peter.ferrie@gmail.com> - 2016-02-20 09:46 -0800
Re: printf for 65c02 Michael Pohoreski <michael.pohoreski@gmail.com> - 2016-02-20 11:35 -0800
Re: printf for 65c02 wssimms@gmail.com - 2016-02-20 04:40 -0800
Re: printf for 65c02 Michael Pohoreski <michael.pohoreski@gmail.com> - 2016-02-20 08:14 -0800
Re: printf for 65c02 Michael J. Mahon <mjmahon@aol.com> - 2016-02-22 14:13 -0600
Re: printf for 65c02 Michael Pohoreski <michael.pohoreski@gmail.com> - 2016-02-20 10:52 -0800
Re: printf for 65c02 Michael Pohoreski <michael.pohoreski@gmail.com> - 2016-02-21 00:53 -0800
Re: printf for 65c02 wssimms@gmail.com - 2016-02-25 09:26 -0800
Re: printf for 65c02 Michael Pohoreski <michael.pohoreski@gmail.com> - 2016-02-25 12:36 -0800
Re: printf for 65c02 Michael Pohoreski <michael.pohoreski@gmail.com> - 2016-02-18 07:38 -0800
Re: printf for 65c02 Michael Pohoreski <michael.pohoreski@gmail.com> - 2016-02-16 15:27 -0800
Re: printf for 65c02 wssimms@gmail.com - 2016-02-16 18:48 -0800
Re: printf for 65c02 Michael Pohoreski <michael.pohoreski@gmail.com> - 2016-02-16 19:13 -0800
Re: printf for 65c02 wssimms@gmail.com - 2016-02-17 07:49 -0800
Re: printf for 65c02 wssimms@gmail.com - 2016-02-17 07:55 -0800
Re: printf for 65c02 wssimms@gmail.com - 2016-02-16 18:55 -0800
Re: printf for 65c02 wssimms@gmail.com - 2016-02-16 18:58 -0800
Re: printf for 65c02 Michael Pohoreski <michael.pohoreski@gmail.com> - 2016-02-18 13:14 -0800
Re: printf for 65c02 Michael Pohoreski <michael.pohoreski@gmail.com> - 2016-02-18 13:27 -0800
Re: printf for 65c02 Michael Pohoreski <michael.pohoreski@gmail.com> - 2016-02-18 15:09 -0800
Re: printf for 65c02 wssimms@gmail.com - 2016-02-18 17:58 -0800
Re: printf for 65c02 Michael Barry <barrym95838@yahoo.com> - 2016-02-19 17:52 -0800
Re: printf for 65c02 wssimms@gmail.com - 2016-02-19 18:09 -0800
Re: printf for 65c02 Michael J. Mahon <mjmahon@aol.com> - 2016-02-20 00:27 -0600
Re: printf for 65c02 Michael Pohoreski <michael.pohoreski@gmail.com> - 2016-02-18 13:37 -0800
Page 2 of 2 — ← Prev page 1 [2]
| From | wssimms@gmail.com |
|---|---|
| Date | 2016-02-25 09:26 -0800 |
| Message-ID | <adc59a74-cc23-4a58-8418-02359a0d37c9@googlegroups.com> |
| In reply to | #2334 |
Am Sonntag, 21. Februar 2016 17:53:47 UTC+9 schrieb Michael Pohoreski: > On Saturday, February 20, 2016 at 4:40:38 AM UTC-8, wss...@gmail.com wrote: > > Thanks. I've incorporated all of your changes into my source. > > I wrote this code probably 8 or 9 months ago and I remember > > thinking I wanted the loops unrolled at the time, but when I > > now think of how I use this routine, the few cycles saved by > > unrolling are completely inconsequential. > > This may be of interest: > > I optimized PrintDec so that it supports a variable width output AND doesn't need to > do a "reverse print" using the bcd buffer. It took me a while to look at this and, frankly, that code is really hard to read with all the conditional assembly stuff, but I think i finally figured out that you are using a different format character for each width. Seems reasonable, and if it saves space, useful too. Personally, at the moment I'm really not that concerned with space optimization. I follow some personal guidelines to keep things somewhat tight, but if my code is 10-15% bigger, so be it for now. I'm hoping to make a preliminary release of my Apple II project sometime in the summer, but unfortunately I don't have much time to work on it and I have a very large amount of code left to be written, so I have to be a bit lax on optimization.
[toc] | [prev] | [next] | [standalone]
| From | Michael Pohoreski <michael.pohoreski@gmail.com> |
|---|---|
| Date | 2016-02-25 12:36 -0800 |
| Message-ID | <741560b8-90ab-487a-a965-b8f0b05efeef@googlegroups.com> |
| In reply to | #2376 |
On Thursday, February 25, 2016 at 10:26:22 AM UTC-7, wss...@gmail.com wrote: > It took me a while to look at this and, frankly, that code is really hard to read with all > the conditional assembly stuff, That's one of the down-sides. > but I think i finally figured out that you are using > a different format character for each width. Seems reasonable, and if it saves space, > useful too. That's the benefit. If you don't use one of the formatting characters, none of the relevant code is included. i.e. Why waste space with Print Octal code if you never use octal ? > Personally, at the moment I'm really not that concerned with space optimization. I > follow some personal guidelines to keep things somewhat tight, but if my code is > 10-15% bigger, so be it for now. I'm hoping to make a preliminary release of my > Apple II project sometime in the summer, but unfortunately I don't have much time to > work on it and I have a very large amount of code left to be written, so I have to be a > bit lax on optimization. Looking forward to when you release this. Keep up posted!
[toc] | [prev] | [next] | [standalone]
| From | Michael Pohoreski <michael.pohoreski@gmail.com> |
|---|---|
| Date | 2016-02-18 07:38 -0800 |
| Message-ID | <ddb593b4-f0dc-43e2-81e8-24be8c766c96@googlegroups.com> |
| In reply to | #2222 |
On Saturday, February 13, 2016 at 11:22:26 PM UTC-8, Antoine Vignau wrote:
> Oh yeah, where are the comments?
I've started adding comments ... since that `PrintDec` is absolutely brilliant!
PrintDec
STX val+0
STY val+1
STZ bcd+0
STZ bcd+1
STZ bcd+2
Dec2BCD
LDX #16
SED
_Dec2BCD
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 _cd+2
DEX
BNE _Dec2BCD
CLD
BCD2Char
LDX #2
LDY #5
_BCD2Char ; Pass 1 Pass 2 Pass 3
LDA bcd,X ; ab?000 a?_0XX ?_YYXX
LSR
LSR
LSR
LSR
CLC
ADC #'0' + $80
STA bcd,Y ; ab?00X a?_YXX ?ZYYXX
DEY
LDA bcd,X ; ab?00X a?_YXX ?ZYYXX
AND #$F
CLC
ADC #'0' + $80
STA bcd,Y ; ab?0XX a?YYXX ZZYYXX
DEY
DEX
BPL _BCD2Char
[toc] | [prev] | [next] | [standalone]
| From | Michael Pohoreski <michael.pohoreski@gmail.com> |
|---|---|
| Date | 2016-02-16 15:27 -0800 |
| Message-ID | <5af5b88b-ed0e-457d-bab8-28f6a4f531a4@googlegroups.com> |
| In reply to | #2219 |
On Saturday, February 13, 2016 at 8:29:36 PM UTC-8, wss...@gmail.com wrote:
> I just posted 65c02 code on comp.sys.apple2 that calls printf.
> I thought that might pique someone's interest, so here is my printf
> for 65c02.
Personally I think printf() is a little overkill / bloated on the 6502, but this is not bad, not bad at all ! Nice job! This is pretty cool, especially the printd !
> If someone actually has an interest in reading and understanding it, and finds themselves stumped, I'll be happy to answer any questions.
0. I wish you had used case to distinguish between Funcs and Vars. :-/ Would of helped with the readability.
1. I assume "scien" is short for Scientific Notation ? Not everyone may be familiar with the abbreviation(s).
Everything is pretty straightforward, except for these two:
2 a) What does "Logical" do? Looks like it an alias for printf Long ?
; %l Print Logical ??
logical
jsr nxtarg
logic1
jsr printd
2 b) What does "Remote" do ? Looks like it prints a Pointer ?
; %r Print Remote
I'll second Antoine's Request For Comments -- maybe document the input registers? :-)
i.e.
; Get Argument Stack Pointer -> XY
getsp
; Set Argument Stack Pointer: XY ->
setsp
; Print 16-bit XY as Decimal
printd
; Print XY as hex
printx
; Get Pointer to next argument -> XY
nxtarg
; Increment argument pointer, return argument in A
nxtargb
; %d Print decimal
; %o Print octal
; %x Print hex
; %f Print float
; %e Print float in Scientific Notation
; %c Print Char
; %s Print string
; %l Print Long
; %r Print Pointer
printf
Assuming my math is correct, one can save 3 bytes by factoring out the double "jsr nxtarg" :-)
nxtarg2 jsr nxtarg ; intentional fall into
nxtarg jsr nxtargb
pfloat
jsr nxtarg2 ; OLD: jsr nxtarg jsr nxtarg
pscien
jsr nxtarg2 ; OLD: jsr nxtarg jsr nxtarg
And save another 1 byte:
float
ldx ndigit
lda ndfnd
jsr pfloat
bra scien2 ; OLD: jmp prbuf
scien
ldx ndigit
lda ndfnd
jsr pscien
scien2
jmp prbuf
Nice 650C02 usage. :-)
> I ripped this code out of a larger project for posting
Yeah, I'm working on m own mini-version taking advantage of Apple'ism since I don't need the useless octal or less needed floats. I really should get that sub-project done. :-)
[toc] | [prev] | [next] | [standalone]
| From | wssimms@gmail.com |
|---|---|
| Date | 2016-02-16 18:48 -0800 |
| Message-ID | <3b4f20f7-f5d2-4147-a62b-27a3fa244853@googlegroups.com> |
| In reply to | #2247 |
Am Mittwoch, 17. Februar 2016 08:27:17 UTC+9 schrieb Michael Pohoreski:
> Everything is pretty straightforward, except for these two:
>
> 2 a) What does "Logical" do? Looks like it an alias for printf Long ?
> ; %l Print Logical ??
>
> logical
> jsr nxtarg
> logic1
> jsr printd
logical prints a 16-bit integer as an unsigned value. This printf doesn't
know about long values. If you look at decimal, you can see that all it
does is test the signedness of the value retrieved from the argument
stack and, if negative, does a manual negation by XORing #$FFFF, etc.,
prints '-', and jumps to logic1
logical, on the other hand, calls printd to generate the decimal repre-
sentation in the BCD buffer. The rest of logical is concerned with the
formatting of the field width and printing number of digits requested,
including leading zeros, if necessary.
>
> 2 b) What does "Remote" do ? Looks like it prints a Pointer ?
> ; %r Print Remote
It allows you to insert another set of arguments to printf.
char *greeting = "Hello";
char *title = "Mr.";
char *nameargs[] = { "%s/%s", "Smith", "Jones" };
printf("%s %s %r!", greeting, title, nameargs);
yielding:
Hello Mr. Smith/Jones!
This was a feature of early printfs that was removed for portability
and type-safety reasons as Unix and C developed.
> Assuming my math is correct, one can save 3 bytes by factoring out the double "jsr nxtarg" :-)
No doubt there are savings to be had. I haven't put much if any
effort into optimizing code size.
[toc] | [prev] | [next] | [standalone]
| From | Michael Pohoreski <michael.pohoreski@gmail.com> |
|---|---|
| Date | 2016-02-16 19:13 -0800 |
| Message-ID | <c2de8e12-e0f5-4cf7-ba1d-5d5d8c747c6e@googlegroups.com> |
| In reply to | #2249 |
On Tuesday, February 16, 2016 at 6:48:43 PM UTC-8, wss...@gmail.com wrote:
> > 2 b) What does "Remote" do ? Looks like it prints a Pointer ?
> > ; %r Print Remote
>
> It allows you to insert another set of arguments to printf.
>
> char *greeting = "Hello";
> char *title = "Mr.";
> char *nameargs[] = { "%s/%s", "Smith", "Jones" };
> printf("%s %s %r!", greeting, title, nameargs);
>
> yielding:
>
> Hello Mr. Smith/Jones!
>
> This was a feature of early printfs that was removed for portability
> and type-safety reasons as Unix and C developed.
Ah, thanks for the clarification Sheldon.
That "should" make sense but I'm missing something ... :-(
I guess it is has been too long of a day ... :-/
Everything but the %r works in this cc65 demo program.
; ca65
.feature c_comments
.feature labels_without_colons
.feature leading_dot_in_identifiers
; 65C02
.PC02
.macro asc text
.byte text
.endmacro
.macro db val
.byte val
.endmacro
.macro dw val
.word val
.endmacro
.macro ds bytes
.res bytes
.endmacro
__MAIN= $6000
.word __MAIN ; 2 byte BLOAD address
.word __END - __MAIN ; 2 byte BLOAD size
.org __MAIN ; .org must come after header else offsets are wrong
HOME = $FC58
JSR HOME
LDX #<DATA
LDY #>DATA
JSR SetArgStackPtr
JSR Printf
RTS
TEXT
asc "Dec = %d, Hex = %x, Oct = %o, Chr = %c"
db $8D
asc "String = %-14s, Long = %7l"
db $8D
asc "Float = %f, Sci = %e"
db $8D
asc "Remote = %r"
db $8D
db 0
DATA
dw TEXT ; printf( text, ... );
dw 123 ; %d 123
dw 123 ; %x 7B
dw 123 ; %o 173
dw 123 ; %c {
dw HELLO ; %s Hello World
dw $FF69 ; %l 65385 == -151 == $FF69
dw $3F80 ; %f // not implemented
dw $3F80 ; %e // not implemented
dw ARG2 ; %r
HELLO
asc "Hello World!"
db 0
APPLE
asc "Apple //e"
db 0
DONE
asc "Done."
db 0
ARG2
dw DATA2
asc "%s/%s"
db 0
DATA2
dw APPLE
dw DONE
ArgStack dw 0
; Main entry point is Printf
; xc
; rel
; use sys
; dsk printf.l
;
;getsp ext
;setsp ext
;putchar ext
; Addr -> XY
GetArgStackPtr
ldx ArgStack+0
ldy ArgStack+1
rts
; XY -> Addr
SetArgStackPtr
stx ArgStack+0
sty ArgStack+1
rts
PutChar
ORA #$80
JMP $FDED
bcd ds 6 ; 999999
nval dw 0
PrintDec
stx nval
sty nval+1
stz bcd
stz bcd+1
stz bcd+2
ldx #16
sed
@_a
asl nval
rol nval+1
lda bcd
adc bcd
sta bcd
lda bcd+1
adc bcd+1
sta bcd+1
lda bcd+2
adc bcd+2
sta bcd+2
dex
bne @_a
cld
ldx #2
ldy #5
@_b lda bcd,x
lsr
lsr
lsr
lsr
clc
adc #'0'
sta bcd,y
dey
lda bcd,x
and #$0F
clc
adc #'0'
sta bcd,y
dey
dex
bpl @_b
rts
; Print XY in Hex
PrintHex
stx nval
sty nval+1
ldx #0
@_1 lda nval
and #15
cmp #10 ; $0..$9
bcc @_2
adc #6 ; $A + (C=1) -> $10
@_2 adc #'0'
sta bcd,x
lsr nval+1
ror nval
lsr nval+1
ror nval
lsr nval+1
ror nval
lsr nval+1
ror nval
inx
cpx #6 ; Print 5 hex digits
bne @_1
rts
; Print XY in Octal
PrintOct
stx nval
sty nval+1
ldx #0
@_1 lda nval
and #7
clc
adc #'0'
sta bcd,x
lsr nval+1
ror nval
lsr nval+1
ror nval
lsr nval+1
ror nval
inx
cpx #6
bne @_1
rts
rjust db 0
ndigit db 0
width db 0
Printf ;ent
jsr GetArgStackPtr
stx argptr+1
sty argptr+2
stz argidx
jsr NxtArg
stx GetFormat+1 ; NOTE: self-modifying
sty GetFormat+2 ; NOTE: self-modifying
loop
jsr FormatChar
cmp #0 ; ASCIIZ
beq @_1a
cmp #'%' ; have escape char?
beq @_2a
@_3
jsr PutChar
bra loop
@_1a ; end of string
jsr FixArgStack
rts
@_2a
stz rjust
stz ndigit
jsr GetFormat
cmp #'-' ; have width?
bne @_2b
jsr FormatChar
inc rjust
@_2b
jsr GetNum
ldx nval
stx width
stz ndfnd
cmp #'.'
bne @_1b
jsr GetNum
ldx nval
stx ndigit
@_1b
sta @_1d+1 ; NOTE: Self-modifying
stz fbidx
ldx #0
@_1c
lda PrintSpecifier,x
beq @_1e
inx
@_1d cmp #0 ; NOTE: Self-modifying: width
bne @_1c
dex
txa
asl
tax
jmp (PrintFunction,x)
@_1e lda @_1d+1
bra @_3 ; always
PrintSpecifier
db 'd'
db 'o'
db 'x'
db 'f'
db 'e'
db 'c'
db 's'
db 'l'
db 'r'
db 0 ; end of table
PrintFunction
dw DoDecimal
dw DoOctal
dw DoHex
dw DoFloatStandard
dw DoFloatScientific
dw DoCharac
dw DoString
dw DoLong
dw DoRemote
DoDecimal
jsr NxtArg
tya
bpl _DoLong1
eor #$FF
sta nval+1
txa
eor #$FF
inc
sta nval
bne @_0
inc nval+1
@_0 lda #'-'
ldy fbidx
inc fbidx
sta fbuf,y
ldx nval
ldy nval+1
bra _DoLong1
; logical
DoLong
jsr NxtArg
;logic1
_DoLong1
jsr PrintDec
nm2bf ldx #5 ; 16-bit max 5 decimal digits
ldy fbidx
@_1a lda bcd,x
cpx ndigit
bcc @_1d
dex
bmi @_1c
cmp #'0'
bne @_1b
bra @_1a ; always
@_1d dex
@_1b sta fbuf,y
iny
lda bcd,x
dex
bpl @_1b
@_1c sta fbuf,y
iny
sty fbidx
jmp PrintBuf
DoCharac
jsr NxtArgB
cmp #0
beq @_1a
ldy fbidx
sta fbuf,y
inc fbidx
@_1a jsr NxtArgB
cmp #0
beq @_1b
ldy fbidx
sta fbuf,y
inc fbidx
@_1b jmp PrintBuf
DoString
jsr NxtArg
stx @_1a+1
sty @_1a+2
ldx ndigit
ldy #0
@_1a
lda $FFFF,y
beq @_1b
iny
dex
bne @_1a
@_1b
tya
ldx @_1a+1
ldy @_1a+2
jmp PrintStr
DoHex
jsr NxtArg
jsr PrintHex
jmp nm2bf
DoOctal
jsr NxtArg
jsr PrintOct
jmp nm2bf
; Print Floating-Point number in standard notation
DoFloatStandard
ldx ndigit
lda ndfnd
jsr PrintFloatStandard
jmp PrintBuf
; Print Floating-Point number in scientific notation
DoFloatScientific
ldx ndigit
lda ndfnd
jsr PrintFloatScientific
jmp PrintBuf
DoRemote
jsr NxtArg
stx @_1+1
sty @_2+1
jsr FixArgStack
@_1 ldx #0 ; NOTE: Self-modifying
@_2 ldy #0 ; NOTE: Self-modifying
stx argptr+1
sty argptr+2
stz argidx
jsr NxtArg
stx GetFormat+1
sty GetFormat+2
_GoLoop
jmp loop
; Print Float Buffer
PrintBuf
lda fbidx
ldx #<fbuf
ldy #>fbuf
PrintStr
stx @_sptr+1
sty @_sptr+2
sta nchar
lda width
sec
sbc nchar
sta nxtra
bcc @_1a
beq @_1a
ldx rjust
bne @_1a
@_2a
lda #' '
jsr PutChar
dec nxtra
bne @_2a
@_1a
lda nchar
beq @_2b
@_1b
@_sptr lda $FFFF ; NOTE: self-modifying
inc @_sptr+1
bne @_sp1
inc @_sptr+2
@_sp1
jsr PutChar
dec nchar
bne @_sptr
@_2b
lda nxtra
bmi @_1c
beq @_1c
@_2c
lda #' '
jsr PutChar
dec nxtra
bne @_2c
@_1c
; jmp loop ; OLD
bra _GoLoop
nxtra db 0
nchar db 0
fbidx db 0 ; Float Buffer # chars
fbuf ds 128 ; Float Buffer
;Return Num in A
GetNum
stz ndfnd
stz nval
stz nval+1
@_1
jsr FormatChar
sec
sbc #'0'
cmp #$100+'*'-'0' ; ca65 bug: 0x2A - 0x30 = 0xFA = -6
bne @_2
jsr NxtArg
stx dval
bra @_3
@_2
cmp #10
bcs @_4
sta dval
@_3
inc ndfnd
; x10
lda nval
sta ntmp
asl
asl
clc
adc ntmp
asl
clc
adc dval
sta nval
bra @_1 ; always
@_4
adc #'0'-1
rts
dval db 0
ntmp db 0
ndfnd db 0
argidx db 0
;pkfmt
GetFormat lda $FFFF
rts
FormatChar jsr GetFormat
inc GetFormat+1
bne @_x ; Doesn't cross page boundary
inc GetFormat+2
@_x rts
NxtArg2 jsr NxtArg ; intentional fall into
NxtArg jsr NxtArgB
tax
jsr NxtArgB
tay
rts
; Inc next arg, return in A
NxtArgB ldy argidx
argptr lda $FFFF,y ; NOTE: Self-Modifying!
inc argidx
bne @_0
inc argptr+2
@_0 rts
; Move to next Argument by skipping 'argidx' bytes
; Return Argument Stack -> XY
FixArgStack
clc
lda argptr+1
adc argidx
tax
lda argptr+2
adc #0
tay
jsr SetArgStackPtr
rts
; Print Floating-Point Number
; Not implemented
PrintFloatStandard
; jsr NxtArg
; jsr NxtArg
jsr NxtArg2
ldx #$FF
@_0 inx
lda flts,x
sta fbuf,x
bne @_0
stx fbidx
rts
; Print Floating-Point in Scientific Notation
; Not implemented
PrintFloatScientific
; jsr NxtArg
; jsr NxtArg
jsr NxtArg2
ldx #$FF
@_0 inx
lda scis,x
sta fbuf,x
bne @_0
stx fbidx
rts
flts asc "<float>" ; Standard Notation
db 0
scis asc "<scien>" ; Scientific Notation
db 0
__END:
[toc] | [prev] | [next] | [standalone]
| From | wssimms@gmail.com |
|---|---|
| Date | 2016-02-17 07:49 -0800 |
| Message-ID | <b32baf15-18f5-4a9a-bb76-9580786aeb07@googlegroups.com> |
| In reply to | #2254 |
Am Mittwoch, 17. Februar 2016 12:13:13 UTC+9 schrieb Michael Pohoreski:
> On Tuesday, February 16, 2016 at 6:48:43 PM UTC-8, wss...@gmail.com wrote:
> > > 2 b) What does "Remote" do ? Looks like it prints a Pointer ?
> > > ; %r Print Remote
> >
> > It allows you to insert another set of arguments to printf.
> >
> > char *greeting = "Hello";
> > char *title = "Mr.";
> > char *nameargs[] = { "%s/%s", "Smith", "Jones" };
> > printf("%s %s %r!", greeting, title, nameargs);
> >
> > yielding:
> >
> > Hello Mr. Smith/Jones!
> >
> > This was a feature of early printfs that was removed for portability
> > and type-safety reasons as Unix and C developed.
>
> Ah, thanks for the clarification Sheldon.
> That "should" make sense but I'm missing something ... :-(
> I guess it is has been too long of a day ... :-/
>
> Everything but the %r works in this cc65 demo program.
I did make a mistake in my previous comment, I think, in that I implied
that printf will come back from the 'remote' argument list to continue
the original format string after the remote list is exhausted. However
that is not the case.
Here's a short exercise for %r that Works For Me (TM):
xc
rel
dsk rtst.l
printf ext
spushw ext
ldx #<args
ldy #>args
jsr spushw
ldx #$A5
ldy #$C3
jsr spushw
ldx #<pfs
ldy #>pfs
jsr spushw
jsr printf
rts
pfs asc 'N=0x%x, more:%r',00
args dw a1
dw 12345
dw a2
a1 asc '(%d : %s)',0A00
a2 asc 'ok?',00
[toc] | [prev] | [next] | [standalone]
| From | wssimms@gmail.com |
|---|---|
| Date | 2016-02-17 07:55 -0800 |
| Message-ID | <b2b0fb1c-b098-4951-ab5b-1c15e75243e8@googlegroups.com> |
| In reply to | #2254 |
Am Mittwoch, 17. Februar 2016 12:13:13 UTC+9 schrieb Michael Pohoreski:
> Everything but the %r works in this cc65 demo program.
Ok I'm kind of a dummy -- always posting before I have thoroughly
digested the post I am responding to. I think your problem isn't with
%r, per se, but rather the problem is that you are providing only a single
word (16 bits) each for %f and %e, but they are expecting 32 bits:
Your code is this:
> DATA
> dw TEXT ; printf( text, ... );
> dw 123 ; %d 123
> dw 123 ; %x 7B
> dw 123 ; %o 173
> dw 123 ; %c {
> dw HELLO ; %s Hello World
> dw $FF69 ; %l 65385 == -151 == $FF69
> dw $3F80 ; %f // not implemented
> dw $3F80 ; %e // not implemented
> dw ARG2 ; %r
But the float handling code pops two words (16 bits args):
> PrintFloatStandard
> ; jsr NxtArg
> ; jsr NxtArg
> jsr NxtArg2
> ldx #$FF
> @_0 inx
> lda flts,x
> sta fbuf,x
> bne @_0
> stx fbidx
> rts
[toc] | [prev] | [next] | [standalone]
| From | wssimms@gmail.com |
|---|---|
| Date | 2016-02-16 18:55 -0800 |
| Message-ID | <d01691e7-4440-4a73-a3fb-cb3d6fcb24e1@googlegroups.com> |
| In reply to | #2247 |
Am Mittwoch, 17. Februar 2016 08:27:17 UTC+9 schrieb Michael Pohoreski:
> Yeah, I'm working on m own mini-version taking advantage of Apple'ism
> since I don't need the useless octal or less needed floats. I really should
> get that sub-project done. :-)
Here's a smaller version, tprintf (tiny-printf) that only does decimal, hex, and
strings. Sorry, also no comments.
Instead of the getsp/setsp routines and an internal pointer, it uses only a
spopw routine to pop a word off of the arg stack into X/Y.
This assembles to 282 bytes.
xc
rel
dsk tprintf.l
spopw ext
putchar ext
bcd ds 6
nval dw 0
printd
stx nval
sty nval+1
stz bcd
stz bcd+1
stz bcd+2
ldx #16
sed
:0a
asl nval
rol nval+1
lda bcd
adc bcd
sta bcd
lda bcd+1
adc bcd+1
sta bcd+1
lda bcd+2
adc bcd+2
sta bcd+2
dex
bne :0a
cld
ldx #2
ldy #5
:0b lda bcd,x
lsr
lsr
lsr
lsr
clc
adc #'0'
sta bcd,y
dey
lda bcd,x
and #$0F
clc
adc #'0'
sta bcd,y
dey
dex
bpl :0b
rts
printx
stx nval
sty nval+1
ldx #0
:1 lda nval
and #15
cmp #10
bcc :2
adc #6
:2 adc #'0'
sta bcd,x
lsr nval+1
ror nval
lsr nval+1
ror nval
lsr nval+1
ror nval
lsr nval+1
ror nval
inx
cpx #6
bne :1
rts
prbf ldx #5
:1a lda bcd,x
dex
bmi :1c
cmp #'0'
beq :1a
:1b jsr putchar
lda bcd,x
dex
bpl :1b
:1c jsr putchar
jmp loop
tprintf ent
jsr spopw
stx fmtc+1
sty fmtc+2
loop jsr fmtc
cmp #0
beq done
and #$7F
cmp #'%'
beq :1
jsr putchar
bra loop
:1 jsr fmtc
cmp #'d'
beq :1F
cmp #'x'
beq :2F
cmp #'s'
beq :3F
jsr putchar
bra loop
* %d
:1F jsr spopw
jsr printd
jmp prbf
* %x
:2F jsr spopw
jsr printx
jmp prbf
* %s
:3F jsr spopw
stx :8+1
sty :8+2
ldx #0
:8 lda $FFFF,x
beq loop
jsr putchar
inx
bne :8
inc :8+2
bra :8
*
fmtc lda $FFFF
inc fmtc+1
bne done
inc fmtc+2
done rts
[toc] | [prev] | [next] | [standalone]
| From | wssimms@gmail.com |
|---|---|
| Date | 2016-02-16 18:58 -0800 |
| Message-ID | <8b979266-2345-4af0-8449-a7eafbe554fe@googlegroups.com> |
| In reply to | #2250 |
Am Mittwoch, 17. Februar 2016 11:55:16 UTC+9 schrieb wss...@gmail.com: Whoops, gmail users be careful, part of the code I just posted is being hidden as "cited text" (at least for me). You have to click on "show cited text" to see it.
[toc] | [prev] | [next] | [standalone]
| From | Michael Pohoreski <michael.pohoreski@gmail.com> |
|---|---|
| Date | 2016-02-18 13:14 -0800 |
| Message-ID | <1d52f16f-2651-4ae0-a8ea-6263ee20a19b@googlegroups.com> |
| In reply to | #2250 |
On Tuesday, February 16, 2016 at 6:55:16 PM UTC-8, wss...@gmail.com wrote:
> Here's a smaller version, tprintf (tiny-printf) that only does decimal, hex, and
> strings. Sorry, also no comments.
Nice job on tprintf! What I hate abour standard printf() is that it provides a useless octal but no portable and essential binary printing. Really?! But thanks for all your source code! It was inspiration to get off my but and finish off my next project ...
I'll call your printf() and raise it with my printm(). A "printf()-the-Apple-way" that provides:
* Hex printing with 2 and 4 widths
* Dec printing, with 2, 3, and 5 widths
* Signed Byte printing
* Binary printing with normal, and inverse 1's.
* Pointer deref printing 2 or 4 bytes
* Strings in Apple, C, and Pascal formats.
Also, you can turn features on/off (at compile time) to reduce the memory footprint since with everything turned on its a little big at 728 bytes.
Anyways, here's the source + demo, *ahem* WITH comments. :-)
I also provide a text dump so you can copy/paste that into your favorite emulator if you're too lazy to assemble this. :-)
- - - 8< printm.s - - -
; ca65
.feature c_comments
/*
printm - a printf replacement for 6502
Michael Pohroeski
Problem:
Ideally we want to print a single line that includes literal and variables.
.byte "X=## Y=### $=####:@@ %%%%%%%%~????????"
without having to waste marking up literals with an escape character
Why printf() on the 6502 sucks:
- 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
To toggle features on / off:
*/
ENABLE_BIN = 1
ENABLE_DEC = 1
ENABLE_BYTE = 1 ; requires ENABLE_DEC
ENABLE_HEX = 1
ENABLE_PTR = 1 ; requires ENABLE_HEX
ENABLE_STR = 1
.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 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
; 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 PASCAL text
.byte .strlen(text)
APPLE text
.endmacro
.macro db val
.byte val
.endmacro
.macro dw val
.word val
.endmacro
.macro ds bytes
.res bytes
.endmacro
HOME = $FC58
TABV = $FB5B
; printm pointer for PrintPtr2, PrintPtr4, PrintStrA, PrintStrC, PrintStrP
_temp = $FE
__MAIN = $4000
; DOS3.3 meta -- remove these 2 if running under ProDOS
.word __MAIN ; 2 byte BLOAD address
.word __END - __MAIN ; 2 byte BLOAD size
/*
Output:
X=39 Y=191 $=2345:D5 11010101~10101011
Byte=-128 -001 000 001 127
Strings: 'HELLO','WORLD'
Apple: 'HOME' Pascal: 'String Len 13'
*/
.org __MAIN ; .org must come after header else offsets are wrong
; Demo printm
JSR HOME
LDA #$D5
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
JSR ReverseByte
STA DATA+12
.if ENABLE_BIN || ENABLE_DEC || ENABLE_HEX
LDY #0
JSR VTABY
LDX #<DATA ; Low Byte of Address
LDY #>DATA ; High Byte of Address
JSR PrintM
.endif
.if ENABLE_BYTE
LDY #2
JSR VTABY
LDX #<DATA2
LDY #>DATA2
JSR PrintM
.endif ; ENABLE_BYTE
.if ENABLE_STR
LDY #4
JSR VTABY
LDX #<DATA3
LDY #>DATA3
JSR PrintM
LDY #6
JSR VTABY
LDX #<DATA4
LDY #>DATA4
JSR PrintM
.endif ; ENABLE_STR
LDA #8
JMP TABV
ReverseByte
LDX #8
STA $FF ; temp working byte
ReverseBit
ASL $FF ; temp working byte
ROR
DEX
BNE ReverseBit
RTS
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
TEXT
;byte "X=## Y=ddd $=xxxx:@@ %%%%%%%%~????????"
APPLE "X="
.byte "#"
APPLE " Y="
.byte "d"
APPLE " $="
.byte "x"
APPLE ":"
.byte "@"
APPLE " "
.byte "%"
APPLE "~"
.byte "?"
.byte 0
DATA
dw TEXT ; aArg[ 0] text
dw 39 ; aArg[ 1] x
dw 191 ; aArg[ 2] y
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
TEXT2
;byte "Byte=b b b b Str=s,s"
APPLE "Byte="
.byte "b"
APPLE " "
.byte "b"
APPLE " "
.byte "b"
APPLE " "
.byte "b"
APPLE " "
.byte "b"
db 0
TEXT_HELLO
APPLE "HELLO"
db 0
TEXT_WORLD
APPLE "WORLD"
db 0
DATA2
dw TEXT2
dw $80 ; -128
dw $FF ; -1
dw $00 ; 0
dw $01 ; +1
dw $7F ; +127
TEXT3
APPLE "Strings: '"
.byte "s"
APPLE "','"
.byte "s"
APPLE "'"
db 0
DATA3
dw TEXT3
dw TEXT_HELLO
dw TEXT_WORLD
TEXT_DCI
DCI "HOME"
TEXT_PASCAL
PASCAL "String Len 13"
TEXT4
APPLE "Apple: '"
.byte "a"
APPLE "' Pascal: '"
.byte "p"
APPLE "'"
db 0
DATA4
dw TEXT4
dw TEXT_DCI
dw TEXT_PASCAL
; Pad until end of page so PrintM starts on new page
ds 256 - <*
; self-modifying variable aliases
_pScreen = PutChar +1
_pFormat = GetFormat +1
_iArg = NxtArgByte+1
_pArg = IncArg +1
.if ENABLE_HEX
_nHexWidth = HexWidth +1
.endif
.if ENABLE_DEC
_nDecWidth = DecWidth +1
.endif ; ENABLE_DEC
; printm( format, args, ... )
; ======================================================================
PrintM
STX _pArg+0
STY _pArg+1
STZ _iArg
NextArg
JSR NxtArgYX
STX _pFormat+0 ; lo
STY _pFormat+1 ; hi
BRA GetFormat ; always
.if ENABLE_HEX
; x Hex 2 Byte
; $ Hex 4 Byte
; ======================================================================
PrintHex4
LDA #4
BNE _PrintHex
PrintHex2
LDA #2
_PrintHex
STA _nHexWidth
JSR NxtArgYX
; Print 16-bit Y,X in hex
; Uses _nHexWidth to limit output width
PrintHexYX
STX _val+0 ; may be tempting to move this to NxtArgYX
STY _val+1 ; as XYtoVal but others call us
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
HexWidth
CPX #0 ; _nHexWidth NOTE: self-modifying!
BNE _HexDigit
; Intentional fall into reverse BCD
; On Entry: X number of chars to print in buffer _bcd
; ======================================================================
PrintReverseBCD
DEX
BMI NextFormat
LDA _bcd, X
JSR PutChar
BRA PrintReverseBCD
.if ENABLE_PTR
; @ Ptr 2 Byte
; & Ptr 4 Byte
; ======================================================================
PrintPtr4
LDA #4
BNE _PrintPtr
PrintPtr2
LDA #2
_PrintPtr
STA _nHexWidth
JSR NxtArgToTemp
; JSR NxtArgYX
; 13 bytes: zero page version
; STX _temp+0 ; zero-page for (ZP),Y
; STY _temp+1
LDY #$0
LDA (_temp),Y
TAX
INY
LDA (_temp),Y
TAY
; 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
BRA PrintHexYX ; needs XYtoVal setup
.endif ; ENABLE_PTR
.endif ; ENABLE_HEX
; ======================================================================
Print
JSR PutChar
; Adjust pointer to next char in format
NextFormat
INC _pFormat+0
BNE GetFormat
INC _pFormat+1
GetFormat
LDA $C0DE ; _pFormat NOTE: self-modifying!
BEQ _Done
BMI Print ; neg = literal
; NOTE: If all features are turned off, will get a ca65 Range Error
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 ===
.if ENABLE_DEC
; # Dec 1 Byte (max 2 digits)
; d Dec 2 Byte (max 3 digits)
; u Dec 2 Byte (max 5 digits)
; ======================================================================
PrintDec5
LDA #5
BNE _PrintDec ; always
PrintDec3
LDA #3
BNE _PrintDec ; always
PrintDec2
LDA #2 ; 2 digits
_PrintDec
STA _nDecWidth
JSR NxtArgYX
PrintDecYX
STX _val+0 ; may be tempting to move this to NxtArgYX
STY _val+1 ; as XYtoVal but others call us
STZ _bcd+0
STZ _bcd+1
STZ _bcd+2
Dec2BCD
LDX #16
SED
_Dec2BCD
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
BNE _Dec2BCD
CLD
BCD2Char
LDX #2
LDY #5
_BCD2Char
LDA _bcd,X ; __c??? _b_?XX a_YYXX
LSR
LSR
LSR
LSR
CLC
ADC #'0'+$80
STA _bcd,Y ; __c??X _b_YXX aZYYXX
DEY
LDA _bcd,X ; __c??X _b_YXX aZYYXX
AND #$F
CLC
ADC #'0'+$80
STA _bcd,Y ; __c?XX _bYYXX ZZYYXX
DEY
DEX
BPL _BCD2Char
DecWidth
LDX #0 ; _nDecDigits NOTE: self-modifying!
JMP PrintReverseBCD
.endif ; ENABLE_DEC
.if ENABLE_BIN
; % Bin 1 Byte normal one's and zeros
; ? Bin 1 Byte inverse one's, normal zeroes
; ======================================================================
PrintBinInv
LDA #$81
BNE _PrintBin
PrintBinAsc
LDA #$01
_PrintBin
STA _PrintBit+1
JSR NxtArgYX ; X = low byte
LDY #8 ; print 8 bits
_Bit2Asc
TXA
CMP #$80 ; C= A>=$80
ROL ; C<-76543210<-C
TAX
AND #$01 ; 0 -> B0
BEQ _FlipBit
_PrintBit
LDA #$81 ; 1 -> 31 NOTE: self-modifying!
_FlipBit
EOR #$B0
JSR PutChar
DEY
BNE _Bit2Asc
.endif ; ENABLE_BIN
_JumpNextFormat
; BRA NextFormat ; always
JMP NextFormat ; JMP :-(
; b Print a signed byte in decimal
; ======================================================================
.if ENABLE_DEC
.if ENABLE_BYTE
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
JMP PrintDecYX ; needs XYtoVal setup
.endif ; ENABLE_BYTE
.endif ; ENABLE_DEC
.if ENABLE_STR
; 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
LDX #1
ORA #$80
BRA _PrintCharA
; 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)
; ======================================================================
PrintStrP
JSR NxtArgToTemp
LDY #$0
LDA (_temp),Y
BEQ _JumpNextFormat
TAX
_PrintStrP
INY
LDA (_temp),Y
_PrintCharA
JSR PutChar
DEX
BNE _PrintStrP
BEQ _JumpNextFormat ; always
.endif ; ENABLE_STR
; __________ Utility __________
; ======================================================================
PutChar
STA $C0DE ; _pScreen NOTE: self-modifying!
INC PutChar+1 ; inc lo
RTS
; ======================================================================
; @return next arg as 16-bit arg value in Y,X
NxtArgToTemp
NxtArgYX
JSR NxtArgByte
TAX
; @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
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 ;
RTS
;
; ======================================================================
_bcd ds 6 ; 6 chars for printing dec
_val dw 0 ; PrintHex2 PrintHex4 temp
MetaChar
.if ENABLE_BIN
db '?' ; PrintBinInv NOTE: 1's printed in inverse
db '%' ; PrintBinAsc
.endif
.if ENABLE_DEC
.if ENABLE_BYTE
db 'b' ; PrintByte NOTE: Signed -128 .. +127
.endif
db 'u' ; PrintDec5
db 'd' ; PrintDec3
db '#' ; PrintDec2
.endif
.if ENABLE_HEX
db 'x' ; PrintHex4
db '$' ; PrintHex2
.if ENABLE_PTR
db '&' ; PrintPtr4
db '@' ; PrintPtr2
.endif
.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
_MetaCharEnd
NumMeta = _MetaCharEnd - MetaChar
MetaFunc
.if ENABLE_BIN
dw PrintBinInv
dw PrintBinAsc
.endif
.if ENABLE_DEC
.if ENABLE_BYTE
dw PrintByte
.endif
dw PrintDec5
dw PrintDec3
dw PrintDec2
.endif
.if ENABLE_HEX
dw PrintHex4
dw PrintHex2
.if ENABLE_PTR
dw PrintPtr4
dw PrintPtr2
.endif
.endif
.if ENABLE_STR
dw PrintStrP
dw PrintStrC
dw PrintStrA
.endif
__END
And if you want to try it out:
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
4068:76 40 8D 8D 43 B9 8E 40
4070:09 04 8D 8E 43 60 00 80
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
4200:8E 9A 43 8C 9B 43 9C 98
4208:43 20 93 43 8E 83 42 8C
4210:84 42 80 6E A9 04 D0 02
4218:A9 02 8D 52 42 20 93 43
4220:8E B0 43 8C B1 43 A2 00
4228:AD B0 43 29 0F C9 0A 90
4230:02 69 06 69 B0 9D AA 43
4238:4E B1 43 6E B0 43 4E B1
4240:43 6E B0 43 4E B1 43 6E
4248:B0 43 4E B1 43 6E B0 43
4250:E8 E0 00 D0 D3 CA 30 22
4258:BD AA 43 20 8C 43 80 F5
4260:A9 04 D0 02 A9 02 8D 52
4268:42 20 93 43 A0 00 B1 FE
4270:AA C8 B1 FE A8 80 A9 20
4278:8C 43 EE 83 42 D0 03 EE
4280:84 42 AD DE C0 F0 14 30
4288:EE A2 0C DD B2 43 F0 05
4290:CA 10 F8 30 E5 8A 0A AA
4298:7C BF 43 60 A9 05 D0 06
42A0:A9 03 D0 02 A9 02 8D 05
42A8:43 20 93 43 8E B0 43 8C
42B0:B1 43 9C AA 43 9C AB 43
42B8:9C AC 43 A2 10 F8 0E B0
42C0:43 2E B1 43 AD AA 43 6D
42C8:AA 43 8D AA 43 AD AB 43
42D0:6D AB 43 8D AB 43 AD AC
42D8:43 6D AC 43 8D AC 43 CA
42E0:D0 DC D8 A2 02 A0 05 BD
42E8:AA 43 4A 4A 4A 4A 18 69
42F0:B0 99 AA 43 88 BD AA 43
42F8:29 0F 18 69 B0 99 AA 43
4300:88 CA 10 E3 A2 00 4C 55
4308:42 A9 81 D0 02 A9 01 8D
4310:21 43 20 93 43 A0 08 8A
4318:C9 80 2A AA 29 01 F0 02
4320:A9 81 49 B0 20 8C 43 88
4328:D0 ED 4C 7A 42 20 93 43
4330:8A 10 0D A9 AD 20 8C 43
4338:8A 49 FF 29 7F 18 69 01
4340:AA A0 00 A9 03 8D 05 43
4348:4C AC 42 20 93 43 A0 00
4350:B1 FE 10 0A 20 8C 43 C8
4358:D0 F6 E6 FF 80 F2 A2 01
4360:09 80 80 20 20 93 43 A0
4368:00 B1 FE F0 BD 20 8C 43
4370:C8 D0 F6 E6 FF 80 F2 20
4378:93 43 A0 00 B1 FE F0 AA
4380:AA C8 B1 FE 20 8C 43 CA
4388:D0 F7 F0 9E 8D DE C0 EE
4390:8D 43 60 20 97 43 AA A0
4398:00 B9 DE C0 EE 98 43 D0
43A0:03 EE 9B 43 A8 86 FE 84
43A8:FF 60 00 00 00 00 00 00
43B0:00 00 3F 25 62 75 64 23
43B8:78 24 26 40 70 73 61 09
43C0:43 0D 43 2D 43 9C 42 A0
43C8:42 A4 42 14 42 18 42 60
43D0:42 64 42 77 43 64 43 4B
43D8:43
[toc] | [prev] | [next] | [standalone]
| From | Michael Pohoreski <michael.pohoreski@gmail.com> |
|---|---|
| Date | 2016-02-18 13:27 -0800 |
| Message-ID | <516443d6-2b52-40ab-9b51-370b7167c025@googlegroups.com> |
| In reply to | #2266 |
On Thursday, February 18, 2016 at 1:14:15 PM UTC-8, Michael Pohoreski wrote: > Also, you can turn features on/off (at compile time) to reduce the memory footprint since with everything turned on its a little big at 728 bytes. Whoops, that should be 0x1D9 = 473 bytes! I didn't realize the demo spilled over another page. (I didn't think it was THAT BIG) > it uses only a spopw routine to pop a word off of the arg stack into X/Y. > This assembles to 282 bytes. /sarcasm "That's cheating" :-) Seriously, a complete demo so we can get a "actual final" byte usage would be, ahem, nice. :-)
[toc] | [prev] | [next] | [standalone]
| From | Michael Pohoreski <michael.pohoreski@gmail.com> |
|---|---|
| Date | 2016-02-18 15:09 -0800 |
| Message-ID | <a0383c9f-78a6-4755-b8bd-8fa1a1b23e6f@googlegroups.com> |
| In reply to | #2269 |
I've cleanup that hideous requirement of interleaving ASCII + APPLE text using a much cleaner
PRINTM macro now.
; ca65
.feature c_comments
/* Version 15
printm - a printf replacement for 65C02
Michael Pohoreski
Problem:
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 ...
.byte "X=## Y=### $=####:@@ %%%%%%%%~????????"
... 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!
PRINTM "X=%# Y=%d $=%x:%@ %%~%?"
Thisis why printf() on the 6502 sucks:
- 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
The printm with everything enabled takes up 472 bytes
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
4068:76 40 8D 8C 43 B9 8E 40
4070:09 04 8D 8D 43 60 00 80
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
4200:8E 99 43 8C 9A 43 9C 97
4208:43 20 92 43 8E 83 42 8C
4210:84 42 80 6E A9 04 D0 02
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
4250:E8 E0 00 D0 D3 CA 30 22
4258:BD A9 43 20 8B 43 80 F5
4260:A9 04 D0 02 A9 02 8D 52
4268:42 20 92 43 A0 00 B1 FE
4270:AA C8 B1 FE A8 80 A9 20
4278:8B 43 EE 83 42 D0 03 EE
4280:84 42 AD DE C0 F0 14 30
4288:EE A2 0C DD B1 43 F0 05
4290:CA 10 F8 30 E5 8A 0A AA
4298:7C BE 43 60 A9 05 D0 06
42A0:A9 03 D0 02 A9 02 8D 05
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
42E0:D0 DC D8 A2 02 A0 05 BD
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
4300:88 CA 10 E3 A2 00 4C 55
4308:42 A9 81 D0 02 A9 01 8D
4310:21 43 20 92 43 A0 08 8A
4318:C9 80 2A AA 29 01 F0 02
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
4338:8A 49 FF 29 7F 18 69 01
4340:AA A0 00 A9 03 8D 05 43
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
To toggle features on / off:
*/
ENABLE_BIN = 1
ENABLE_DEC = 1
ENABLE_BYTE = 1 ; requires ENABLE_DEC
ENABLE_HEX = 1
ENABLE_PTR = 1 ; requires ENABLE_HEX
ENABLE_STR = 1
; more ca65
.feature labels_without_colons
.feature leading_dot_in_identifiers
; 65C02
.PC02
; 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
; 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 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
; 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 PASCAL text
.byte .strlen(text)
APPLE text
.endmacro
.macro db val
.byte val
.endmacro
.macro dw val
.word val
.endmacro
.macro ds bytes
.res bytes
.endmacro
HOME = $FC58
TABV = $FB5B
; printm pointer for PrintPtr2, PrintPtr4, PrintStrA, PrintStrC, PrintStrP
_temp = $FE
__MAIN = $4000
; DOS3.3 meta -- remove these 2 if running under ProDOS
.word __MAIN ; 2 byte BLOAD address
.word __END - __MAIN ; 2 byte BLOAD size
/*
Output:
X=39 Y=191 $=2345:D5 11010101~10101011
Byte=-128 -001 000 001 127
Strings: 'HELLO','WORLD'
Apple: 'HOME' Pascal: 'String Len 13'
*/
.org __MAIN ; .org must come after header else offsets are wrong
; Demo printm
JSR HOME
LDA #$D5
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
JSR ReverseByte
STA DATA+12
.if ENABLE_BIN || ENABLE_DEC || ENABLE_HEX
LDY #0
JSR VTABY
LDX #<DATA ; Low Byte of Address
LDY #>DATA ; High Byte of Address
JSR PrintM
.endif
.if ENABLE_BYTE
LDY #2
JSR VTABY
LDX #<DATA2
LDY #>DATA2
JSR PrintM
.endif ; ENABLE_BYTE
.if ENABLE_STR
LDY #4
JSR VTABY
LDX #<DATA3
LDY #>DATA3
JSR PrintM
LDY #6
JSR VTABY
LDX #<DATA4
LDY #>DATA4
JSR PrintM
.endif ; ENABLE_STR
LDA #8
JMP TABV
ReverseByte
LDX #8
STA $FF ; temp working byte
ReverseBit
ASL $FF ; temp working byte
ROR
DEX
BNE ReverseBit
RTS
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
TEXT
;byte "X=## Y=ddd $=xxxx:@@ %%%%%%%%~????????"
PRINTM "X=%# Y=%d $=%x:%@ %%~%?"
DATA
dw TEXT ; aArg[ 0] text
dw 39 ; aArg[ 1] x
dw 191 ; aArg[ 2] y
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
TEXT2
PRINTM "Byte=%b %b %b %b %b"
TEXT_HELLO
APPLE "HELLO"
db 0
TEXT_WORLD
APPLE "WORLD"
db 0
DATA2
dw TEXT2
dw $80 ; -128
dw $FF ; -1
dw $00 ; 0
dw $01 ; +1
dw $7F ; +127
TEXT3
PRINTM "Strings: '%s','%s'"
DATA3
dw TEXT3
dw TEXT_HELLO
dw TEXT_WORLD
TEXT_DCI
DCI "HOME"
TEXT_PASCAL
PASCAL "String Len 13"
TEXT4
PRINTM "Apple: '%a' Pascal: '%p'"
DATA4
dw TEXT4
dw TEXT_DCI
dw TEXT_PASCAL
; Pad until end of page so PrintM starts on new page
ds 256 - <*
; self-modifying variable aliases
_pScreen = PutChar +1
_pFormat = GetFormat +1
_iArg = NxtArgByte+1
_pArg = IncArg +1
.if ENABLE_HEX
_nHexWidth = HexWidth +1
.endif
.if ENABLE_DEC
_nDecWidth = DecWidth +1
.endif ; ENABLE_DEC
; ======================================================================
; printm( format, args, ... )
; ======================================================================
PrintM
STX _pArg+0
STY _pArg+1
STZ _iArg
NextArg
JSR NxtArgYX
STX _pFormat+0 ; lo
STY _pFormat+1 ; hi
BRA GetFormat ; always
.if ENABLE_HEX
; x Hex 2 Byte
; $ Hex 4 Byte
; ======================================================================
PrintHex4
LDA #4
BNE _PrintHex
PrintHex2
LDA #2
_PrintHex
STA _nHexWidth
JSR NxtArgYX
; Print 16-bit Y,X in hex
; Uses _nHexWidth to limit output width
PrintHexYX
STX _val+0 ; may be tempting to move this to NxtArgYX
STY _val+1 ; as XYtoVal but others call us
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
HexWidth
CPX #0 ; _nHexWidth NOTE: self-modifying!
BNE _HexDigit
; Intentional fall into reverse BCD
; On Entry: X number of chars to print in buffer _bcd
; ======================================================================
PrintReverseBCD
DEX
BMI NextFormat
LDA _bcd, X
JSR PutChar
BRA PrintReverseBCD
.if ENABLE_PTR
; @ Ptr 2 Byte
; & Ptr 4 Byte
; ======================================================================
PrintPtr4
LDA #4
BNE _PrintPtr
PrintPtr2
LDA #2
_PrintPtr
STA _nHexWidth
JSR NxtArgToTemp
; JSR NxtArgYX
; 13 bytes: zero page version
; STX _temp+0 ; zero-page for (ZP),Y
; STY _temp+1
LDY #$0
LDA (_temp),Y
TAX
INY
LDA (_temp),Y
TAY
; 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
BRA PrintHexYX ; needs XYtoVal setup
.endif ; ENABLE_PTR
.endif ; ENABLE_HEX
; ======================================================================
Print
JSR PutChar
NextFormat ; Adjust pointer to next char in format
INC _pFormat+0
BNE GetFormat
INC _pFormat+1
GetFormat
LDA $C0DE ; _pFormat NOTE: self-modifying!
BEQ _Done ; zero-terminated
BMI Print ; neg = literal
; NOTE: If all features are turned off, will get a ca65 Range Error
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 ===
.if ENABLE_DEC
; # Dec 1 Byte (max 2 digits)
; d Dec 2 Byte (max 3 digits)
; u Dec 2 Byte (max 5 digits)
; ======================================================================
PrintDec5
LDA #5
BNE _PrintDec ; always
PrintDec3
LDA #3
BNE _PrintDec ; always
PrintDec2
LDA #2 ; 2 digits
_PrintDec
STA _nDecWidth
JSR NxtArgYX
PrintDecYX
STX _val+0 ; may be tempting to move this to NxtArgYX
STY _val+1 ; as XYtoVal but others call us
STZ _bcd+0
STZ _bcd+1
STZ _bcd+2
Dec2BCD
LDX #16
SED
_Dec2BCD
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
BNE _Dec2BCD
CLD
BCD2Char
LDX #2
LDY #5
_BCD2Char
LDA _bcd,X ; __c??? _b_?XX a_YYXX
LSR
LSR
LSR
LSR
CLC
ADC #'0'+$80
STA _bcd,Y ; __c??X _b_YXX aZYYXX
DEY
LDA _bcd,X ; __c??X _b_YXX aZYYXX
AND #$F
CLC
ADC #'0'+$80
STA _bcd,Y ; __c?XX _bYYXX ZZYYXX
DEY
DEX
BPL _BCD2Char
DecWidth
LDX #0 ; _nDecDigits NOTE: self-modifying!
JMP PrintReverseBCD
.endif ; ENABLE_DEC
.if ENABLE_BIN
; % Bin 1 Byte normal one's and zeros
; ? Bin 1 Byte inverse one's, normal zeroes
; ======================================================================
PrintBinInv
LDA #$81
BNE _PrintBin
PrintBinAsc
LDA #$01
_PrintBin
STA _PrintBit+1
JSR NxtArgYX ; X = low byte
LDY #8 ; print 8 bits
_Bit2Asc
TXA
CMP #$80 ; C= A>=$80
ROL ; C<-76543210<-C
TAX
AND #$01 ; 0 -> B0
BEQ _FlipBit
_PrintBit
LDA #$81 ; 1 -> 31 NOTE: self-modifying!
_FlipBit
EOR #$B0
JSR PutChar
DEY
BNE _Bit2Asc
.endif ; ENABLE_BIN
_JumpNextFormat
; BRA NextFormat ; always
JMP NextFormat ; JMP :-(
; b Print a signed byte in decimal
; ======================================================================
.if ENABLE_DEC
.if ENABLE_BYTE
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
JMP PrintDecYX ; needs XYtoVal setup
.endif ; ENABLE_BYTE
.endif ; ENABLE_DEC
.if ENABLE_STR
; 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
; 6 byte:
; LDX #1
; ORA #$80
; BRA _PrintCharA
; 5 byte:
ORA #$80
JMP Print
; 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)
; ======================================================================
PrintStrP
JSR NxtArgToTemp
LDY #$0
LDA (_temp),Y
BEQ _JumpNextFormat
TAX
_PrintStrP
INY
LDA (_temp),Y
_PrintCharA
JSR PutChar
DEX
BNE _PrintStrP
BEQ _JumpNextFormat ; always
.endif ; ENABLE_STR
; __________ Utility __________
; ======================================================================
PutChar
STA $C0DE ; _pScreen NOTE: self-modifying!
INC PutChar+1 ; inc lo
RTS
; ======================================================================
; @return next arg as 16-bit arg value in Y,X
NxtArgToTemp
NxtArgYX
JSR NxtArgByte
TAX
; @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
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 ;
RTS
;
; ======================================================================
_bcd ds 6 ; 6 chars for printing dec
_val dw 0 ; PrintHex2 PrintHex4 temp
MetaChar
.if ENABLE_BIN
db '?' ; PrintBinInv NOTE: 1's printed in inverse
db '%' ; PrintBinAsc
.endif
.if ENABLE_DEC
.if ENABLE_BYTE
db 'b' ; PrintByte NOTE: Signed -128 .. +127
.endif
db 'u' ; PrintDec5
db 'd' ; PrintDec3
db '#' ; PrintDec2
.endif
.if ENABLE_HEX
db 'x' ; PrintHex4
db '$' ; PrintHex2
.if ENABLE_PTR
db '&' ; PrintPtr4
db '@' ; PrintPtr2
.endif
.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
_MetaCharEnd
NumMeta = _MetaCharEnd - MetaChar
MetaFunc
.if ENABLE_BIN
dw PrintBinInv
dw PrintBinAsc
.endif
.if ENABLE_DEC
.if ENABLE_BYTE
dw PrintByte
.endif
dw PrintDec5
dw PrintDec3
dw PrintDec2
.endif
.if ENABLE_HEX
dw PrintHex4
dw PrintHex2
.if ENABLE_PTR
dw PrintPtr4
dw PrintPtr2
.endif
.endif
.if ENABLE_STR
dw PrintStrP
dw PrintStrC
dw PrintStrA
.endif
__END
[toc] | [prev] | [next] | [standalone]
| From | wssimms@gmail.com |
|---|---|
| Date | 2016-02-18 17:58 -0800 |
| Message-ID | <b56a3f9a-d08b-43e2-b543-816572c69a85@googlegroups.com> |
| In reply to | #2273 |
Am Freitag, 19. Februar 2016 08:09:39 UTC+9 schrieb Michael Pohoreski: > I've cleanup that hideous requirement of interleaving ASCII + APPLE text using a much cleaner > PRINTM macro now. > > PRINTM "X=%# Y=%d $=%x:%@ %%~%?" I like this version much better. This makes it much easier to use. Also I agree with you on the octal. It's mystifying to me how those guys (like Ken Thompson, Dennis Ritchie, etc.) put up with using octal for everything on a 16-bit computer in the 60s and 70s. Of course I can always justify it by telling myself that they are/were way smarter than I am.
[toc] | [prev] | [next] | [standalone]
| From | Michael Barry <barrym95838@yahoo.com> |
|---|---|
| Date | 2016-02-19 17:52 -0800 |
| Message-ID | <ac829b2c-6460-4ddb-b09d-c610774130b3@googlegroups.com> |
| In reply to | #2285 |
On Thursday, February 18, 2016 at 5:58:02 PM UTC-8, wss...@gmail.com wrote: > ... > Also I agree with you on the octal. It's mystifying to me how those > guys (like Ken Thompson, Dennis Ritchie, etc.) put up with using octal > for everything on a 16-bit computer in the 60s and 70s. Of course I > can always justify it by telling myself that they are/were way smarter > than I am. Octal was a natural fit for all of the 12-bit and 18-bit word machines DEC cranked out in the 60s, but it takes an examination of the pdp-11 instruction field format to understand why octal was also "natural" for that 16-bit word machine. Mike B.
[toc] | [prev] | [next] | [standalone]
| From | wssimms@gmail.com |
|---|---|
| Date | 2016-02-19 18:09 -0800 |
| Message-ID | <d221c69a-fb99-4ac8-9946-e308758269ed@googlegroups.com> |
| In reply to | #2300 |
Am Samstag, 20. Februar 2016 10:52:06 UTC+9 schrieb Michael Barry: > On Thursday, February 18, 2016 at 5:58:02 PM UTC-8, wss...@gmail.com wrote: > > ... > > Also I agree with you on the octal. It's mystifying to me how those > > guys (like Ken Thompson, Dennis Ritchie, etc.) put up with using octal > > for everything on a 16-bit computer in the 60s and 70s. Of course I > > can always justify it by telling myself that they are/were way smarter > > than I am. > > Octal was a natural fit for all of the 12-bit and 18-bit word machines > DEC cranked out in the 60s, but it takes an examination of the pdp-11 > instruction field format to understand why octal was also "natural" for > that 16-bit word machine. > > Mike B. Granted, it was marginally useful for dealing with three bit fields in the instruction word. But in practice that was done approximately never. The assembler took care of that nonsense. Really, it was mainly familiarity. Once you're comfortable with octal, there's no problem, and no obvious need to use anything else.
[toc] | [prev] | [next] | [standalone]
| From | Michael J. Mahon <mjmahon@aol.com> |
|---|---|
| Date | 2016-02-20 00:27 -0600 |
| Message-ID | <JYCdnRZWUq36mlXLnZ2dnUU7-RmdnZ2d@giganews.com> |
| In reply to | #2301 |
<wssimms@gmail.com> wrote: > Am Samstag, 20. Februar 2016 10:52:06 UTC+9 schrieb Michael Barry: >> On Thursday, February 18, 2016 at 5:58:02 PM UTC-8, wss...@gmail.com wrote: >>> ... >>> Also I agree with you on the octal. It's mystifying to me how those >>> guys (like Ken Thompson, Dennis Ritchie, etc.) put up with using octal >>> for everything on a 16-bit computer in the 60s and 70s. Of course I >>> can always justify it by telling myself that they are/were way smarter >>> than I am. >> >> Octal was a natural fit for all of the 12-bit and 18-bit word machines >> DEC cranked out in the 60s, but it takes an examination of the pdp-11 >> instruction field format to understand why octal was also "natural" for >> that 16-bit word machine. >> >> Mike B. > > Granted, it was marginally useful for dealing with three bit fields in > the instruction word. But in practice that was done approximately > never. The assembler took care of that nonsense. > > Really, it was mainly familiarity. Once you're comfortable with octal, > there's no problem, and no obvious need to use anything else. > Exactly. The pre-360 IBM binary machines had 36-bit words and two 3-bit instruction fields, and octal seemed natural for those machines. Also, there was no standard for hex digits greater than 9 at first, and non-numeric digits seemed strange--until they became commonplace. In the US, that happened with the 32-bit 360 series. After you've become familiar with hex, it seems quite natural--just like your favorite text editor. ;-) -- -michael - NadaNet 3.1 and AppleCrate II: http://michaeljmahon.com
[toc] | [prev] | [next] | [standalone]
| From | Michael Pohoreski <michael.pohoreski@gmail.com> |
|---|---|
| Date | 2016-02-18 13:37 -0800 |
| Message-ID | <3605e58c-b6ff-4f72-9e73-5592afe66d8e@googlegroups.com> |
| In reply to | #2219 |
Just wanted to send a public shoutout "Thanks!" to * Sheldon, * Antoine, * anyone else who posts assembly for sharing all their 6502 (assembly) code & write-ups. Just when one thinks one understand 6502 assembly you guys come along and teach an old dog new tricks. ;-) Thanks for keeping this (ancient) hobby exciting! I've finally "relented" and started using 65C02 instructions. Hey, better late, then never, right. :-) If only we had a CAX (compare A with X), and CAY (compare A with Y) instructions ... Sheldon, I like your self-modifying code tricks. :-)
[toc] | [prev] | [standalone]
Page 2 of 2 — ← Prev page 1 [2]
Back to top | Article view | comp.sys.apple2.programmer
csiph-web