bigbat 发表于 2021-1-24 12:35

升级嵌入式RISC-V编译器

<p>ch32v103c8t6的板子使用的是MounRiver Studio工具开发,这个工具的集成度还是不错的,但是里面的项目模板有点&ldquo;简单&rdquo;。看来要详细研究芯片的工作原理有点懵逼。所以就花了些时间来研究,发现该工具集成的是xpack出品的gnu risc-v工具和调试器OpenOCD。下载了xpack-riscv-none-embed-gcc-10.1.0-1.1-win32-x64.zip这个最新版本的工具。辛辛苦苦的一番配置,结果很是悲剧:MounRiver的IDE无法下载程序了,于是只好卸了重装吧,经过几番折腾的成果就是了解到MounRiver的工具的makefile文件在哪里了。</p>

<p>看到了吧就是这里啦,就是每个项目的obj目录。</p>

<p>赶忙将下载的文件xpack-riscv-none-embed-gcc-10.1.0-1.1-win32-x64.zip解压,把文件的主目录命名为F:\RVGCC。openocd的目录也考到这个目录下l,make工具也是拷贝到这个目录。下面的操作都是基于这个目录的。</p>

<p>首先,设置目录路径</p>

<div aria-label="代码段 小部件" contenteditable="false" role="region" tabindex="-1">
<pre data-widget="codesnippet">
<code class="hljs language-bash"><span class="hljs-keyword">set</span> PATH=%PATH%;F:\RVGCC\bin;F:\RVGCC\BTools\bin;F:\RVGCC\OpenOCD\bin</code></pre>
<img src="data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==" /><span style="background: url(&quot;https://bbs.eeworld.com.cn/static/editor/plugins/widget/images/handle.png&quot;) rgba(220, 220, 220, 0.5); top: -15px; left: 0px; display: block;"><img height="15" role="presentation" src="data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==" title="点击并拖拽以移动" width="15" /></span></div>

<p>使用测试一下环境是否正确。</p>

<div aria-label="代码段 小部件" contenteditable="false" role="region" tabindex="-1">
<pre data-widget="codesnippet">
<code class="hljs language-bash">riscv-none-embed-gcc --vserion</code></pre>
<img src="data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==" /><span style="background: url(&quot;https://bbs.eeworld.com.cn/static/editor/plugins/widget/images/handle.png&quot;) rgba(220, 220, 220, 0.5); top: -15px; left: 0px; display: block;"><img height="15" role="presentation" src="data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==" title="点击并拖拽以移动" width="15" /></span></div>

<p>二、找到项目目录路径</p>

<div aria-label="代码段 小部件" contenteditable="false" role="region" tabindex="-1">
<pre data-widget="codesnippet">
<code class="hljs language-bash"><span class="hljs-built_in">cd</span> F:\MounRiver\MounRiver_Studio\workspace\gcctest\obj</code></pre>
<img src="data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==" /><span style="background: url(&quot;https://bbs.eeworld.com.cn/static/editor/plugins/widget/images/handle.png&quot;) rgba(220, 220, 220, 0.5); top: -15px; left: 0px; display: block;"><img height="15" role="presentation" src="data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==" title="点击并拖拽以移动" width="15" /></span></div>

<p>三、编译&nbsp;</p>

<div aria-label="代码段 小部件" contenteditable="false" role="region" tabindex="-1">
<pre data-widget="codesnippet">
<code class="hljs language-apache"><span class="hljs-keyword">make</span> clean
<span class="hljs-keyword">make</span> -j8 <span class="hljs-literal">all</span></code></pre>
<img src="data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==" /><span style="background: url(&quot;https://bbs.eeworld.com.cn/static/editor/plugins/widget/images/handle.png&quot;) rgba(220, 220, 220, 0.5); top: -15px; left: 0px; display: block;"><img height="15" role="presentation" src="data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==" title="点击并拖拽以移动" width="15" /></span></div>

<p>先清除一下,项目在编译。</p>

<p>编译时出现了警告,我没有理会。有点草率了,将程序烧写到芯片后,能够正常运行。这时我就误认为升级成功了,还发了一篇帖子&ldquo;炫耀一下&rdquo;。结果被打脸啦啦!</p>

<p>后来,我就进行了外部中断的实验,结果这个编译器编译的程序就出问题啦。<span style="color:#e74c3c;">程序看着一切正常,但是只能中断一次。马上去帖子里说明道歉。</span></p>

<p>后来我有点不服气,尤其是看到</p>

<div aria-label="代码段 小部件" contenteditable="false" role="region" tabindex="-1">
<pre data-widget="codesnippet">
<code class="hljs language-cpp"><span class="hljs-keyword">void</span> NMI_Handler(<span class="hljs-keyword">void</span>) __attribute__((interrupt(<span class="hljs-string">&quot;WCH-Interrupt-fast&quot;</span>)));
<span class="hljs-keyword">void</span> HardFault_Handler(<span class="hljs-keyword">void</span>) __attribute__((interrupt(<span class="hljs-string">&quot;WCH-Interrupt-fast&quot;</span>)));
<span class="hljs-keyword">void</span> EXTI0_IRQHandler(<span class="hljs-keyword">void</span>) __attribute__((interrupt(<span class="hljs-string">&quot;WCH-Interrupt-fast&quot;</span>)));
</code></pre>
<img src="data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==" /><span style="background: url(&quot;https://bbs.eeworld.com.cn/static/editor/plugins/widget/images/handle.png&quot;) rgba(220, 220, 220, 0.5); top: -15px; left: 0px; display: block;"><img height="15" role="presentation" src="data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==" title="点击并拖拽以移动" width="15" /></span></div>

<p>啥意思:&ldquo;interrupt(&quot;WCH-Interrupt-fast&quot;)难道还是特制的编译器吗!&rdquo;。按道理说不可能吧!是不是在&rdquo;装神弄鬼&ldquo;这个就不知道了。</p>

<p>随后,通过反汇编对比&nbsp;</p>

<div aria-label="代码段 小部件" contenteditable="false" role="region" tabindex="-1">
<pre data-widget="codesnippet">
<code class="hljs language-cpp"><span class="hljs-comment">//新版编译汇编程序</span>
<span class="hljs-number">2</span>e:        <span class="hljs-number">40</span>b2                        lw        ra,<span class="hljs-number">12</span>(sp)
<span class="hljs-number">30</span>:        <span class="hljs-number">0141</span>                        addi        sp,sp,<span class="hljs-number">16</span>
<span class="hljs-number">32</span>:        <span class="hljs-number">8082</span>                        ret

<span class="hljs-comment">//专用版编译汇编程序</span>
<span class="hljs-number">1</span>c:        <span class="hljs-number">4505</span>                        li        a0,<span class="hljs-number">1</span>
<span class="hljs-number">1</span>e:        <span class="hljs-number">00000097</span>                  auipc        ra,<span class="hljs-number">0x0</span>
<span class="hljs-number">22</span>:        <span class="hljs-number">000080e7</span>                  jalr        ra <span class="hljs-preprocessor"># 1e &lt;.LVL1+0x2&gt;</span>

<span class="hljs-number">00000026</span> &lt;.L4&gt;:
}
}
<span class="hljs-number">26</span>:        <span class="hljs-number">30200073</span>                  mret
</code></pre>
<img src="data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==" /><span style="background: url(&quot;https://bbs.eeworld.com.cn/static/editor/plugins/widget/images/handle.png&quot;) rgba(220, 220, 220, 0.5); top: -15px; left: 0px; display: block;"><img height="15" role="presentation" src="data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==" title="点击并拖拽以移动" width="15" /></span></div>

<p>果然是中断的返回指令有问题,新版的指令是ret,专版是mret&nbsp;</p>

<p>这下明白了,原来是新版的程序不认识&ldquo;interrupt(&quot;WCH-Interrupt-fast&quot;)这个属性造成的。后来找到了GUN的说明。</p>

<p><a href="https://gcc.gnu.org/onlinedocs/gcc/RISC-V-Function-Attributes.html#RISC-V-Function-Attributes" target="_blank">https://gcc.gnu.org/onlinedocs/gcc/RISC-V-Function-Attributes.html#RISC-V-Function-Attributes</a></p>

<p>这个说明中明确了该属性: Permissible values for this parameter are&nbsp;<code>user</code>,&nbsp;<code>supervisor</code>, and&nbsp;<code>machine</code>. If there is no parameter, then it defaults to&nbsp;<code>machine</code>.</p>

<div aria-label="代码段 小部件" contenteditable="false" role="region" tabindex="-1">
<pre data-widget="codesnippet">
<code class="hljs language-cpp"><span class="hljs-keyword">void</span> NMI_Handler(<span class="hljs-keyword">void</span>) __attribute__((interrupt(<span class="hljs-string">&quot;machine&quot;</span>)));
<span class="hljs-keyword">void</span> HardFault_Handler(<span class="hljs-keyword">void</span>) __attribute__((interrupt(<span class="hljs-string">&quot;machine&quot;</span>)));
<span class="hljs-keyword">void</span> EXTI0_IRQHandler(<span class="hljs-keyword">void</span>) __attribute__((interrupt(<span class="hljs-string">&quot;machine&quot;</span>)));
</code></pre>
<img src="data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==" /><span style="background: url(&quot;https://bbs.eeworld.com.cn/static/editor/plugins/widget/images/handle.png&quot;) rgba(220, 220, 220, 0.5); top: -15px; left: 0px; display: block;"><img height="15" role="presentation" src="data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==" title="点击并拖拽以移动" width="15" /></span></div>

<p>然后编译测试,呵呵反正是一切正常。后来又测试其它程序也正常。</p>

<p>那为什么不是user或supervisor呢?应该user, supervisor是用在具有MMU的机器里的吧。接着就进行了测试,果然不行而且中断后马上死机。</p>

<p>虽然升级成功但是心里真的很别扭。为什么国内的公司非要装神弄鬼的呢?而且这个芯片的资料很是粗糙,开发手册是用与ARM的体系合起来的。难道就不能彻底的测试一下写个完整的文档吗?说实话我真没有勇气把产品直接改到国产芯片上来的。如果出问题了可能老板家就彻底翻不了身了。</p>

<p>&nbsp;</p>

bigbat 发表于 2021-1-24 12:54

<p>其实中断代码一点也不神秘,startup_ch32v10x.s代码中的各种中断函数声明。</p>

<pre>
<code class="language-cpp">/********************************** (C) COPYRIGHT *******************************
* File Name          : startup_ch32v10x.s
* Author             : WCH
* Version            : V1.0.0
* Date               : 2020/04/30
* Description      : CH32V10x vector table for eclipse toolchain.
*******************************************************************************/

        .section        .init,"ax",@progbits
        .global        _start
        .align        1
_start:
        j        handle_reset
        .word 0x00000013
        .word 0x00000013
        .word 0x00000013
        .word 0x00000013
        .word 0x00000013
        .word 0x00000013
        .word 0x00000013
        .word 0x00000013
        .word 0x00000013
        .word 0x00000013
        .word 0x00000013
        .word 0x00000013
        .word 0x00100073
    .section    .vector,"ax",@progbits
    .align1
_vector_base:
    .option norvc;
      j   _start
    .word   0
      j   NMI_Handler               /* NMI Handler */
      j   HardFault_Handler         /* Hard Fault Handler */
    .word   0
    .word   0
    :
    :
    :
    .word   0
    .word   0
      j   SysTick_Handler            /* SysTick Handler */
    .word   0
      j   SW_handler               /* SW Handler */
    .word   0
    /* External Interrupts */
      j   WWDG_IRQHandler            /* Window Watchdog */
      j   PVD_IRQHandler             /* PVD through EXTI Line detect */
      j   TAMPER_IRQHandler          /* TAMPER */
      j   RTC_IRQHandler             /* RTC */
      j   FLASH_IRQHandler         /* Flash */
      j   RCC_IRQHandler             /* RCC */
      j   EXTI0_IRQHandler         /* EXTI Line 0 */
      j   EXTI1_IRQHandler         /* EXTI Line 1 */
      j   EXTI2_IRQHandler         /* EXTI Line 2 */
      j   EXTI3_IRQHandler         /* EXTI Line 3 */
      j   EXTI4_IRQHandler         /* EXTI Line 4 */
      j   DMA1_Channel1_IRQHandler   /* DMA1 Channel 1 */
      j   DMA1_Channel2_IRQHandler   /* DMA1 Channel 2 */
      j   DMA1_Channel3_IRQHandler   /* DMA1 Channel 3 */
      j   DMA1_Channel4_IRQHandler   /* DMA1 Channel 4 */
      j   DMA1_Channel5_IRQHandler   /* DMA1 Channel 5 */
      j   DMA1_Channel6_IRQHandler   /* DMA1 Channel 6 */
      j   DMA1_Channel7_IRQHandler   /* DMA1 Channel 7 */
      j   ADC1_2_IRQHandler          /* ADC1_2 */
      .word   0
      .word   0
      .word   0
      .word   0
      j   EXTI9_5_IRQHandler         /* EXTI Line 9..5 */
      j   TIM1_BRK_IRQHandler      /* TIM1 Break */
      j   TIM1_UP_IRQHandler         /* TIM1 Update */
      j   TIM1_TRG_COM_IRQHandler    /* TIM1 Trigger and Commutation */
      j   TIM1_CC_IRQHandler         /* TIM1 Capture Compare */
      j   TIM2_IRQHandler            /* TIM2 */
      j   TIM3_IRQHandler            /* TIM3 */
      j   TIM4_IRQHandler            /* TIM4 */
      j   I2C1_EV_IRQHandler         /* I2C1 Event */
      j   I2C1_ER_IRQHandler         /* I2C1 Error */
      j   I2C2_EV_IRQHandler         /* I2C2 Event */
      j   I2C2_ER_IRQHandler         /* I2C2 Error */
      j   SPI1_IRQHandler            /* SPI1 */
      j   SPI2_IRQHandler            /* SPI2 */
      j   USART1_IRQHandler          /* USART1 */
      j   USART2_IRQHandler          /* USART2 */
      j   USART3_IRQHandler          /* USART3 */
      j   EXTI15_10_IRQHandler       /* EXTI Line 15..10 */
      j   RTCAlarm_IRQHandler      /* RTC Alarm through EXTI Line */
      j   USBWakeUp_IRQHandler       /* USB Wakeup from suspend */
      j   USBHD_IRQHandler         /* USBHD */

    .option rvc;

    .section    .text.vector_handler, "ax", @progbits
    .weak   NMI_Handler
   :
   :
   :

        .section        .text.handle_reset,"ax",@progbits
        .weak        handle_reset
        .align        1
handle_reset:
.option push
.option        norelax
        la gp, __global_pointer$
.option        pop
1:
        la sp, _eusrstack
2:
        /* Load data section from flash to RAM */
        la a0, _data_lma
        la a1, _data_vma
        la a2, _edata
        bgeu a1, a2, 2f
1:
        lw t0, (a0)
        sw t0, (a1)
        addi a0, a0, 4
        addi a1, a1, 4
        bltu a1, a2, 1b
2:
        /* clear bss section */
        la a0, _sbss
        la a1, _ebss
        bgeu a0, a1, 2f
1:
        sw zero, (a0)
        addi a0, a0, 4
        bltu a0, a1, 1b
2:
        /* enable all interrupt */
li t0, 0x88
csrs mstatus, t0
        la t0, _vector_base
ori t0, t0, 1
        csrw mtvec, t0

jalSystemInit
        la t0, main
        csrw mepc, t0
        mret

</code></pre>

<p>不难发现这些中断函数就是预先声明好的例程。当程序中有同名的程序就用该程序覆盖。所以中断函数都是不能改名的。有什么中断函数就到startup_ch32v10x.s中查找就可以了。</p>

<p>下一步,测试将整个ide环境迁移到vscode中。eclipse的环境我的电脑上有点卡。</p>

<p>&nbsp;</p>

freebsder 发表于 2021-1-25 22:31

<p>国内的东西要学要追的确实很多,手册是一个老生常谈的缺失了。</p>

stars.under 发表于 2022-9-1 16:00

<p>找了下资料,还对比了下汇编</p>

<p>这个东西确实是有用的,WCH在基础架构上增加了个中断硬件入栈.</p>

<p>使用自带的编译器和这个选项可以省去软件入栈的时间,不过确实找半天没有手册</p>

stars.under 发表于 2022-9-1 17:16

stars.under 发表于 2022-9-1 16:00
找了下资料,还对比了下汇编

这个东西确实是有用的,WCH在基础架构上增加了个中断硬件入栈.

使用自带的 ...

<p>找到描述的手册了,在官网下有青稞V4架构的手册</p>

<p><a href="https://www.wch.cn/downloads/QingKeV4_Processor_Manual_PDF.html">QingKeV4_Processor_Manual.PDF - 南京沁恒微电子股份有限公司 (wch.cn)</a></p>

<p>在第16页有较为详细的描述</p>
页: [1]
查看完整版本: 升级嵌入式RISC-V编译器