Re: [cc65] new target

Date view Thread view Subject view

From: Ullrich von Bassewitz (uz_at_musoftware.de)
Date: 2002-03-23 11:41:38


Hi!

On Fri, Mar 22, 2002 at 03:51:16PM -0800, Adam Wozniak wrote:
> I think I need a better understanding of how the cc65 parameter stack
> relates to the 6502 call/return stack.
>
> Are these the same beast?  Do they overlap?  Or ar they completely separate?

They are completely separate.

> I've only got 128 bytes of real ram to work with, mapped at 0x80->0xFF
> I've got some other areas (0x00->0x3F and 0x280->0x29F) which are memory
> mapped devices.  My ROM is 0xF000->0xFFFF.
>
> Where should the 6502 stack go?  The parameter stack?

You will become quite some problems with such a limited target system. The
compiler and runtime needs 24 bytes in the zero page for itself (you may be
able to strip that down to 18 bytes, but I cannot guarantee that this will
work with new versions of the compiler).

So you are left with 104 bytes for your data and both stacks. Assuming that
you will use 10 nested levels of subroutine calls plus a few bytes for
register saves inside these routines, plus 6 bytes for an interrupt handler,
you will need about 30 bytes of call stack. The size of the parameter stack
depends heavily on your code and setup. Let's assume you will use mostly
global variables, and almost no parameters passed on the stack. This would
mean that 30-50 bytes for the parameter stack should be ok for 10 nested
subroutine levels. This sums up to

        128             RAM bytes total
     -   24             Zero page usage of the compiler
     -   30             Call stack size
     -   30             Parameter stack size
   ---------
         44             Bytes left for your program

As you can see there is not much left.

> MEMORY {
> RAM:   start = $80,   size=$80, file="trash.bin";
> ROM:   start = $F000, size=$1000, file="rom.bin";
> TIA:   start = $00,   size=$40, file="trash.bin";
> RIOT:  start = $280,  size=$20, file="trash.bin";
> }

If you leave the file name empty (file=""), the data will be discarded and not
written to any file. So there is no need to use a "trash" file. And %O is
replaced by the output file name from the command line, so using

        MEMORY {
            RAM:   start = $80,   size=$80, file="";
            ROM:   start = $F000, size=$1000, file=%O;
            TIA:   start = $00,   size=$40, file="";
            RIOT:  start = $280,  size=$20, file="";
        }
        
the target file name may be specified on the linker command line using the -o
option.

Adding the devices to the linker config is possible, but since the actual
values are then unknown by the compiler, the compiler generated code is not as
good as it could be. So I would suggest to use define these devices as memory
mapped structures in a header file like this:

        struct RIOT_ {
            unsigned char       a;              /* Register a */
            unsigned char       b;              /* Register b */
        };

        /* Map a RIOT structure to $280 */
        #define RIOT    (*(struct RIOT_*)0x280)

This will allow you to use the RIOT as

        unsigned char x = RIOT.b;
        RIOT.a = 0x01;

while the compiler still works with known target addresses.

> SYMBOLS {
>    __STACKSIZE__ = $80;
> }

This symbol is unused in your code, so there is no need to define it.

You may also need the FEATURE CONDES declarations depending on which library
file you use. If in doubt, it is better to include it.

> ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
> ;;;;;;;;;;; Is any of this right???
>
>    ; set the 6502 stack pointer to FF
>    ldx #$ff
>    txs
>
>    ; set up the cc65 parameter stack
>    tsx
>    stx spsave

Since your program will probably run forever, there is no need to save the
current stackpointer, since you will never come back and restore it.

>    lda #<TOPMEM
>    sta sp
>    lda #>TOPMEM
>    sta sp+1

This would mean that your call stack lives at $E0-$FF, and below that, the
parameter stack. Assuming the parameter stack will also have 32 bytes, the RAM
left goes from $80 to $BF. This is the memory available for the RAM segment,
so you have to change the linker config accordingly:

        MEMORY {
            RAM:   start = $80,   size=$40, file="";
            ROM:   start = $F000, size=$1000, file=%O;
        }

You can also move the symbols for the stack sizes into the linker config, so
you can change the stack sizes without changing your sources. Please note that
you will have to adjust the size of the RAM segment manually when changing the
stack sizes, the linker will not do that automatically.

        MEMORY {
            # The following three areas cover the $80-$FF range completely
            RAM:        start = $80,   size = $40, file = "";
            PARMSTACK:  start = $C0,   size = $20, file = "", define = yes;
            CALLSTACK:  start = $E0,   size = $20, file = "", define = yes;
            #
            ROM:        start = $F000, size = $1000, file=%O;
        }

The following code will use this symbols:

        ; Import linker generated symbols
        .import         __CALLSTACK_START__, __CALLSTACK_SIZE__;
        .import         __PARMSTACK_START__, __PARMSTACK_SIZE__;

        ; Set the 6502 call stack as defined in the linker config
        ldx     #<(__CALLSTACK_START__ + __CALLSTACK_SIZE__ - 1)
        txs

        ; Set the parameter stack as defined in the linker config
        lda     #<(__PARMSTACK_START__ + __PARMSTACK_SIZE__)
        sta     sp
        lda     #>(__PARMSTACK_START__ + __PARMSTACK_SIZE__)
        sta     sp+1

BTW: There are several ways to achieve the same result, you may also declare
call and parameter stack as BSS style segments and map the into the RAM
segment. The disadvantage is that the linker will emit a warning if none such
segment is found, so you will have to generate it in an assembly file. The
advantage is, that the linker will do all the needed size calculations for
you.

Regards


        Uz


-- 
Ullrich von Bassewitz                                  uz_at_musoftware.de
----------------------------------------------------------------------
To unsubscribe from the list send mail to majordomo_at_musoftware.de with
the string "unsubscribe cc65" in the body(!) of the mail.


Date view Thread view Subject view

This archive was generated by hypermail 2.1.3 : 2002-03-23 11:41:58 CET