[Z88dk-users] How to allocate a variable in a specific memory locati

Bridge to the z88dk-users mailing list
Post Reply
Fabrizio
Member
Posts: 58
Joined: Tue Jul 11, 2017 9:28 pm

[Z88dk-users] How to allocate a variable in a specific memory locati

Post by Fabrizio »

Hi!

How to allocate a variable in a specific memory location?

Some systems have "ram holes" (e.g., unused tape/video/rs232 buffers, etc.) in their memory map that I would like to use for some variables (not the code).
Example: vg5k may have usable ram at $4000 (unused video buffer).

How can I achieve this in Z88DK?
In CC65 I would declare the variables as extern in the C file and add an assembly file where the variable is mapped at a given memory location:
"
.extern foo;
foo = $ba7
"

What is the syntax and solution in Z88DK?

Fabrizio
User avatar
dom
Well known member
Posts: 1195
Joined: Sun Jul 15, 2007 10:01 pm

Post by dom »

Hi!

How to allocate a variable in a specific memory location?

...

What is the syntax and solution in Z88DK?

Fabrizio
Both compilers (sccz80 and zsdcc) understand the following syntax

__at (0x4000) char c = 1;

__at (0x3000) int e = 8192;

__at (0x500) char buf[] = "Hello there" ;
Fabrizio
Member
Posts: 58
Joined: Tue Jul 11, 2017 9:28 pm

Post by Fabrizio »

@Dom

I am using:
"
__at (0x4A00) Character ghosts[];
__at (0x4A05) Character bombs[];
__at (0x4A0A) Character player[];
__at (0x4A0F) unsigned short ghostSlowDown;
__at (0x4A11) unsigned short points;
__at (0x4A13) unsigned short highScore;
__at (0x4A15) unsigned char lives;
__at (0x4A16) unsigned char level;
__at (0x4A17) unsigned char ghostCount;
"
but it won't compile:
"
...
PROCESSING cross_lib/memory/gal_memory.c
zsdcpp -iquote"." -DZ80 -DGAL -D__GAL__ -DTINY_GAME -DNO_SLEEP -DLESS_TEXT -D__GAL__ -DNO_INITIAL_SCREEN -DNO_CONTROL_INSTRUCTIONS -DALT_MOVE -DNO_RANDOM_LEVEL -DNO_SET_SCREEN_COLORS -DFORCE_BOMBS_NUMBER=4 -DFORCE_GHOSTS_NUMBER=8 -DNO_DEAD_GHOSTS -DNO_INIT_GRAPHICS -DFLAT_ENEMIES -DALT_HIGHSCORE -DCONIO -D__SDCC -isystem"c:\Z88DK\lib\config\..\..\/include" "cross_lib/memory/gal_memory.c" "C:\cygwin\tmp\zcc258813.i2"
zpragma < "C:\cygwin\tmp\zcc258813.i2" > "C:\cygwin\tmp\zcc258813.i"
zsdcc --constseg rodata_compiler --max-allocs-per-node200000 --reserve-regs-iy -cross_lib/memory/gal_memory.c:3: syntax error: token -> 'ghosts' ; column 30
mz80 --no-optsdcc-in-asm --c1mode --emit-externs --no-c-code-in-asm --no-peep --peep-file "c:\Z88DK\lib\config\..\..\/libsrc/_DEVELOPMENT/sdcc_peeph.3" < "C:\cygwin\tmp\zcc258813.i" -o "C:\cygwin\tmp\zcc258813.opt"
make: *** [Makefile:6285: gal_6k] Error 1
"
User avatar
dom
Well known member
Posts: 1195
Joined: Sun Jul 15, 2007 10:01 pm

Post by dom »

@Dom

I am using:

__at (0x4A00) Character ghosts[];

...

zsdcc --constseg rodata_compiler --max-allocs-per-node200000 --reserve-regs-iy -cross_lib/memory/gal_memory.c:3: syntax error: token -> 'ghosts' ; column 30
Is the type Character defined? I get this error if I don't have a typedef for it.
Fabrizio
Member
Posts: 58
Joined: Tue Jul 11, 2017 9:28 pm

Post by Fabrizio »

Thanks @Dom,

I will try to include Character declaration.

A better solution would be to have a linker config file or assembly file where the variables names are associated to a given memory location or memory area.
Ideally one would just have to declare the start address of the memory area and then give a list of variable names and the byte offset of each of them.

The type of the variable should be irrelevant for this purpose.


Fabrizio


@Dom

I am using:

__at (0x4A00) Character ghosts[];

...

zsdcc --constseg rodata_compiler --max-allocs-per-node200000 --reserve-regs-iy -cross_lib/memory/gal_memory.c:3: syntax error: token -> 'ghosts' ; column 30
Is the type Character defined? I get this error if I don't have a typedef for it.
User avatar
dom
Well known member
Posts: 1195
Joined: Sun Jul 15, 2007 10:01 pm

Post by dom »

Thanks @Dom,

I will try to include Character declaration.

A better solution would be to have a linker config file or assembly file where the variables names are associated to a given memory location or memory area.
Ideally one would just have to declare the start address of the memory area and then give a list of variable names and the byte offset of each of them.

The type of the variable should be irrelevant for this purpose.
If you don't care to the layout yourself, then just add -pragma-define:CRT_ORG_BSS=nnnn and the zero initialised variables will be shifted to the address you specified. Initialised ones will remain within the main program area. You'll need to check there's no overflow manually since there's no fencing.
alvin
Well known member
Posts: 1872
Joined: Mon Jul 16, 2007 7:39 pm

Post by alvin »

I personally prefer using an external asm file to define the locations of fixed items in memory. The "at" syntax in zsdcc cannot accommodate all scenarios (I think sccz80 had problems fixed some time ago) and keeping it out of the c keeps the c itself clean and portable.

In a separate asm file, define some important memory addresses:

Code: Select all

PUBLIC _os_clock, _os_reset_clock

defc _os_clock = 56698         ; memory address holding an integer
defc _os_reset_clock = 62109   ; start address of function
In a C header, tell the compiler what the addresses are:

Code: Select all

extern unsigned int os_clock;
extern void os_reset_clock(void);
Then just add the asm file to the compile line.


Another alternative which is related to moving BSS is to create a new memory section and place variables there. This way the C compiler lays out everything but you lose control of exact address placement and gain control of where some things are in a region of memory. This is most often used by bankswitching programs that place things in different memory banks.

In a separate asm file declare a new section with org:

Code: Select all

SECTION BLOCKVARS
org 0x4000
You can place asm data and code in that block in the same file. You can get the C compilers to put stuff there by changing the section assignment on the compile line.

In the output there will be an additional binary file "*_BLOCKVARS.bin". If it's just bss data you can just ignore it. If it's bss data that your program expects to be zero then you must add code that initializes that block to zero. You can do that by inserting code into the crt in section "code_crt_init" (newlib) or by adding code to main. If it's non-zero initialized data then you must find a way for your program to initialize it separately as the c compiler won't do it for you.


After that you can look at defining your own memory map for full control of everything but this should be almost never necessary.
Fabrizio
Member
Posts: 58
Joined: Tue Jul 11, 2017 9:28 pm

Post by Fabrizio »

Thanks!

Indeed the defc solution is the clean one!

Fabrizio
I personally prefer using an external asm file to define the locations of fixed items in memory. The "at" syntax in zsdcc cannot accommodate all scenarios (I think sccz80 had problems fixed some time ago) and keeping it out of the c keeps the c itself clean and portable.

In a separate asm file, define some important memory addresses:

Code: Select all

PUBLIC _os_clock, _os_reset_clock

defc _os_clock = 56698         ; memory address holding an integer
defc _os_reset_clock = 62109   ; start address of function
In a C header, tell the compiler what the addresses are:

Code: Select all

extern unsigned int os_clock;
extern void os_reset_clock(void);
Then just add the asm file to the compile line.


Another alternative which is related to moving BSS is to create a new memory section and place variables there. This way the C compiler lays out everything but you lose control of exact address placement and gain control of where some things are in a region of memory. This is most often used by bankswitching programs that place things in different memory banks.

In a separate asm file declare a new section with org:

Code: Select all

SECTION BLOCKVARS
org 0x4000
You can place asm data and code in that block in the same file. You can get the C compilers to put stuff there by changing the section assignment on the compile line.

In the output there will be an additional binary file "*_BLOCKVARS.bin". If it's just bss data you can just ignore it. If it's bss data that your program expects to be zero then you must add code that initializes that block to zero. You can do that by inserting code into the crt in section "code_crt_init" (newlib) or by adding code to main. If it's non-zero initialized data then you must find a way for your program to initialize it separately as the c compiler won't do it for you.


After that you can look at defining your own memory map for full control of everything but this should be almost never necessary.
Post Reply