0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

RISC-V中一个优化导致的问题案例

嵌入式USB开发 来源:嵌入式USB开发 作者:嵌入式USB开发 2023-06-08 10:02 次阅读

本文转自公众号,欢迎关注

优化导致的问题案例 (qq.com)

  • 一.过程
  • 二.思考

一.过程

关键代码如下

通过串口驱动接口,注册串口接收回调函数,uart_rx_callback

该回调函数中如果收到串口数据,长度非0,则更新全局变量uart_rx_len

主循环中再检查全局变量uart_rx_len,如果大于0说明收到了串口数据,将收到的数据再发送出去,实现简单的串口回环测试。

static int uart_rx_len = 0;
void uart_rx_callback(const void *buffer, uint32_t length)
{
    if(length >0)
    {
        uart_rx_len = length;
    }
}
int main(void)
{
    ......
    debug_uart_init(IOT_UART_PORT_1);
    uint8_t buffer[64];
    iot_uart_register_rx_callback(IOT_UART_PORT_1,buffer,sizeof(buffer),uart_rx_callback);
    while(1)
    {
        if(uart_rx_len > 0)
        {
            iot_uart_write_buffer(IOT_UART_PORT_1,buffer,uart_rx_len);
            uart_rx_len=0;
        }
    }
}

现象是并没有实现上述回环测试的功能。

于是进行调试,先确认是否进入了接收处理,

b uart_rx_callback

发现可以进入该回调函数,说明收到了数据。

step单步运行到执行完uart_rx_len = length;,再查看该变量的值

(gdb) p uart_rx_len
$2 = 1

也确实收到了一个字节。

然后继续往下看,看如下条件是否进入

if(uart_rx_len  > 0)
        {
            iot_uart_write_buffer(IOT_UART_PORT_1,buffer,uart_rx_len);
            uart_rx_len=0;
        }

b main.c:146iot_uart_write_buffer(IOT_UART_PORT_1,buffer,uart_rx_len所在行146行,打断点。

发现进不了该断点。

这里就比较奇怪了,前面uart_rx_len确实是1,了但是这里条件却进不去,其他地方也没有写uart_rx_len的地方。

那么只有继续看该处代码对应的汇编代码

先在uart_rx_callback前打断点,串口接收一个字节触发该回调执行。再在 if(uart_rx_len > 0)所在的行144行前打断点,b main.c:144c运行到该处。

此时看到uart_ex_len的值是1正确的。

(gdb) p uart_rx_len
$2 = 1

layout split打开汇编和C对照窗口。

查看变量uart_rx_len的地址,为0x20300c8

(gdb) p &uart_rx_len
$4 = (int *) 0x20300c8 < uart_rx_len >
(gdb) info reg s1
s1             0x2030000        33751040

S1寄存器的值设置为0x2030000, lui s1,0x2030 lui的u表示up(高20位),加载0x2030到S1的高20位。

lw a2,200(S1)即将S1对应的地址偏移200(0xC8)地址处的值加载到a2寄存器。

正好是获取0x2030C8(uart_rx_len)的值到A2,

然后再执行

blez a2,0x20001ba进行判断uart_rx_len和0的值比较,判断是否往下执行还是在此死循环。

图片

初看没问题,一细看就有端倪了。

假设一开始uart_rx_len=0,

那么后面始终执行的是一条语句,blez a2,0x20001ba,a2寄存器的值不再更新了,这就有问题了,内存中0x2030C8(uart_rx_len)的值变了,但是寄存器a2的值不再变化。

这就是编译器自作主张优化,生成的代码没有继续去从内存0x2030C8(uart_rx_len)处更新值到a2寄存器了。理论上是需要再次执行上述lw a2,200(S1)指令的。这就编译器优化导致的问题。

我们修改

static int uart_rx_len = 0;

改为

`static volatile int uart_rx_len = 0;``

再来看汇编代码。

可以看到如果a5小于0,会跳转到addi s1,s2,200处执行再继续lw a5,0(S1)处加载uart_rx_len的值到a5,会不断从内存处更新值到寄存器。

图片

这就是volatile的作用,加了volatile后编译器始终,会从内存中更新值到寄存器,而不会自作主张使用寄存器中缓存的值。

默认SCons/riscv_tools.py中是Os优化,

CCFLAGS = common_flags + [
        "-Os",
    ]

不加volatile且优化改为

-O3,-O2,-O1,-O0分别看一下。

可以看到-O1优化编译就进行了优化,后面-O2,-O3就不用看了。

-O0

图片

-O1

图片

二.思考

这里函数uart_rx_callback写了变量uart_rx_len

void uart_rx_callback(const void *buffer, uint32_t length)
{
    if(length >0)
    {
        uart_rx_len = length;
    }
}

且uart_rx_callback函数也作为回调函数使用了,理论上编译器应该指导uart_rx_len会被改写,不应该作此优化。

手动调用以下uart_rx_callback

uart_rx_callback(0, 0);
    debug_uart_init(IOT_UART_PORT_1);

还是一样的优化了

图片

看来编译器还是聪明过头了。

这里主要是

while(1)后面第一条语句就是判断uart_rx_len,如果之前还有其他语句,则编译器可能不会优化了。

while(1)

    {

        if(uart_rx_len > 0)

        {

            iot_uart_write_buffer(IOT_UART_PORT_1,buffer,uart_rx_len);

            uart_rx_len=0;

        }

    }

图片

审核编辑:汤梓红

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 嵌入式
    +关注

    关注

    5016

    文章

    18489

    浏览量

    293042
  • 串口
    +关注

    关注

    14

    文章

    1509

    浏览量

    74828
  • 优化
    +关注

    关注

    0

    文章

    218

    浏览量

    23754
  • 函数
    +关注

    关注

    3

    文章

    4117

    浏览量

    61547
  • RISC-V
    +关注

    关注

    42

    文章

    2007

    浏览量

    45364
收藏 人收藏

    评论

    相关推荐

    RISC-V有哪些优缺点?是坚持ARM方向还是投入risc-V的怀抱?

    优势。同时,这种设计也降低了制造成本,使得RISC-V在成本敏感的应用场景中更具竞争力。 缺点 : 性能问题 :虽然RISC-V设计简洁,但相对于某些专用ISA(如ARM),其性
    发表于 04-28 08:51

    RISC-V有哪些优点和缺点

    和工业界的众多参与者。这为RISC-V的技术发展、生态建设和应用推广提供了有力保障。 低功耗和低成本:由于RISC-V的简洁设计,其内核面积更小,功耗更低,这对于需要长时间运行的设备来说是
    发表于 04-28 09:03

    RISC-V的MCU与ARM对比

    和实现。这意味着RISC-V具有高度的灵活性和可定制性,可以根据不同的应用需求进行优化和扩展。 ARM :ARM是种专有的架构,任何想要使用ARM的指令集或实现的设计者都必须向ARM公司支付版权费
    发表于 05-27 15:58

    浅谈RISC-V

    RISC-V社区最近很热闹,也有人来问我的看法。这里胡扯两句。RISC-V这么热闹,媒体功不可没。在中国,媒体就是生产力。在2016年ARM被孙正义收购以后,下子成为了
    发表于 09-11 17:44

    为什么选择RISC-V

    。例如,如果工程师在FPGA中实现软RISC-V内核,则通常可以使用RTL源代码。由于RISC-V免版税,这为将基于RISC-V的设计从FPGA移植到ASIC或另一个FPGA带来了极大
    发表于 07-27 17:38

    科普RISC-V生态架构(认识RISC-V)

    RISC-V指令集正式因为伯克利大学想开发款CPU时,要么是些老旧的架构,要么收费昂贵,芯片设计领域亟需开源的指令集。神说要有光,
    发表于 08-02 11:50

    RISC-V有哪些特点

    。  不过,RISC-V也存在隐忧,那就是缺乏强有力的主导者,进而导致破碎化的问题。当年的MIPS其实也非常学院派,MIPS阵营的商业公司可以自由添加指令,比如龙芯就以MIPS为基
    发表于 08-25 11:17

    如何设计好的RISC-V

    文章目录写在前面什么是RISC-VRISC-V诞生的背景ISA霸权摩尔定律的穷途末路穷困潦倒的学者不断增长的指令数量RISC-V架构设计思想如何设计好的ISARISC-
    发表于 07-26 06:42

    文看懂RISC-V代码密度

    要的指标之。那么,代码密度由什么决定?如何提高代码密度呢?RISC-V的代码密度现状又如何?代码密度的决定因素如上面的倒金字塔所示,代码密度主要由指令集、ABI、编译器、Runtime库、程序代码五
    发表于 09-01 14:29

    RISC-V MCU开发相关资料分享

    开发工作中。 工欲善其事必先利其器,要想实现基于RISC-V MCU的项目开发,与之配套的集成开发环境必不可少。目前市场上可供选择的RISC-V MCU开发工具已初具规模,由MounRiver团队打造的MounRiver® Studio(MRS)便是其
    发表于 11-10 07:50

    优化的关键,RISC-V中的性能监控

    RISC-V在云端、数据中心、汽车与网络技术中的频繁创新和亮相,已经让这成长中的ISA只脚迈入了高性能计算场景。然而缺少强大的性能监测工具让RISC-V的应用
    发表于 12-27 08:00

    RISC-V简介

    RISC-V简介  RISC-V自由和开放的 ISA(开源指令集架构),通过开放的标准协作实现处理器创新的新时代。RISC-V IS
    发表于 02-27 19:56

    我了解的RISC-V

    、南京沁恒等等很多家都推出了自己的RISC-V内核的芯片,而据我了解,RISC-V从2010年成立以来,到2015年有了初步的第一个发布版的的时候,RISC-V了解的人还是很少的,直到
    发表于 03-19 10:52

    RISC-V 发展

    是必选的,扩展指令集是可选的。意思就是可以根据你的实际需求,选择需要使用的指令。例如在项目中,如果不需要用到压缩指令,那么就不需要把压缩指令添加进来,从而做到定制化,这也是RISC-V
    发表于 04-14 10:18

    第一届RISC-V中国峰会看点 risc-v开发要怎么优化risc-v指令集架构代码密度

    在第一届RISC-V中国峰会上看点很多,RISC-V是开源的,那么代码密度要怎么控制,会不会因为开源而导致代码密度特别大? 我们一起来看看risc-v峰会其
    发表于 06-23 18:22 9538次阅读
    第一届<b class='flag-5'>RISC-V</b>中国峰会看点 <b class='flag-5'>risc-v</b>开发要怎么<b class='flag-5'>优化</b><b class='flag-5'>risc-v</b>指令集架构代码密度