Making real 256kb ROMs in SDCC

Page 1/4
| 2 | 3 | 4

By samsaga2

Resident (57)

samsaga2's picture

09-05-2020, 13:30

In the web there is some solutions to make something-like megarom in SDCC. But they are not complete megaroms, they have a lot of limitations.

Now I have a real solution to make a megarom in SDCC and having the possiblity to call functions from one page to another efficiently (without a huge list of push and pops).

The solution is to make a custom linker to create the megarom. The linker it is not mine, I have found it searching in github (linker https://github.com/samsaga2/azombie/blob/master/util/k5link.cc)

I am developing a little roguelike game using that linker (the Makefile is linux only, sorry). There is no documentation, but you have my source code and I can answer any question about it.

https://github.com/samsaga2/azombie

Login or register to post comments

By S0urceror

Master (138)

S0urceror's picture

10-05-2020, 09:06

Interesting concept. Easy way of creating Megaroms. Do you support Konami SCC mapper or also ASCII 8/16?

By samsaga2

Resident (57)

samsaga2's picture

10-05-2020, 12:20

It creates a 256kb ROM with Konami SCC mapper. It's hardcoded in the linker code.

By salutte

Expert (108)

salutte's picture

22-05-2020, 23:11

Yup! That's my linker Smile
I'm super happy that you are using it! I thought it was too complicate to document it properly, so I am really happy that you got your hands into it and could exploit it Smile

BWT, there are significant updates in the linker. The current version "module_linker" supports any kind of 8 kb mapper, and has some extra support for calls between banks, but it's also harder to use.

If anyone is interested on it, is in:
https://github.com/MartinezTorres/sdcc_msx

and do not hesitate to ask for questions, or improvements.

By Bengalack

Master (192)

Bengalack's picture

23-05-2020, 10:18

"real 256kb ROMs" - I've been wondering about that. One thing is to make the software and get the rom-file assembled, and maybe get it emulated in megaram-cartridges/mappers. But what are your options when it comes to physical copies of a 64kb+ game or "megarom"? Where to go or who to turn to, and would it be costly to make (produce an end-user product)?

By geijoenr

Master (180)

geijoenr's picture

23-05-2020, 11:08

salutte that is quite interesting,
I currently do manual bank switching and I am realizing that when you hit the limit of 32kb of CODE some sort of linker support is necessary to go further to switch pages without hangs.

I think I will incorporate your linker into my engine as well.

By salutte

Expert (108)

salutte's picture

23-05-2020, 11:19

I'm happy it works! I have it thorougly ingrained in my "framework", but I think that the approach done by samsaga2 is excellent, where he took the linker and the basic bank switching utilities in msxhal.c and msxhal.h, and this makes it easier to integrate into own productions.

I'm still feeling a little bit uneasy by the need to manually select banks, and often I'm inclined to modify sdcc to enable completely free bank to bank calls, but this would complicate the workflow significantly, and the current linker is good enough for most cases.

By geijoenr

Master (180)

geijoenr's picture

23-05-2020, 11:30

salutte,
I have a modified version of sdcc that accepts a bank N parameter and emits rel files in segment CODE_N. I need to wrap my head around your code, but I have the feeling that should be enough to avoid explicit manual switching.

https://github.com/retrodeluxe/sdcc-msx

By salutte

Expert (108)

salutte's picture

23-05-2020, 12:11

I see, the linker in my repo allocates modules (i.e., c files) into banks automatically.

If you don't do anything to a module, it will be placed in page A (0x4000-0x5FFF), and placed in the 1st segment of the rom.

If you aim to run, e.g., the PSG module in page B, you must do it something like this:

#include 
USING_MODULE(psg,PAGE_B);
//this indicates to the linker that the code of the psg.c file can be placed in any segment of the rom, but it will be used in page B (0x6000-0x7FFF).

Then, to use a psg function, the usual way to call it is the following one:

void audio_isr() {
    uint8_t oldSegmentPageB = mapper_load_module(psg, PAGE_B);
    // This ensures that the segment that contains psg is mapped to the page B addresses.
    PSG_init();    
    ayr_spin();
    ayFX_spin();
    PSG_syncRegisters();
    mapper_load_segment(oldSegmentPageB, PAGE_B);
    // here we restore the segment that was mapped in page B previously.
}

A current shortcut is:

CALL_PAGE( psg, PAGE_B,  PSG_init());
// This will call the PSG_init function which is defined in psg.c.

Also, a novelty is that you can know at which rom segment will be placed a module:

MODULE_SEGMENT(psg,PAGE_B);

There are many limitations, i.e., a function in page B can not call a function from another module that is also mapped in page B, So interaction between modules is somewhat limited and must be done carefully. Modules can not be mapped in different pages (e.g, in the previous case, psg must always be placed in PAGE_B or else the addresses will not be consistent.

THe linker catches several, but not all, possible missuses.

By geijoenr

Master (180)

geijoenr's picture

23-05-2020, 12:34

I see, you use the linker to find those indicators.

The way I see it once you are modifying or adding a new linker; then going one step further and making it totally transparent is not that difficult. e.g you can have long jumps across pages handled by the linker.

While processing the relocations you can replace the actual address of the symbol with a call somewhere else where the bank is switched before doing the actual jump, and revert back on return.

By geijoenr

Master (180)

geijoenr's picture

23-05-2020, 12:44

I currently do something quite simpler than your solution, but works well enough for data. All banks are linked on the same location and you can split the code in different segments using the build system:

include $(CONFIG_ROM)

LOCAL_RES_DIR := ./res
include $(BUILD_RESOURCES)

LOCAL_ROM_NUM_PAGES := 2
LOCAL_PAGE_1_SRC_FILES := swap1.c
LOCAL_PAGE_2_SRC_FILES := swap2.c

LOCAL_ROM_NAME := test
LOCAL_SRC_FILES := main.c logic.c anim.c scene.c
include $(BUILD_ROM_ASCII8

Then set the page before reading the data, and restore when done.

sys_ascii_set(PAGE_SPRITES);
spr_copy_pattern_set(PATRN_BAT, bat, bat_color);
sys_ascii_restore();

When doing the same with code is way more involved, because you can have nested calls to other places... including builtin sdcc functions like _multint or _modint, so I don't even try to do it manually.

Page 1/4
| 2 | 3 | 4