Forum > FPC development

RISCV32 Embedded -> Adding Microcontroller

(1/2) > >>

kupferstecher:
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_microcontrollers

A 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~

PascalDragon:
Please report bugs for each of these issues and maybe an additional one for officially adding the CH32V307 (if you want), that references the other three as requirements.

kupferstecher:
OK, I will file the bug reports.


--- Quote from: PascalDragon on May 26, 2022, 04:40:43 pm ---and maybe an additional one for officially adding the CH32V307 (if you want), that references the other three as requirements.

--- End quote ---

Yes, I wanted to wait until I got it working so far.
What is the proper way of providing the changes? Just the modified files, or together with the version of the unmodified ones? I don't really know the git workflow.

Laksen:
The part about interrupts should be pretty easy to do with a modification to the compiler. We did something similar for interrupt handling on ARM by using the interrupt; procedure directive

kupferstecher:
I created the bug reports:
https://gitlab.com/freepascal.org/fpc/source/-/issues/39737
https://gitlab.com/freepascal.org/fpc/source/-/issues/39738
https://gitlab.com/freepascal.org/fpc/source/-/issues/39739


--- Quote from: Laksen on May 26, 2022, 09:05:15 pm ---The part about interrupts should be pretty easy to do with a modification to the compiler. We did something similar for interrupt handling on ARM by using the interrupt; procedure directive

--- End quote ---
In my understanding other riscv32 microcontrollers don't have a user mode (but do have interrupts), so also don't need/support MRET. This maybe should be considered.

Navigation

[0] Message Index

[#] Next page

Go to full version