KarolS / millfork

Millfork: a middle-level programming language targeting 6502- and Z80-based microcomputers and home consoles
https://karols.github.io/millfork/
GNU General Public License v3.0
253 stars 21 forks source link

Potential Support Params #42

Open oziphantom opened 4 years ago

oziphantom commented 4 years ago

So I'm looking to make a Tactics game for the Commodore 64 and Commodore 128, but I want to also be able to port it to the MSX2 and possibly other architectures (68K, 65816, x86). So this seems to be the best fit, however I need a full 512K GMod2 supported, and 512K MSX2 cart support. Is this system capable of handling such carts. With it me being able to have Cart resident code and code that is copied to RAM, possibly compressed with say Exomizer to get every last drop of space out of it. But then the 128 version might have the "ROM banks" execute from its extra RAM and it loads data from disk etc.

KarolS commented 4 years ago

So there's a lot to unpack here, I'll try to answer each question you might have:

So I'm looking to make a Tactics game for the Commodore 64 and Commodore 128, but I want to lso be able to port it to the MSX2 and possibly other architectures (68K, 65816, x86).

C64, C128, MSX2 – there should be no problem. There are no premade libraries for interfacing with MSX hardware, but this leaves you freedom to implement them yourself as you see fit.

68K, x86 – sorry, Millfork does not support these at the moment. There's an experimental x86 support, but it uses the tiny memory model, emits COM executables and at best it allows you to quickly port small text-mode programs from CP/M to DOS. For these platforms I'd recommend C.

65816 – it's complicated, but I wouldn't recommend Millfork here either. The only 65816 platform that anyone successfully got working was SuperCPU, which, with its 16-bit address space, is more of a weird 65C02 rather than real 65816 platform like SNES or IIgs. For 65816, I think going pure assembly is the best way forward, unless you want to deal with inefficient and buggy C compilers.

So this seems to be the best fit, however I need a full 512K GMod2 supported, and 512K MSX2 cart support. Is this system capable of handling such carts.

One of the design goals of Millfork was being able to easily handle most common cartridge types. I checked out GMod2 and it looks like it should work fine.

The general idea is you want to:

See these for inspiration:
separate files, loading from disk:
https://github.com/KarolS/millfork/blob/master/examples/c64/multifile.ini
https://github.com/KarolS/millfork/blob/master/examples/c64/multifile.mfk
multiple cartridge banks, running code directly from there:
https://github.com/KarolS/millfork/blob/master/include/nes_mmc4.ini
https://github.com/KarolS/millfork/blob/master/examples/nes/nestest_mmc4.mfk

With it me being able to have Cart resident code and code that is copied to RAM, possibly compressed with say Exomizer to get every last drop of space out of it. But then the 128 version might have the "ROM banks" execute from its extra RAM and it loads data from disk etc.

That should work. You will have to write separate loading/unpacking/copying routines for each platform and separate configuration files. If the code will be split into the same segments on each platform, then usually you shouldn't need anything else.

If you have any further questions, feel free to ask.

oziphantom commented 4 years ago

Ok. How do I teach Milfork how to swap banks?

Is it possible to get another "listing" output that lists the source file lines and the memory addresses of code? something along the lines of main: file studio.mfx:1 ;line:71:stdio.mfk 1:71:080d LDA #$E 1:71:080f JSR putchar I have a source code level debugger https://csdb.dk/release/index.php?id=178008 which needs to know where each line sits in RAM, and I would rather not have to make an assembler to work out where each part is ;)

KarolS commented 4 years ago

How do I teach Milfork how to swap banks?

Millfork doesn't swap banks automatically. You need to do it manually. Any generic automated solution would risk being suboptimal.

If by "bank swapping" you wanted to ask how to call a function that was defined in another segment, well, you just call it, but if that segment wasn't containing that function at runtime (wasn't loaded, wasn't banked in, etc.), then oops. In the MMC4 case, I defined a function set_prg_bank that let's you switch PRGROM banks and therefore access functions from another segment. In a more complicated case, if you want to call a function from another function in an overlapping segment, then you need to write a trampoline that resides in another segment and does all the swapping back and forth.

If you wanted to ask how you swap banks on a cartridge, then that depends on the cartridge itself. I'm not familiar with GMod2 or MSX2 cartridges.

Is it possible to get another "listing" output that lists the source file lines and the memory addresses of code?

Currently, you can use -s -fsource-in-asm. The format is missing memory addresses for each instruction, they're given only for functions.
You can also get a VICE-compatible symbol list with -g.

I have a source code level debugger https://csdb.dk/release/index.php?id=178008

I haven't used that, it looks very interesting, thanks! I'll try it out and add support for it in the next release if possible.

oziphantom commented 4 years ago

I see hours of me going "why does this fail" and then eventually working out I'm calling "this function" which is not visible at the time of calling because it is in another bank and the code just jumps into random data. Also on the 128 it could be in the other RAM bank. having say a call_long and having compiler know when things are not in parts that are visible at the same time. Maybe just throws a warning? since the banks occupy the same address space, the check could check if the addresses are in the same "area" but not the same final address. i.e say func is in 01:8956 and other_func is in 03:9A23 it can detect that I'm in a an area that has overlap XX:8000 - XX:9FFFF and that the the 01 and 03 don't match? Since we can output a 24bit file, are we able to get the "bank" byte of a function, so I can work out where it is in the cart?

It would be a huge convenience if one could make say Macros that force set the bank, and the optimizer knows to look for them. so if I do set_bank(4) call_func set_bank(4) call_other_func the optimizer knows the second set_bank is redundant and removes it. Giving me piece of mind without paying the penalty.

A trampoline is fine, but how do I construct a trampoline that can take "what ever params" the function wants and bounce. Is there a concept of "set these params" then I can call_trampoline separately?

Speaking of Other 128 bank, what are the guidelines for the 128 MMU usage, does milfork need 'Shared Memory' always enabled? both upper -and lower, just lower, 1K 4K etc There was nothing mentioned on the 'commodore-programming-guide.md' Side note there is a typo in 'You can use a variety of tools to perform that task, for example the c1531 tool shipped with the VICE emulator.' its c1541.