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
[Z88dk-users] How to allocate a variable in a specific memory locati
@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
"
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
"
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
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
Is the type Character defined? I get this error if I don't have a typedef for it.@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
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.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.
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:
In a C header, tell the compiler what the addresses are:
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:
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.
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
Code: Select all
extern unsigned int os_clock;
extern void os_reset_clock(void);
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
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.
Thanks!
Indeed the defc solution is the clean one!
Fabrizio
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:
In a C header, tell the compiler what the addresses are: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
Then just add the asm file to the compile line.Code: Select all
extern unsigned int os_clock; extern void os_reset_clock(void);
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:
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.Code: Select all
SECTION BLOCKVARS org 0x4000
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.