Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RAM tutorial question #5

Open
gicking opened this issue Dec 23, 2018 · 2 comments
Open

RAM tutorial question #5

gicking opened this issue Dec 23, 2018 · 2 comments

Comments

@gicking
Copy link
Contributor

gicking commented Dec 23, 2018

hi lujji,

thanks a lot for your excellent tutorial! I really marvel at your minimalist approach :-) The RAM example worked out of the box and is easy to understand :-) However, I still have some questions / remarks:

  1. do I understand correctly that this approach requires that the RAM routines don't use absolute jumps within RAM or calls between RAM routines...? Because the .map file shows e.g. RAM0 in flash at 0x81E6. If my understanding is correct, how do you ensure that absolute jumps/calls within RAM are not used by SDCC?

  2. and if absolute jumps or calls within RAM are required for some reason, how about this (different) procedure (for example @ 0x00a0):

    a) link for RAM (-Wl-bRAM0=0x00a0) --> absolute addresses are ok, but in hexfile code is in RAM and is lost after reset (already verified)

    b) in hexfile move code segment from RAM to flash address --> is not lost after reset, but located at wrong address. I plan to add this "move" feature to hexfile_merger within the next few days

    c) copy to same RAM address as above just like you already do, but with an additional __at (0x00a0) for f_ram[] to ensure the correct address.

Optionally one could also reserve a buffer of sufficient size in RAM @ 0x00a0 (or wherever) via linker and only point *f_ram to that address in the main program.

The main issue I see is how to pass the parameters like link address and code length between the different tools/steps.

I understand that this is not minimalist anymore (sorry for that!). But is my understanding correct and, if yes, any idea how to perform this in a fool-proof way?

Thanks again for your great tutorials and have a great day! :-)

Regards,
Georg / gicking

@lujji
Copy link
Owner

lujji commented Jan 6, 2019

Hi Georg, glad you found it useful.

Usually, when executing from RAM the biggest problem with function calls is relative addressing. For example: you have functions f_ram() and f_flash(), where f_ram() is copied into RAM during start-up. Let's say at some point your RAM function calls a function from flash (and compiler knows nothing about our intentions to put f_ram() somewhere else). Since both functions reside in the same memory section, the compiler might use more compact relative addressing: instead of calling f_flash() by its absolute address (i.e. setting PC = f_flash_address) an offset will be used (PC = PC + some_offset). Now if we copy the resulting code into RAM, this will no longer work, since program counter is in a different place and some_offset will point to a wrong location.

I'm not sure if this explanation was necessary, but I just wanted to make sure that I understood your question correctly and that we're talking about the same thing :)

Now the thing about SDCC is that it always uses call/ret instructions regardless of the position. In other words, you're always using absolute calls, so the above example will work properly.

The situation is different with jumps though: a relative jump instruction takes a signed 8-bit offset, which won't take you far, so if your function is large enough, absolute jumps will be used. That will be an issue when executing from RAM, as you've already mentioned. Forcing the compiler to use relative jumps only and adding veneers when necessary would be a workaround, although I believe it's not possible with SDCC. Another workaround is the one you suggested: linking required sections in RAM and processing compiled objects with external tools. To be honest, I don't think any of these approaches are correct - RAM code should be handled by the compiler/linker to begin with. Perhaps Philipp [@spth] might give us some insight? The example in question is this one.

@spth
Copy link

spth commented Jan 6, 2019

I'm not an expert on linker stuff. Code generation emits absolute jumps / calls only. Then the peephole optimizer transforms them into relative ones where it can (this only happens for calls / jumps within the same function, as the peephole optimizer works function by function).

The linker fills in the absolute addresses for global / static variables, absolute jumps and calls. If you have a function that will only be executed from RAM, we'd need the linker to fill in the addresses as if the function was already there. Maybe specifiying a different code segment for that function (i.e. place it in a different source file and use --codeseg when compiling that file will help; if you want it in the same file as the other functions, using #pragma codeseg should do). Then use linker options, maybe -b or -g to tell the linker about the location of the function in RAM.

Philipp

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants