升级嵌入式RISC-V编译器
<p>ch32v103c8t6的板子使用的是MounRiver Studio工具开发,这个工具的集成度还是不错的,但是里面的项目模板有点“简单”。看来要详细研究芯片的工作原理有点懵逼。所以就花了些时间来研究,发现该工具集成的是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("https://bbs.eeworld.com.cn/static/editor/plugins/widget/images/handle.png") 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("https://bbs.eeworld.com.cn/static/editor/plugins/widget/images/handle.png") 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("https://bbs.eeworld.com.cn/static/editor/plugins/widget/images/handle.png") 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-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("https://bbs.eeworld.com.cn/static/editor/plugins/widget/images/handle.png") 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>编译时出现了警告,我没有理会。有点草率了,将程序烧写到芯片后,能够正常运行。这时我就误认为升级成功了,还发了一篇帖子“炫耀一下”。结果被打脸啦啦!</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">"WCH-Interrupt-fast"</span>)));
<span class="hljs-keyword">void</span> HardFault_Handler(<span class="hljs-keyword">void</span>) __attribute__((interrupt(<span class="hljs-string">"WCH-Interrupt-fast"</span>)));
<span class="hljs-keyword">void</span> EXTI0_IRQHandler(<span class="hljs-keyword">void</span>) __attribute__((interrupt(<span class="hljs-string">"WCH-Interrupt-fast"</span>)));
</code></pre>
<img src="data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==" /><span style="background: url("https://bbs.eeworld.com.cn/static/editor/plugins/widget/images/handle.png") 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>啥意思:“interrupt("WCH-Interrupt-fast")难道还是特制的编译器吗!”。按道理说不可能吧!是不是在”装神弄鬼“这个就不知道了。</p>
<p>随后,通过反汇编对比 </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 <.LVL1+0x2></span>
<span class="hljs-number">00000026</span> <.L4>:
}
}
<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("https://bbs.eeworld.com.cn/static/editor/plugins/widget/images/handle.png") 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 </p>
<p>这下明白了,原来是新版的程序不认识“interrupt("WCH-Interrupt-fast")这个属性造成的。后来找到了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 <code>user</code>, <code>supervisor</code>, and <code>machine</code>. If there is no parameter, then it defaults to <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">"machine"</span>)));
<span class="hljs-keyword">void</span> HardFault_Handler(<span class="hljs-keyword">void</span>) __attribute__((interrupt(<span class="hljs-string">"machine"</span>)));
<span class="hljs-keyword">void</span> EXTI0_IRQHandler(<span class="hljs-keyword">void</span>) __attribute__((interrupt(<span class="hljs-string">"machine"</span>)));
</code></pre>
<img src="data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==" /><span style="background: url("https://bbs.eeworld.com.cn/static/editor/plugins/widget/images/handle.png") 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> </p>
<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> </p>
<p>国内的东西要学要追的确实很多,手册是一个老生常谈的缺失了。</p>
<p>找了下资料,还对比了下汇编</p>
<p>这个东西确实是有用的,WCH在基础架构上增加了个中断硬件入栈.</p>
<p>使用自带的编译器和这个选项可以省去软件入栈的时间,不过确实找半天没有手册</p>
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]