(classic) Complete gameboy support #1287
Comments
|
Re banking. It looks like sdcc supports Within z88dk we use I think placing all z88dk library code within the always paged in bank makes life easier so we'll only end up with user code being manually placed within banks. Conventionally, GBDK used the
Where Function address can be populated using a regular z80asm patch expression. The bank could be populated by an appmake stage as follows:
This does, however feel fragile - I'd be worried about functions having clashing addresses in different banks (which will happen for functions at the start of a bank unless we fudge the first usable address within a bank). Thus, I think we will need z80asm support for this - effectively a way of parsing the section name of symbol and allowing that to be used within source code. Thoughts, @pauloscustodio ? |
|
Re Banking. This matches the way that it is done on YAZ180 with the Using a signed bank definition allows easy relative bank calls (i.e. call a bank above, or a bank below the current bank), and zero refers to the current bank. But this is not baked in concrete. Happy to align to whatever becomes the standard way to do this. Would it be sensible to make the addressing somewhat linear with a The patching mechanism for banks looks quite like the REL format, with the bitmap attached to indicate items (call, jp, etc) to be patched. |
|
Re Banking. Two options below. Please comment or suggest alternatives. Extend z80asm to handle 24- or 32-bit addresses, where the lower 16-bits are the address seen by the CPU, and the upper 8- or 16-bits are the bank id (platform dependent, e.g. value to be written to the bank register).
This solution is easy to implement in z80asm; all the infrastructure is in place, we just need to handle the 32-bit addresses gracefully. Let the linker automatically resolve banked calls. Same as above, use the upper 16-bit of a 32-bit address as the bank id. Create new opcodes for banked calls that reserve space in the object code for the call to the
This solution is a bit more complex, but gives additional flexibility in arranging the code in banks. |
|
I quite like option 1 since it offers the compiler (or assembler author) more control as to how to invoke a function - I do suspect there may well be many ways of actually invoking the trampoline (for example via a The automatic conversion in this case:
would be incorrect if func2 was a C function with parameters (the parameters wouldn't be at the expected stack offset). |
Extend z80asm to handle 24- or 32-bit addresses, where the lower 16-bits are the address seen by the CPU, and the upper 8- or 16-bits are the bank id (platform dependent, e.g. value to be written to the bank register). CALL, JP, ... need to accept the 32-bit address and ignore the upper 16-bits. For the Spectrum 128K (which I know better than the GameBoy), one could write section xxx1 ; name is not relevant org $00C000 ; select page 0 at address $C000 public func1 func1: ... section xxx2 org $01C000 ; select page 1 at address $C000 extern func1 ... call banked_call ; platform-dependent function that switches banks and calls the function defp func1 ; patch in a 24-bit address (Spectrum 128k); use defq for a 32-bit address As a side-effect of this change, z80asm no longer emits warnings for 16-bit values out of range.
|
Option 1 implemented in z80asm_32bit_addresses branch. Please let me know of any issues, |
|
Thank you Paulo, I'll give it a try this evening I hope. |
|
The z80asm changes works for my requirements - I've successfully had a banked call execute and return a value. I don't think losing the range checking is too much bother so please feel free to merge. |
That’s correct Inside the linker Adding bank and address after the call became EDIT:
What does that mean? gbdk-n followed the return in e, de, hlde SDCC uses on gbz80 |
The z88dk libraries and the z80 targets use l, hl, dehl so for the libraries to work with zsdcc (gbz80) 8/16 bit functions have the return value in de and hl. |
|
Does that also mean that you have |
|
We haven’t changed anything in sdcc regarding gbz80. However sccz80 supports fastcall and callee functions for gbz80 |
|
Well, if I was nearly done with implementing |
|
Well, back to this. I could try to implement
|
|
I'm all over the place at the moment, working on far too many things at the same time, so I've not had a chance to fix the other issue - apologies. Yes, There's two cases to consider for mixing/matching. Libraries and user code. Although it's theoretically possible to mix-and-match compilers for user-code in classic it's not particularly well tested and there are caveats (there's a wiki page somewhere but I can't find it at the moment) Getting library interop working is important though, to get sdcc to work together with the libraries I had to make the following modifications:
As a explanatory note, for library routines, sdcc enters via the labels My feeling is that the priority order is:
|
No problem, it's not urgent, I was just playing around a bit with it and noticed that stuff.
Is that a general rule for sdcc or for gbz80 specifically? 3 is part of 1, sdcc user guide explicitly says that Do I have to care about the upper byte of chars or can I just push trash into them? The equivalient to ld a, d
ld d, h
ld h, a
ld a, e
ld e, l
ld l, awhich are 6 bytes and 24 cycles wasted. push de
push hl
pop de
pop hlit would be 4 bytes and 54 cycles wasted. ldhl sp, #2
ld a, (hl+)
ld h, (hl)
ld l, aMy main interest is indeed to have a e,de,hlde And this is probably a bug z88dk/libsrc/target/gb/gbdk/mode.asm Lines 26 to 31 in bd1442a |
It's not desirable but came out of necessity for the interop - the z80 1b pushing was only fixed a couple of years ago. | 3 is part of 1, sdcc user guide explicitly says that __smallc is left to right and that 1 byte arguments are passed as 2 bytes, with the value in the lower byte. Though it does not say anything about the return value. Do they never return <2B? I suspect that everything in the libraries is rounded up to be 2b return value (of which only 1b is of significance). | The equivalient to ex de, hl is... Yes, it's not pretty, for single parameter entry it's just 3 bytes since we just need to do Oh yes, thank you. |
|
It looks like
which is a weird way of doing
So it really only needs different return registers. Implementing fastcall would be trivial, the return would probably only need to care about It's not designed for changing registers of calling conventions dynamically, but I can maybe treat them as completely new calling conventions (smallc_return, smalc_fastcall). |
The following need to be completed for a full target:
joystick()maps into GBDK joypad codeCRT_FONTioctl()[ ] Get MBF32 running (tricky due to lack of JP P/M/PO)[ ] Hires plotting via APA- accessible via gbdk, so hold offThe following should be done:
The text was updated successfully, but these errors were encountered: