RISC-V compilation errors - mismatched libgcc? - Page 1
Forum section: electronics / general

author: HwAoRrDk
author_rank: Super Contributor
timestamp: February 15, 2023, 12:16:50 am
content: I am attempting to forge my own path in setting up a build environment for WCH CH32V003 RISC-V chips - that is, not using WCH's MounRiver or anything that comes with it. What I am using is thexPack RISC-V GCCdistribution for Windows (specifically, xpack-riscv-none-elf-gcc-12.2.0).But, I've hit a bit of a roadblock.When attempting to compile some code that does integer multiplication (e.g. something as simple asa = b * c), I'm getting a linking error:Code:ld.exe: error: ../lib/gcc/riscv-none-elf/12.2.0\libgcc.a(muldi3.o): mis-matched ISA string to merge 'i' and 'e'ld.exe: failed to merge target specific data of file ../lib/gcc/riscv-none-elf/12.2.0\libgcc.a(muldi3.o)What I'm wondering is, because the error message mentions "mis-matched ISA", is there somehow a mis-match in the architecture of my code and that of the libgcc it's trying to link? That is, GCC is using thewronglibgcc? If I go digging in the folder path that it gives for libgcc.a, I notice that particular library file seems to be a 'generic' one, and not one of the architecture-specific versions (e.g. 'rv32e', 'rv32i', etc.) residing in sub-folders. What also is of note is that thereisn'tone in existence for the architecture I'm specifying when compiling. So, is that why it's falling back to a 'generic' library?The command line options I'm compiling with are:Code:riscv-none-elf-gcc.exe -mabi=ilp32e -march=rv32ec_zicsr -msave-restore -misa-spec=2.2 -fdata-sections -ffunction-sections -fsigned-char -g -c main.c -o obj\Debug\main.oAs mentioned above, there isn't a libgcc for 'rv32ec_zicsr', but there is one for 'rv32ec'. What will changing to the latter affect? What am I gaining or losing with or without the Zicsr (Control and Status Register) extension?Also, on a related note, the QingKeV2 CPU manual from WCH says that it also features the 'XW' extension, but that appears to be non-standard. I'm guessing that's only available with the version of GCC they bundle with the MounRiver IDE? Seems like it just provides some extra 'compressed' versions of some instructions ("c.lbu/c.lhu/c.sb/c.sh/c.lbusp/c.lhusp/c.sbsp/c.shsp"), so the only impact would be on code size, right?

author: brucehoult
author_rank: Super Contributor
timestamp: February 15, 2023, 09:37:29 am
content: It's unsurprising that a generic gcc package doesn't include RV32EC/ILP32E libraries, as the CH32V003 is probably the only chip in existence implementing RV32E.Fair enough not wanting to use the MounRiver stuff, but I think you'll have to build your own libraries.It's easy to build your own toolchain fromhttps://github.com/riscv-collab/riscv-gnu-toolchain, either specifying a single arch and ISA, or following the "Build with customized multi-lib configure" section.QuoteNote that a number of those are in a standard extension that should be ratified maybe in July. I have no idea whether the opcodes are compatible!Also, there is WCH's fast interrupt hardware register saving feature. Assuming you poke the right CSRs to enable that, you can use it from a standard toolchain by declaring your interrupt handler as __attribute__((naked)) (no function prolog or epilog .. no register saving/restoring, no "ret") and putting an inline asm "mret" at the end.

author: GromBeestje
author_rank: Frequent Contributor
timestamp: February 15, 2023, 09:57:52 am
content: I have experienced similar problems,The problem lies the linker doesn't recognise "-march=rv32ec_zicsr" means it should link the "rv32ec" libraries.The solution would be to replace "-march=rv32ec_zicsr" with "-misa-spec=2.2 -march=rv32ec".Using the ISA specs version 2.2, means before _zicsr was split off, and thus it should still be able to compile the code,while the architecture is now set to rv32ec, causing the right libraries to be linked in.Edit: I see you already got isa spec 2.2, then you could just use -march-rv32ec I guessAnyways, building with "-march=rv32ec_zicsr" and linking with "--march=rv32ec" will work

author: HwAoRrDk
author_rank: Super Contributor
timestamp: February 15, 2023, 03:51:43 pm
content: Quote from: GromBeestje on February 15, 2023, 09:57:52 amAh, so later versions of the spec include Zicsr in the RV32EC specification by default? I only thought to include the -misa-spec=2.2 because the QingKeV2 CPU manual specifically says it implements v2.2.I'm a bit confused about the ISA specification versions actually. GCC only takes three possible options for the 'isa' option: 20190608, 20191213, 2.2 (with the middle being default). Which is the latest/earliest?Quote from: GromBeestje on February 15, 2023, 09:57:52 amThis turned out to be the solution. In actual fact, I realised I did not have any 'arch' or 'abi' options being passed at the linking stage at all! I needed to pass both -march=rv32ec and -mabi=ilp32e on the linker command line. The -misa-spec=2.2 option seemed not to be necessary or relevant to the linker. Confirmed in the .map file that it is now showing it is linking in rv32ec/ilp32e/libgcc.a(muldi3.o).Quote from: brucehoult on February 15, 2023, 09:37:29 amThanks, I will bear that in mind.

author: GromBeestje
author_rank: Frequent Contributor
timestamp: February 15, 2023, 08:07:02 pm
content: In another thread were I was talking about some debugging issues on riscv (turns out generating assembly listing generates broken DWARF)The _zicsr / isa 2.2 was discussed on the rv32i rather then the rv32e. But I suppose the zicsr part is the same.https://www.eevblog.com/forum/microcontrollers/risc-v-compiling-and-debugging/msg4682741/#msg4682741

author: brucehoult
author_rank: Super Contributor
timestamp: February 15, 2023, 11:21:05 pm
content: Quote from: HwAoRrDk on February 15, 2023, 03:51:43 pmThe opposite. Zicsr was split off from RV32I etc before ratification in mid 2019 so that extremely basic cores e.g. deeply embedded in an FPGA could be RV32I/RV32E compliant without having CSR instructions.Quote2.2 is the oldest, from May 8 2017, more than two years before the ISA was ratified and the base ISAs frozen forever.https://github.com/riscv/riscv-isa-manual/tree/eb86a900f418a5436b8e31abc0563be3cb402a16Arbitrarily incompatible changed are allowed in draft versions of the base ISAs or any extension before ratification, but never allowed after.

author: HwAoRrDk
author_rank: Super Contributor
timestamp: February 17, 2023, 07:44:03 pm
content: I've been trying to load my compiled code onto the WCH CH32V003 eval kit board, but with no success.I'm able to successfully compile to an ELF file and have used objcopy to produce a hex file. I have the eval board connected to the WCH-LinkE programmer and, using the WCH-LinkUtility software (not trying OpenOCD just yet) can successfully identify the CH32V003 chip and read the flash (when it's blank).However, if I write my hex file to it, it appears to do so successfully, but the chip stops responding to the programmer, and I can't do anything like identify or read flash (error is "Failed,the chip type is not matched or status of chip is wrong!"). The only thing that gets it back is to do a 'Clear All Code Flash - By Power Off' command from the Target menu.I'm not sure what I'm doing wrong here, or where the problem lies. Can't determine at this point whether something about my code is wrong, or if the programming is not working correctly. At first I thought it was a stupid mistake with the hex file not having the proper address offset of 0x8000000, so I changed that, but no dice. (In retrospect, looking at the datasheet, it appears address range 0x0-0x7FFFFFF is aliased to either 'code' (0x8000000) or 'system' (i.e. bootloader; 0x1FFFF000) flash areas, so I guess that shouldn't have mattered? Although I'm not sure how you tell which one it's aliased to. Maybe that's what the 'Address' selection drop-down in the WCH-LinkUtility software does.)Does anybody have a basic 'blinky' firmware hex file for the CH32V003 that I could try to flash, just to eliminate programming problems?

author: HwAoRrDk
author_rank: Super Contributor
timestamp: February 17, 2023, 11:16:12 pm
content: I figured out the problem. I made a minor mistake in my code which had a very unexpected side-effect.Narrowed it down to something with some code I was using to initialise the GPIO port D for use with USART1, which of course happens to also be where the SWIO pin lives, on PD1.What was happening was that when I was reconfiguring pins PD5 and PD6, I was masking out the CNF and MODE bits in CFGLR for those pins, and then setting the appropriate values for use as TX and RX (push-pull output, input with pull-up) - but I had made a mistake! When masking, I forgot to invert the mask, which meant I was setting the entirety of the rest of the CFGLR register to zero.So why did that stop SWIO on PD1 from working? A value of zero for a pin's CNF bits makes it an analog input, and when a pin is set as an analog input the logic-level schmitt trigger input on the pin is disabled! And so now the chip is deaf to any attempt by the WCH-Link programmer to talk to it! Which explains the behaviour I was seeing.I am surprised it is possible to 'neuter' the SWIO functionality like that. I would have assumed that the SWIO function was 'hard-coded' to the pin. But I guess it kind of makes sense, given the programmer can initiate SWIO functions at any time without needing to reset the chip (indeed, I don't even have the NRESET pin PD7 connected to anything), so there's no opportunity for PD1 to default to SWIO upon or during reset or anything.

author: brucehoult
author_rank: Super Contributor
timestamp: February 18, 2023, 01:39:18 am
content: Quote from: HwAoRrDk on February 17, 2023, 11:16:12 pmOn low pin count devices (CH32V003 is available in an 8 pin package, and even 20 isn't a lot) you don't want pins you can't use for arbitrary purposes.For example, on the ATTiny85 (etc) in the 8 pin package one of the pins is usually used for RESET. To program the chip you hold RESET low while using SPI on the other pins to send data to program into flash. Given reasonable values of pull-ups etc on the various pins, you can do this even while the chip is mounted on a production board with all the pins used. But if you need 6 I/O signals then you can reprogram the RESET just like any other pin. And then you can't physically re-program the chip like that any more. (there is another method, unsoldering the chip and using a "high voltage programmer")

author: HwAoRrDk
author_rank: Super Contributor
timestamp: February 18, 2023, 02:13:04 am
content: I didn't mean 'hard-coded' as in 'dedicated function', I meant as in the pin is always an input to SWIO, regardless of what else you're using it for. Like in the same way that when you configure a GPIO pin as output, you can still read its input value.Although, I guess that would mess with that pin's capability as an analog input, especially in terms of power usage. But they could then have just not made it an analog-capable pin.

author: jnk0le
author_rank: Regular Contributor
timestamp: February 21, 2023, 06:47:36 pm
content: Quote from: brucehoult on February 15, 2023, 09:37:29 amThose are most probably from Zce v0.50 or older.None is compatible with what was ratified.

author: robots
author_rank: Contributor
timestamp: June 06, 2023, 09:24:05 pm
content: Quote from: jnk0le on February 21, 2023, 06:47:36 pmYou are right. I have tried to understand those instructions and they are from 0.5 zce:https://github.com/riscv/riscv-code-size-reduction/releases/download/V0.50-TOOLCHAIN-DEV/Zce_spec.v0.50.toolchain.release.pdfPage 26MRS studio emits these instructions, they are present in binary code coming from WCH. Ghidra understands them not.

author: SiliconWizard
author_rank: Super Contributor
timestamp: June 06, 2023, 10:14:55 pm
content: Note that the zicsr extension was enabled by default in GCC (didn't require explicitely setting it in -march) up to GCC 11.x. I have skipped GCC 12.x for RISC-V so, not sure about it, but in GCC 13.1, it's now required to be set explicitely.

author: brucehoult
author_rank: Super Contributor
timestamp: June 07, 2023, 04:22:13 am
content: Quote from: SiliconWizard on June 06, 2023, 10:14:55 pmThat's not quite right.If you include "f", "d", or "g" in the -march string then _zicsr is included automatically, as an FPU implies several CSRs are implemented and used, including the ones containing fields enabling and disabling it, holding the dynamic rounding mode, recording the dirty and exception statuses etc.You only need to add _zicsr yourself if you're using just I, IM, IC, IMAC etc without FP and then of course only if the core you are using has CSRs.https://godbolt.org/z/3qWsWjbaW

author: SiliconWizard
author_rank: Super Contributor
timestamp: June 07, 2023, 04:58:30 am
content: That's nice to know. But if you don't enable FP, you're going to run into what I just said. So, just to help those who may run into this, had a project that compiled successfully, updated GCC and suddenly it doesn't recognize CSR instructions anymore.Just the base RV32I enabled CSRs by default up to GCC 11.x. Not so starting with GCC 12.x.You can see for yourself using godbolt. Up to GCC 11.3.0, CSRs are supported with for instance '-march=rv32i -mabi=ilp32'.Starting with GCC 12.x, not so, you need to add _zicsr (unless sure as you showed, you have enabled other extensions that themselves include zicsr.)

author: brucehoult
author_rank: Super Contributor
timestamp: June 07, 2023, 06:00:19 am
content: Quote from: SiliconWizard on June 07, 2023, 04:58:30 amThat is because pre-ratification RV32I included the CSR instructions ... Zicsr didn't exist then.In what was ratified in July 2019 -- and will be forever more unchanged -- RV32I does not include CSR instructions.Pre-ratification ISAs or extensions are subject to arbitrary change during the development process, and have no guarantee of any backward compatibility at all.You can use the "-misa-spec=2.2" option with gcc. Valid values are "2.2" (which was published 20170507), "20190608" (frozen ratification candidate), and "20191213" (the first ratified version)In ISA version 2.2 the CSR instructions are included in RV32I/RV64I. In the others they are not.20191213 is the default from gcc 12 on, unless you build the compiler with a different option for "--with-isa-spec". Versions up to 11.3 defaulted to 2.2 but can be explicitly set to 20190608 or 20191213.The -misa-spec option itself was introduced in gcc 11 (with all three options). Before that only 2.2 was available.So, in short:gcc 10: RISC-V 2.2gcc 11: RISC-V 2.2 default, accepts 20190608 or 20191213.gcc 12: RISC-V 20191213 default, accepts 2.2 or 20190608 (also gcc 13 and current trunk)