Log inRegister an accountBrowse CSDbHelp & documentationFacts & StatisticsThe forumsAvailable RSS-feeds on CSDbSupport CSDb Commodore 64 Scene Database
You are not logged in 
CSDb User Forums


Forums > C64 Coding > safe way to call something in ROM
2020-05-01 13:30
oziphantom

Registered: Oct 2014
Posts: 410
safe way to call something in ROM

So given a 128, and an internal function rom ( or external )
A say way to call a routine and pass params to it.

I though about using BRK to trigger a call, where you
lda
ldx
ldy
brk XX to call function XX

however one can not accurately detect a brk on a 128. because the stack is not guaranteed.

I also though about using the Processor flags to hold a value temporarily, however the PHP returns bits 5 and 4 as 1 so you can't hold an 8 bit value in it.

I'm fine with also having a GEO/NEO RAM installed which gives ram at DFXX but that also means you need IO visible.

Storing "function + vars" at say $100- mostly safe but again can't guarantee that $100 is actually $100..

doing params stored as bytes after the function is probably mostly fine, only if the code is under the ROM then it needs a trampoline somewhere, or if there is GEO/NEO RAM then if it is under IO it needs a trampoline..

anybody got any ideas? maybe an obscure trick I've not thought of, some other device I can add in VICE/real life that gets me out of the problem?
 
... 2 posts hidden. Click here to view all posts....
 
2020-05-01 14:28
Oswald

Registered: Apr 2002
Posts: 4627
use pla / pha to get the params, and push back the return address. then stack might be anywhere.
2020-05-01 14:28
TWW

Registered: Jul 2009
Posts: 480
You can use a stack param. handler. Just pull the return address from the stack, add it to a indirect parameter pointer and fetch your parameters. Add Y to rts return address and puh it back to the stack. This way you don't need to care where the stack is, only where the jsr i executed.

Here is the one I currently use:


    //-------------------------------------------------------------------------
    // StackEntry & StackExit
    // ==========   =========
    //
    // Entry fetches .PC to byte after last jsr call and places it into ZP_Reg1
    // Parameters are then passed to the routine via indirect fetches (ZP_Reg1)
    // StackFix is called to push exit address after the parameters (by Y-Reg)
    // Exit adjust the ZP_Reg1 vector to return the .PC to last parameter
    //
    // The idea is to not spend a lot of memory passing parameters to subr.
    // but instead by using some overhead code to save bytes by calling
    // Subroutines throughout a code project.
    //
    // By using registers or ZP the preparation code for each call would grow
    // in each call. A MemSet routine needs two 16 bit values and a fillbyte
    // set up for each call to the Subroutine wich will quickly add up.
    //
    //
    // Example:
    //
    //     jsr Subroutine
    //         .byte Parameter1, Parameter2
    //     rts
    //
    // Subroutine:
    //     jsr StackEntry    // Arrange ZP_Reg1 to point to parameters
    //     // Fetch parameters
    //     ldy #$01
    //     lda (ZP_Reg1),y
    //     sta Parameter1
    //     iny
    //     lda (ZP_Reg1),y
    //     sta Parameter2
    //     jsr StackFix      // Adds Y-Reg to ZP_Reg1 to set return address
    //
    //     // Subroutine Code
    //     lda Parameter1
    //     clc
    //     adc Parameter2
    //     sta result
    //
    //     // Handle Subroutine Exit
    //     jsr Stackexit     // Push ZP_Reg1 back to the Stack
    //     rts
    //
    //  40 bytes added by the stack routines and 9 bytes in sub.
    //  Overhead in sub is situation dependent. Few bytes at worst.
    //  These routines are universal and can be used by all subroutines.
    //  The routine also handles variable parameters (like textstrings).
    //-------------------------------------------------------------------------

    #importonce


StackFix:
    tya
    clc
    adc ZP_Reg1Lo
    bcc !+
        inc ZP_Reg1Hi
!:  sta ZP_Reg1Lo
    rts

StackExit:
    clc
    .byte $24      // BIT OP Code (skips the sec after StackEntry)

StackEntry:
    sec

    // Store Return Address
    pla
    tax
    pla
    tay

    pla                      // pla is used by Entry and Exit routine (common)
    bcc !+

        // Entry Code
        sta ZP_Reg1Lo
        pla
        sta ZP_Reg1Hi        // Write pointer to first parameter to ZP_Reg1
        bcs !Done+

    // Exit Code
!:  pla                      // ignore old return address caller (before parameters)
    lda ZP_Reg1Hi
!Done:
    pha
    lda ZP_Reg1Lo
    pha                      // Restore return address of caller (last parameter byte)

    // Restore return address
    tya
    pha
    txa
    pha
    rts

2020-05-01 14:44
oziphantom

Registered: Oct 2014
Posts: 410
Quoting Oswald
use pla / pha to get the params, and push back the return address. then stack might be anywhere.


I guess with the NeoRam I can stash the return + the trampoline return + memory config into its RAM, then restore them for the return.
2020-05-01 14:46
oziphantom

Registered: Oct 2014
Posts: 410
Quoting TWW
You can use a stack param. handler. Just pull the return address from the stack, add it to a indirect parameter pointer and fetch your parameters. Add Y to rts return address and puh it back to the stack. This way you don't need to care where the stack is, only where the jsr i executed.


the JSR is a lot bigger problem than where the Stack is :D say the initial jsr ( to the trampoline to call functions ) is under the ROM, or under IO or in another bank, under ROM...
2020-05-01 14:50
Oswald

Registered: Apr 2002
Posts: 4627
tww, why not just pass in x/y ?
2020-05-01 15:32
TWW

Registered: Jul 2009
Posts: 480
@Ozi: Could you not store the return-info at a fixed bank/RAM-address instead of NeoRam?


@Oswald: If you f.ex. need to pass more than 2-3 bytes to the subroutine. Like this mem-copy routine (which could be called quite often in a project):

MemCpy:
    jsr StackEntry
    ldy #$01
!:  lda (ZP_Reg1),y            // Address From Lo
    sta ZP_Reg2Lo-1,y
    iny
    cpy #$05                   // The consessive parameters will automatically be put into ZP_Reg2Hi, ZP_Reg3Lo & ZP_RegHi
    bne !-
    lda (ZP_Reg1),y            // Size Lo
    sta ZP_Temp                // Hold # of bytes less than 256 to copy
    iny
    jsr StackFix               // Add Y to ZP_Reg1
    ldy #$00
    lda (ZP_Reg1),y            // Size Hi
    beq !LessThan256+
    tax
!:  lda (ZP_Reg2),y
    sta (ZP_Reg3),y
    iny
    bne !-
    inc ZP_Reg2Hi
    inc ZP_Reg3Hi
    dex
    bne !-
!LessThan256:
    lda ZP_Temp
    cmp #$00
    beq !End+
!:  lda (ZP_Reg2),y
    sta (ZP_Reg3),y
    iny
    cpy ZP_Temp
    bne !-
!End:
    jsr StackExit
    rts


So instead of setting up all ZP vectors and parameters each time you call the routine, you do:

    jsr MemCpy
        .word from, to, length
or:

    :MemCPY($0400,1000,$01)

    .macro MemCpy(AddressFrom, AddressTo, Quantity) {
        jsr MemCpy
        .word AddressFrom, AddressTo, Quantity
    }


Each call cost you 9 bytes vs 39 bytes if you lda #$nn sta $ZP x 6 byte + jsr. Then imagine calling it several times. It can then also be used by any subroutine in the same way to pass parameters. I guess it's many way's to handle this though.
2020-05-01 15:38
Oswald

Registered: Apr 2002
Posts: 4627
tww, no I mean a pointer to a data structure.
2020-05-01 15:47
oziphantom

Registered: Oct 2014
Posts: 410
@TWW This is a debug rom, so I want it to be as invisible as possible.

you know how you write a routine to draw an X/Y at the top the screen, so as you move things you can track positions etc But you need to put 16 chars of 0-F and normally it has to be multi colour and you have to worry about CRAM etc etc
128 has a whole VDC just sitting there doing nothing with its own 16K of RAM. so debug strings, I upload all the strings into the VDC. Given a 80x25 screen needs 2K, the char set uses 4K that leaves 10K for data. So to print a string, it just looks up the X/Y then sets the Src/Dest on the VDC and uses the internal DMA to copy N chars from Src -> Screen location, in parallel, as once you start the DMA the CPU is free. This make it easy and somewhat fast to print out debug info. I'm at the point of doing collision detection and having, a bunch of x/ys and "player state" strings on display while I debug is going to make life easier. I'm sure I will find a pile more uses for it, so I want to keep it "I can just drop call in here and not worry about trashing this register/what bank I'm in etc"

brk XX YY ZZ WW etc was ideal as it allows me to move the handler anywhere I want with ease,and uses minimal in code bytes. I just insert some code into the IRQ routine to detect and fix up, but BRK is tricky on a 128
2020-05-01 17:01
TWW

Registered: Jul 2009
Posts: 480
@ Ozi:

Ah, ok I see.


@Oswald:

Assume you mean something like this:

    ldx #<param1
    ldy #>param1
    jsr subroutine
    …
    ldx #<param2
    ldy #>param2
    jsr subroutine
    rts



subroutine:
    stx $fb
    sty $fc
    ldy #$00
    lda ($fb),y
    sta ..
    iny
    …

    // dosomething
    rts

param1:
    .word $1000, $2000, $1000
param2:
    .word $2000, $1000, $1000


It's faser and smaller with fewer calls (but at some point you would break even and then face a net loss due to the ldx/ldy vs the overhead of the stack handler).

You would also need to detach the parameters from the call (unless you manipulate the stack in which case you could just as well use the stack handler unless you're pressed for cycles). Whatever fits your project I guess.
2020-05-01 17:41
oziphantom

Registered: Oct 2014
Posts: 410
also ^^^^
can't call other helper functions from withing a function as it will trash the vectors, and not interrupt safe which may also call some functions while the post function call data is.
Previous - 1 | 2 - Next
RefreshSubscribe to this thread:

You need to be logged in to post in the forum.

Search the forum:
Search   for   in  
All times are CET.
Search CSDb
Advanced
Users Online
Rick/AFL
Didi/Laxity
Toggle/Padua
encore
Powerslave/ΤRIΛD
Jazzcat/Onslaught
Street Tuff/TRSi
Viti/Hokuto Force
Sister Despair
Guests online: 58
Top Demos
1 Coma Light 13  (9.6)
2 Uncensored  (9.6)
3 Memento Mori  (9.6)
4 Edge of Disgrace  (9.6)
5 Unboxed  (9.6)
6 Comaland 100%  (9.6)
7 Lunatico  (9.6)
8 The Shores of Reflec..  (9.5)
9 X Marks the Spot  (9.5)
10 Rivalry  (9.5)
Top onefile Demos
1 Copper Booze  (9.9)
2 Quadrants  (9.6)
3 Elite Code Mechanics  (9.6)
4 Square Booze  (9.6)
5 Dawnfall V1.1  (9.5)
6 Smile to the Sky  (9.5)
7 Daah, Those Acid Pil..  (9.5)
8 Crystal Gazer  (9.4)
9 Cuarentenauta  (9.4)
10 Listen to Your Eyes  (9.4)
Top Groups
1 Booze Design  (9.4)
2 Censor Design  (9.4)
3 Oxyron  (9.3)
4 PriorArt  (9.3)
5 Triad  (9.3)
Top Diskmag Editors
1 hedning  (9.8)
2 Jazzcat  (9.5)
3 Newscopy  (9.4)
4 A Life in Hell  (9.2)
5 Peter  (9.1)

Home - Disclaimer
Copyright © No Name 2001-2020
Page generated in: 0.046 sec.