Hi Basil,
it's of course easier with an environment that has a data stack - not
messing up your return stack is a bit more difficult.
One option is splitting the problem in two parts:
* change the LDF part in place,
* push a ret
* load buf from the stack to X and push it to the return stack
* push the opcode for LD A,(*,x)
* change the old stack location of buf to a JRA (-*) to skip whatever is
in between LDF and LD A,(buf, x)
The entry address for the string of executable code needs to be
calculated from SP for the CALL (Y). Before restore registers etc you
need to pop 4 bytes from the return stack (e.g. 2x POPW X).
I admit that this procedure is a but messy, but this is hacking a
machine, so what else can it be?
Kind regards,
Thomas
On 09.03.20 15:40, Basil Hussain wrote:
Hi Thomas,
If you need reentrance it's also possible to turn the far address and
a bit of the buffer address on the stack into a piece of code
(Addr_MSB = 0xAF, MSB_buf = 0x81) and call it using the Y register.
Documenting such a solution would be "interesting" (an example for
adding "missing" addressing modes that way is here
<https://github.com/TG9541/stm8ef/blob/4a5053236605787c23c322ea39a51a1072f3db35/forth.asm#L892>,
and a bit about how SDCC represents parameters on the stack is here
<https://github.com/TG9541/stm8ef/wiki/STM8S-Programming#combining-c-and-assembly>).
That's an interesting idea. So, if I am understanding correctly, I
could avoid the use of static temporary variables (which is what is
preventing re-entrancy) by instead converting the stack arguments of
my function to code, and directly executing that?
Let's see: to turn the 32-bit 'addr' variable into a "LDF ($1234, X),
A" instruction, we make use of the unused high byte and set it to
0xA7, the opcode for that LDF operation, and the following three bytes
remain as the source address: 0x00027F80 => 0xA7027F80. Okay, cool.
But I don't see how the 'buf' variable could be turned into an "LD A,
($1234, X)" instruction, because that needs 3 bytes, and the variable
is only 2!
Also, I need to *precede* the LDF with an LD instruction (remember,
the purpose of my function is to write the contents of buf to addr,
not the opposite), but if my function has the signature of
"flash_write_block(const uint32_t addr, const void *buf)", the
arguments on the stack will be ordered as addr then buf, which is the
opposite of what's needed.
And where would a return instruction get put? I am assuming this
stack-as-code stuff would get invoked like this:
ldw y, sp ; copy stack pointer value
addw y, #0x04 ; offset to the first function arg
call (y) ; make the jump
Therefore necessitating a RET instruction to be a final part of the
code on the stack. How?
Regards,
Basil
_______________________________________________
Sdcc-user mailing list
Sdcc-user@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/sdcc-user
_______________________________________________
Sdcc-user mailing list
Sdcc-user@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/sdcc-user