So the retro Z80 DIY project is in full flight with GPIO, LCD screen etc. Another PCB is in the works with period PIO, CTC and DART.
ASM coding is "ok" right now, I write some test code to get some hardware working and test a few different modes etc. Then I collect up all the scattered routines and put them into a "xx_driver.asm". As it progresses each new test application uses library routines used and tested by the last one. It's still "tiny" < 1000 lines of ASM.
But it's getting to the point where I can't hide in "Level 1 ASM" code with registers and a little stack. I need to start with isolating functions, parameters, return values and stop relying on my register file as my main state. Its just too damn hard tracking register use, register mutation and register restore once you put mode 2 (or any!) interrupts into play. I still can't even decide if sub-routines should be responsible for restoring state or not. To me it seems as though sub-routines storing and restoring state "just in case" the parent was using it is wasteful ... is the parent wasn't. Should a "blocking delay" function which uses the accumulator "PUSH/POP AF" for example. I mean if the parent is using A or F and is relying on it, then sure. But is it not better that the caller assumes the callee will corrupt the register file and take its own measures?
Load A, B, D, E
Call something
Reload A, B, D, E again
Call something
Reload A, B, D, E again
etc.
I need C. Badly. I know I am about to tie myself in knots in ASM, so I need to start prioritising getting a C compiler in the toolchain.
I opened the can of worms with Chat GPT and regretted it. It's probably not going to help much. It offered me "sdcc". I checked it out, compiled hello-world.c and checked the files produced.
To my horror it was dumping everying at 0x0000 and up, code, constants, everything. All over the page 0 RST/ISR blocks and all over my 0x100-0x2000 ROM code area.
Actually that wasn't the horror, the horror was noting there were nearly 40 different segments declared in the map file. I tried the "easy options" like "--code-loc" and "--data-loc" but that only moved the "main" segments to those addresses, the other 32 of them remained at 0x0000 and up.
So like all these toolkits and retro application suites, the probably started out to be what I wanted, but have had so many features and so much opinion added to them over the years that they are no longer "DIY Homebrew hardware" compatible. They are far more suited to "Insert Retro Kit Product w/ full CP/M support" build and run projects.
I need something far more low level. Far simpler. I need a compiler that doesn't have 35 different ways to store variables but has just 3 or 4. The "classics", .bss, .text etc. Although it is my choice if I choose that nomeclature or not.
I thought I was on to a winner when I noticed the "ASM" output it produced was "tamable" by changing just the labels that contained anything in the symbol file it might produce working code if I just lifted the 16 bytes of ASM in question, the addresses might just line up.
My assembler doesn't like that format though. So I need to find, setup and use an ASM that does, then use a linker to merge the two objects into a ROM image with "dd".
I am using sjasmplus for Z80 ASM. It's not "GNU ASM" compatible. That's fine. I looked at the GNU route and recoiled away. If you want opinionated ... GNU. Nothing is simple. If you want to go the "GNU Stack" route, it involves the full GNU devel stack, configure, automake, autoconf, gcc, ld and so on and so forth. It will produce "elf" outputs and your "boot.asm" will need to OBEY all that that entails if you want "ELF" binaries from a GNU C compiler to run. Including any parts of the memory mapping which it dictates and are too annoying to change. This "IS" the stack used by many MCUs today. Just a bit too complex from where I am right now.
I don't think I want to go that far. Not with this project. It's perfume on a pig.
I want to explore how it may have been done in the early days. Before you even got to the likes of CPM and BASIC. I realise both where mostly written in ASM, but C was around. I want the simple view from necessity to solve the problems I presently face. The next step not the 1990s solutions, the 1970s solutions.
I envision a blunt simple C compiler than turns C code into Z80 ASM. When I declare a "const" it can go in "rom_data". If I declare a variable it can put it in "ram_data". If it has an initial value a two stage will be required. Someway to load "ram_data" from "rom_data" initial values at "user land boot".
I don't need 48 different segments and full C99 compliance. I just want to make writing some code easier. Just simple things. A managed call structure which handles pass by register, pass by stack or pass by memory pointer. Maintains CPU state between nested calls. Auto 16bit indirect load and store so I don't have to write the ASM for them. Just the basics

What are my best options?
Right now I am exploring z88dk which is another huge z80 dev kit project, but it attracted me as it has a "Homebrew hardware how-to" near the top of it's docs, which on a quick scan suggests it supports much simpler memory models and configurations like mine. Down side is... after an hour, I still hadn't been able to download it, install all the tools required to build it.... solutions which are larger than the project its self are hard to swallow.