This is part 2 of the look at the GD32VF103 and the CH32V103. Microcontrollers with a RISC-V RV32IMAC core and STM32F103 compatible peripherals. As stated in the pervious article, their main difference is how the interrupts are handled. Of course, both can do interrupts as per RISC-V standard, the main issue is the fact the numbering is different. Nevertheless, on the GD32VF103 we also have a CLIC mode for interrupt handling, which I’ll use as we have to handle them separately anyways, due to the numbering issue. So, upon startup, we’ll have to detect what mcu we are running on and initialise it accordingly.
How will we tell them apart? The RISC-V standard described marchid
and mvendorid
registers that allow to identify the core we are running on.
According to the specification, the combination of mvendorid and marchid should uniquely identify the type of hart microarchitecture that is implemented.
The GD32VF103 uses a BumbleBee core by Nuclei, while the CH32V103 uses a core, which I believe is developed by WinChipHead themselves. Looking at the marchid
for the GD32, we see 0x80000022
. Notice the high bit is set. According to the RISC-V specifications, this indicates a commercial implementation, and the rest of the value is defined by the vendor, which is indicated by the mvendorid
register. When the high bit of the marchid
is not set, a non-zero value indicates an open source design registered with RISC-V International. When we look at the mvendorid
register, we see value 0x31e
. This register contains the JEDEC id of the vendor. The 7 least significant bits encode the entry, and the rest the page. Thus 0x31e >> 7 = 6, and 0x31e & 0x7f = 0x1e = 30. Looking at the JP106 table, this indicates Andes Technology Corporation. As the BumbleBee core was made by them in collaboration with Nuclei, this value is to be expected.
As for the CH32, we see this field is zero, and the vendor id has been set to 0x01020304. This is obviously not a valid JP106 id, and thus it appears this value violates the specifications. When I looked at STM32F103 clones with Cortex-M3 core, we’ve seen most clones have ARM in the ROMTABLE, rather then their own ID. The only exception was GigaDevice. It seems most manufacturers don’t bother registering with JEDEC. According to the RISC-V specifications, at the time of writing (of the specs) registering would be a one-time fee of US$500. Hardly a reason not to register for a chip manufacturer I would say. Nevertheless, it seems many Chinese MCU makers don’t.
An empty marchid would be valid according to the specification, indicating the field has not been implemented. While the values returned by the CH32V103 might not fully identify the core, the values for the GD32 do. Either way, since we are only interested in telling these two MCUs apart, we have enough information to do that. So, let’s have a look at some RISC-V assembly to detect what core we are running on
.equ GD32_MARCHID, 0x80000022 # Identifiers for GD32VF103 .equ GD32_MVENDORID, 0x0000031E # Identifiers for GD32VF103 .equ CH32_MARCHID, 0x00000000 # Identifiers for CH32V103 .equ CH32_MVENDORID, 0x01020304 # Identifiers for CH32V103 .extern _init_gd32 .extern _init_ch32 identify_chip: csrr a0, marchid # load the marchid into register a0 csrr a1, mvendorid # load the mvendorid into register a1 try_gd32: li a2, GD32_MARCHID # load GD32_MARCHID into register a2 bne a0, a2, try_ch32 # branch to try_ch32 if a0 != a2 li a2, GD32_MVENDORID # load GD32_MVENDORID into register a2 bne a1, a2, not_supported # branch to not_supported if a0 != a2 j _init_gd32 # GD32VF103 identified, jump to _init_gd32 try_ch32: # Check if we are running on a CH32V103 li a2, CH32_MARCHID bne a0, a2, not_supported li a2, CH32_MVENDORID bne a1, a2, not_supported j _init_ch32 # CH32VF103 identified, not_supported: j not_supported # Endless loop for unknown chip
This way we can identify the mcu we are running and and initialise it accordingly.