6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Thu May 16, 2024 1:03 am

All times are UTC




Post new topic Reply to topic  [ 6 posts ] 
Author Message
PostPosted: Mon Jan 30, 2023 3:10 pm 
Offline

Joined: Fri Mar 18, 2022 6:33 pm
Posts: 443
So I have this little routine:

Code:
_LCD_strout:
    ldy    #0
LCD_strout_nextchar:
    lda    (R0),y
    beq     LCD_strout_return
    jsr     _LCD_chrout     ; sends the character in .A to the LCD
    iny
    jmp     LCD_strout_nextchar
LCD_strout_return:
    rts


"R0" is a 16bit pseudo-register in ZP. Somewhere in ROM there's an asciiz message constant.

Code:
R0      = $80
R0L     = $80
R0H     = $81

.org    $8000

message:    .asciiz     "Hello, world"


I call the routine like this:

Code:
    lda     #<message
    sta     R0L
    lda    #>message
    sta     R0H
    jsr     _LCD_strout


This is works perfectly well. However, for unrelated reasons, my firmware code is starting to get unwieldy, and I thought now would be a good time to implement a ZP data stack like Garth describes and rewrite some of my routines. The ones like _LCD_chrout that just take a byte in .A I will leave alone. But _LCD_strout seemed like a good candidate for reworking, since it takes an address, and is called randomly from all over the place (in addition to using it for output, I also stick it in various places for debugging) which means nothing else can ever use R0, in case a string output call steps on it.

So I'd like to do something like this:

Code:
STACK      = $0
STACKL     = $0
STACKH     = $1
reset:
    ldx     #$FF
    txs             ; Hardware stack -> $01FF
    dex             ; Data stack -> $00FE

; (later on)

    lda     #<message
    sta     STACKL,x
    lda     #>message
    sta     STACKH,x
    dex
    dex
    jsr     _LCD_strout


My question is, is there some way to leave the address on the stack while indexing into the string? It seems like I need the equivalent of (STACK,x),y in order to index into the string, and it is not obvious to me how to express that. If I have to pull the address off the stack and into a scratchpad variable it seems like I might as well just keep on using the "pseudo register."

Code:
_LCD_strout:    ; Stack version
    ldy    #0
    inx
    inx
LCD_strout_nextchar:
    lda    (STACK,x),y      ; what really goes here?
    beq     LCD_strout_return
    jsr     _LCD_chrout     ; sends the character in .A to the LCD
    iny
    jmp     LCD_strout_nextchar
LCD_strout_return:
    rts


(I have read Garth's page about the magic of inlining parameters, but I'd like to do it this way first, if there is a way.)

_________________
"The key is not to let the hardware sense any fear." - Radical Brad


Top
 Profile  
Reply with quote  
PostPosted: Mon Jan 30, 2023 6:41 pm 
Offline

Joined: Wed Jan 08, 2014 3:31 pm
Posts: 575
An "LDA (STACK,x),y" would be an awesome instruction for just the reason you site. When I am using a page zero data stack I tackle this in one of two ways:

I have a page zero location called TMPPTR and pop TOS into it, and then use "LDA (TMPPTR),y" but as you point out, you could just use a known page zero location to pass the argument. But using a data stack avoids slamming that address accidentally elsewhere. This avoids a reentrancy issue which can make for hard to find bugs.

Since string I/O isn't time critical, incrementing the pointer directly on the stack avoids needing to use the Y register or another page zero location. I increment the pointer on the stack directly using a macro called inctos which looks like this:

; increments the TOS value
.macro incTos
inc TOS_LSB,x
bne _over
inc TOS_MSB,x
_over:
.macend

Performance wise this isn't great because indirect Y addressing is much faster, but in some cases I don't think it is a problem.


Top
 Profile  
Reply with quote  
PostPosted: Mon Jan 30, 2023 7:12 pm 
Offline

Joined: Fri Mar 18, 2022 6:33 pm
Posts: 443
Martin_H wrote:
Since string I/O isn't time critical, incrementing the pointer directly on the stack avoids needing to use the Y register or another page zero location.


AH! I'm equally split between "of course, why didn't I think of that, what a dope" and "that's super clever, you are a genius!" :D

I think that will be fine; this just needs to print out short strings on the LCD, which is already super slow. The added overhead of incrementing a 16-bit pointer will probably be unnoticeable. Thanks!

_________________
"The key is not to let the hardware sense any fear." - Radical Brad


Top
 Profile  
Reply with quote  
PostPosted: Mon Jan 30, 2023 8:31 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8435
Location: Southern California
You can have both.  On the page you referenced, about 90% of the way to the bottom, see the paragraph starting with "I should mention here that some routines will make so many accesses", about "N" as a ZP scratchpad space for this kind of thing and is not to be used to pass parameters between routines.

You might find an efficient self-modifying-code (SMC) solution also, if the code doesn't have to be in ROM.  See the article at http://wilsonminesco.com/SelfModCode/ .

_________________
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?


Top
 Profile  
Reply with quote  
PostPosted: Mon Jan 30, 2023 9:30 pm 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8186
Location: Midwestern USA
Martin_H wrote:
An "LDA (STACK,x),y" would be an awesome instruction...

Yep! You can do that with the 65C816, as in LDA (<offset>,S),Y, where <offset> is relative to the current value in the (16-bit) stack pointer (SP). You don't even have to know what’s in SP. :D

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
PostPosted: Thu Feb 02, 2023 9:59 pm 
Offline
User avatar

Joined: Mon Apr 23, 2012 12:28 am
Posts: 760
Location: Huntsville, AL
Second BDD’s response. Although my enhanced soft-core is not in a working state at the moment, I too included a full set of these type of stack-relative instructions in its instruction set. I also included a base-pointer relative mode, where I use X loaded with the value of S at the start of the subroutine, and use sign extension of the 8-bit offset to access local variables (negative offsets from the base pointer) and subroutine parameters (positive offsets from base pointer). Works well with the Pascal compiler that I ported to work with my extended 65C02 processor.

These accesses can be synthesized with the 6502 instruction set, but the stack-pointer relative addressing mode makes complex equation evaluations much easier. My base pointer relative addressing mode also can be synthesized, but it really make passing and using parameters in the stack much easier. Dereferencing pointers and data on the stack is so much faster with these addressing modes that including them in my processor model was well worth the additional hw complexity.

_________________
Michael A.


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 6 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 13 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: