Hello,
once again i need some help with my code, i use SDCC with Cpctelera.
My code is being too large and i don't know to solve it, i have read with interest the post of ervin SDCC question - how to deal with program being too large? (http://www.cpcwiki.eu/forum/programming/sdcc-question-how-to-deal-with-program-being-too-large/msg104733/#msg104733)
but i didn't found a solution and in addition i'm a real beginner in assembler :picard:
For information :
- I use firmware in order to load data from file, and i disable and reenable it when needed.
- I use bank switching at 0x4000.
Here my memory map :
0x0040 Code Begin
0x3FFF Code End
0x4000 Data Begin with Bank switching
0x7FFF Data End
0x8000 Swap Begin
0x9FFF Swap End
... Free memory
Problem :
When my code location is between 0x0040 and 0x3FFF all works, when my code is above 0x4000 my program crash.
I guess the problem is my code is replaced by data when bank switching.
I have tried several solutions:
1. I have set an array of 16384 bytes at 0x4000 to prevent SDCC to use this memory area:
__at(0x4000) const char _BufferBk0[16384] = {0};
-> It doesn't works, I have overlapped warning because global variables (and others things) are always
set to 0x40xx whereas i think have forbidden this.
2. I have try to force compilation of functions at specific area (0x9000 or 0x9FFF) with this code I found on internet :
void begin_absolute_code(void) __naked
{
__asm
.area ABSCODE (ABS)
.org 0x9FFF
__endasm;
}
MyFunctions()...
void end_absolute_code(void) __naked
{
__asm
.area CSEG (REL)
__endasm;
}
-> It directly freeze I don't know why, however the functions are at the right address in the map file
3. I have also try to locate my code at 0x8000, move the stack to 0x1FF and set video memory to 0x200 with the Cpctelera functions.
-> It directly crashes because I overwrite firmware at 0xA6FC
Well now i'm stuck, any easy solution ?
Thanks,
Arnaud.
It's certainly not easy to solve. It depends much on what you want to do and what your code does. On your specific case, ¿have you tried splitting your code between 0x040-0x3FFF and 0x9FFF-0xA500 ? You could try to use two absolutely located code areas and put part of your code in one, and part in the other. Looking at the .map file generated by SDCC on compilation you can be sure that your code is bound within each of the areas.
Other solutions involve generating 16K binaries with your code and loading/swapping them as if they were data. Then, you'll need to manually call the functions knowing their place in memory (you could create your own symbols for calling the functions, giving them absolute adresses). That's another idea, much more flexible, but also much more complicated.
If CPCTelera would work together with SymbOS and FutureOS then memory would be no issue. Both have memory management support.
I somebody wants to target FutureOS then I'm glad to provide help with that. That includes making some libraries etc. But I'm not a C programmer, I do the machine code part. :)
btw. I'm sure @Prodatron (http://www.cpcwiki.eu/forum/index.php?action=profile;u=13) will help to target SymbOS.
Quote from: ronaldo on 19:46, 21 October 15
have you tried splitting your code between 0x040-0x3FFF and 0x9FFF-0xA500 ?
Good idea, but how can i do this ?
Edit : with basic loader ?
A Problem i had:
Do you have Exomizer in use? It has a unfound bug and sometime it behaves strange with its compressed data at decompressing and datafragments are thrown around in the memory, overwriting vital routines, variables etc.
Also allergic to bankswitching: Interrupt-Routines...
Quote from: Fessor on 20:15, 21 October 15
A Problem i had:
Do you have Exomizer in use? It has a unfound bug and sometime it behaves strange with its compressed data at decompressing and datafragments are thrown around in the memory, overwriting vital routines, variables etc.
Also allergic to bankswitching: Interrupt-Routines...
Yes i use it at loading and in game... I hope Exomizer is not the problem.
Quote from: Arnaud on 20:07, 21 October 15
Good idea, but how can i do this ?
The same way you've found to absolutely locate code using a defined ABS area for SDCC, you can create 2 areas, one starting at 0x0040 and other one starting at 0x9FFF. Then, you only have to put your functions on one area or the other. Put some of your functions in one area, and some on the other.
@Fessor (http://www.cpcwiki.eu/forum/index.php?action=profile;u=1495): I've seen tens of times people blaming exomizer and most of the time being an error of the program using exomizer. Just corrupting 1 bit of exomized data is completely fatal, as exomizer will uncompress rubbish and may not found the end of the compressed buffer, effectively creating an endless loop and corrupting memory. This also happens if you have pointers to exomized data and you have any problem with your pointers, finally giving exomizer an incorrect memory address as start address of the compressed buffer.
I'm not stating that exomizer is bugfree, but that I'm yet to see a concrete case where blaming exomizer is to be considered correct. In fact, I'd like to see cases in order to help solving the bug, if it actually exists.
The exomizer bug does exist, and it's kind of weird. It may be one reason for problems.
EDIT: Of course this bug is only seen once in a while. Also if for one everything works well, it deosn't mean that the bug isn't there. Once I used it in a ROM, it worked without autostart, but crased with autostart. And it WAS the exomizer part, I could clearly trace that.
I've read similar accounts of exomizer being buggy, but I've used it A LOT for over 4 years (in Chunky Pixel Curator, and now in RUNCPC), and the only time I thought exomizer was causing problems turned out to be my mistake (I had declared something as an 8-bit byte variable, when it should have been a 16-bit word variable).
My programs use bank-switching, stack abuse, and RUNCPC has the firmware disabled as well. And exomizer has been fine.
Also, in Chunky Pixel Curator, I experimented with custom interrupt routines, and they worked fine alongside exomizer.
Of course, that isn't proof of whether exomizer is/isn't buggy; it's just my experiences with it.
8)
Quote from: Arnaud on 18:49, 21 October 15
[/i] 2. I have try to force compilation of functions at specific area (0x9000 or 0x9FFF) with this code I found on internet :
void begin_absolute_code(void) __naked
{
__asm
.area ABSCODE (ABS)
.org 0x9FFF
__endasm;
}
MyFunctions()...
void end_absolute_code(void) __naked
{
__asm
.area CSEG (REL)
__endasm;
}
-> It directly freeze I don't know why, however the functions are at the right address in the map file
Running out of RAM is indeed a very difficult problem to solve.
I had the exact same problem just one week ago (in fact, it threatened RUNCPC's completion).
The solutions I found on the internet didn't work; perhaps because they were talking about different compilation targets.
After much experimentation, and examination of source code produced by SDCC, I arrived at the following:
// To save some RAM, initMain() resides inside the SPRITE_BUFFER area.
// It will get overwritten the first time a sprite is decompressed.
// This is ok, as this code is only run at startup, and is not required anymore after it is run.
void begin_absolute_initMain(void) __naked{
__asm
.area _INIT_MAIN_BEGIN (ABS)
.org 0x2200
__endasm;
}
void initMain()
{
u8 i;
u8 j;
cpct_clearScreen(0x00);
cpct_setVideoMode(0);
cpct_fw2hw(g_palette,16);
cpct_setPalette(g_palette,16);
cpct_setBorder(g_palette[0]);
page=0;
for (i=0;i<7;i++){
hiScoreTable[i]=hiScoreTableInit[i];
for (j=0;j<5;j++){
hiScoreDisplay[i][j]=hiScoreDisplayInit[i][j];
}
for (j=0;j<8;j++){
hiScoreNameList[i].text[j]=hiScoreNameListInit[i].text[j];
}
}
}
void end_absolute_initMain(void) __naked{
__asm
.area _INIT_MAIN_END (REL)
__endasm;
}
Here is the start of my main() routine.
void main(){
cpct_disableFirmware();
cpct_setStackLocation(NEW_STACK);
initMain();
The important things to note here are that I've previously disabled the firmware, and moved the stack.
Disabling the firmware has allowed me to use ALL the memory between 0x8000 and 0xC000 (yes, including the area above 0xA6FC). That's over 6KB reclaimed!
In fact, with the firmware disabled, I'm using 0x8000 and 0xC000 as my 2 screens, for double-buffering (I didn't know that this was even possible until recently).
I've got my stack at 0x8000-#64 (i.e. 128 bytes reserved for stack movement up/down under 0x8000), and my data area starts at 0x100.
So in effect, I've got *almost* a full 32KB for data and code.
My main() routine is at 0x4F20.
Simply change the cfg/build_config.mk file to have a different code location.
# Name of the project (without spaces, as it will be used as filename)
# and Z80 memory location where code will start in the generated binary
PROJNAME := runcpc
Z80CODELOC := 0x4f20
In main(), I had to put the following code *before* the call to initMain(), as my program would crash otherwise:
cpct_disableFirmware();
cpct_setStackLocation(NEW_STACK);
A quick explanation... I was able to reclaim a nice amount of RAM by putting code (that runs *once* at startup) into a buffer area that is used for decompressing sprite data. Once the game starts, the code in initMain() is overwritten, never to be seen again.
But that's perfectly ok, because it isn't needed anymore after startup.
initMain() resides well below main() itself, at 0x2200 (near the end of my sprite buffer).
I've had to use exomizer extensively in my game. There is no way I would have fit everything in otherwise.
I have almost 10KB set aside for storing exomized sprite data, and individual compressed files are decompressed from there into the sprite buffer as required.
I used the cpct_bin2c script a lot during RUNCPC's development!
Also, my music only plays on the title screen.
The music is also exomized and stored in the 10KB area, and decompressed to the audio buffer every time the title screen appears.
The audio buffer is only 256 bytes; enough for the sfx, but too small for the music. The uncompressed music crosses over into the sprite buffer, which is fine as sprites are not needed at the same time as music.
My sfx are also exomized, and decompressed to the audio buffer every time a new game is started.
The Arkos Player routines to play music/sfx are pointed to the audio buffer.
Here is part of my memory map:
#define ADDR_FRAME_BUFFER 0x0100
#define ADDR_SCREEN_BUFFER 0x0500
#define ADDR_BACK_BUFFER 0x0900
#define ADDR_AUDIO 0x0d00 // 256
#define ADDR_SPRITE 0x0e00 // 5888 (allow for 5667+140=5807)
#define ADDR_T_SIZE 0x2500 // 128
#define ADDR_G_PALETTE 0x2580 // 16
#define ADDR_TILEBANK 0x2590 // 512
#define ADDR_EXO_BUFFER 0x2790 // 0x4f20-0x2790=10128
#define OLD_STACK (void*)0xC000
#define NEW_STACK (void*)0x8000-64
I hope that helps you.
:)
I found a way!
See the attached zip.
(I have not included the crt0 in the linker script)
I have two c files.
At the top of each i define the code segment using a pragma.
I then compile each seperately.
At link time I define the location of the code segments.
I then link and use hex2bin to make a binary. This gives me a binary file.
In the binary file there is code at 0x0100 (main) and code at 0x08000 (other), between them there is lots of 0x0ff bytes. The hex2bin utility filled up the space between them.
@Arnaud (http://www.cpcwiki.eu/forum/index.php?action=profile;u=1424), at this point you can then split the file into two and exclude the 0x04000-0x07fff. I don't know if that is possible with the linker?
I think both pieces of code will share a data segment. I didn't define it here.
I don't know if you can define variables in one code and link against them in the other. I didn't test that.
Hopefully this solves your problem?
@Arnaud (http://www.cpcwiki.eu/forum/index.php?action=profile;u=1424): Here you are an example of what I was telling you. I've done exacly the same as you found (generating absolute code areas) but using a preprocessor macro to simplify its use.
#include <cpctelera.h>
#include <stdio.h>
#define LOCATE_ABSOLUTE(AREA,MEM) \
void AREA (void) __naked { \
__asm \
.area AREA (ABS) \
.org MEM \
__endasm; \
}
#define LOCATE_RELATIVE(FNAME) \
void FNAME (void) __naked { \
__asm \
.area CSEG (REL) \
__endasm; \
}
LOCATE_ABSOLUTE(ABS_1, 0x040)
void helloWorld_1() {
printf("HelloWorld from 0x040!\n\r");
}
LOCATE_RELATIVE(REL_1)
void helloWorld_rel() {
printf("HelloWorld relatively located!\n\r");
}
LOCATE_ABSOLUTE(ABS_2, 0x9FFF)
void helloWorld_2() {
printf("HelloWorld from 0x9FFF!\n\r");
}
LOCATE_RELATIVE(REL_2)
//
// Main
//
void main(void) {
helloWorld_1();
helloWorld_rel();
helloWorld_2();
// Loop forever
while (1);
}
So, when you need to locate some part of your code in an absolute location, you can use LOCATE_ABSOLUTE(CODE_AREA_NAME, LOCATION). When you finish your absolutely located part, you can tell the compiler that next part will be relatively located with LOCATE_RELATIVE(RELATIVE_AREA_NAME). Area names are not important, they only need to be different.
Following this, you can set up your project to be loaded at 0x0040, for instance, and put some of your functions at 0x9FFF creating an absolutely located code area with LOCATE_ABSOLUTE(ABS_AREA_1, 0x9FFF). So, if your code goes beyond 0x3FFF, just place part of it at 0x9FFF using this.
Beware with this. SDCC will warn you about overlapping records when part of your absolutely located code collides in the same area with SDCC's relatively located code or data. It's your job to control sizes of your different parts and keep them away from each other. Always look at .map file to do this.
Also, take into account that your binaries will be padded with zeros, as there is no other way to absolutely locate things. The compiler and linker output a binary, not a loading system. They can only guarantee location of things with padding, as they only know the initial location where the binary will be loaded. So, your binaries may be bigger doing this.
Thanks @arnoldemu (http://www.cpcwiki.eu/forum/index.php?action=profile;u=122), @ervin (http://www.cpcwiki.eu/forum/index.php?action=profile;u=82), @Fessor (http://www.cpcwiki.eu/forum/index.php?action=profile;u=1495), @TFM (http://www.cpcwiki.eu/forum/index.php?action=profile;u=179) and @ronaldo (http://www.cpcwiki.eu/forum/index.php?action=profile;u=1227) for your answers.
@ervin (http://www.cpcwiki.eu/forum/index.php?action=profile;u=82) : i keep in mind to put my initialisation functions in temporary memory location
@ronaldo (http://www.cpcwiki.eu/forum/index.php?action=profile;u=1227) : i try your macro and my program directly freeze but i found the problem, it's the compilation option --fomit-frame-pointer.
I don't why i have to use it, but i remove it and all works i have more than 4kb free for code :D
You could keep your macros in Cpctelera, they are very useful.
@Arnaud (http://www.cpcwiki.eu/forum/index.php?action=profile;u=1424): Oh! Man! That option was required by previous version of CPCRSLib to run properly. If you are not using it, that was just messing up your code :).
Nice to know that your code works again :). I will put macros on the tasklist, as I think this issue of absolutely locating code deserves more analysis. But they will be definitelly added to CPCtelera (http://lronaldo.github.io/cpctelera) :).
Quote from: ronaldo on 19:32, 22 October 15
@Arnaud (http://www.cpcwiki.eu/forum/index.php?action=profile;u=1424): Oh! Man! That option was required by previous version of CPCRSLib to run properly. If you are not using it, that was just messing up your code :) .
But if i use this option the code location don't work ???
Quote from: ronaldo on 19:32, 22 October 15
That option was required by previous version of CPCRSLib to run properly.
Is there a new version of cpcrslib without the need of -
-fomit-frame-pointer ? It could help me.
@ervin (http://www.cpcwiki.eu/forum/index.php?action=profile;u=82) : Do you use cpcrslib for exomizer ?
@Arnaud (http://www.cpcwiki.eu/forum/index.php?action=profile;u=1424): if you are using CPCRSLib only for exomizer, you can put exomizer's code only in your project and remove dependency from CPCRSLib. If you want to use CPCRSLib you should migrate to the latest version (http://www.cpcwiki.eu/forum/sourceforge.net/projects/cpcrslib/). Artaburu has made a great job improving CPCRSLib: it now is faster and does not require --fomit-frame-pointer, which is a deprecated option.
OK i just download cpcrslib and compile my code with it.
But with the lib provided, my program crashes directly and when i rebuild the lib with SDCC in Cpctelera i have the same problem.
I guess you have not the problem ?
Edit : well i'm going to keep only exomizer and remove all cpcrslib function, it will be easier.
Quote from: Arnaud on 19:39, 22 October 15
@ervin (http://www.cpcwiki.eu/forum/index.php?action=profile;u=82) : Do you use cpcrslib for exomizer ?
I'm using cpctelera.
To create my exomized data, I do the following...
I create a project folder (let's call it "rainbow").
Inside the "rainbow" folder I have a "src" folder and an "obj" folder.
(cpctelera does this for you automatically using the cpct_mkproject script).
Inside the "src" folder is main.c.
main.c contains the C array definition for whatever you like.
In this case, it's the tile reference lists for the rainbow obstacles in my RUNCPC game.
If I remember correctly, I had to put the main() function definition at the top, because if I had it after the array definition, the .bin file would be 2 bytes larger, and would have to be taken into account for decompressing (i.e. those 2 bytes would need to be skipped). This problem can be avoided by declaring main() first.
[EDIT] Actually, I wonder if that sort of thing has been one of the reasons why people have had problems with exomizer in the past!
void main(void) __naked{}
const unsigned char spData[5667]={
255,126,126,255,
10,255,255,10,
110,255,255,110,
255,94,126,94,255,
255,5,255,5,255,
10,255,255,255,10,
11,255,255,255,11,
...
};
Compiling it gives me rainbow.bin in the "obj" folder.
I compile it using the default code address in cpctelera, which is 0x4000.
I run it through exomizer (2.07) at the command line (I'm using Windows; I don't know if that matters).
(You'll need to adjust the command line to include your own paths to rainbow.bin, and where you want rainbow.exo to go).
exomizer raw "obj\rainbow.bin" -o "exo\rainbow.exo"
[EDIT] I don't believe it! I just checked the exomizer website, and they have released 2 new versions in the last few days!
It's now up to 2.09. Maybe the latest version fixes the bugs that people have experienced in the past. Hopefully my decompress routine will still work!
For cpctelera, I'm using Cygwin, due to the fact that I'm in Windows.
So, in Cygwin, I navigate to my "exo" folder, which is where I told exomizer to put the compressed file.
The rainbow.exo file is then converted to a C array like this:
cpct_bin2c rainbow.exo > rainbow.c
That gives me a big list of data, like this:
// File rainbow.exo converted using cpct_bin2c
const unsigned char G_rainbow[1259] = {
0x20, 0x22, 0x22, 0x11, 0xd3, 0x70, 0x20, 0x76, 0x04, 0x21, 0x26, 0x11, 0x55, 0x33, 0xf3, 0xf4,
0x06, 0x04, 0x36, 0x31, 0x54, 0x66, 0x01, 0x32, 0x25, 0x40, 0x5a, 0xff, 0x7e, 0x90, 0x2a, 0x0a,
0xc1, 0x09, 0x6e, 0x11, 0xbc, 0x5e, 0x7e, 0x68, 0x34, 0x05, 0x41, 0x8c, 0x20, 0x54, 0x0b, 0x55,
...
};
In my main runcpc\src folder, I have a file called exo.h.
It contains all the arrays of exomizer data that I need in my program.
It looks like this (in cut-down form):
(Notice the use of
__at(ADDR) to carefully position each array, one after the other).
#define SIZE_MUSIC 280
#define SIZE_SFX 180
#define SIZE_A 1020
#define SIZE_Z 802
#define SIZE_RAINBOW 1259
#define SIZE_SLALOM 786
#define SIZE_SLALOM2 765
#define SIZE_BUBBLE 1164
#define SIZE_FLOWER 1117
#define SIZE_SNAKES 1134
#define SIZE_SWORDS 670
#define SIZE_CORNERSIGN 941
__at(ADDR_EXO_BUFFER)
const unsigned char G_music[SIZE_MUSIC] = {
0x04, 0x20, 0x32, 0xab, 0x09, 0x10, 0x00, 0xb1, 0x00, 0x10, 0x20, 0x00, 0x21, 0x99, 0xb9, 0x78,
...
};
__at(ADDR_EXO_BUFFER+SIZE_MUSIC)
const unsigned char G_sfx[SIZE_SFX] = {
0x01, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc4, 0xc0, 0x88, 0x40, 0x8a,
...
};
__at(ADDR_EXO_BUFFER+SIZE_MUSIC+SIZE_SFX)
const unsigned char G_a[SIZE_A] = {
0x20, 0x26, 0x62, 0x16, 0xf2, 0x30, 0x05, 0x00, 0x00, 0x66, 0x62, 0x52, 0x33, 0x35, 0x8f, 0x88,
...
};
__at(ADDR_EXO_BUFFER+SIZE_MUSIC+SIZE_SFX+SIZE_A)
const unsigned char G_z[SIZE_Z] = {
0x14, 0xcc, 0xa2, 0xa2, 0x12, 0x4e, 0xc8, 0x0e, 0x00, 0xcc, 0xc4, 0x28, 0x0a, 0x66, 0xee, 0x19,
...
};
__at(ADDR_EXO_BUFFER+SIZE_MUSIC+SIZE_SFX+SIZE_A+SIZE_Z)
const unsigned char G_rainbow[SIZE_RAINBOW] = {
0x20, 0x22, 0x22, 0x11, 0xd3, 0x70, 0x20, 0x76, 0x04, 0x21, 0x26, 0x11, 0x55, 0x33, 0xf3, 0xf4,
...
};
__at(ADDR_EXO_BUFFER+SIZE_MUSIC+SIZE_SFX+SIZE_A+SIZE_Z+SIZE_RAINBOW)
const unsigned char G_slalom[SIZE_SLALOM] = {
0xc0, 0x99, 0x19, 0x59, 0x38, 0x0d, 0x00, 0x00, 0x80, 0x89, 0x10, 0x90, 0xd1, 0xcc, 0xcc, 0xb2,
...
};
__at(ADDR_EXO_BUFFER+SIZE_MUSIC+SIZE_SFX+SIZE_A+SIZE_Z+SIZE_RAINBOW+SIZE_SLALOM)
const unsigned char G_slalom2[SIZE_SLALOM2] = {
0x08, 0x98, 0x99, 0x11, 0x35, 0xdc, 0x10, 0xd9, 0x11, 0x98, 0x08, 0x01, 0x90, 0x80, 0xd4, 0xcd,
...
};
__at(ADDR_EXO_BUFFER+SIZE_MUSIC+SIZE_SFX+SIZE_A+SIZE_Z+SIZE_RAINBOW+SIZE_SLALOM+SIZE_SLALOM2)
const unsigned char G_bubble[SIZE_BUBBLE] = {
0x08, 0x88, 0x88, 0x91, 0x98, 0x34, 0xdc, 0xc4, 0x11, 0x84, 0x88, 0x48, 0xd5, 0xcc, 0x2c, 0x22,
...
};
__at(ADDR_EXO_BUFFER+SIZE_MUSIC+SIZE_SFX+SIZE_A+SIZE_Z+SIZE_RAINBOW+SIZE_SLALOM+SIZE_SLALOM2+SIZE_BUBBLE)
const unsigned char G_flower[SIZE_FLOWER] = {
0x24, 0x24, 0x22, 0x66, 0x50, 0x08, 0x37, 0x71, 0x64, 0x46, 0x44, 0x46, 0x55, 0x33, 0xf3, 0xac,
...
};
__at(ADDR_EXO_BUFFER+SIZE_MUSIC+SIZE_SFX+SIZE_A+SIZE_Z+SIZE_RAINBOW+SIZE_SLALOM+SIZE_SLALOM2+SIZE_BUBBLE+SIZE_FLOWER)
const unsigned char G_snakes[SIZE_SNAKES] = {
0x02, 0x20, 0x22, 0x62, 0x54, 0x87, 0x50, 0x66, 0x45, 0x21, 0x11, 0x11, 0x53, 0x53, 0x8b, 0x88,
...
};
__at(ADDR_EXO_BUFFER+SIZE_MUSIC+SIZE_SFX+SIZE_A+SIZE_Z+SIZE_RAINBOW+SIZE_SLALOM+SIZE_SLALOM2+SIZE_BUBBLE+SIZE_FLOWER+SIZE_SNAKES)
const unsigned char G_swords[SIZE_SWORDS] = {
0x04, 0x10, 0xb1, 0xb8, 0xab, 0x83, 0xb1, 0x03, 0x00, 0x30, 0x11, 0x02, 0xb1, 0x1a, 0xb9, 0xa7,
...
};
__at(ADDR_EXO_BUFFER+SIZE_MUSIC+SIZE_SFX+SIZE_A+SIZE_Z+SIZE_RAINBOW+SIZE_SLALOM+SIZE_SLALOM2+SIZE_BUBBLE+SIZE_FLOWER+SIZE_SNAKES+SIZE_SWORDS)
const unsigned char G_cornersign[SIZE_CORNERSIGN] = {
0x02, 0x60, 0x46, 0x62, 0x03, 0xc5, 0x70, 0x02, 0x00, 0x60, 0x42, 0x44, 0x00, 0x20, 0x42, 0xf7,
...
};
Now in my main runcpc\src folder, I also have main.c.
At the top of main.c, I have this:
#include "exo.h"
In the appropriate places in main.c I have the following lines:
decompressMusic();
...
decompressSfx();
...
decompressSpriteData();
Those three routines look like this:
void decompressMusic() __naked{
__asm
push ix
ld hl,#_G_music
ld de,#ADDR_AUDIO
call _deexo
pop ix
ret
__endasm;
}
void decompressSfx() __naked{
__asm
push ix
ld hl,#_G_sfx
ld de,#ADDR_AUDIO
call _deexo
pop ix
ret
__endasm;
}
void decompressSpriteData() __naked{
__asm
push ix
ld a,(_currentLevel)
ld hl,#_G_a
cp #0
jr z,performDeexo
ld hl,#_G_z
cp #1
jr z,performDeexo
ld hl,#_G_rainbow
cp #2
jr z,performDeexo
...
performDeexo:
ld de,#ADDR_SPRITE
call _deexo
pop ix
ret
__endasm;
}
Finally (phew!), we need a routine to decompress the data.
Here's the one I use:
void deexo() __naked{
__asm
ld iy,#exo_mapbasebits+11
ld a,(hl)
inc hl
ld b,#52
push de
cp a
exo_initbits:
ld c,#16
jr nz,exo_get4bits
.db 0xdd
ld l,c
ld de,#1
exo_get4bits:
call exo_getbit
rl c
jr nc,exo_get4bits
inc c
push hl
ld hl,#1
ld 41(iy),c
exo_setbit:
dec c
jr nz,#exo_setbit-1
ld -11(iy),e
ld 93(iy),d
add hl,de
ex de,hl
inc iy
pop hl
.db 0xdd
dec l
djnz exo_initbits
pop de
jr exo_mainloop
exo_literalrun:
ld e,c
exo_getbits:
dec b
ret z
exo_getbits1:
call exo_getbit
rl e
rl d
jr nc,exo_getbits
ld b,d
ld c,e
pop de
exo_literalcopy:
ldir
exo_mainloop:
inc c
call exo_getbit
jr c,exo_literalcopy
ld c, #239
exo_getindex:
call exo_getbit
inc c
jr nc,exo_getindex
ret z
push de
ld d,b
jp p,exo_literalrun
ld iy,#exo_mapbasebits-229
call exo_getpair
push de
rlc d
jr nz,exo_dontgo
dec e
ld bc,#512+32
jr z,exo_goforit
dec e
exo_dontgo:
ld bc,#1024+16
jr z,exo_goforit
ld de,#0
ld c,d
exo_goforit:
call exo_getbits1
ld iy,#exo_mapbasebits+27
add iy,de
call exo_getpair
pop bc
ex (sp),hl
push hl
sbc hl,de
pop de
ldir
pop hl
jr exo_mainloop
exo_getpair:
add iy,bc
ld e,d
ld b,41(iy)
call exo_getbits
ex de,hl
ld c,-11(iy)
ld b,93(iy)
add hl,bc
ex de,hl
ret
exo_getbit:
srl a
ret nz
ld a,(hl)
inc hl
rra
ret
exo_mapbasebits:
.db 0,0,0,0,0,0,0,0,0,0,0,0
.db 0,0,0,0,0,0,0,0,0,0,0,0
.db 0,0,0,0,0,0,0,0,0,0,0,0
.db 0,0,0,0,0,0,0,0,0,0,0,0
.db 0,0,0,0,0,0,0,0,0,0,0,0
.db 0,0,0,0,0,0,0,0,0,0,0,0
.db 0,0,0,0,0,0,0,0,0,0,0,0
.db 0,0,0,0,0,0,0,0,0,0,0,0
.db 0,0,0,0,0,0,0,0,0,0,0,0
.db 0,0,0,0,0,0,0,0,0,0,0,0
.db 0,0,0,0,0,0,0,0,0,0,0,0
.db 0,0,0,0,0,0,0,0,0,0,0,0
.db 0,0,0,0,0,0,0,0,0,0,0,0
__endasm;
}
I hope someone finds all of that useful.
:)
Sadly, when my programs are too large I just roll on the floor and cry... :picard2:
Quote from: ||C|-|E|| on 00:42, 23 October 15
Sadly, when my programs are too large I just roll on the floor and cry... :picard2:
Yes, that happened to me a few times!
I *barely* had enough space left to fit all my exomized files into.
(I have over 58KB of data compressed down to just under 10KB)!
Quote from: ||C|-|E|| on 00:42, 23 October 15
Sadly, when my programs are too large I just roll on the floor and cry... :picard2:
Please don't cry. Just use overlays.
:laugh:
Edit:
In SamaruX under CP/M I use PRL files for external commands.
They are relocatable and I need only to get the assembler symbol addresses of the main program and put that information at the begining of the overlays (the PRL files) source code.
I wrote a little program that extracts that info from the PRN files when I compile.
Another way can be a sort of CP/M BIOS jump table at a known memory address.
Think about it, but please, stop crying!
:laugh:
Quote from: ||C|-|E|| on 00:42, 23 October 15
Sadly, when my programs are too large I just roll on the floor and cry... :picard2:
Yes we all get to that stage.
There were some coders from the commercial era coming here.
We were all like "hey Speccy port boo boo" and they told us about the challenge to get anything done in 64k only...
You really have to go deep like having the graphics coded in lesser bit per pixels volume then recode/convert them when you put some pixels in the "VRAM".
Yeah, not as many colours, but half the place in RAM for the graphics.
Also have to abandon a lot of cool features because this simply won't cut it.
check Brian Beuken posts perhaps (and others...)
Try writing it on a real CPC language.
Quote from: MacDeath on 18:00, 23 October 15
There were some coders from the commercial era coming here.
We were all like "hey Speccy port boo boo" and they told us about the challenge to get anything done in 64k only...
You really have to go deep like having the graphics coded in lesser bit per pixels volume then recode/convert them when you put some pixels in the "VRAM".
Yeah, not as many colours, but half the place in RAM for the graphics.
Also have to abandon a lot of cool features because this simply won't cut it.
check Brian Beuken posts perhaps (and others...)
Jokes aside, RAM limitation has always been a big problem in most 8 bit microcomputers. Luckily, nowadays is at least possible to crosscompile and crossdevelop and that helps a lot :)
RAM limitation, cpu limitation and gpu limitation happens now on modern consoles such as the xbox one and ps4.
It has never been any different.
It is true that with each generation people have thought larger and more complex and more beautiful games, but the same problems exist.
How to fit it into ram, how to make it run at 30fps and how to make it render fast enough.
It's not a thing of the past, it happens all the time.
Happened to my brother a while back. Him and a mate had been working on a game for the Xbox for years, only to find out it just didn't run fast enough on it. And then they lost interest.
Quote from: ||C|-|E|| on 01:48, 24 October 15
Jokes aside, RAM limitation has always been a big problem in most 8 bit microcomputers. Luckily, nowadays is at least possible to crosscompile and crossdevelop and that helps a lot :)
I agree. But I think we lose the point sometimes, and we want things that our machine is not able to do in its normal configuration.
Of course, we can add memory banking, disk space, ram compression, overlays, add-ons, etc. and... we've lost the point again.
I can develop an ERP for my PCW to do my accountigs and invoicing but...
Nobody needs more than 640kb?
(http://www.webinapage.com/wp-content/uploads/2010/05/steve_jobs_bill-gates-joke4.jpg)
Edit :
QuoteNobody needs more than 640kb?
Dixit same Gates....
May I be incorrect in saying that adding RAM complicates things?
I keep thinking of the poor blighter with an 1Kb ZX81, though perhaps they could shine some light on the tight memory requirements. With books like Usbornes "Computer Spacegames" though, they show what programs work with 1kb and what needs extra memory, I guess if the other programs were to work, they would have to be simplified.