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

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

[复制链接]

  离线 

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

    [LV.4]

    发表于 2020-8-18 16:12:16 | 显示全部楼层 |阅读模式

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

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

    x
    本帖最后由 新ちゃん 于 2020-8-29 14:35 编辑

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


    1.RISC-V编译环境框架

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

    1. build  case  common  toolchain
    复制代码

    一级目录二级目录说明
    build-xx.hex、xx.bin、xx.dump & xx.elf生成的目录。
    -Makefile编译脚本。
    -test生成文件,根据test.c生成的xx.hex、xx.bin、xx.dump & xx.elf
    project-各个目录的源代码。
    -test放test项目的全部H文件&C文件。
    common-各个项目公用的文件。
    -encoding.h/riscv-tests/env目录中的H文件。
    -program.ld类似/riscv-tests/benchmarks/common/test.ld的文件,用于链接物理地址、汇编和C语言代码。
    -program.S最底层的汇编。
    toolchain-工具链。我在/riscv-tools/riscv-gnu-toolchain/的工具链上提取了对我有用的部分。

    2.各目录内容介绍

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


    2.2 project:这个目录就是放你的项目代码的。每个项目建立一个目录。在这个例子中,我放的是test目录,test的源代码如下(修改于/riscv-tests/benchmarks/vvadd):

    1. #define U32 *(volatile unsigned int *)
    2. #define DATA_SIZE 100

    3. int input1_data[DATA_SIZE] =
    4. {
    5.    41, 833, 564, 187, 749, 350, 132, 949, 584, 805, 621,   6, 931, 890, 392, 694, 961, 110, 116, 296,
    6.   426, 314, 659, 774, 319, 678, 875, 376, 474, 938, 539, 569, 203, 280, 759, 606, 511, 657, 195,  81,
    7.   267, 229, 337, 944, 902, 241, 913, 826, 933, 985, 195, 960, 566, 350, 649, 657, 181, 111, 859,  65,
    8.   288, 349, 141, 905, 886, 264, 576, 979, 761, 241, 478, 499, 403, 222, 444, 721, 676, 317, 224, 937,
    9.   288, 119, 615, 606, 389, 351, 455, 278, 367, 358, 584,  62, 985, 403, 346, 517, 559, 908, 775, 255
    10. };

    11. int input2_data[DATA_SIZE] =
    12. {
    13.   454, 335,   1, 989, 365, 572,  64, 153, 216, 140, 210, 572, 339, 593, 898, 228,  12, 883, 750, 646,
    14.   500, 436, 701, 812, 981, 150, 696, 564, 272, 258, 647, 509,  88, 703, 669, 375, 551, 936, 592, 569,
    15.   952, 800, 584, 643, 368, 489, 328, 313, 592, 388, 543, 649, 979, 997, 814,  79, 208, 998, 629, 847,
    16.   704, 997, 253, 715, 430, 415, 538, 700,   4, 494, 100, 864, 693, 416, 296, 285, 620,  78, 351, 540,
    17.   646, 169, 527, 289, 796, 801, 720, 758, 745,  92, 989, 271, 853, 788, 531, 222, 461, 241, 358, 332
    18.   };

    19. //--------------------------------------------------------------------------
    20. // handle_trap function

    21. void handle_trap()
    22. {
    23.   while(1);
    24. }

    25. //--------------------------------------------------------------------------
    26. // test function

    27. void test( int n, int a[], int b[])
    28. {
    29.   int i;
    30.   for ( i = 0; i < n; i++ )
    31.     U32(0x20800000+4*i) = a[i] + b[i];
    32. }

    33. //--------------------------------------------------------------------------
    34. // Main

    35. void main()
    36. {
    37.   test( DATA_SIZE, input1_data, input2_data);
    38. }
    复制代码

    2.3 common:这个目录比较重要,而且改动的地方比较多。


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


    2.3.2 program.ld:这个文件是修改于/riscv-tests/benchmarks/common/test.ld。

    1. 修改点:
    2.         1)修改了代码的启始地址。
    3.         /* text: test code section */
    4.           . = 0x80000000;
    5.         2)去除了这个一大段的空白空间。
    6.         /*. = ALIGN(0x1000);*/
    复制代码

    2.3.3 program.S:这个文件改动比较大(修改于/riscv-tests/benchmarks/common/crt.S),这个文件改动需要注意以下几点:


    1)扩展名必须为大写的S,大写的S可以使gcc自动识别汇编程序中的C预处理命令,像#include、#define、#ifdef、 #endif等,也就是说,使用gcc进行编译,你可以在汇编程序中使用C的预处理命令。
    2)因为我生成的rocket-chip是不使用浮点的,不使用虚拟内存,不使用ROCC的,所以很多内容我直接删改了,而且栈和异常入口都是根据我生成的rocket-chip来设定的,大家可以根据自己的情况进行修改。

    1. 代码:
    2. #include "encoding.h"

    3. #define LREG lw
    4. #define SREG sw
    5. #define REGBYTES 4

    6.   .section ".text.init"
    7.   .globl _start
    8. _start:
    9.   #####我是注释,下面的操作是清除32个通用寄存器。
    10.   li  x1, 0
    11.   li  x2, 0
    12.   li  x3, 0
    13.   li  x4, 0
    14.   li  x5, 0
    15.   li  x6, 0
    16.   li  x7, 0
    17.   li  x8, 0
    18.   li  x9, 0
    19.   li  x10,0
    20.   li  x11,0
    21.   li  x12,0
    22.   li  x13,0
    23.   li  x14,0
    24.   li  x15,0
    25.   li  x16,0
    26.   li  x17,0
    27.   li  x18,0
    28.   li  x19,0
    29.   li  x20,0
    30.   li  x21,0
    31.   li  x22,0
    32.   li  x23,0
    33.   li  x24,0
    34.   li  x25,0
    35.   li  x26,0
    36.   li  x27,0
    37.   li  x28,0
    38.   li  x29,0
    39.   li  x30,0
    40.   li  x31,0

    41.   #####我是注释,下面的操作是配置异常入口,异常入口为trap_entry这个标志。
    42.   # initialize trap vector
    43.   la t0, trap_entry
    44.   csrw mtvec, t0

    45.   # initialize global pointer
    46. .option push
    47. .option norelax
    48.   la gp, __global_pointer$
    49. .option pop

    50.   #####我是注释,下面的操作是配置栈的地址。
    51.   li sp, 0x80F00000

    52.   #####我是注释,下面的操作跳到我test项目中的main函数中。
    53.   j main

    54.    #####我是注释,下面的是trap_entry这个函数的内容,申请栈空间,压栈,保存
    55.    #####mcasue&mepc,跳到handle_trap函数中(上面的test.c有这个函数),处理完后
    56.    #####还原MSTATUS_MPP的模式,出栈,跳出trap_entry函数。
    57.   .align 2
    58. trap_entry:
    59.   addi sp, sp, -272

    60.   SREG x1, 1*REGBYTES(sp)
    61.   SREG x2, 2*REGBYTES(sp)
    62.   SREG x3, 3*REGBYTES(sp)
    63.   SREG x4, 4*REGBYTES(sp)
    64.   SREG x5, 5*REGBYTES(sp)
    65.   SREG x6, 6*REGBYTES(sp)
    66.   SREG x7, 7*REGBYTES(sp)
    67.   SREG x8, 8*REGBYTES(sp)
    68.   SREG x9, 9*REGBYTES(sp)
    69.   SREG x10, 10*REGBYTES(sp)
    70.   SREG x11, 11*REGBYTES(sp)
    71.   SREG x12, 12*REGBYTES(sp)
    72.   SREG x13, 13*REGBYTES(sp)
    73.   SREG x14, 14*REGBYTES(sp)
    74.   SREG x15, 15*REGBYTES(sp)
    75.   SREG x16, 16*REGBYTES(sp)
    76.   SREG x17, 17*REGBYTES(sp)
    77.   SREG x18, 18*REGBYTES(sp)
    78.   SREG x19, 19*REGBYTES(sp)
    79.   SREG x20, 20*REGBYTES(sp)
    80.   SREG x21, 21*REGBYTES(sp)
    81.   SREG x22, 22*REGBYTES(sp)
    82.   SREG x23, 23*REGBYTES(sp)
    83.   SREG x24, 24*REGBYTES(sp)
    84.   SREG x25, 25*REGBYTES(sp)
    85.   SREG x26, 26*REGBYTES(sp)
    86.   SREG x27, 27*REGBYTES(sp)
    87.   SREG x28, 28*REGBYTES(sp)
    88.   SREG x29, 29*REGBYTES(sp)
    89.   SREG x30, 30*REGBYTES(sp)
    90.   SREG x31, 31*REGBYTES(sp)

    91.   csrr a0, mcause
    92.   csrr a1, mepc
    93.   SREG a1, 32*REGBYTES(sp)
    94.   mv a2, sp
    95.   jal handle_trap
    96.   LREG a1, 32*REGBYTES(sp)
    97.   csrw mepc, a1

    98.   # Remain in M-mode after eret
    99.   li t0, MSTATUS_MPP
    100.   csrs mstatus, t0

    101.   LREG x1, 1*REGBYTES(sp)
    102.   LREG x2, 2*REGBYTES(sp)
    103.   LREG x3, 3*REGBYTES(sp)
    104.   LREG x4, 4*REGBYTES(sp)
    105.   LREG x5, 5*REGBYTES(sp)
    106.   LREG x6, 6*REGBYTES(sp)
    107.   LREG x7, 7*REGBYTES(sp)
    108.   LREG x8, 8*REGBYTES(sp)
    109.   LREG x9, 9*REGBYTES(sp)
    110.   LREG x10, 10*REGBYTES(sp)
    111.   LREG x11, 11*REGBYTES(sp)
    112.   LREG x12, 12*REGBYTES(sp)
    113.   LREG x13, 13*REGBYTES(sp)
    114.   LREG x14, 14*REGBYTES(sp)
    115.   LREG x15, 15*REGBYTES(sp)
    116.   LREG x16, 16*REGBYTES(sp)
    117.   LREG x17, 17*REGBYTES(sp)
    118.   LREG x18, 18*REGBYTES(sp)
    119.   LREG x19, 19*REGBYTES(sp)
    120.   LREG x20, 20*REGBYTES(sp)
    121.   LREG x21, 21*REGBYTES(sp)
    122.   LREG x22, 22*REGBYTES(sp)
    123.   LREG x23, 23*REGBYTES(sp)
    124.   LREG x24, 24*REGBYTES(sp)
    125.   LREG x25, 25*REGBYTES(sp)
    126.   LREG x26, 26*REGBYTES(sp)
    127.   LREG x27, 27*REGBYTES(sp)
    128.   LREG x28, 28*REGBYTES(sp)
    129.   LREG x29, 29*REGBYTES(sp)
    130.   LREG x30, 30*REGBYTES(sp)
    131.   LREG x31, 31*REGBYTES(sp)

    132.   addi sp, sp, 272
    133.   mret

    134. .section ".tdata.begin"
    135. .globl _tdata_begin
    136. _tdata_begin:

    137. .section ".tdata.end"
    138. .globl _tdata_end
    139. _tdata_end:

    140. .section ".tbss.end"
    141. .globl _tbss_end
    142. _tbss_end:
    复制代码

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


    部分代码:

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

    6. proj_name ?= test

    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/program.ld
    14. SOURCE_FILE ?= -I ../common/*.h ../common/*.S ../project/$(proj_name)/*.c

    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.         
    23. all: elf
    复制代码

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





    上一篇:RISC-V可能成为CPU领域的BSD,但很难成为CPU领域的Linux
    下一篇:rocket-chip工具链的编译与使用
    RISCV作者优文
    全球首家只专注于RISC-V单片机行业应用的中文网站
    回复

    使用道具 举报

    高级模式
    B Color Image Link Quote Code Smilies

    本版积分规则

    关闭

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



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

    GMT+8, 2024-4-20 13:55 , Processed in 2.845196 second(s), 46 queries .

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