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

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

3天内不再提示

在SOC环境里面C代码是怎么执行的?

sanyue7758 来源:处芯积律 2023-11-06 09:38 次阅读

不少同学很好奇在SOC环境里面C代码是怎么执行的?

是通过DPI实现SV和C的交互,然后用 SV的task将C的数据转成对应的总线数据下发到各个外设?

DPI 调用例子

e97f59dc-7bcc-11ee-939d-92fbcf53809c.png

e9916852-7bcc-11ee-939d-92fbcf53809c.png

是在verilog里面调用PLI获取C里面的内容?

PLI调用例子

e97f59dc-7bcc-11ee-939d-92fbcf53809c.png

e9a8b7aa-7bcc-11ee-939d-92fbcf53809c.png

还是通过TLM1.0 或者TLM2.0 完成C和verilog 的交互?

TLM2.0 使用例子

e9b9a614-7bcc-11ee-939d-92fbcf53809c.png

e9dd319c-7bcc-11ee-939d-92fbcf53809c.png

实际上,以上三种都不是!

在SOC验证环境中,需要仿真一颗芯片真实的工作状态。通过上面三种手段验证不CPU boot的过程,CPU处理 interrupt的过程,芯片进出低功耗的过程。

在SOC环境中怎么模拟芯片的工作过程呢?

下面是一个典型的RISCV CPU。在这个系统中,CPU会通过指令总线获取执行的程序指令,然后通过数据总线访问存储的数据和外设等。

e9f03922-7bcc-11ee-939d-92fbcf53809c.png

在下面的这个系统中,我们将RISCV的指令总线和数据总线作为两个master 挂在AHB总线上,将程序指令存储在SRAM中,当SOC启动时,会通过指令总线访问SRAM获取指令信息

CPU中拿到指令后会进行解码,然后通过执行单元执行解码的指令,如果需要用到外部的存储数据,则会通过数据总线访问SRAM获取存储的数据内容。如果解码内容配置外设寄存器,则通过数据总线访问外设,对外设进行配置等等。

ea08378e-7bcc-11ee-939d-92fbcf53809c.png

这里需要注意的是程序代码放在SRAM里面,一些数据内容也是分在SRAM中,假如中间不作分割,那么指令和数据会混在一起,导致RISCV在执行程序的时候会跑飞。所以我们在后面编译指令的时候,需要对memory空间进行分割。

通过上面的描述,我们大概清楚了CPU是怎么工作起来的,但是这个和我们的C程序有什么关系呢?

CPU执行的是机器码指令,这些指令是由一个个特定数据和摆放的格式决定的。

下面是32bit RISCV的部分指令格式。

ea168f32-7bcc-11ee-939d-92fbcf53809c.png

在这里R,I S,B U,J分别代表6种不同的指令。

R-formatfor register-register arithmetic/logical operations

I-formatfor register-immediate arith/logical operations and loads

S-formatfor stores

B-formatfor branches

U-formatfor 20-bit upper immediate instructions

J-formatfor jumps

R是寄存器类型指令, I是立即数类型指令,S是存储类指令,B是分支类指令,U是高20bit立即数指令,J是跳转指令。

我们以简单的立即数加法运算为例,比如我想做一个 a0= s0+16 这样一个立即数加法运算,伪代码就是 add a0,s0,16 。这个案例中我们用的是立即数类型的指令。

根据上述表格,该指令格式为

ea2a0832-7bcc-11ee-939d-92fbcf53809c.png

funct3,opcode又是什么呢?通过查询 riscv 手册可以查到以下结果。

ea387142-7bcc-11ee-939d-92fbcf53809c.png

这个立即数加法最终编译成机器码 0x01048513

ea4812b4-7bcc-11ee-939d-92fbcf53809c.png

将这个机器放在地址0x29a 的位置。

ea660c10-7bcc-11ee-939d-92fbcf53809c.png

我们把这些机器码放在SRAM里面,CPU看到拿到 0x01048513 就可以解码出来这是一个a0=s0+16的立即数操作。

到这里,我们大概知道底层的CPU是怎么执行的,现在要解决的问题是如何将C编译成机器码。

下面这个图是C语言编译成机器码的过程。

ea81296e-7bcc-11ee-939d-92fbcf53809c.png

C语言首先编译成汇编语言,再由汇编语言编译成机器指令,最后通过链接形成目标机器指令。

我们以SOC3.0的环境为例子,看看这个过程怎么执行的。

首先我们看SOC3.0的环境里面都有哪些文件。

crt0.S

"crt"代表"C runtime"(零表示"一切的开始")。

crt0是一组执行启动例程,编译到程序中,在调用程序的主函数之前执行任何必要的初始化工作——它是一个基本的运行时库/运行时系统。crt0的工作取决于程序的语言、编译器、操作系统和C标准库的实现。

在SOC3.0里面crt0.S 是汇编语言写的。

这段代码做什么事情呢?

异常处理程序:

default_exc_handler 是一个通用的异常处理程序,似乎被设置为各种异常的处理程序,比如外部中断、非法指令和系统调用 (ecall)。

还有其他异常向量的占位符(nop指令),表明它们可能以类似的方式处理。

复位处理程序:

reset_handler 将所有寄存器设置为零,并通过加载堆栈起始地址来初始化堆栈。

清除BSS段:

它通过用零填充来清除BSS(由符号开始的块)段。通常这样做是为了确保所有未初始化的全局和静态变量都以零值开始。

跳转到主函数:

最后,它跳转到 main 函数,并将 argc 和 argv 设置为零。

注意我们C 代码的main 函数的命名不是天生就是这么命名的,是在这里给定的。

异常向量:

.vectors 部分定义了异常向量。它似乎对各种异常使用默认的异常处理程序,还有一个重置向量指向 reset_handler。

ea97f4be-7bcc-11ee-939d-92fbcf53809c.png

2. C函数

以spi1_test test为例子

common.c ,这里定义了一些打印字符串和读写寄存器的函数。

eab93386-7bcc-11ee-939d-92fbcf53809c.png

spi1_test.c ,这里实现对spi1这个IP的配置及自我检查。

ead9c128-7bcc-11ee-939d-92fbcf53809c.png

3. 链接文件link.ld

我们在上文说了,在SRAM里面如果不对程序存储空间和数据存储空间进行分割,那么CPU执行的时候很可能跑飞。为了组织内存分配,需要一个链接文件进行配置。

link.ld是一个链接脚本(linker script),用于指导链接器如何组织程序在内存中的布局。具体来说,它包含了以下关键信息:

内存布局:

内存被划分为两个区域:rom(48 kB)和stack(16 kB)。

rom从地址0x00000000开始,stack从地址0x0000C000开始。

堆栈信息:

_min_stack设置为0x2000(8 kB),表示要保留的最小堆栈空间。

_stack_len是stack区域的长度。

_stack_start是堆栈的起始地址。

各个段:

.vectors 段包含中断向量,位于rom的开头。

.text 段包含程序代码。构造函数和析构函数列表用于处理C++

.rodata 段包含只读数据。

.shbss 段在rom中对齐并放置。

.data 段包含已初始化的数据。

.bss 段包含未初始化的数据。

.stack 段确保堆栈有足够的空间。

特殊段(NOLOAD):

.stack 段标记为 NOLOAD,意味着它不会加载到最终的二进制文件中。它只是为堆栈保留空间。

.stab 和 .stabstr 段也被定义,但标记为 NOLOAD,表明它们是调试信息。

eafc3ad2-7bcc-11ee-939d-92fbcf53809c.png

有了上面这些文件,我们看看Makefile 怎么将spi1_test.c 编译成机器码的。

第一步,通过riscv提供的工具链将C和汇编.S的文件编译成目标文件。

eb1e3132-7bcc-11ee-939d-92fbcf53809c.png

eb3272e6-7bcc-11ee-939d-92fbcf53809c.png  --->

eb4442fa-7bcc-11ee-939d-92fbcf53809c.png

第二步,将生成的.o目标文件链接成elf文件

ELF(Executable and Linkable Format)是一种用于可执行文件、目标文件、共享库和核心转储文件的标准文件格式。它是一种二进制文件格式,设计用于在多种操作系统上支持可执行文件可重定位代码的交互性。

eb518834-7bcc-11ee-939d-92fbcf53809c.png

第三步,用elf文件生成 二进制文件(机器码) .bin文件

eb6ed77c-7bcc-11ee-939d-92fbcf53809c.png

到这里我们已经产生了机器码的文件.bin,按理说CPU拿这个文件就可以执行了。但是在我们环境里面,我们需要将机器码放到verilog 的sram memory里面去。所以我们还做了第四步。

第四步,将.bin 文件转换为一个包含二进制数据的Verilog内存初始化文件。

eb81db7e-7bcc-11ee-939d-92fbcf53809c.png

通过上面四步,我们实现了C到机器码的转换。

我们将生成的spi1_test.vmem 放到SOC环境中,sram的memory 通过readm 读进这些机器码。然后通过仿真,就可以模拟SOC执行的过程。

按理说到里面我们应该结束今天的文章,但是当我们回头看看我们环境似乎还缺些什么。

没错那就是机器码的反标,当我们debug cpu的时候,cpu记录当前执行的指令和指令行数,我们通过这些信息可以定位具体在操作哪条机器码,但是我们怎么样才知道当前的机器码对应是C代码里面的拿哪段内容呢?

这就需要机器码的反标,在我们SOC3.0的环境里面,我们通过下面指令完成机器码到C的反标。

eb9c247a-7bcc-11ee-939d-92fbcf53809c.png

我们看看效果。

ebacdcac-7bcc-11ee-939d-92fbcf53809c.png

非常方便。

以上是我们文章的所有内容,上述所列案例在我们SOC3.0里面都有,欢迎感兴趣的小伙伴咨询。

关于 SOC3.0,小伙伴们可以点这里。

SOC3.0有哪些东西?

或者直接联系梨果。







审核编辑:刘清

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

    关注

    31

    文章

    5258

    浏览量

    119406
  • soc
    soc
    +关注

    关注

    38

    文章

    4034

    浏览量

    217271
  • Verilog
    +关注

    关注

    28

    文章

    1333

    浏览量

    109777
  • DPI
    DPI
    +关注

    关注

    0

    文章

    34

    浏览量

    11488
  • SRAM存储器
    +关注

    关注

    0

    文章

    88

    浏览量

    13253

原文标题:干货,在SOC验证环境中,C代码是怎么被执行起来的?

文章出处:【微信号:处芯积律,微信公众号:处芯积律】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    modustoolbox开发环境里面如何通过快捷方式批量屏蔽代码

    modustoolbox开发环境里面如何通过快捷方式批量屏蔽代码,目前是通过/*********/的方式来屏蔽, 谢谢!
    发表于 02-01 06:52

    芯海通用 MCU 应用笔记: MDK 开发环境代码重定向到 RAM 执行的几种方法

    空间并写入新的代码。此外还具备执行效率高,寿命长优点。 本文档介绍和说明 MDK 开发环境下将代码重定向到 RAM 中
    发表于 05-16 11:58

    SOC快速入门

    的“gizwitsEventProcess()函数里添加驱动外设执行事件函数即可实现控制设备上报云端状态事件处理,可以“GizLamp\app\user”文件目录下“user_main.c”文件
    发表于 02-27 18:21

    请教关于c6678的sy***ios代码执行疑问

    EVM_init代码?(2)为什么不将EVM_init代码放到main里面去?main之前执行EVM_init有什么好处?
    发表于 07-25 06:22

    ucos执行问题

    假设我设置了3个任务A、B、C,然后每个任务里面都有while(1),while(1)里面执行了相应
    发表于 04-02 23:04

    如何提高C语言程序的执行效率

    我们平常所说的执行效率就是使用相同的算法相同输入条件下完成相同计算所产生的系统开销,目前来说一般会更多关注执行时间方面的开销。所有语言编写的代码最终要运行,都要转化成机器码。
    发表于 07-20 06:39

    程序的翻译环境执行环境有何不同

    程序的翻译环境执行环境ANSI C的任何一种实现中,存在两个不同的环境。翻译
    发表于 02-28 06:57

    一个优秀的SOC验证环境应该具备哪些功能呢

    小编前段时间帮客户找到一些人解决了SOC验证环境的问题。招人的时候我们和不少人进行了沟通交流,从中发现SOC验证环境一千家公司有一千家公司
    发表于 05-31 11:39

    怎样用C语言去启动SOC验证环境

    SOC,CPU通过总线访问SPI,USB,PCIE,DDR,I2C等。SOC验证环境里面,通
    发表于 06-17 14:41

    执行环境(EE)协议栈中的定位

    执行环境(EE)协议栈中的定位 前面提到,执行环境应当在协议栈中相对较低的层次上实现。设计
    发表于 03-02 11:11 605次阅读

    高效的C编程之条件执行

    4.3 条件执行 ARM指令都是可以条件执行的。代码中使用条件执行指令可以减小代码密度并提高程
    发表于 10-17 16:52 2次下载

    C语言的源代码文件和目标文件与可执行文件的详细介绍

    1、源代码文件 存放程序代码的文件,即我们编辑代码的文件,称为源代码文件。 C语言源程序文件的扩展名为“.
    的头像 发表于 02-18 11:52 8372次阅读

    使用C语言Linux环境下运行推箱子游戏的代码免费下载

    本文档的主要内容详细介绍的是使用C语言Linux环境下运行推箱子游戏的代码免费下载,现在分享给大家游戏游戏,现在有80多关。如果需要添加其他关卡,很容易扩展,仅供娱乐学习!。
    发表于 05-19 08:00 5次下载
    使用<b class='flag-5'>C</b>语言<b class='flag-5'>在</b>Linux<b class='flag-5'>环境</b>下运行推箱子游戏的<b class='flag-5'>代码</b>免费下载

    IAR 8051 与Keil C51 的代码差异

    51 和Keil C51 代码写法方面的基本差异。注:最大的差异是可以用C++ 了~ 模板,命名空间什么的都有。启动代码
    发表于 11-21 15:36 12次下载
    IAR 8051 与Keil <b class='flag-5'>C</b>51 的<b class='flag-5'>代码</b>差异

    MIMXRT1176代码放在ITCM里面运行,为什么执行速度并没有在外部Flash里面执行的快?

    通过IAR环境下添加__RAMFUNC,修改了函数SysTick_Ticks 以ITCM中运行,实际测得的运行速度变慢,系统计数累加的次数也减少了,代码
    的头像 发表于 01-30 09:22 1154次阅读