News:

Printed Amstrad Addict magazine announced, check it out here!

Main Menu
avatar_Arnaud

Bis - How to deal with program being too large ?

Started by Arnaud, 18:49, 21 October 15

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Arnaud

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?
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.


ronaldo

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.

TFM

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 will help to target SymbOS.
TFM of FutureSoft
Also visit the CPC and Plus users favorite OS: FutureOS - The Revolution on CPC6128 and 6128Plus

Arnaud

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 ?

Fessor

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...



Arnaud

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.

ronaldo

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: 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.

TFM

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.
TFM of FutureSoft
Also visit the CPC and Plus users favorite OS: FutureOS - The Revolution on CPC6128 and 6128Plus

ervin

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)

ervin

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.
:)

arnoldemu

#10
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, 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?
My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

ronaldo

#11
@Arnaud: 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.

Arnaud

Thanks @arnoldemu, @ervin, @Fessor, @TFM and @ronaldo for your answers.

@ervin : i keep in mind to put my initialisation functions in temporary memory location

@ronaldo : 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.

ronaldo

@Arnaud: 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 :).

Arnaud

Quote from: ronaldo on 19:32, 22 October 15
@Arnaud: 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 : Do you use cpcrslib for exomizer ?

ronaldo

@Arnaud: 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. Artaburu has made a great job improving CPCRSLib: it now is faster and does not require --fomit-frame-pointer, which is a deprecated option.

Arnaud

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.

ervin

Quote from: Arnaud on 19:39, 22 October 15
@ervin : 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.
:)

||C|-|E||

Sadly, when my programs are too large I just roll on the floor and cry...  :picard2:

ervin

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)!


FloppySoftware

#20
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:
floppysoftware.es < NEW URL!!!
cpm-connections.blogspot.com.es

arnoldemu

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.

My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

MacDeath

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...)

AMSDOS

Try writing it on a real CPC language.
* Using the old Amstrad Languages :D * And create my own ;)
* Incorporating the Firmware :P
* I also like to problem solve code in BASIC :)   * And type-in Type-Ins! :D

Home Computing Weekly Programs
Popular Computing Weekly Programs
Your Computer Programs
Updated Other Program Links on Profile Page (Update April 16/15 phew!)
Programs for Turbo Pascal 3

||C|-|E||

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 :)

Powered by SMFPacks Menu Editor Mod