CH32V003 and Flash alias address - Page 1
Forum section: electronics / general

author: rhodges
author_rank: Frequent Contributor
timestamp: August 17, 2024, 04:25:48 pm
content: This is not a problem, but a question that has been nagging me for a while.In the CH32V003 datasheet and reference manual, the address for the 16K of Flash is 0x08000000 and this is the address that I use with wlink to program the Flash. This is also the address area that I use with the 64-byte Flash erase and block program functions. So I would expect that this would be the "normal" address for my code.But the linker script I am using (I forgot where I found it) gives a flash address of zero:Code:MEMORY{FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 16KRAM (xrw) : ORIGIN = 0x20000000, LENGTH = 2K}Both the datasheet state that the area at 0x00000000 is "Aliased to Flash or system memory depending on software configuration". But I can't seem to find any more information on that.I am not happy with my code "just working fine" because of a configuration setting I can't find. I would like to get advice on whether it would be best to ignore it or change my linker script to 0x08000000 to be sure. Any other opinions on this? Thanks.

author: zilp
author_rank: Frequent Contributor
timestamp: August 17, 2024, 06:31:25 pm
content: I don't think that the remapping is documented anywhere. But it doesn't really matter, the "code flash" is mapped to 0 by default, and gets executed from there on reset, and that's what is relevant for the linker. That there is a second copy in the address space doesn't matter, and what addresses the programmer has to write to the registers of the flash controller is also irrelevant for the linker.

author: ataradov
author_rank: Super Contributor
timestamp: August 17, 2024, 10:28:19 pm
content: This is a leftover from the system being STM32 clone. In "STM32" version of the design you can select to boot from the bootloader (system) or from the flash. The actual physical address for the flash is 0x08000000. And depending on the BOOTx pin values, either boot ROM or the flash is mapped at 0. The CPU always executes from 0, so it will run either your program or the ROM.

author: rhodges
author_rank: Frequent Contributor
timestamp: August 17, 2024, 10:45:34 pm
content: Thank you."If the CH32V documentation is unclear, read the STM32 manual..."UPDATE:Okay, I see in the CH32V003 manual 16.5 "User option bytes", there is a bit START_MODE to choose between:0: Boot from user area1: Boot from BOOT area (default)Maybe this is part of the answer? But it does not seem right that the default would map the chip BOOT code to zero.I guess I will leave it alone for now. Thanks again!

author: SiliconWizard
author_rank: Super Contributor
timestamp: August 17, 2024, 10:52:10 pm
content: True for a lot of the CH32V MCUs, often you'll find complementary info in the STM32 manuals.The CH32V003 has a bootloader in ROM and can "boot" either from it or from Flash directly (depending not on a pin on this chip IIRC, but on a config bit). Either is mapped at address zero for execution/read access, but you can't *write* Flash at this address.

author: HwAoRrDk
author_rank: Super Contributor
timestamp: August 18, 2024, 09:49:25 am
content: Quote from: SiliconWizard on August 17, 2024, 10:52:10 pmIndeed.I have resorted to referring to the STM32F103 documentation when the CH32V003 docs weren't clear.Quote from: SiliconWizard on August 17, 2024, 10:52:10 pmActually, the 2K bootloader area is not ROM, but just another flash area. You can write to it with the WCH-LinkUtility.In fact, IIRC it doesn't even come programmed with a bootloader from factory; you have to write it there yourself with their 'IAP' UART bootloader (available from their GitHub) if you want to use the WCHISPTool utility.Or you can write your own bootloader and put it there.

author: zilp
author_rank: Frequent Contributor
timestamp: August 18, 2024, 11:12:01 am
content: Quote from: HwAoRrDk on August 18, 2024, 09:49:25 amWhat does "not at runtime" mean here?! I mean, all the programming is done via the debug interface, and I would guess that the vendor stuff also executes code on the MCU for programming, so ... what exactly determines that it is "not at runtime"?!

author: HwAoRrDk
author_rank: Super Contributor
timestamp: August 18, 2024, 12:34:09 pm
content: Quote from: zilp on August 18, 2024, 11:12:01 amAs in, not in-application. That is, where code running on the MCU is what is re-programming the flash memory - as opposed to programming done via the SWIO debug interface (which does not actually involve, as far as I know, any code executing on the MCU).However, I take back the statement that bootloader flash cannot be programmed at runtime. Upon checking the reference manual, it seems I was wrong. The reference manual documents a BOOT Key register (FLASH_BOOT_MODEKEYR) that allows you to unlock the bootloader area for writing. So I guess it will work similarly to regular programming of flash, but instead specifying a different address (e.g. 0x1FFFF000).Edit:No, wait, I might be wrong again (and perhaps correct the first time). It seems the FLASH_BOOT_MODEKEYR register is simply used only to allow the bootmodeto be changed - i.e. to specify that at next reset you want to the MCU to alias 0x00000000 to either user flash (0x08000000) or bootloader flash (0x1FFFF000). That is the only thing WCH's HAL code uses it for anyway.

author: zilp
author_rank: Frequent Contributor
timestamp: August 18, 2024, 01:25:03 pm
content: Quote from: HwAoRrDk on August 18, 2024, 12:34:09 pmI mean, I ultimately have no idea what the vendor stuff does for programming, but at least the available documentation of the debug interface doesn't mention any way to write to the flash without executing code. And also, given that you can write to the flash by executing code via the debug interface, it would seem weird if they made the die larger to add a dedicated flash programming state machine rather than just repurpose the exiting stuff that can do the job already!?Quote from: HwAoRrDk on August 18, 2024, 12:34:09 pmYeah. I mean, I haven't tried it, and the documentation obviously isn't always entirely correct, but that's also part of why I was surprised that you couldn't program the boot flash "at runtime" specifically.Quote from: HwAoRrDk on August 18, 2024, 12:34:09 pmHaha ... well, yeah, the documentation isn't exactly clear, I guess one would have to just try ...

author: SiliconWizard
author_rank: Super Contributor
timestamp: August 18, 2024, 08:18:57 pm
content: Quote from: HwAoRrDk on August 18, 2024, 09:49:25 amAh, so it's like the CH32V3xx. The latter has 28KB flash dedicated to the bootloader. It does come preprogrammed from factory, though, and yes, you can reprogram this area. Can't tell for the CH32V003.

author: rhodges
author_rank: Frequent Contributor
timestamp: August 18, 2024, 10:39:54 pm
content: I just dumped the boot code, but objdump won't disassemble a binary. Does anyone have a disassembler handy?Argh. The forum won't let me post with a .bin file, so I renamed it .hex

author: zilp
author_rank: Frequent Contributor
timestamp: August 18, 2024, 10:51:54 pm
content: Quote from: rhodges on August 18, 2024, 10:39:54 pmCode:riscv64-unknown-elf-objdump -b binary -m riscv -D boot_code.hex

author: HwAoRrDk
author_rank: Super Contributor
timestamp: August 19, 2024, 03:53:07 pm
content: Quote from: SiliconWizard on August 18, 2024, 08:18:57 pmAh, you're right, it is pre-programmed. Don't remember why I had the idea it wasn't. I just dumped the bootloader from a CH32V003 that I've never touched the boot area on, and it matches what rhodges dumped.The command line that zilp posted will perform the disassembly. But one note: I suspect unless you are using objdump from MounRiver-supplied toolchain, it will not correctly decode WCH's proprietary XW instruction set extension. So all those instructions (and there are quite a few) will mistakenly come out as floating-point operations (which the CH32V003 obviously doesn't have!). I found a decoder for XW instructions here:https://xw.macyler.moe/

author: rhodges
author_rank: Frequent Contributor
timestamp: August 19, 2024, 04:46:08 pm
content: I was wondering about those FP instructions in the listing. "This must be data embedded in code? What is this?"Thanks for pointing that out.I saw the pointer to the USART in there, as well as the unlock codes, FWIW.

author: HwAoRrDk
author_rank: Super Contributor
timestamp: August 20, 2024, 02:19:42 pm
content: I have been nerd-sniped into some reverse engineering of the disassembly of the bootloader.A question to those more in-the-know: the "zext.b" instruction (zero-extend byte?) is part of the 'B' RISC-V extension (specifically, Zbb), correct? Which the CH32V003 (i.e. QingKe V2) does not support. So therefore any such instructions present in the disassembly have been mis-interpreted and should instead (as far as I can tell) be "andi rd, rs, 255"? That is, an instruction to truncate/mask a word in a register to the LSB?

author: HwAoRrDk
author_rank: Super Contributor
timestamp: August 20, 2024, 03:17:47 pm
content: From what little I have seen so far I can say right now that the 'IAP' bootloader on WCH's GitHub (https://github.com/openwch/ch32v003/tree/main/EVT/EXAM/USART_IAP/CH32V003_IAP) isnotexactly the same as the 'factory' bootloader that I pulled off one of my CH32V003F4P6 (TSSOP20) chips. There are similarities, but they don't have the same behaviour. For instance:- 'IAP' checks pin PC0 and resets straight into user code if pin is low; factory bootloader doesn't do anything at all with GPIOC.- Different UART baud rates - 'IAP' runs at 460800, factory appears to be 115384 (unsure about this, USART_BRR = 0xD0).- Factory bootloader seems to read the CHIPID for some purpose, 'IAP' doesn't appear to.I wonder if newer chips contain changed bootloader code and I just have early chips (date code 4123). I don't see any kind of version number in the flash - unless the four zero bytes after the watermark ASCII string "MCU ISP & WCH.CN" at the end of bootloader flash is a version number of zero...

author: westfw
author_rank: Super Contributor
timestamp: August 21, 2024, 02:38:13 am
content: Quote115384 is about 0.2% away from 115200... (closer than the built-in oscillator is likely to be?)

author: SiliconWizard
author_rank: Super Contributor
timestamp: August 21, 2024, 04:09:27 am
content: Quote from: HwAoRrDk on August 20, 2024, 02:19:42 pmzext.b and andi rd, rs, 255 are the same instruction indeed:https://github.com/riscvarchive/riscv-code-size-reduction/issues/101So "misinterpreted" is up to... interpretation. You can consider in this particular case that zext.b is a pseudo-instruction.

author: brucehoult
author_rank: Super Contributor
timestamp: August 21, 2024, 04:33:25 am
content: Quote from: HwAoRrDk on August 20, 2024, 02:19:42 pmNo.Zbbadds onlysext.b,sext.h, andzext.h. Thezext.byou found is just an assembler alias ofandi, which of course the CH32V003's RV32E has, not an extension.(andzext.was an alias of Zba'sadd.uw)Try runningobjdump -Mno-aliases

author: brucehoult
author_rank: Super Contributor
timestamp: August 21, 2024, 04:48:07 am
content: Quote from: SiliconWizard on August 21, 2024, 04:09:27 amI took the "I found aZbbinstruction in CH32V003 code" to mean "It can't possibly actually bezext.b, so it must be some WCH custom instruction, and the code would have to have used anandiif it wanted to zero extend a byte".Which is wrong on two levels. Both thatzext.bis an alias forandi, but also that no manufacturer should be putting custom instructions into opcode space reserved for standard extensions and therefore no WCH (or any other) custom extension should be mistakenly disassembled as something like aZbbinstruction.The one exception to this is the political decision to call XTHeadVector a "custom extension" when in fact it is binary compatible with (uses the same opcode space and in fact 99% the same opcodes as) the official RVV 1.0 for a lot of interesting code. This was demonstrated once again when someone blogged about writing atolower()function in AVX-512 and I wrote the equivalent in RVV and ran exactly the same binary on the RVV 1.0 BananaPi F3 and the XTHeadVector LicheePi 4A and Milk-V Duo.https://lobste.rs/s/bfgsh6/tolower_with_avx_512

author: HwAoRrDk
author_rank: Super Contributor
timestamp: August 21, 2024, 12:24:27 pm
content: Quote from: westfw on August 21, 2024, 02:38:13 amThat's what I thought - supposed to be nominally 115200. Especially as the WCHISPTool apparently only allows setting a choice between 115200, 1M, and 2M for baud rate. Although, it's a fractional baud rate generator, so why couldn't they make it a value that gives exactly 115200?Quote from: brucehoult on August 21, 2024, 04:33:25 amAh, I see now. I was referring to theRISC-V Wikipedia articleand now I look again itonlymentionszext.h- must've skim-read too quickly.So I guess that technicallyzext.bisn't part of Zbb because it's just an alias forandi, but the alias was added to 'B' extension for completeness.Quote from: brucehoult on August 21, 2024, 04:48:07 amNo, it wasn't so much that I thought it can't bezext.b- I realised it's an alias forandi- by "misinterpreted" I meant that I thought the disassembler should have output the un-aliasedandiinstruction because I hadn't told it that the architecture supported 'B' extension. But ifzext.bis fine for RV32EC and is just a matter of nomenclature, then I suppose it doesn't really matter.