Author Topic: ch32v307, risc-v minicore with ethernet  (Read 34149 times)

0 Members and 2 Guests are viewing this topic.

Offline hydrabus

  • Contributor
  • Posts: 13
  • Country: fr
    • HydraBus open source multi-tool hardware
Re: ch32v307, risc-v minicore with ethernet
« Reply #50 on: December 24, 2022, 10:25:50 am »
Quote
That's amazing!

In a first view, the toolchain only have a subset of multilib activated...
Your team are planning to add more multilib options?

Or only the necesary to support the wch devices?

What do you mean by "add more multilib options?" ?

Like explained in https://github.com/hydrausb3/riscv-none-elf-gcc-xpack/releases/tag/12.2.0-1 (it is a fork from original https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack/releases/tag/v12.2.0-1)
All multilib are enabled using bash ${HOME}/Work/riscv-none-elf-gcc-xpack.git/scripts/helper/build.sh --develop --disable-tests --linux64 --win64
So it support all RISC-V with addition of special interrupt("WCH-Interrupt-fast") for WCH RISC-V and nothing has been removed

« Last Edit: December 24, 2022, 10:31:00 am by hydrabus »
 

Offline martinribelotta

  • Regular Contributor
  • *
  • Posts: 56
  • Country: ar
  • A camel is a horse designed by a committee
    • Martin Ribelotta design services
Re: ch32v307, risc-v minicore with ethernet
« Reply #51 on: December 24, 2022, 05:13:53 pm »
Quote
That's amazing!

In a first view, the toolchain only have a subset of multilib activated...
Your team are planning to add more multilib options?

Or only the necesary to support the wch devices?

What do you mean by "add more multilib options?" ?

Like explained in https://github.com/hydrausb3/riscv-none-elf-gcc-xpack/releases/tag/12.2.0-1 (it is a fork from original https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack/releases/tag/v12.2.0-1)
All multilib are enabled using bash ${HOME}/Work/riscv-none-elf-gcc-xpack.git/scripts/helper/build.sh --develop --disable-tests --linux64 --win64
So it support all RISC-V with addition of special interrupt("WCH-Interrupt-fast") for WCH RISC-V and nothing has been removed

The original xpack-riscv-none-elf 12.2.0-1 have this content in {install prefix}/xpack-riscv-none-elf-gcc-12.2.0-1/riscv-none-elf/lib/:

Code: [Select]
crt0.o         libgfortran.spec  libnosys.a          libsupc++.a       rv32eac   rv32i            rv32iaf_zicsr   rv32im            rv32imc          rv64ia           rv64ic          rv64ima           rv64imc          sim.specs
ldscripts      libgloss.a        libsemihost.a       libsupc++_nano.a  rv32ec    rv32ia           rv32ic          rv32ima           rv32imfc_zicsr   rv64iac          rv64ifc_zicsr   rv64imac          rv64imfc_zicsr
libc.a         libgloss_nano.a   libsim.a            nano.specs        rv32em    rv32iac          rv32ifc_zicsr   rv32imafc_zicsr   rv32imfdc_zicsr  rv64iafc_zicsr   rv64ifdc_zicsr  rv64imafc_zicsr   rv64imfdc_zicsr
libc_nano.a    libg_nano.a       libstdc++.a         nosys.specs       rv32ema   rv32iafc_zicsr   rv32ifdc_zicsr  rv32imafdc_zicsr  rv32imfd_zicsr   rv64iafdc_zicsr  rv64ifd_zicsr   rv64imafdc_zicsr  rv64imfd_zicsr
libg.a         libm.a            libstdc++.a-gdb.py  rv32e             rv32emac  rv32iafdc_zicsr  rv32ifd_zicsr   rv32imafd_zicsr   rv32imf_zicsr    rv64iafd_zicsr   rv64if_zicsr    rv64imafd_zicsr   rv64imf_zicsr
libgfortran.a  libm_nano.a       libstdc++_nano.a    rv32ea            rv32emc   rv32iafd_zicsr   rv32if_zicsr    rv32imaf_zicsr    rv64i            rv64iaf_zicsr    rv64im          rv64imaf_zicsr    semihost.specs

And your compilation have only this:

Code: [Select]
crt0.o     libc.a       libg.a         libgfortran.spec  libgloss_nano.a  libm.a       libnosys.a     libsim.a     libstdc++.a-gdb.py  libsupc++.a       nano.specs   rv32emac  rv64imac        sim.specs
ldscripts  libc_nano.a  libgfortran.a  libgloss.a        libg_nano.a      libm_nano.a  libsemihost.a  libstdc++.a  libstdc++_nano.a    libsupc++_nano.a  nosys.specs  rv32ima   semihost.specs

You can verify the bundled multilib libraries with -print-multi-lib gcc option:

Code: [Select]
$> /opt/xpack-riscv-none-elf-gcc-12.2.0-1-wch/bin/riscv-none-elf-gcc -print-multi-lib
.;
rv32emac/ilp32e;@march=rv32emac@mabi=ilp32e
rv32ima/ilp32;@march=rv32ima@mabi=ilp32
rv64imac/lp64;@march=rv64imac@mabi=lp64

$> /opt/xpack-riscv-none-elf-gcc-12.2.0-1/bin/riscv-none-elf-gcc -print-multi-lib
.;
rv32e/ilp32e;@march=rv32e@mabi=ilp32e
rv32ea/ilp32e;@march=rv32ea@mabi=ilp32e
rv32eac/ilp32e;@march=rv32eac@mabi=ilp32e
rv32ec/ilp32e;@march=rv32ec@mabi=ilp32e
rv32em/ilp32e;@march=rv32em@mabi=ilp32e
rv32ema/ilp32e;@march=rv32ema@mabi=ilp32e
rv32emac/ilp32e;@march=rv32emac@mabi=ilp32e
rv32emc/ilp32e;@march=rv32emc@mabi=ilp32e
rv32i/ilp32;@march=rv32i@mabi=ilp32
rv32ia/ilp32;@march=rv32ia@mabi=ilp32
rv32iac/ilp32;@march=rv32iac@mabi=ilp32
rv32iaf_zicsr/ilp32f;@march=rv32iaf_zicsr@mabi=ilp32f
rv32iafc_zicsr/ilp32f;@march=rv32iafc_zicsr@mabi=ilp32f
rv32iafd_zicsr/ilp32d;@march=rv32iafd_zicsr@mabi=ilp32d
rv32iafdc_zicsr/ilp32d;@march=rv32iafdc_zicsr@mabi=ilp32d
rv32ic/ilp32;@march=rv32ic@mabi=ilp32
rv32if_zicsr/ilp32f;@march=rv32if_zicsr@mabi=ilp32f
rv32ifc_zicsr/ilp32f;@march=rv32ifc_zicsr@mabi=ilp32f
rv32ifd_zicsr/ilp32d;@march=rv32ifd_zicsr@mabi=ilp32d
rv32ifdc_zicsr/ilp32d;@march=rv32ifdc_zicsr@mabi=ilp32d
rv32im/ilp32;@march=rv32im@mabi=ilp32
rv32ima/ilp32;@march=rv32ima@mabi=ilp32
rv32imaf_zicsr/ilp32f;@march=rv32imaf_zicsr@mabi=ilp32f
rv32imafc_zicsr/ilp32f;@march=rv32imafc_zicsr@mabi=ilp32f
rv32imafd_zicsr/ilp32d;@march=rv32imafd_zicsr@mabi=ilp32d
rv32imafdc_zicsr/ilp32d;@march=rv32imafdc_zicsr@mabi=ilp32d
rv32imc/ilp32;@march=rv32imc@mabi=ilp32
rv32imf_zicsr/ilp32f;@march=rv32imf_zicsr@mabi=ilp32f
rv32imfc_zicsr/ilp32f;@march=rv32imfc_zicsr@mabi=ilp32f
rv32imfd_zicsr/ilp32d;@march=rv32imfd_zicsr@mabi=ilp32d
rv32imfdc_zicsr/ilp32d;@march=rv32imfdc_zicsr@mabi=ilp32d
rv64i/lp64;@march=rv64i@mabi=lp64
rv64ia/lp64;@march=rv64ia@mabi=lp64
rv64iac/lp64;@march=rv64iac@mabi=lp64
rv64iaf_zicsr/lp64f;@march=rv64iaf_zicsr@mabi=lp64f
rv64iafc_zicsr/lp64f;@march=rv64iafc_zicsr@mabi=lp64f
rv64iafd_zicsr/lp64d;@march=rv64iafd_zicsr@mabi=lp64d
rv64iafdc_zicsr/lp64d;@march=rv64iafdc_zicsr@mabi=lp64d
rv64ic/lp64;@march=rv64ic@mabi=lp64
rv64if_zicsr/lp64f;@march=rv64if_zicsr@mabi=lp64f
rv64ifc_zicsr/lp64f;@march=rv64ifc_zicsr@mabi=lp64f
rv64ifd_zicsr/lp64d;@march=rv64ifd_zicsr@mabi=lp64d
rv64ifdc_zicsr/lp64d;@march=rv64ifdc_zicsr@mabi=lp64d
rv64im/lp64;@march=rv64im@mabi=lp64
rv64ima/lp64;@march=rv64ima@mabi=lp64
rv64imac/lp64;@march=rv64imac@mabi=lp64
rv64imaf_zicsr/lp64f;@march=rv64imaf_zicsr@mabi=lp64f
rv64imafc_zicsr/lp64f;@march=rv64imafc_zicsr@mabi=lp64f
rv64imafd_zicsr/lp64d;@march=rv64imafd_zicsr@mabi=lp64d
rv64imafdc_zicsr/lp64d;@march=rv64imafdc_zicsr@mabi=lp64d
rv64imc/lp64;@march=rv64imc@mabi=lp64
rv64imf_zicsr/lp64f;@march=rv64imf_zicsr@mabi=lp64f
rv64imfc_zicsr/lp64f;@march=rv64imfc_zicsr@mabi=lp64f
rv64imfd_zicsr/lp64d;@march=rv64imfd_zicsr@mabi=lp64d
rv64imfdc_zicsr/lp64d;@march=rv64imfdc_zicsr@mabi=lp64d

The ch32v30x have a QingKe v4f (imafc) core and ch569 have v3a (maybe a typo for v4a?) that claim be a rv32imac.

In any case, your toolchain lacks the c and f extentions for rv32 (have rv32emac, rv32ima and rv64imac but not rv32imac or rv32imacf) that be crucial in many cases (c is a big improve of code size reduction and f is essential if you work with floating point primitives)

I'm investigating what is the problem with the scripts that generate this behaviour in your compilation...
« Last Edit: December 24, 2022, 05:20:35 pm by martinribelotta »
 

Offline martinribelotta

  • Regular Contributor
  • *
  • Posts: 56
  • Country: ar
  • A camel is a horse designed by a committee
    • Martin Ribelotta design services
Re: ch32v307, risc-v minicore with ethernet
« Reply #52 on: December 24, 2022, 05:26:23 pm »
Quote
That's amazing!

In a first view, the toolchain only have a subset of multilib activated...
Your team are planning to add more multilib options?

Or only the necesary to support the wch devices?


What do you mean by "add more multilib options?" ?

Like explained in [url]https://github.com/hydrausb3/riscv-none-elf-gcc-xpack/releases/tag/12.2.0-1[/url] (it is a fork from original [url]https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack/releases/tag/v12.2.0-1[/url])
All multilib are enabled using bash ${HOME}/Work/riscv-none-elf-gcc-xpack.git/scripts/helper/build.sh --develop --disable-tests --linux64 --win64
So it support all RISC-V with addition of special interrupt("WCH-Interrupt-fast") for WCH RISC-V and nothing has been removed


The original xpack-riscv-none-elf 12.2.0-1 have this content in {install prefix}/xpack-riscv-none-elf-gcc-12.2.0-1/riscv-none-elf/lib/:

Code: [Select]
crt0.o         libgfortran.spec  libnosys.a          libsupc++.a       rv32eac   rv32i            rv32iaf_zicsr   rv32im            rv32imc          rv64ia           rv64ic          rv64ima           rv64imc          sim.specs
ldscripts      libgloss.a        libsemihost.a       libsupc++_nano.a  rv32ec    rv32ia           rv32ic          rv32ima           rv32imfc_zicsr   rv64iac          rv64ifc_zicsr   rv64imac          rv64imfc_zicsr
libc.a         libgloss_nano.a   libsim.a            nano.specs        rv32em    rv32iac          rv32ifc_zicsr   rv32imafc_zicsr   rv32imfdc_zicsr  rv64iafc_zicsr   rv64ifdc_zicsr  rv64imafc_zicsr   rv64imfdc_zicsr
libc_nano.a    libg_nano.a       libstdc++.a         nosys.specs       rv32ema   rv32iafc_zicsr   rv32ifdc_zicsr  rv32imafdc_zicsr  rv32imfd_zicsr   rv64iafdc_zicsr  rv64ifd_zicsr   rv64imafdc_zicsr  rv64imfd_zicsr
libg.a         libm.a            libstdc++.a-gdb.py  rv32e             rv32emac  rv32iafdc_zicsr  rv32ifd_zicsr   rv32imafd_zicsr   rv32imf_zicsr    rv64iafd_zicsr   rv64if_zicsr    rv64imafd_zicsr   rv64imf_zicsr
libgfortran.a  libm_nano.a       libstdc++_nano.a    rv32ea            rv32emc   rv32iafd_zicsr   rv32if_zicsr    rv32imaf_zicsr    rv64i            rv64iaf_zicsr    rv64im          rv64imaf_zicsr    semihost.specs

And your compilation have only this:

Code: [Select]
crt0.o     libc.a       libg.a         libgfortran.spec  libgloss_nano.a  libm.a       libnosys.a     libsim.a     libstdc++.a-gdb.py  libsupc++.a       nano.specs   rv32emac  rv64imac        sim.specs
ldscripts  libc_nano.a  libgfortran.a  libgloss.a        libg_nano.a      libm_nano.a  libsemihost.a  libstdc++.a  libstdc++_nano.a    libsupc++_nano.a  nosys.specs  rv32ima   semihost.specs

You can verify the bundled multilib libraries with -print-multi-lib gcc option:

Code: [Select]
$> /opt/xpack-riscv-none-elf-gcc-12.2.0-1-wch/bin/riscv-none-elf-gcc -print-multi-lib
.;
rv32emac/ilp32e;@march=rv32emac@mabi=ilp32e
rv32ima/ilp32;@march=rv32ima@mabi=ilp32
rv64imac/lp64;@march=rv64imac@mabi=lp64

$> /opt/xpack-riscv-none-elf-gcc-12.2.0-1/bin/riscv-none-elf-gcc -print-multi-lib
.;
rv32e/ilp32e;@march=rv32e@mabi=ilp32e
rv32ea/ilp32e;@march=rv32ea@mabi=ilp32e
rv32eac/ilp32e;@march=rv32eac@mabi=ilp32e
rv32ec/ilp32e;@march=rv32ec@mabi=ilp32e
rv32em/ilp32e;@march=rv32em@mabi=ilp32e
rv32ema/ilp32e;@march=rv32ema@mabi=ilp32e
rv32emac/ilp32e;@march=rv32emac@mabi=ilp32e
rv32emc/ilp32e;@march=rv32emc@mabi=ilp32e
rv32i/ilp32;@march=rv32i@mabi=ilp32
rv32ia/ilp32;@march=rv32ia@mabi=ilp32
rv32iac/ilp32;@march=rv32iac@mabi=ilp32
rv32iaf_zicsr/ilp32f;@march=rv32iaf_zicsr@mabi=ilp32f
rv32iafc_zicsr/ilp32f;@march=rv32iafc_zicsr@mabi=ilp32f
rv32iafd_zicsr/ilp32d;@march=rv32iafd_zicsr@mabi=ilp32d
rv32iafdc_zicsr/ilp32d;@march=rv32iafdc_zicsr@mabi=ilp32d
rv32ic/ilp32;@march=rv32ic@mabi=ilp32
rv32if_zicsr/ilp32f;@march=rv32if_zicsr@mabi=ilp32f
rv32ifc_zicsr/ilp32f;@march=rv32ifc_zicsr@mabi=ilp32f
rv32ifd_zicsr/ilp32d;@march=rv32ifd_zicsr@mabi=ilp32d
rv32ifdc_zicsr/ilp32d;@march=rv32ifdc_zicsr@mabi=ilp32d
rv32im/ilp32;@march=rv32im@mabi=ilp32
rv32ima/ilp32;@march=rv32ima@mabi=ilp32
rv32imaf_zicsr/ilp32f;@march=rv32imaf_zicsr@mabi=ilp32f
rv32imafc_zicsr/ilp32f;@march=rv32imafc_zicsr@mabi=ilp32f
rv32imafd_zicsr/ilp32d;@march=rv32imafd_zicsr@mabi=ilp32d
rv32imafdc_zicsr/ilp32d;@march=rv32imafdc_zicsr@mabi=ilp32d
rv32imc/ilp32;@march=rv32imc@mabi=ilp32
rv32imf_zicsr/ilp32f;@march=rv32imf_zicsr@mabi=ilp32f
rv32imfc_zicsr/ilp32f;@march=rv32imfc_zicsr@mabi=ilp32f
rv32imfd_zicsr/ilp32d;@march=rv32imfd_zicsr@mabi=ilp32d
rv32imfdc_zicsr/ilp32d;@march=rv32imfdc_zicsr@mabi=ilp32d
rv64i/lp64;@march=rv64i@mabi=lp64
rv64ia/lp64;@march=rv64ia@mabi=lp64
rv64iac/lp64;@march=rv64iac@mabi=lp64
rv64iaf_zicsr/lp64f;@march=rv64iaf_zicsr@mabi=lp64f
rv64iafc_zicsr/lp64f;@march=rv64iafc_zicsr@mabi=lp64f
rv64iafd_zicsr/lp64d;@march=rv64iafd_zicsr@mabi=lp64d
rv64iafdc_zicsr/lp64d;@march=rv64iafdc_zicsr@mabi=lp64d
rv64ic/lp64;@march=rv64ic@mabi=lp64
rv64if_zicsr/lp64f;@march=rv64if_zicsr@mabi=lp64f
rv64ifc_zicsr/lp64f;@march=rv64ifc_zicsr@mabi=lp64f
rv64ifd_zicsr/lp64d;@march=rv64ifd_zicsr@mabi=lp64d
rv64ifdc_zicsr/lp64d;@march=rv64ifdc_zicsr@mabi=lp64d
rv64im/lp64;@march=rv64im@mabi=lp64
rv64ima/lp64;@march=rv64ima@mabi=lp64
rv64imac/lp64;@march=rv64imac@mabi=lp64
rv64imaf_zicsr/lp64f;@march=rv64imaf_zicsr@mabi=lp64f
rv64imafc_zicsr/lp64f;@march=rv64imafc_zicsr@mabi=lp64f
rv64imafd_zicsr/lp64d;@march=rv64imafd_zicsr@mabi=lp64d
rv64imafdc_zicsr/lp64d;@march=rv64imafdc_zicsr@mabi=lp64d
rv64imc/lp64;@march=rv64imc@mabi=lp64
rv64imf_zicsr/lp64f;@march=rv64imf_zicsr@mabi=lp64f
rv64imfc_zicsr/lp64f;@march=rv64imfc_zicsr@mabi=lp64f
rv64imfd_zicsr/lp64d;@march=rv64imfd_zicsr@mabi=lp64d
rv64imfdc_zicsr/lp64d;@march=rv64imfdc_zicsr@mabi=lp64d

The ch32v30x have a QingKe v4f (imafc) core and ch569 have v3a (maybe a typo for v4a?) that claim be a rv32imac.

In any case, your toolchain lacks the c and f extentions for rv32 (have rv32emac, rv32ima and rv64imac but not rv32imac or rv32imacf) that be crucial in many cases (c is a big improve of code size reduction and f is essential if you work with floating point primitives)

I'm investigating what is the problem with the scripts that generate this behaviour in your compilation...


I found the cause of the miltilib lack...
https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack/discussions/6

When you use the flag --develop this restrict the multilib options due to improve the compilation time.

You can remove --develop flag on your build and reupload the toolchain? This is very usefull for many peoples like me that maintain a separated startup/interrupt code due to the lack of "wch-interrupt-fast" implementation in a vanilla xpack-riscv-gcc
 

Offline PavelS

  • Newbie
  • Posts: 1
  • Country: ru
Re: ch32v307, risc-v minicore with ethernet
« Reply #53 on: December 26, 2022, 08:56:33 am »
Hello! I need to use alternative pins for uart5 (problems with cross connection). TX-B.4 RX-B.5 vs TX-C.12 RX-D.2 the original.
Using MounRiver studio with standard libraries.
Code:
Code: [Select]
(config USART)

    GPIO_PinRemapConfig(GPIO_PartialRemap_USART5, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART5, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    USART_InitStructure.USART_BaudRate = 115200;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;

    USART_Init(UART5, &USART_InitStructure);
    USART_ITConfig(UART5, USART_IT_RXNE, ENABLE);

    NVIC_InitStructure.NVIC_IRQChannel = UART5_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    USART_Cmd(UART5, ENABLE);


But this code didn't work.

In the original PIN configuration, everything worked correctly.
Please help me :)
« Last Edit: January 09, 2023, 11:51:47 am by PavelS »
 

Offline hydrabus

  • Contributor
  • Posts: 13
  • Country: fr
    • HydraBus open source multi-tool hardware
Re: ch32v307, risc-v minicore with ethernet
« Reply #54 on: January 05, 2023, 07:12:18 pm »
Quote
That's amazing!

In a first view, the toolchain only have a subset of multilib activated...
Your team are planning to add more multilib options?

Or only the necesary to support the wch devices?


What do you mean by "add more multilib options?" ?

Like explained in [url]https://github.com/hydrausb3/riscv-none-elf-gcc-xpack/releases/tag/12.2.0-1[/url] (it is a fork from original [url]https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack/releases/tag/v12.2.0-1[/url])
All multilib are enabled using bash ${HOME}/Work/riscv-none-elf-gcc-xpack.git/scripts/helper/build.sh --develop --disable-tests --linux64 --win64
So it support all RISC-V with addition of special interrupt("WCH-Interrupt-fast") for WCH RISC-V and nothing has been removed


The original xpack-riscv-none-elf 12.2.0-1 have this content in {install prefix}/xpack-riscv-none-elf-gcc-12.2.0-1/riscv-none-elf/lib/:

Code: [Select]
crt0.o         libgfortran.spec  libnosys.a          libsupc++.a       rv32eac   rv32i            rv32iaf_zicsr   rv32im            rv32imc          rv64ia           rv64ic          rv64ima           rv64imc          sim.specs
ldscripts      libgloss.a        libsemihost.a       libsupc++_nano.a  rv32ec    rv32ia           rv32ic          rv32ima           rv32imfc_zicsr   rv64iac          rv64ifc_zicsr   rv64imac          rv64imfc_zicsr
libc.a         libgloss_nano.a   libsim.a            nano.specs        rv32em    rv32iac          rv32ifc_zicsr   rv32imafc_zicsr   rv32imfdc_zicsr  rv64iafc_zicsr   rv64ifdc_zicsr  rv64imafc_zicsr   rv64imfdc_zicsr
libc_nano.a    libg_nano.a       libstdc++.a         nosys.specs       rv32ema   rv32iafc_zicsr   rv32ifdc_zicsr  rv32imafdc_zicsr  rv32imfd_zicsr   rv64iafdc_zicsr  rv64ifd_zicsr   rv64imafdc_zicsr  rv64imfd_zicsr
libg.a         libm.a            libstdc++.a-gdb.py  rv32e             rv32emac  rv32iafdc_zicsr  rv32ifd_zicsr   rv32imafd_zicsr   rv32imf_zicsr    rv64iafd_zicsr   rv64if_zicsr    rv64imafd_zicsr   rv64imf_zicsr
libgfortran.a  libm_nano.a       libstdc++_nano.a    rv32ea            rv32emc   rv32iafd_zicsr   rv32if_zicsr    rv32imaf_zicsr    rv64i            rv64iaf_zicsr    rv64im          rv64imaf_zicsr    semihost.specs

And your compilation have only this:

Code: [Select]
crt0.o     libc.a       libg.a         libgfortran.spec  libgloss_nano.a  libm.a       libnosys.a     libsim.a     libstdc++.a-gdb.py  libsupc++.a       nano.specs   rv32emac  rv64imac        sim.specs
ldscripts  libc_nano.a  libgfortran.a  libgloss.a        libg_nano.a      libm_nano.a  libsemihost.a  libstdc++.a  libstdc++_nano.a    libsupc++_nano.a  nosys.specs  rv32ima   semihost.specs

You can verify the bundled multilib libraries with -print-multi-lib gcc option:

Code: [Select]
$> /opt/xpack-riscv-none-elf-gcc-12.2.0-1-wch/bin/riscv-none-elf-gcc -print-multi-lib
.;
rv32emac/ilp32e;@march=rv32emac@mabi=ilp32e
rv32ima/ilp32;@march=rv32ima@mabi=ilp32
rv64imac/lp64;@march=rv64imac@mabi=lp64

$> /opt/xpack-riscv-none-elf-gcc-12.2.0-1/bin/riscv-none-elf-gcc -print-multi-lib
.;
rv32e/ilp32e;@march=rv32e@mabi=ilp32e
rv32ea/ilp32e;@march=rv32ea@mabi=ilp32e
rv32eac/ilp32e;@march=rv32eac@mabi=ilp32e
rv32ec/ilp32e;@march=rv32ec@mabi=ilp32e
rv32em/ilp32e;@march=rv32em@mabi=ilp32e
rv32ema/ilp32e;@march=rv32ema@mabi=ilp32e
rv32emac/ilp32e;@march=rv32emac@mabi=ilp32e
rv32emc/ilp32e;@march=rv32emc@mabi=ilp32e
rv32i/ilp32;@march=rv32i@mabi=ilp32
rv32ia/ilp32;@march=rv32ia@mabi=ilp32
rv32iac/ilp32;@march=rv32iac@mabi=ilp32
rv32iaf_zicsr/ilp32f;@march=rv32iaf_zicsr@mabi=ilp32f
rv32iafc_zicsr/ilp32f;@march=rv32iafc_zicsr@mabi=ilp32f
rv32iafd_zicsr/ilp32d;@march=rv32iafd_zicsr@mabi=ilp32d
rv32iafdc_zicsr/ilp32d;@march=rv32iafdc_zicsr@mabi=ilp32d
rv32ic/ilp32;@march=rv32ic@mabi=ilp32
rv32if_zicsr/ilp32f;@march=rv32if_zicsr@mabi=ilp32f
rv32ifc_zicsr/ilp32f;@march=rv32ifc_zicsr@mabi=ilp32f
rv32ifd_zicsr/ilp32d;@march=rv32ifd_zicsr@mabi=ilp32d
rv32ifdc_zicsr/ilp32d;@march=rv32ifdc_zicsr@mabi=ilp32d
rv32im/ilp32;@march=rv32im@mabi=ilp32
rv32ima/ilp32;@march=rv32ima@mabi=ilp32
rv32imaf_zicsr/ilp32f;@march=rv32imaf_zicsr@mabi=ilp32f
rv32imafc_zicsr/ilp32f;@march=rv32imafc_zicsr@mabi=ilp32f
rv32imafd_zicsr/ilp32d;@march=rv32imafd_zicsr@mabi=ilp32d
rv32imafdc_zicsr/ilp32d;@march=rv32imafdc_zicsr@mabi=ilp32d
rv32imc/ilp32;@march=rv32imc@mabi=ilp32
rv32imf_zicsr/ilp32f;@march=rv32imf_zicsr@mabi=ilp32f
rv32imfc_zicsr/ilp32f;@march=rv32imfc_zicsr@mabi=ilp32f
rv32imfd_zicsr/ilp32d;@march=rv32imfd_zicsr@mabi=ilp32d
rv32imfdc_zicsr/ilp32d;@march=rv32imfdc_zicsr@mabi=ilp32d
rv64i/lp64;@march=rv64i@mabi=lp64
rv64ia/lp64;@march=rv64ia@mabi=lp64
rv64iac/lp64;@march=rv64iac@mabi=lp64
rv64iaf_zicsr/lp64f;@march=rv64iaf_zicsr@mabi=lp64f
rv64iafc_zicsr/lp64f;@march=rv64iafc_zicsr@mabi=lp64f
rv64iafd_zicsr/lp64d;@march=rv64iafd_zicsr@mabi=lp64d
rv64iafdc_zicsr/lp64d;@march=rv64iafdc_zicsr@mabi=lp64d
rv64ic/lp64;@march=rv64ic@mabi=lp64
rv64if_zicsr/lp64f;@march=rv64if_zicsr@mabi=lp64f
rv64ifc_zicsr/lp64f;@march=rv64ifc_zicsr@mabi=lp64f
rv64ifd_zicsr/lp64d;@march=rv64ifd_zicsr@mabi=lp64d
rv64ifdc_zicsr/lp64d;@march=rv64ifdc_zicsr@mabi=lp64d
rv64im/lp64;@march=rv64im@mabi=lp64
rv64ima/lp64;@march=rv64ima@mabi=lp64
rv64imac/lp64;@march=rv64imac@mabi=lp64
rv64imaf_zicsr/lp64f;@march=rv64imaf_zicsr@mabi=lp64f
rv64imafc_zicsr/lp64f;@march=rv64imafc_zicsr@mabi=lp64f
rv64imafd_zicsr/lp64d;@march=rv64imafd_zicsr@mabi=lp64d
rv64imafdc_zicsr/lp64d;@march=rv64imafdc_zicsr@mabi=lp64d
rv64imc/lp64;@march=rv64imc@mabi=lp64
rv64imf_zicsr/lp64f;@march=rv64imf_zicsr@mabi=lp64f
rv64imfc_zicsr/lp64f;@march=rv64imfc_zicsr@mabi=lp64f
rv64imfd_zicsr/lp64d;@march=rv64imfd_zicsr@mabi=lp64d
rv64imfdc_zicsr/lp64d;@march=rv64imfdc_zicsr@mabi=lp64d

The ch32v30x have a QingKe v4f (imafc) core and ch569 have v3a (maybe a typo for v4a?) that claim be a rv32imac.

In any case, your toolchain lacks the c and f extentions for rv32 (have rv32emac, rv32ima and rv64imac but not rv32imac or rv32imacf) that be crucial in many cases (c is a big improve of code size reduction and f is essential if you work with floating point primitives)

I'm investigating what is the problem with the scripts that generate this behaviour in your compilation...


I found the cause of the miltilib lack...
[url]https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack/discussions/6[/url]

When you use the flag --develop this restrict the multilib options due to improve the compilation time.

You can remove --develop flag on your build and reupload the toolchain? This is very usefull for many peoples like me that maintain a separated startup/interrupt code due to the lack of "wch-interrupt-fast" implementation in a vanilla xpack-riscv-gcc


Update:
Thanks for the details I have rebuild it see https://github.com/hydrausb3/riscv-none-elf-gcc-xpack/releases/tag/12.2.0-1


« Last Edit: January 06, 2023, 09:54:03 am by hydrabus »
 

Offline mean00

  • Newbie
  • Posts: 1
  • Country: fr
Re: ch32v307, risc-v minicore with ethernet
« Reply #55 on: January 16, 2023, 06:34:00 pm »
I'm posting this in case it can help someone.
 
I've modified the nice LLVM-embedded-toolchain-for-Arm project so that it builds a standalone clang/llvm+picolibc toolchain for riscv32
(tested on linux only, might work or not on windows).

I'm using it with the CH32V307, without too much issue so far (see below). Better to use clang if you do a mix of c++ & rust.

The modification is very small, the original project is very well done

https://github.com/mean00/LLVM-embedded-toolchain-for-rv32.git

It is experimental, but works nicely so far for me, including lto.

Some notes  :
It should be mostly a drop-in replacement for gcc with the following :
- you need to add --target=riscv32  to your cflags i.e.
 -march=rv32imac -mabi=ilp32  => --target=riscv32 -march=rv32imac -mabi=ilp32
- Clang linker script  is mostly compatible with gcc/ld one, but you may have to tweak it a bit.
- There is tiny compatibility between gcc & clang, like removing .func and .endfunc in asm files. Nothing painful.
- The above toolchain does not contain  the fast interrupt stuff, i  think you can get by with asm("mret")+ naked or something similar so that it works everywhere without every toolchain (not looked into it deeply yet).
- You still have to use gnu-gdb to debug
- The generated code size is similar to the one with gcc 12 + picolibc

Your typical build script is :
mkdir build && cd build && cmake -G Ninja && ninja && ninja  package-llvm-toolchain

/!\ You may have to create a symlink : ln -s $PWD/build/_deps/llvmproject-src/llvm/lib lib


Notice : It takes a while to build



 
The following users thanked this post: paf, chickenHeadKnob

Offline paf

  • Regular Contributor
  • *
  • Posts: 91
Re: ch32v307, risc-v minicore with ethernet
« Reply #56 on: January 22, 2023, 11:32:55 am »

About the CH32V307:

There is a nice Chinese development board called Chitu/OpenCH: 
https://gitee.com/verimaker/opench-ch32v307
https://verimake.com/d/37-opench-ch32v307-risc-v

Yes, the docs are in chinese, and some links do not work.
You can login on gitee using a github account.

There is a youtube playlist about this board:
https://www.youtube.com/playlist?list=PL5k6lPIGwPvQ5SrKA6NajEQSRbbhgoJLg

The CH32V307 is supported by RT-Thread:
https://www.rt-thread.io
 

Offline SiliconWizard

  • Super Contributor
  • ***
  • Posts: 14466
  • Country: fr
Re: ch32v307, risc-v minicore with ethernet
« Reply #57 on: October 30, 2023, 08:26:19 pm »
Digging up this thread as I've just ordered a couple dev boards for the CH32V307.
It has an impressive set of features for a $3 (per 1) chip, I particularly like having USB 2.0 HS and Ethernet at this price point. It's in stock at LCSC, although the stock levels are not very high, so wondering what happens if you need a few thousands of them? Does WCH sell directly?

Has anyone done anything significant with this MCU in the meantime? What about GCC now? (And OpenOCD?)
 

Offline brucehoult

  • Super Contributor
  • ***
  • Posts: 4034
  • Country: nz
Re: ch32v307, risc-v minicore with ethernet
« Reply #58 on: October 30, 2023, 09:46:07 pm »
WCH sells directly and are very responsive both at @patrick_riscv (Technical Director) on twitter (see his bio for other contacts) and by email etc.

Their flashing/debug protocol is documented and a modified OpenOCD is on github.

It uses standard GCC or LLVM with the sole exception of their gcc knowing how to make the correct interrupt handlers for their "fast interrupt" mode -- an on-chip shadow register stack for a0-a7,t0-t6,ra on the 307, save to stack on the 003 (software transparent).  You can fake that up in regular GCC/LLVM with the overhead of a 2-instruction inline asm function that calls the actual handler.

Code: [Select]
__attribute__((naked))
void my_handler_wrapper(){
    asm volatile ("call my_handler; mret");
}

You write my_handler() as a normal C function.
« Last Edit: October 30, 2023, 11:30:24 pm by brucehoult »
 
The following users thanked this post: newbrain, SiliconWizard, rhodges

Offline martinribelotta

  • Regular Contributor
  • *
  • Posts: 56
  • Country: ar
  • A camel is a horse designed by a committee
    • Martin Ribelotta design services
Re: ch32v307, risc-v minicore with ethernet
« Reply #59 on: October 30, 2023, 10:30:53 pm »
Quote
It uses standard GCC or LLVM with the sole exception of their gccknowing how to make the correct interrupt handlers for their "fast interrupt" mode -- an on-chip shadow register stack for a0-a8,t0-t7 on the 307, save to stack on the 003 (software transparent).  You can fake that up in regular GCC with the overhead of a 2-instruction inline asm function that calls the actual handler.

Code: [Select]
__attribute__((naked))
void my_handler_wrapper(){
    asm volatile ("call my_handler; mret");
}

You write my_handler() as a normal C function.

Be careful with it. This trick is only valid if you do not use FPU. The shadow stack is only for X registers in psABI... if you use FPU, the F0..31 is not saved by interrupt. Same carer if you use another abi that not follow the psABI specifications.

You can see a brief distuccion about it here:
https://github.com/hydrausb3/riscv-none-elf-gcc-xpack/issues/5

The user mengfanyuc@github (https://github.com/mengfanyuc) was create a patch for original xpack-riscv-none-elf to handle correctly the interrupt situation:
https://github.com/mengfanyuc/riscv-none-elf-gcc-xpack/commit/59ee16df7b6bf5ebbfa881a79f61dcf67eadb8e9

A definitive solution about vendor-specific interrupt management sould be the "prestacked annotation" in draft for revision:
https://github.com/jnk0le/riscv-total-embedded/blob/master/riscv-total-embedded.adoc#151-prestacked-annotation
 
The following users thanked this post: SiliconWizard

Offline SiliconWizard

  • Super Contributor
  • ***
  • Posts: 14466
  • Country: fr
Re: ch32v307, risc-v minicore with ethernet
« Reply #60 on: October 30, 2023, 10:41:30 pm »
This interrupt thing is the thing I was meaning to investigate, as I want to be able to use mainline GCC. So, thanks for the pointers.

Regarding the code Bruce posted: wouldn't just that work (neglecting the FPU thing):

Code: [Select]
__attribute__((interrupt, naked))
I've used the 'interrupt' attribute (without 'naked') for my RISC-V core which does emit 'mret', so no need to add it in assembly. But is the 'naked' attribute maybe incompatible with 'interrupt'?
Edit: answering my own question after a quick test, yes, they are unfortunately incompatible with each other.

The solution provided by Bruce is detailed here: https://blog.dan.drown.org/ch32v307-dev-board-part-2/
Note that while it works, it's slightly slower since it has to make an additional branch.
« Last Edit: October 30, 2023, 11:12:12 pm by SiliconWizard »
 

Offline brucehoult

  • Super Contributor
  • ***
  • Posts: 4034
  • Country: nz
Re: ch32v307, risc-v minicore with ethernet
« Reply #61 on: October 30, 2023, 11:16:37 pm »
__attribute__((interrupt)) causes the compiler to use mret instead of ret and also to save only and exactly what registers it uses if you don't call any other function, or a0-a7,t0-t6,ra if you call any normal C function from the handler. It it for normal RISC-V interrupts (which WCH does by default).

But if you enable their "HPE" feature then a0-a7,t0-t6,ra are already saved for you in 1 cycle (on 307) by duplicate hardware registers, so saving them yourself is a waste of time.

__attribute__((naked)) makes the compiler not save ANY registers, not make any stack frame, not emit any ret etc ... only and precisely code for what you actually write. It's very dangerous.
 

Offline brucehoult

  • Super Contributor
  • ***
  • Posts: 4034
  • Country: nz
Re: ch32v307, risc-v minicore with ethernet
« Reply #62 on: October 30, 2023, 11:28:02 pm »
Be careful with it. This trick is only valid if you do not use FPU. The shadow stack is only for X registers in psABI... if you use FPU, the F0..31 is not saved by interrupt.

Good point. I've only used it on chips without FPU. It would also be a pretty unusual interrupt handler that used FP.

But if you do ... then you need to save f0-7,f10-17,f28-31 yourself before calling arbitrary C code.

At that point the benefit from HPE is getting pretty marginal -- it's only saving 44% of the needed registers or 28% of the bytes if you have RV32 with a DP FPU (307 is SP) -- so you might as well just use standard RISC-V interrupts.
 

Offline SiliconWizard

  • Super Contributor
  • ***
  • Posts: 14466
  • Country: fr
Re: ch32v307, risc-v minicore with ethernet
« Reply #63 on: October 30, 2023, 11:39:06 pm »
__attribute__((interrupt)) causes the compiler to use mret instead of ret and also to save only and exactly what registers it uses if you don't call any other function, or a0-a7,t0-t6,ra if you call any normal C function from the handler. It it for normal RISC-V interrupts (which WCH does by default).

Yep. With a small caveat, that you can check easily for yourself.
GCC will save *only* the registers the 'interrupt' attributed function uses... if you enable optimizations, from -O1 to -O3. With no optimization (probably expected), or (something that probably can bite many people here OTOH) with -Os, it does save ALL registers. I currently use GCC 13.2, but I checked that it has this behavior back to GCC 10.2. I didn't go further back than this, so dunno about earlier versions yet. Compile with '-Os', and bang, the whole set of registers is saved. Nasty if you ask me.

So for the article I posted above, the optimization level was likely set at -Os. If it was set at -O1 or above, there wouldn't be any difference in code between both variants of the code, as far as I can tell.

But if you enable their "HPE" feature then a0-a7,t0-t6,ra are already saved for you in 1 cycle (on 307) by duplicate hardware registers, so saving them yourself is a waste of time.

Yes, but how do you enable their HPE feature with mainline GCC?

__attribute__((naked)) makes the compiler not save ANY registers, not make any stack frame, not emit any ret etc ... only and precisely code for what you actually write. It's very dangerous.

Yep. But the function you call inside the 'naked' interrupt handler will itself save the registers it uses, so what do you gain compared to just using the 'interrupt' attribute and writing your code directly inside of it?
As long as you don't use '-Os', see my point above as well. (Again, nasty one, as '-Os' is a relatively "popular" opt. flag for embedded stuff.)
What am I missing here?
« Last Edit: October 30, 2023, 11:42:41 pm by SiliconWizard »
 

Offline martinribelotta

  • Regular Contributor
  • *
  • Posts: 56
  • Country: ar
  • A camel is a horse designed by a committee
    • Martin Ribelotta design services
Re: ch32v307, risc-v minicore with ethernet
« Reply #64 on: October 30, 2023, 11:49:36 pm »
Quote
At that point the benefit from HPE is getting pretty marginal -- it's only saving 44% of the needed registers or 28% of the bytes if you have RV32 with a DP FPU (307 is SP) -- so you might as well just use standard RISC-V interrupts.

For this reason, the best way to do interrupts is the IPRA optimization (inter procedural register allocation) that is present only in last LLVM versions (not gcc for now)

If you mark function with __attribute__((interrupt)) the compiler only view in the current function (or inlined functions) for the current compilation unit.

When IPRA is enabled, the resiger allocation optimizer can view across function call at link time. At least, for static binaries (mostly in embedded area).

The HPE techniques includes dedicated caches with big access word (like TriCore stack memory) and is not uncommon in DSP and onther FPGA/ASIC based implementations.
The idea of prestacked-annotation is fully flexible and cover many implementations. I hope that will be accepted in mainstream risc-v soon
 
The following users thanked this post: SiliconWizard

Offline brucehoult

  • Super Contributor
  • ***
  • Posts: 4034
  • Country: nz
Re: ch32v307, risc-v minicore with ethernet
« Reply #65 on: October 31, 2023, 12:01:54 am »
__attribute__((interrupt)) causes the compiler to use mret instead of ret and also to save only and exactly what registers it uses if you don't call any other function, or a0-a7,t0-t6,ra if you call any normal C function from the handler. It it for normal RISC-V interrupts (which WCH does by default).

Yep. With a small caveat, that you can check easily for yourself.
GCC will save *only* the registers the 'interrupt' attributed function uses... if you enable optimizations, from -O1 to -O3. With no optimization (probably expected), or (something that probably can bite many people here OTOH) with -Os, it does save ALL registers. I currently use GCC 13.2, but I checked that it has this behavior back to GCC 10.2. I didn't go further back than this, so dunno about earlier versions yet. Compile with '-Os', and bang, the whole set of registers is saved. Nasty if you ask me.

I have no idea what you're on about here. Seems to me -Os works fine, and even -O0 is relatively sensible.

https://godbolt.org/z/GdcoxPfWf

Quote
But if you enable their "HPE" feature then a0-a7,t0-t6,ra are already saved for you in 1 cycle (on 307) by duplicate hardware registers, so saving them yourself is a waste of time.

Yes, but how do you enable their HPE feature with mainline GCC?

By fiddling the right bits in the right CSR? I don't have it to hand, but easy enough to find in the QingKe V4F manual.

Quote
__attribute__((naked)) makes the compiler not save ANY registers, not make any stack frame, not emit any ret etc ... only and precisely code for what you actually write. It's very dangerous.

Yep. But the function you call inside the 'naked' interrupt handler will itself save the registers it uses, so what do you gain compared to just using the 'interrupt' attribute and writing your code directly inside of it?

The standard C function you call inside the 'naked' interrupt handler will save, as usual, ONLY whatever of s0-s11,ra it uses.

It will blithely overwrite a0-a7,t0-t6 which will make whatever code was interrupted not very happy after you return from the interrupt if HPE is not enabled.

HPE instantly saves and restores a0-a7,t0-t6,ra for you.

If you are writing a small self-contained interrupt function (like in my godbolt example above) then __attribute__((interrupt)) is fine and will be only very slightly slower than HPE -- or even faster on the 003 which saves/restores to stack.

If your interrupt handler calls any standard C function then an __attribute__((interrupt)) handler will manually save/restore all of a0-a7,t0-t6.

« Last Edit: October 31, 2023, 12:05:13 am by brucehoult »
 

Online uer166

  • Frequent Contributor
  • **
  • Posts: 890
  • Country: us
Re: ch32v307, risc-v minicore with ethernet
« Reply #66 on: October 31, 2023, 12:07:32 am »
I was mildly interested in RISC-V until I dug a little deeper and realized how much of a pain in the a$$ the nester interrupt handling is on RISC-V. The ARM NVIC "just works" without drama, this seems like you have to bend over backwards to achieve a similar result with ASM or compiler fuckery..
 

Offline martinribelotta

  • Regular Contributor
  • *
  • Posts: 56
  • Country: ar
  • A camel is a horse designed by a committee
    • Martin Ribelotta design services
Re: ch32v307, risc-v minicore with ethernet
« Reply #67 on: October 31, 2023, 12:31:34 am »
Quote
I was mildly interested in RISC-V until I dug a little deeper and realized how much of a pain in the a$$ the nester interrupt handling is on RISC-V. The ARM NVIC "just works" without drama, this seems like you have to bend over backwards to achieve a similar result with ASM or compiler fuckery..

Is the same in any processor... interrupts is a mess... ARM created bad habits for us by giving us the NVIC in such a transparent way. The big problem os NVIC is the latency... any interrupt need a fixed amount of clocks and is not posible any optimization... Because this, the cortex-R line uses a more common vectored interrupt handling with IRQ and FIQ signals and software-based stack management.
 

Offline SiliconWizard

  • Super Contributor
  • ***
  • Posts: 14466
  • Country: fr
Re: ch32v307, risc-v minicore with ethernet
« Reply #68 on: October 31, 2023, 12:33:48 am »
__attribute__((interrupt)) causes the compiler to use mret instead of ret and also to save only and exactly what registers it uses if you don't call any other function, or a0-a7,t0-t6,ra if you call any normal C function from the handler. It it for normal RISC-V interrupts (which WCH does by default).

Yep. With a small caveat, that you can check easily for yourself.
GCC will save *only* the registers the 'interrupt' attributed function uses... if you enable optimizations, from -O1 to -O3. With no optimization (probably expected), or (something that probably can bite many people here OTOH) with -Os, it does save ALL registers. I currently use GCC 13.2, but I checked that it has this behavior back to GCC 10.2. I didn't go further back than this, so dunno about earlier versions yet. Compile with '-Os', and bang, the whole set of registers is saved. Nasty if you ask me.

I have no idea what you're on about here. Seems to me -Os works fine, and even -O0 is relatively sensible.

https://godbolt.org/z/GdcoxPfWf

I had to extract the minimal code that was leading to what I saw, to understand where it came from exactly. The piece of code I was trying with godbolt.org contained several functions to test various approaches for ISRs rather than just one.
I'm posting here the minimal code that triggers it with only '-Os',  actually not at '-O0' or any other level.

Code: [Select]
static volatile int n;

void Inc(void)
{
n++;
}

void __attribute__((interrupt)) MyISR2_Handler(void)
{
n++;
}

The reason I had this Inc() function was to test calling it from a naked function as you showed. But removing this naked function calling it (with an assembly call) doesn't change a thing in the behavior, so removed it for a minimal test case.

The reason only '-Os' triggers this odd behavior is that GCC will "aggressively" factor all code it can (while OTOH '-O3' tends to aggressively inline as much as it can.)
So if you look at the generated assembly, MyISR2_Handler() does call Inc() instead of having the "n++" statement inlined. Yes, pretty much the opposite behavior as you'd seen with '-O3' inlining almost every call of a function that is in sight.

And while calling Inc(), it doesn't consider any context of what Inc() does (I suppose), so it just saves all registers just in case. This is what I'd call a nice "bug". I have a knack for finding those.

Long story short here, regardless of ISRs or anything else, be careful about '-Os' as it may transform inline code as function calls. You may argue that it would mean that you have duplicated code (duplicated enough for GCC to do this), but when the duplicaiton is just one statement, that is frankly as odd as it can be counter-productive.

Quote
But if you enable their "HPE" feature then a0-a7,t0-t6,ra are already saved for you in 1 cycle (on 307) by duplicate hardware registers, so saving them yourself is a waste of time.

Yes, but how do you enable their HPE feature with mainline GCC?

By fiddling the right bits in the right CSR? I don't have it to hand, but easy enough to find in the QingKe V4F manual.

Yes maybe, or maybe it doesn't need anything enabled and it is by default? Didn't check either, but that was not my question. My point is that we still have no way with mainline GCC to have it NOT save registers in an ISR at all if the code is going to use some of them. Calling a function from a 'naked' function as shown above doesn't solve that. The called function will still save the registers it uses, while normally the HPE feature would avoid it altogether.

Quote
__attribute__((naked)) makes the compiler not save ANY registers, not make any stack frame, not emit any ret etc ... only and precisely code for what you actually write. It's very dangerous.

Yep. But the function you call inside the 'naked' interrupt handler will itself save the registers it uses, so what do you gain compared to just using the 'interrupt' attribute and writing your code directly inside of it?

The standard C function you call inside the 'naked' interrupt handler will save, as usual, ONLY whatever of s0-s11,ra it uses.

Yes, just like the 'interrupt' attribute does (when we don't run into this odd '-Os' bug)?
So I still don't get the benefit of using a 'naked' function call another function rather than directly use the interrupt attribute, which will achieve the same (when all goes well)?
« Last Edit: October 31, 2023, 12:37:52 am by SiliconWizard »
 

Online uer166

  • Frequent Contributor
  • **
  • Posts: 890
  • Country: us
Re: ch32v307, risc-v minicore with ethernet
« Reply #69 on: October 31, 2023, 12:38:27 am »
Quote from: martinribelotta link=topic=322309.msg5143845#msg5143845
any interrupt need a fixed amount of clocks and is not posible any optimization...

That is complete news to me. I've never had to have a defined (by clock cycle) ISR latency for any system (even high frequency control loop DSMPS). I mean it's nice, but clocks don't matter, absolute time does.
 

Offline brucehoult

  • Super Contributor
  • ***
  • Posts: 4034
  • Country: nz
Re: ch32v307, risc-v minicore with ethernet
« Reply #70 on: October 31, 2023, 12:46:41 am »
I was mildly interested in RISC-V until I dug a little deeper and realized how much of a pain in the a$$ the nester interrupt handling is on RISC-V. The ARM NVIC "just works" without drama, this seems like you have to bend over backwards to achieve a similar result with ASM or compiler fuckery..

As you wish, but NVIC is a lot of hardware that can be emulated -- nested interrupts, chained interrupts (i.e. without restoring and re-saving registers), servicing a higher priority interrupt that arrives while registers are being stacked -- with a few dozen instructions top level interrupt handler that has been worked out, published [1] and is not significantly slower than the "hardware" mechanism on CM0, CM3/4, CM7.

It's a slightly more RISCy DIY approach, but just as effective and NBD for pros. Certainly ARMv7-M makes things simple for beginners, but it comes at a cost. You can get into and out of simple RISC-V handlers (e.g. increment a global, or read a byte and insert into a buffer) faster than with ARM's heavyweight non-optional mechanism.

[1] https://github.com/riscv/riscv-fast-interrupt/blob/master/clic.adoc#111-c-abi-trampoline-code
 

Offline SiliconWizard

  • Super Contributor
  • ***
  • Posts: 14466
  • Country: fr
Re: ch32v307, risc-v minicore with ethernet
« Reply #71 on: October 31, 2023, 12:56:26 am »
Quote
I was mildly interested in RISC-V until I dug a little deeper and realized how much of a pain in the a$$ the nester interrupt handling is on RISC-V. The ARM NVIC "just works" without drama, this seems like you have to bend over backwards to achieve a similar result with ASM or compiler fuckery..

Is the same in any processor... interrupts is a mess...

RISC-V is by nature a modular ISA, so while it's great from a number of POVs, it obviously leads to fragmentation.
Interrupts were defined in a very basic way in the RISC-V specs, so that almost if not all companies creating products have implemented their own interrupt controller. The RISC-V PLIC spec was ratified much later on, and even if it's a reasonable interrupt controller, even new CPU/MCU designs will come up with a different interrupt controller than the RISC-V PLIC, or add various extensions to it, thus in turn often requiring specific additions to the compilers.

That may all converge over time, but I still don't know how it'll turn out.

ARM created bad habits for us by giving us the NVIC in such a transparent way. The big problem os NVIC is the latency... any interrupt need a fixed amount of clocks and is not posible any optimization... Because this, the cortex-R line uses a more common vectored interrupt handling with IRQ and FIQ signals and software-based stack management.

Well, it's a bit like comparing Linux and macOS. ARM is a closed approach, it just works but you get what they give you and nothing more.
 

Offline brucehoult

  • Super Contributor
  • ***
  • Posts: 4034
  • Country: nz
Re: ch32v307, risc-v minicore with ethernet
« Reply #72 on: October 31, 2023, 01:04:37 am »
__attribute__((interrupt)) causes the compiler to use mret instead of ret and also to save only and exactly what registers it uses if you don't call any other function, or a0-a7,t0-t6,ra if you call any normal C function from the handler. It it for normal RISC-V interrupts (which WCH does by default).

Yep. With a small caveat, that you can check easily for yourself.
GCC will save *only* the registers the 'interrupt' attributed function uses... if you enable optimizations, from -O1 to -O3. With no optimization (probably expected), or (something that probably can bite many people here OTOH) with -Os, it does save ALL registers. I currently use GCC 13.2, but I checked that it has this behavior back to GCC 10.2. I didn't go further back than this, so dunno about earlier versions yet. Compile with '-Os', and bang, the whole set of registers is saved. Nasty if you ask me.

I have no idea what you're on about here. Seems to me -Os works fine, and even -O0 is relatively sensible.

https://godbolt.org/z/GdcoxPfWf

I had to extract the minimal code that was leading to what I saw, to understand where it came from exactly. The piece of code I was trying with godbolt.org contained several functions to test various approaches for ISRs rather than just one.
I'm posting here the minimal code that triggers it with only '-Os',  actually not at '-O0' or any other level.

Code: [Select]
static volatile int n;

void Inc(void)
{
n++;
}

void __attribute__((interrupt)) MyISR2_Handler(void)
{
n++;
}

Ugh! Certainly a bug, as it causes huge code expansion, sontrary to the expressed intent of -Os

"static" on Inc() fixes it.  Also Clang is fine.

Quote
Quote
But if you enable their "HPE" feature then a0-a7,t0-t6,ra are already saved for you in 1 cycle (on 307) by duplicate hardware registers, so saving them yourself is a waste of time.

Yes, but how do you enable their HPE feature with mainline GCC?

By fiddling the right bits in the right CSR? I don't have it to hand, but easy enough to find in the QingKe V4F manual.

Yes maybe, or maybe it doesn't need anything enabled and it is by default?

Certainly not! That would break all standard RISC-V code.

Quote
My point is that we still have no way with mainline GCC to have it NOT save registers in an ISR at all if the code is going to use some of them. Calling a function from a 'naked' function as shown above doesn't solve that. The called function will still save the registers it uses, while normally the HPE feature would avoid it altogether.

NO!

With HPE the called wrapped standard C function will freely use a0-a7,t0-t6 -- that's up to 15 registers -- WITHOUT saving them. It will only make a stack frame and save some of s0-s11 if it calls some other C function or needs more than 15 live variables.

An __attribute__((interrupt)) function will save every register it uses, right from the first one.
 

Offline SiliconWizard

  • Super Contributor
  • ***
  • Posts: 14466
  • Country: fr
Re: ch32v307, risc-v minicore with ethernet
« Reply #73 on: October 31, 2023, 01:42:52 am »
With HPE the called wrapped standard C function will freely use a0-a7,t0-t6 -- that's up to 15 registers -- WITHOUT saving them. It will only make a stack frame and save some of s0-s11 if it calls some other C function or needs more than 15 live variables.

An __attribute__((interrupt)) function will save every register it uses, right from the first one.

Ok, I had to try a representative example to see exactly how GCC would handle the difference (and I used -O2 just to not have any potential quirkness of -Os which would not be relevant here).
https://godbolt.org/z/qdc4je3bE

So yeah, I see. If calling an external function (which I commented out here), that gets much worse of course.

Now whether the additional call/ret will add more cycles than saving a couple registers (in the simplest cases) is yet to be seen. But if you call any external function, the difference will certainly be significant.

Note: to enable HPE, set the HWSTKEN bit of the INTSYSCR CSR to 1 - the reset value is indeed 0. I've looked at their SDK. It's so-so. There is no definition for most CSRs that I could find, they use hard-coded values almost everywhere they use CSRs. Yuck. They enable the nested and hardware stacks for instance in their provided startup code: startup_ch32v30x_D8.S.
Code: [Select]
li t0, 0x0b
csrw 0x804, t0
0x0b = 0b1011 => that's PMTCFG set to "4 levels of nesting, with 2 preemption bits", Interrupt nesting enabled and HPE enabled.

So if you don't want it enabled, don't use their startup code or modify it.
CSRs are documented in the "QingKeV4 Microprocessor Manual".
« Last Edit: October 31, 2023, 02:28:30 am by SiliconWizard »
 

Online jnk0le

  • Contributor
  • Posts: 41
  • Country: pl
Re: ch32v307, risc-v minicore with ethernet
« Reply #74 on: October 31, 2023, 11:43:39 pm »
FYI, llvm meeting liked the prestacked annotation. Here is the more formal version of the proposal for wider review: https://github.com/riscv-non-isa/riscv-c-api-doc/pull/53

 
The following users thanked this post: newbrain


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf