查看: 2005|回复: 0
收起左侧

如何建立自己的RISC-V编译环境--汇编?

[复制链接]

  离线 

  • TA的每日心情
    奋斗
    2021-1-15 13:53
  • 签到天数: 26 天

    [LV.4]

    发表于 2020-8-19 12:06:26 | 显示全部楼层 |阅读模式

    有人预言,RISC-V或将是继Intel和Arm之后的第三大主流处理器体系。欢迎访问全球首家只专注于RISC-V单片机行业应用的中文网站

    您需要 登录 才可以下载或查看,没有帐号?立即注册

    x
    本帖最后由 新ちゃん 于 2020-8-20 22:18 编辑

    如何建立自己的RISC-V编译环境–汇编?
    1.RISC-V编译环境框架

    这是我RISC-V编译环境的架构:

    1. build  case  common  toolchain
    复制代码


    一级目录二级目录说明
    build-xx.hex、xx.bin、xx.dump & xx.elf生成的目录。
    -Makefile编译脚本。
    -add(例子)生成文件,根据test.c生成的xx.hex、xx.bin、xx.dump & xx.elf
    project-各个目录的源代码。
    -add(例子)放add项目的S文件。
    common-各个项目公用的文件。
    -encoding.h/riscv-tests/env目录中的H文件。
    -asm.h/riscv-tests/env/p/riscv_test.h文件,只是我改为asm.h。
    -asm.ld/riscv-tests/env/p/link.ld文件,用于链接物理地址和汇编,我改名字为asm.ld了。
    toolchain-工具链。我在/riscv-tools/riscv-gnu-toolchain/的工具链上提取了对我有用的部分。

    2.各目录内容介绍

    2.1 toolchain:工具链目录我不打算介绍,如果有不明白的,可以看 rocket-chip工具链的编译与使用


    2.2 project:这个目录就是放你的项目代码的。每个项目建立一个目录。在这个例子中,我放的是add目录,add的源代码如下(全为汇编代码):

    此外,RISC-V汇编不熟悉的可以参考以下链接:


    https://github.com/riscv/riscv-asm-manual/blob/master/riscv-asm.md
    https://mp.weixin.qq.com/s/-syKN0DibKGGPCllaeNqMg
    https://mp.weixin.qq.com/s/jyI-SSm_5Gg-KQyjKsIj5Q
    https://mp.weixin.qq.com/s/3RHss3vhfK004-TtM8fpeA
    https://mp.weixin.qq.com/s/Ln4qBYvSsgRvdiK1IJqI6Q


    下面贴图为.section的说明。

    国内芯片技术交流-如何建立自己的RISC-V编译环境--汇编?risc-v单片机中文社区(1)



    注意,下文中使用“###”形式的均是我添加的注释,原代码中没有。


    1. <font size="3">#*****************************************************************************
    2. # add.S
    3. #-----------------------------------------------------------------------------
    4. #
    5. # Test add instructions.
    6. #

    7. #屏蔽了原来的include "riscv_test.h"
    8. ######include "riscv_test.h"
    9. #使用我自己的asm.h
    10. #include "asm.h"

    11. ###使用RVTEST_RV32U段内容
    12. RVTEST_RV32U
    13. ###使用RVTEST_CODE_BEGIN段内容
    14. RVTEST_CODE_BEGIN
    15. ###按2^2字节(4字节)数据对齐
    16.   .align 2
    17.   ###“.option push”伪操作暂时将当前的选项设置保存起来,
    18.   ###从而允许之后使用.option伪操作指定新的选项;
    19.   ###而“.option pop”伪操作将最近保存的选项设置恢复出来重新生效。
    20.   ###通过“.option push”和“.option pop”的组合,便可以在汇编程序中在不影响全
    21.   ###局选项设置的情况下,为其中嵌入的某一段代码特别地设置不同的选项。
    22.   ###意思就是:
    23.   ###在add.S这个汇编文件中,将前面其他.S/.h文件中的配置选项保存起来,
    24.   ###然后在add.S文件中设置一些新的选项,新的选项就是下面的.option norvc
    25.   .option push
    26.   ###伪操作表示接下来的汇编程序不可以被汇编生成16位宽的压缩指令。
    27.   .option norvc

    28. ###定义标签asm_start
    29. asm_start:
    30.   ###将0xAAAAAAAA赋给a1
    31.   li   a1, 0xAAAAAAAA
    32.   ###将0x22222222赋给a1
    33.   li   a0, 0x22222222
    34.   ###将a0和a1相加,并出入a2中
    35.   add  a2, a1, a0
    36.   ###将0x7000_0000存入a4中
    37.   lui  a4, 0x70000
    38.   ###将a4的值+4并存入a6中
    39.   addi a6, a4, 4
    40.   ###将a2的结果存到总线为0x7000_0004的memory中
    41.   sw   a2, 0(a6)
    42.   ###将0xFF存到a5中
    43.   li   a5, 255
    44.   ###将a5的结果存到总线为0x7000_0000的memory中,用于停止VCS仿真
    45.   sw   a5, 0(a4)

    46.   ###恢复原选项配置
    47.   .option pop

    48. ###使用RVTEST_CODE_END段内容
    49. RVTEST_CODE_END
    50.   
    51.   ###数据段.data:已初始化的C程序全局变量和静态局部变量。
    52.   .data
    53. ###使用RVTEST_DATA_BEGIN段内容
    54. RVTEST_DATA_BEGIN

    55. ###使用RVTEST_DATA_END段内容
    56. RVTEST_DATA_END</font>
    复制代码


    以下的定义在asm.h中有详细的说明。


    RVTEST_RV32U
    RVTEST_CODE_BEGIN
    RVTEST_CODE_END
    RVTEST_DATA_BEGIN
    RVTEST_DATA_END


    2.3 common:这个目录放的是通用的内容,例如asm.h和asm.lk。


    2.3.1 encoding.h:这个文件不解释,就是RISC-V各重要CSR寄存器的定义。



    2.3.2 asm.h:这个我是根据/riscv-tests/env/p/riscv_test.h文件进行修改的,下面简单说明一下里面各汇编的含义。
    此外,我修改的是p目录下的文件,p目录下是单核的,而且是没有MMU的。具体env中各目录的差异大家可以看:
    https://github.com/riscv/riscv-tests/tree/7ef425b4aea0a93568c788e68acebcc2f08da8d6



    国内芯片技术交流-如何建立自己的RISC-V编译环境--汇编?risc-v单片机中文社区(2)

    1. // See LICENSE for license details.

    2. #ifndef _ENV_PHYSICAL_SINGLE_CORE_H
    3. #define _ENV_PHYSICAL_SINGLE_CORE_H

    4. #include "./encoding.h"

    5. //-----------------------------------------------------------------------
    6. // Begin Macro
    7. //-----------------------------------------------------------------------

    8. ###定义宏init
    9. #define RVTEST_RV64U                                                    \
    10.   .macro init;                                                          \
    11.   .endm

    12. ###定义宏init,同时运行RVTEST_FP_ENABLE段
    13. #define RVTEST_RV64UF                                                   \
    14.   .macro init;                                                          \
    15.   RVTEST_FP_ENABLE;                                                     \
    16.   .endm

    17. ###定义宏init
    18. #define RVTEST_RV32U                                                    \
    19.   .macro init;                                                          \
    20.   .endm

    21. ###定义宏init,同时运行RVTEST_FP_ENABLE段
    22. #define RVTEST_RV32UF                                                   \
    23.   .macro init;                                                          \
    24.   RVTEST_FP_ENABLE;                                                     \
    25.   .endm

    26. ###定义宏init
    27. #define RVTEST_RV64M                                                    \
    28.   .macro init;                                                          \
    29.   RVTEST_ENABLE_MACHINE;                                                \
    30.   .endm

    31. ###定义宏init,同时运行RVTEST_ENABLE_SUPERVISOR段
    32. #define RVTEST_RV64S                                                    \
    33.   .macro init;                                                          \
    34.   RVTEST_ENABLE_SUPERVISOR;                                             \
    35.   .endm

    36. ###定义宏init,同时运行RVTEST_ENABLE_MACHINE段
    37. #define RVTEST_RV32M                                                    \
    38.   .macro init;                                                          \
    39.   RVTEST_ENABLE_MACHINE;                                                \
    40.   .endm

    41. ###定义宏init,同时运行RVTEST_ENABLE_SUPERVISOR段
    42. #define RVTEST_RV32S                                                    \
    43.   .macro init;                                                          \
    44.   RVTEST_ENABLE_SUPERVISOR;                                             \
    45.   .endm

    46. ###运行CHECK_XLEN段
    47. #if __riscv_xlen == 64
    48. ###将1装入a0;将a0的值进行逻辑左移31位;如果a0的值≥0,跳转至标志为1的地方;
    49. ###运行RVTEST_PASS段;标志1的位置。
    50. ###1f的意思是向前找第一个数字为1的标志,即往下面的行找
    51. # define CHECK_XLEN li a0, 1; slli a0, a0, 31; bgez a0, 1f; RVTEST_PASS; 1:
    52. #else
    53. ###将1装入a0;将a0的值进行逻辑左移31位;如果a0的值<0,跳转至标志为1的地方;
    54. ###运行RVTEST_PASS段;标志1的位置。
    55. # define CHECK_XLEN li a0, 1; slli a0, a0, 31; bltz a0, 1f; RVTEST_PASS; 1:
    56. #endif

    57. ###定义INIT_PMP段的内容
    58. #define INIT_PMP                                                        \
    59.   ###将标志1的PC赋值给t0
    60.   la t0, 1f;                                                            \
    61.   ###将t0的值赋值给mtvec
    62.   csrw mtvec, t0;                                                       \
    63.   ###将-1赋值给t0,实际上是赋0xFFFF_FFFF给t0
    64.   li t0, -1;        /* Set up a PMP to permit all accesses */           \
    65.   ###将t0的值写入pmpaddr0 CSR寄存器中
    66.   csrw pmpaddr0, t0;                                                    \
    67.   ###将PMP_NAPOT | PMP_R | PMP_W | PMP_X的值赋给t0,这些值在encoding.h中定义
    68.   li t0, PMP_NAPOT | PMP_R | PMP_W | PMP_X;                             \
    69.   ###将t0的值写入pmpcfg0 CSR寄存器中
    70.   csrw pmpcfg0, t0;                                                     \
    71.    ###按2^2字节(4字节)数据对齐
    72.   .align 2;                                                             \
    73. ###标志1的具体位置
    74. 1:

    75. /*Configure MMU*/
    76. /*SATP:Supervisor Address Translation and Protection (satp) Register*/
    77. #define INIT_SATP                                                       \
    78.   ###将标志1的PC赋值给t0
    79.   la t0, 1f;                                                            \
    80.   ###t0的值赋给mtvec
    81.   csrw mtvec, t0;                                                       \
    82.   ###写CSR寄存器sptrb为0
    83.   csrwi sptbr, 0;                                                       \
    84.   ###按2^2字节(4字节)数据对齐
    85.   .align 2;                                                             \
    86. ###标志1的具体位置
    87. 1:

    88. ###定义DELEGATE_NO_TRAPS段的内容,这是对应多模式情况下的
    89. ###将中断权限分配到其他模式中,不单单机器模式可以处理中断
    90. #define DELEGATE_NO_TRAPS                                               \
    91.   ###将标志1的PC赋值给t0
    92.   la t0, 1f;                                                            \
    93.   ###t0的值赋给mtvec
    94.   csrw mtvec, t0;                                                       \
    95.   ###写CSR寄存器medeleg(异常)为0,如果没有这个CSR寄存器会产生异常
    96.   csrwi medeleg, 0;                                                     \
    97.   ###写CSR寄存器mideleg(中断)为0,如果没有这个CSR寄存器会产生异常
    98.   csrwi mideleg, 0;                                                     \
    99.   ###写CSR寄存器mie为0,清除中断使能
    100.   csrwi mie, 0;                                                         \
    101.    ###按2^2字节(4字节)数据对齐
    102.   .align 2;                                                             \
    103. ###标志1的具体位置
    104. 1:

    105. ###定义RVTEST_ENABLE_SUPERVISOR段的内容
    106. ###SUPERVISOR模式的定义
    107. #define RVTEST_ENABLE_SUPERVISOR                                        \
    108.   li a0, MSTATUS_MPP & (MSTATUS_MPP >> 1);                              \
    109.   csrs mstatus, a0;                                                     \
    110.   ###将SIP_SSIP | SIP_STIP赋给a0
    111.   li a0, SIP_SSIP | SIP_STIP;                                           \
    112.   ###将a0赋值给mideleg CSR寄存器,用于授权SUPERVISOR模式可以处理中断
    113.   csrs mideleg, a0;                                                     \

    114. ###定义RVTEST_ENABLE_MACHINE段的内容
    115. ### MACHINE模式的定义
    116. #define RVTEST_ENABLE_MACHINE                                           \
    117.   ###将MSTATUS_MPP赋给a0,MSTATUS_MPP在encoding.h中定义
    118.   li a0, MSTATUS_MPP;                                                   \
    119.   ###将a0的值赋给mstatus
    120.   csrs mstatus, a0;                                                     \

    121. ###定义VTEST_FP_ENABLE段的内容
    122. ###浮点模式的定义
    123. #define RVTEST_FP_ENABLE                                                \
    124.   ###将MSTATUS_FS & (MSTATUS_FS >> 1)赋给a0
    125.   li a0, MSTATUS_FS & (MSTATUS_FS >> 1);                                \
    126.   ###将a0赋给mstatus
    127.   csrs mstatus, a0;                                                     \
    128.   ###将0写入到fcsr CSR寄存器中,如果核没有支持浮点功能,则不会存在fcsr,
    129.   ###写fcsr的行为会报异常
    130.   csrwi fcsr, 0

    131. ###定义RISCV_MULTICORE_DISABLE段的内容
    132. ###不使用多核的配置
    133. #define RISCV_MULTICORE_DISABLE                                         \
    134.   ###读mhartid CSR寄存器的值,并赋给a0
    135.   csrr a0, mhartid;                                                     \
    136.   ###判断a0的值,如果不等于0,则一直保持在标志1的位置,即多核情况下,
    137.   ###一直保持在标志1的位置,1b为向后找第一个数字为1的标志,也就是这条指令
    138.   ###若等于0,则为单核,可以进行下面的指令执行
    139.   1: bnez a0, 1b

    140. ###定义EXTRA_TVEC_USER、EXTRA_TVEC_MACHINE、
    141. ###EXTRA_INIT和EXTRA_INIT_TIMER,这些段虽然定义了,但没有内容,
    142. ###需要用到的自己补充汇编内容
    143. #define EXTRA_TVEC_USER
    144. #define EXTRA_TVEC_MACHINE
    145. #define EXTRA_INIT
    146. #define EXTRA_INIT_TIMER

    147. ###定义NTERRUPT_HANDLER段内容,将跳到other_exception函数中
    148. #define INTERRUPT_HANDLER j other_exception /* No interrupts should occur */

    149. ###定义RVTEST_CODE_BEGIN段的内容
    150. #define RVTEST_CODE_BEGIN                                               \
    151.         ###指令代码段.text
    152.         .section .text.init;                                            \
    153.         ###按2^6(64字节)对齐
    154.         .align  6;                                                      \
    155.         ###占个位置,后面有对stvec_handler定义的,就会覆盖
    156.         .weak stvec_handler;                                            \
    157.         ###占个位置,后面有对mtvec_handler定义的,就会覆盖
    158.         .weak mtvec_handler;                                            \
    159.         ### .global和.globl伪操作用于定义一个全局的符号,使得链接器能够全
    160.         ###局识别它,即一个程序文件中定义的符号能够被所有
    161.         ###其他程序文件可见。指定汇编程序入口为_start,即代码的最开始地方。
    162.         .globl _start;                                                  \
    163. _start:                                                                 \
    164.         /* reset vector */                                              \
    165.                 ###跳到reset_vector函数中
    166.         j reset_vector;                                                 \
    167.         ###跳到asm_start函数中,这是我自己改的,不用那么多繁琐的步骤,直接跳
    168.         /* j asm_start; */                                                \
    169.         ###按2^2(4字节)对齐
    170.         .align 2;                                                       \
    171. trap_vector:                                                            \
    172.         /* test whether the test came from pass/fail */                 \
    173.                 ###将mcasue的值赋给t5
    174.         csrr t5, mcause;                                                \
    175.         ###将CAUSE_USER_ECALL值赋给t6
    176.         li t6, CAUSE_USER_ECALL;                                        \
    177.         ###如果t5和t6相等,则跳到write_tohost函数中
    178.         beq t5, t6, write_tohost;                                       \
    179.         ###将CAUSE_SUPERVISOR_ECALL值赋给t6
    180.         li t6, CAUSE_SUPERVISOR_ECALL;                                  \
    181.         ###如果t5和t6相等,则跳到write_tohost函数中
    182.         beq t5, t6, write_tohost;                                       \
    183.         ###将CAUSE_MACHINE_ECALL值赋给t6
    184.         li t6, CAUSE_MACHINE_ECALL;                                     \
    185.         ###如果t5和t6相等,则跳到write_tohost函数中
    186.         beq t5, t6, write_tohost;                                       \
    187.         /* if an mtvec_handler is defined, jump to it */                \
    188.         la t5, mtvec_handler;                                           \
    189.         ###如果没有定义mtvec_handler函数,则mtvec_handler为0,等于0则跳到标志1
    190.         beqz t5, 1f;                                                    \
    191.         jr t5;                                                          \
    192.         /* was it an interrupt or an exception? */                      \
    193.         ###前面的异常/中断都不符合了,才跳到这,对mcause的值到t5中
    194.   1:    csrr t5, mcause;                                                \
    195.         ###如果t5≥0,则跳到handle_exception中
    196.         bgez t5, handle_exception;                                      \
    197.         ###如果连handle_exception都不是,那就跳到other_exception中
    198.         INTERRUPT_HANDLER;                                              \
    199. handle_exception:                                                       \
    200.         /* we don't know how to handle whatever the exception was */    \
    201.         ###意思就是,这里需要你自己补充,如果想用的话
    202.   other_exception:                                                      \
    203.         /* some unhandlable exception occurred */                       \
    204.         ###意思就是,这里需要你自己补充,如果想用的话
    205.   ###利用TESTNUM和立即数1337进行或操作
    206.   1:    ori TESTNUM, TESTNUM, 1337;                                     \
    207.   ### write_tohost函数
    208.   write_tohost:                                                         \
    209.                 ###将TESTNUM的值存到tohost的位置上
    210.         sw TESTNUM, tohost, t5;                                         \
    211.                 ###PC一直保持在当前位置,进入死循环
    212.         j write_tohost;                                                 \
    213. reset_vector:                                                           \
    214.         ###运行RISCV_MULTICORE_DISABLE的内容
    215.         RISCV_MULTICORE_DISABLE;                                        \
    216.         ###运行INIT_SATP的内容,因为我生成的没有MMU,所以屏蔽了这句
    217.         ###如果不屏蔽,会产生异常,但也没有影响,因为异常处理的PC就是接下来的指令
    218.         /*INIT_SATP;*/                                                  \
    219.         ###运行INIT_PMP的内容
    220.         INIT_PMP;                                                       \
    221.         ###运行DELEGATE_NO_TRAPS的内容
    222.         DELEGATE_NO_TRAPS;                                              \
    223.                 ###因为运行DELEGATE_NO_TRAPS时产生了异常,所以下一句清除异常
    224.         csrw mcause, 0;                                                 \
    225.                 ###将0赋值给TESTNUM(gp)
    226.         li TESTNUM, 0;                                                  \
    227.         ###将trap_vector的物理地址赋值给t0
    228.         la t0, trap_vector;                                             \
    229.         ###将t0赋值给mtvec CSR寄存器
    230.         csrw mtvec, t0;                                                 \
    231.         ###运行CHECK_XLEN的内容
    232.         CHECK_XLEN;                                                     \
    233.         /* if an stvec_handler is defined, delegate exceptions to it */ \
    234.         ###这里如果有定义stvec_handler就会进入下面的指令,没有就跳到标志1
    235.         la t0, stvec_handler;                                           \
    236.         beqz t0, 1f;                                                    \
    237.         csrw stvec, t0;                                                 \
    238.         ###将一些特殊的中断或者异常,MMU相关,授权给其他模式处理
    239.         li t0, (1 << CAUSE_LOAD_PAGE_FAULT) |                           \
    240.                (1 << CAUSE_STORE_PAGE_FAULT) |                          \
    241.                (1 << CAUSE_FETCH_PAGE_FAULT) |                          \
    242.                (1 << CAUSE_MISALIGNED_FETCH) |                          \
    243.                (1 << CAUSE_USER_ECALL) |                                \
    244.                (1 << CAUSE_BREAKPOINT);                                 \
    245.         csrw medeleg, t0;                                               \
    246.         csrr t1, medeleg;                                               \
    247.         bne t0, t1, other_exception;                                    \
    248.         ###将0写入mstatus CSR寄存器中
    249. 1:      csrwi mstatus, 0;                                               \
    250.                 ###这句编译出来的是auipc        t0,0x0
    251.         init;                                                           \
    252.                  ###这个没有定义,所以是空的
    253.         EXTRA_INIT;                                                     \
    254.         ###这个没有定义,所以是空的
    255.         EXTRA_INIT_TIMER;                                               \
    256.                 ###跳到标志1的位置赋值给t0
    257.         la t0, 1f;                                                      \
    258.         ###将t0赋值给mepc
    259.         csrw mepc, t0;                                                  \
    260.                 ###将mhartid的值赋值给a0
    261.         csrr a0, mhartid;                                               \
    262.                 ###M模式return
    263.         mret;                                                           \
    264. 1:

    265. //-----------------------------------------------------------------------
    266. // End Macro
    267. //-----------------------------------------------------------------------

    268. #define RVTEST_CODE_END                        \
    269. ###UNIMP : C0001073. This is an alias for CSRRW x0, cycle, x0. Since cycle is a
    270. ###read-only CSR, then #(whether this CSR exists or not) an attempt to write into
    271. ###it will generate an illegal instruction #exception. This 32-bit form of UNIMP is
    272. ###emitted when targeting a system without the C #extension, or when the .option
    273. ###norvc directive is used.                                         
    274.         unimp

    275. //-----------------------------------------------------------------------
    276. // Pass/Fail Macro
    277. //-----------------------------------------------------------------------

    278. #define RVTEST_PASS                                                     \
    279.                 ###执行fence指令,可以清楚ICache内容;将1赋值给gp;最后执行ecall
    280.         fence;                                                          \
    281.         li TESTNUM, 1;                                                  \
    282.         ecall

    283. #define TESTNUM gp
    284. #define RVTEST_FAIL                                                     \
    285.         ###执行fence指令
    286.         fence;                                                          \
    287.                 ###如何TESTNUM等于0,则一直停在这,不为0则执行下面的程序
    288. 1:      beqz TESTNUM, 1b;                                               \
    289.                 ###将TESTNUM的值逻辑左移1位,并重新赋值给TESTNUM
    290.         sll TESTNUM, TESTNUM, 1;                                        \
    291.         ###将TESTNUM的值与1或,并重新赋值给TESTNUM
    292.         or TESTNUM, TESTNUM, 1;                                         \
    293.         ecall

    294. //-----------------------------------------------------------------------
    295. // Data Section Macro
    296. //-----------------------------------------------------------------------

    297. ###定义了EXTRA_DATA,但是是空的
    298. #define EXTRA_DATA

    299. ###此段基本是空的,需要用到的,要自己添加内容
    300. #define RVTEST_DATA_BEGIN                                               \
    301.         EXTRA_DATA                                                      \
    302.         ###将之前的段设置保存,并将当前的段设置改名.tohost
    303.         .pushsection .tohost,"aw",@progbits;                            \
    304.         .align 6; .global tohost; tohost: .dword 0;                     \
    305.         .align 6; .global fromhost; fromhost: .dword 0;                 \
    306.         ###恢复之前的段设置
    307.         .popsection;                                                    \
    308.         .align 4; .global begin_signature; begin_signature:

    309. #define RVTEST_DATA_END .align 4; .global end_signature; end_signature:

    310. #endif
    复制代码


    2.3.3 asm.lk:这个文件就是/riscv-tests/env/p/link.ld文件,只是我改了名字。

    1. SECTIONS
    2. {
    3.   /*. = 0x80000000;*/
    4.   ###这里我修改了,因为我想它从我的ROM直接执行,我的ROM地址是0x10000
    5.   . = 0x00010000;
    6.   .text.init : { *(.text.init) }
    7.   . = ALIGN(0x1000);
    8.   .tohost : { *(.tohost) }
    9.   . = ALIGN(0x1000);
    10.   .text : { *(.text) }
    11.   . = ALIGN(0x1000);
    12.   .data : { *(.data) }
    13.   .bss : { *(.bss) }
    14.   _end = .;
    15. }
    复制代码


    2.4 bulid:这个目录最主要的是Makefile脚本,用于调用工具链编译asm。我只贴部分代码,是生成elf的代码,生成bin、hex和dump的方法大家参考/riscv-tests/benchmarks/Makefile。
    部分代码:


    1. #--------------------------------------------------------------------
    2. # author        :        x
    3. # data        :        2019.4.2
    4. # name        :        project compiler for rocket-chip
    5. #--------------------------------------------------------------------

    6. proj_name ?= add

    7. #--------------------------------------------------------------------
    8. # Build rules
    9. #--------------------------------------------------------------------

    10. RISCV_PREFIX ?= ../toolchain/bin/riscv32-unknown-elf-
    11. RISCV_GCC ?= $(RISCV_PREFIX)gcc
    12. RISCV_GCC_OPTS ?= -DPREALLOCATE=1 -mcmodel=medany -static -std=gnu99 -O2 -ffast-math -fno-common -fno-builtin-printf
    13. RISCV_LINK_OPTS ?= -static -nostdlib -nostartfiles -lm -lgcc -T ../common/asm.ld
    14. SOURCE_FILE ?= ../common ../asm/$(proj_name)/*.S

    15. #--------------------------------------------------------------------
    16. # Object
    17. #--------------------------------------------------------------------

    18. default:
    19.         make all

    20. elf:
    21.         $(RISCV_GCC) $(RISCV_GCC_OPTS) -o $(proj_name)/$(proj_name).elf $(SOURCE_FILE) $(RISCV_LINK_OPTS)

    22. all: elf
    复制代码



    3.反汇编文件

    1. add/add.elf:     file format elf32-littleriscv


    2. Disassembly of section .text.init:

    3. 00010000 <_start>:
    4. _start():
    5.    10000:        a081                        j        10040 <reset_vector>
    6.    10002:        0001                        nop

    7. 00010004 <trap_vector>:
    8. trap_vector():
    9.    10004:        34202f73                  csrr        t5,mcause
    10.    10008:        4fa1                        li        t6,8
    11.    1000a:        03ff0663                  beq        t5,t6,10036 <write_tohost>
    12.    1000e:        4fa5                        li        t6,9
    13.    10010:        03ff0363                  beq        t5,t6,10036 <write_tohost>
    14.    10014:        4fad                        li        t6,11
    15.    10016:        03ff0063                  beq        t5,t6,10036 <write_tohost>
    16.    1001a:        ffff0f17                  auipc        t5,0xffff0
    17.    1001e:        fe6f0f13                  addi        t5,t5,-26 # 0 <_start-0x10000>
    18.    10022:        000f0363                  beqz        t5,10028 <trap_vector+0x24>
    19.    10026:        8f02                        jr        t5
    20.    10028:        34202f73                  csrr        t5,mcause
    21.    1002c:        000f5363                  bgez        t5,10032 <handle_exception>
    22.    10030:        a009                        j        10032 <handle_exception>

    23. 00010032 <handle_exception>:
    24. handle_exception():
    25.    10032:        5391e193                  ori        gp,gp,1337

    26. 00010036 <write_tohost>:
    27. write_tohost():
    28.    10036:        00001f17                  auipc        t5,0x1
    29.    1003a:        fc3f2523                  sw        gp,-54(t5) # 11000 <tohost>
    30.    1003e:        bfe5                        j        10036 <write_tohost>

    31. 00010040 <reset_vector>:
    32. reset_vector():
    33.    10040:        f1402573                  csrr        a0,mhartid
    34.    10044:        e101                        bnez        a0,10044 <reset_vector+0x4>
    35.    10046:        00000297                  auipc        t0,0x0
    36.    1004a:        01a28293                  addi        t0,t0,26 # 10060 <reset_vector+0x20>
    37.    1004e:        30529073                  csrw        mtvec,t0
    38.    10052:        52fd                        li        t0,-1
    39.    10054:        3b029073                  csrw        pmpaddr0,t0
    40.    10058:        42fd                        li        t0,31
    41.    1005a:        3a029073                  csrw        pmpcfg0,t0
    42.    1005e:        0001                        nop
    43.    10060:        00000297                  auipc        t0,0x0
    44.    10064:        01828293                  addi        t0,t0,24 # 10078 <reset_vector+0x38>
    45.    10068:        30529073                  csrw        mtvec,t0
    46.    1006c:        30205073                  csrwi        medeleg,0
    47.    10070:        30305073                  csrwi        mideleg,0
    48.    10074:        30405073                  csrwi        mie,0
    49.    10078:        34205073                  csrwi        mcause,0
    50.    1007c:        4181                        li        gp,0
    51.    1007e:        00000297                  auipc        t0,0x0
    52.    10082:        f8628293                  addi        t0,t0,-122 # 10004 <trap_vector>
    53.    10086:        30529073                  csrw        mtvec,t0
    54.    1008a:        4505                        li        a0,1
    55.    1008c:        057e                        slli        a0,a0,0x1f
    56.    1008e:        00054763                  bltz        a0,1009c <reset_vector+0x5c>
    57.    10092:        0ff0000f                  fence
    58.    10096:        4185                        li        gp,1
    59.    10098:        00000073                  ecall
    60.    1009c:        ffff0297                  auipc        t0,0xffff0
    61.    100a0:        f6428293                  addi        t0,t0,-156 # 0 <_start-0x10000>
    62.    100a4:        00028e63                  beqz        t0,100c0 <reset_vector+0x80>
    63.    100a8:        10529073                  csrw        stvec,t0
    64.    100ac:        0000b2b7                  lui        t0,0xb
    65.    100b0:        10928293                  addi        t0,t0,265 # b109 <_start-0x4ef7>
    66.    100b4:        30229073                  csrw        medeleg,t0
    67.    100b8:        30202373                  csrr        t1,medeleg
    68.    100bc:        f6629be3                  bne        t0,t1,10032 <handle_exception>
    69.    100c0:        30005073                  csrwi        mstatus,0
    70.    100c4:        00000297                  auipc        t0,0x0
    71.    100c8:        01428293                  addi        t0,t0,20 # 100d8 <asm_start>
    72.    100cc:        34129073                  csrw        mepc,t0
    73.    100d0:        f1402573                  csrr        a0,mhartid
    74.    100d4:        30200073                  mret

    75. 000100d8 <asm_start>:
    76. asm_start():
    77.    100d8:        aaaab5b7                  lui        a1,0xaaaab
    78.    100dc:        aaa58593                  addi        a1,a1,-1366 # aaaaaaaa <_end+0xaaa98aaa>
    79.    100e0:        22222537                  lui        a0,0x22222
    80.    100e4:        22250513                  addi        a0,a0,546 # 22222222 <_end+0x22210222>
    81.    100e8:        00a58633                  add        a2,a1,a0
    82.    100ec:        70000737                  lui        a4,0x70000
    83.    100f0:        00470813                  addi        a6,a4,4 # 70000004 <_end+0x6ffee004>
    84.    100f4:        00c82023                  sw        a2,0(a6)
    85.    100f8:        0ff00793                  li        a5,255
    86.    100fc:        00f72023                  sw        a5,0(a4)
    87.         ...

    88. Disassembly of section .tohost:

    89. 00011000 <tohost>:
    90.         ...

    91. 00011040 <fromhost>:
    复制代码

    4.仿真测试

    在说明仿真前,先贴部分TB中的代码,此代码用于自动停止VCS仿真。


    具体的操作是CPU利用总线往0x7000_0000的地址写0xFF的值,然后TB就会执行$finish。


    TB的代码是:

    1.   /**************************/
    2.   /*    download memory     */
    3.   /**************************/
    4.   initial begin
    5.       #100 $readmemh("../compiler/build/add/add.hex",ldut.bootrom.rom);
    6.   end

    7.   /**************************/
    8.   /*    capture finish      */
    9.   /**************************/
    10.   always @* begin
    11.       if((mmio_axi4_0_aw_bits_addr == 31'h70000000) && mmio_axi4_0_aw_ready && mmio_axi4_0_aw_valid && (mmio_axi4_0_w_bits_data == 32'hFF)) begin
    12.           #10 $finish(2);
    13.       end
    14.   end
    复制代码



    汇编中对应的代码是:

    1. lui  a4, 0x70000
    2. li   a5, 255
    3. sw   a5, 0(a4)
    复制代码

    接下来是仿真的波形分析。

    国内芯片技术交流-如何建立自己的RISC-V编译环境--汇编?risc-v单片机中文社区(3)





    本篇完,感谢关注:RISC-V单片机中文网




    上一篇:Chisel3 &amp; Scala &amp; Rocket-chip verilog的生成
    下一篇:如何配置一个自定义的rocket-chip?
    RISCV作者优文
    全球首家只专注于RISC-V单片机行业应用的中文网站
    回复

    使用道具 举报

    高级模式
    B Color Image Link Quote Code Smilies

    本版积分规则

    关闭

    RISC-V单片机中文网上一条 /2 下一条



    版权及免责声明|RISC-V单片机中文网 |网站地图

    GMT+8, 2024-4-16 15:51 , Processed in 1.044695 second(s), 49 queries .

    快速回复 返回顶部 返回列表