Hello,
currently I try to use fpc on a risc-v 32bit microcontroller, namely the CH32V307 from WCH. Therefor I ported the c header file to pascal and modified the fpc source as described in the wiki:
https://wiki.freepascal.org/TARGET_Embedded#Adding_new_microcontrollersA very basic program is working now, but there are issues, point 1 is the most important.
1. Interrupts
Functions/procedures are returned with the assembler command "JALR" and fpc also uses this command for interrupts, but there it should be the "MRET" command instead. Could that be implemented? I'm not sure if this a special case for this microcontroller. The command is mentioned in the risc-v specification in "Volume II: Privileged Architecture". It seems interrupts automatically change the mode from user to machine mode which has to do with memory protection, and MRET switches the mode back.
For testing I added the "MRET" in inline assembler at the end of the interrupt handler and it works. But then the stackframe and pushed registers have to be cleaned up manually in inline assembler as well, and that of course is not suitable in 'productive code'.
2. Inline Assembler
The inline assembler seems not to support any pseudo instructions like LA, LI, CSRW which makes a 'translation' of startup code that is written in assembler a bit difficult. Also it seems not all register name aliases are working, e.g. the alias "zero" for X0. And in the used register list in the end of an asm section aliases that were accepted in code didn't work.
asm lui t0, 0x06 end['x5']; // t0 is alias of x5
3. Stack pointer address
The stack address is defined in the linker script providing a symbol. The linker script is generated in the file compiler/systems/t_embed.pas with the following line:
Add('_stack_top = 0x' + IntToHex(srambase+sramsize-1,4) + ';');
As far as I understand the microcontroller only allows 32bit alligned memory access, so I had to change it to
Add('_stack_top = 0x' + IntToHex(srambase+sramsize-4,4) + ';');
Now I'm not sure what is the best way to fulfill this without breaking existing code. In t_embed.pas it could be distinguished between each controller, but that would perspectively blow up the file. The offset could also be adjusted in the controllers startup code, where the stack pointer is initialized. But then it would differ from the original startup code making future porting of other devices more difficult. Or it could be changed to -4 for all devices, perhaps it doesn't break any compatibility, but just wastes 3 byte for devices that would support byte allignment? Or is the -1 even wrong, as a a 32bit access (riscv32) to (srambase+sramsize-1) would result in an access including the 3 bytes outside of the defined SRAM region?
Thanks!
Regards~