mercredi 4 mars 2026

SDCC Z80 crt0.s & __GSINIT

Until now, I've been using SDCC without fully mastering its compilation and linking process. For simple applications on the Z80 processor, it usually worked fine, even if I sometimes encountered code that didn't behave exactly as I expected. By making simple workarounds in my C code, I could easily bypass the issue. But this time, the situation is different.

Indeed, I need to test the functionality of the Z80-style SIO that I am currently developing for an FPGA. Therefore, I need to be as confident as possible in the code produced by the compiler.

So I became interested in this 'famous' crt0.s initialization file. I have to admit that I had already looked into the matter but remained quite skeptical about how it works. Mainly regarding the method of organizing the different memory segments managed by SDCC.

No matter how I modified the order of the segments, the memory mapping never actually changed. As a result, I remained somewhat unclear on this subject. My code still worked, so it didn't really bother me. But now, it was time to address the issue. Along with the segment problem, there was also the matter of initializing the 'famous' global variables, especially if they need to be set to a specific value at application startup.

The 'famous' directives concerning memory segments in the crt0.S file :

And the correct result in this example :

Actually, I declared my code to start at 0x0110 and the data at 0x2000 because I have 8KB of program space available starting from address 0x0000, and the RAM starts at 0x2000. The output from the linking procedure correctly shows the __GSINIT routine located in the code area.

However, and this is where the problem lies, until I understood the various issues and their causes, I could never get this __GSINIT code to be present in the code segment—it always ended up in the data segment.

This __GSINIT procedure is supposed to contain the initialization code for global variables. So until now, I was initializing these variables directly in my code. I couldn't have them properly set BEFORE the program started. That's why I sometimes had to modify my code, fully understanding why the initialization wasn't happening at startup, but having absolutely no idea why I couldn't change this behavior.

It took me a few hours to understand the underlying problem, fix it, and finally refine the crt0.s code to place the segments in the right locations and write the correct initialization sequence for global variables.

And I must say that AI was of no help whatsoever in finding the root problem. I had to search for hours on the internet without finding an answer to this issue. And yet, there are plenty of people struggling with this!

In short, the problem is actually quite simple to solve. Once done, the logic behind the segments becomes very easy to understand and define.

After half a sleepless night, I finally have knowledge of this matter. Now I can move forward with testing the SIO...

Aucun commentaire:

Enregistrer un commentaire