• riscv引导程序及仿真记录


    1.riscv基本的寄存器列表

    这里只关注32个通用寄存器x0-x31

     2.引导程序代码

    1. # 1 "iriscvboot.casm"
    2. # 1 ""
    3. # 1 ""
    4. # 1 "/usr/include/stdc-predef.h" 1 3 4
    5. # 1 "" 2
    6. # 1 "iriscvboot.casm"
    7. ###define 0x52080000 0
    8. # 29 "iriscvboot.casm"
    9. .section .text
    10. .org 0x0
    11. _th0_reset:
    12. l.j _th0_main
    13. l.nop
    14. _LOOP:
    15. l.j _LOOP
    16. ## === version info start at 0x80 ==
    17. .org 0x80
    18. .global _pack_version
    19. .global _build_date
    20. .global _api_version
    21. _pack_version:
    22. .word 0x0171
    23. _svn_version:
    24. .word 0x0367ad3
    25. _build_date:
    26. .word 0x07e60701
    27. _api_version:
    28. .word 0x0180
    29. _silicon_version:
    30. .word 1000
    31. ## === version info end ===
    32. ###################################################################
    33. _th0_main:
    34. l.addi x2,x0,0x0
    35. l.addi x3,x0,0x0
    36. l.addi x4,x0,0x0
    37. l.addi x5,x0,0x0
    38. l.addi x6,x0,0x0
    39. l.addi x7,x0,0x0
    40. l.addi x8,x0,0x0
    41. l.addi x9,x0,0x0
    42. l.addi x10,x0,0x0
    43. l.addi x11,x0,0x0
    44. l.addi x12,x0,0x0
    45. l.addi x13,x0,0x0
    46. l.addi x14,x0,0x0
    47. l.addi x15,x0,0x0
    48. l.addi x16,x0,0x0
    49. l.addi x17,x0,0x0
    50. l.addi x18,x0,0x0
    51. l.addi x19,x0,0x0
    52. l.addi x20,x0,0x0
    53. l.addi x21,x0,0x0
    54. l.addi x22,x0,0x0
    55. l.addi x23,x0,0x0
    56. l.addi x24,x0,0x0
    57. l.addi x25,x0,0x0
    58. l.addi x26,x0,0x0
    59. l.addi x27,x0,0x0
    60. l.addi x28,x0,0x0
    61. l.addi x29,x0,0x0
    62. l.addi x30,x0,0x0
    63. l.addi x31,x0,0x0
    64. l.lui x2,0x52086
    65. _init_cmem_done_th0:
    66. l.jal _mymain
    67. l.j _LOOP

     3.引导代码含义,及相关指令。

    .section .text表示下面的代码链接时放在.text段,.org设置当前代码的地址偏移(相对于链接时指定定.text段的起始地址)。

    接下来定义了标签_th0_reset,riscv执行时从这儿开始执行指令,l.j  _th0_main表示跳转到
    _th0_main标签处,
    _th0_reset:
     l.j _th0_main
     l.nop

    _th0_main标签处,连续的l.addi 指令可以理解为对32个通用寄存器的清操作。

    但是注意 l.lui  x2,0x52086指令指定了sp寄存器(栈指针)的,开始地址。(lui 指令将 20 位立即数的值左移 12 位(低 12 位补 0)成为一个 32 位数,将此数写 回寄存器 x2 中。)

    接着执行_init_cmem_done_th0标签处。此处就是我们定义的c程序的入口处。l.jal _mymain表示跳转到_mymain处,可以看下面c代码的汇编,其中会根据mymain函数创建_mymain标签。(jal 指令完成跳转并且将其下一条指令的 PC(即当前指令 PC+4)的值写入其结果寄存器 ra 中。注意:在实际的汇编程序编写中,跳转的目标往往使用汇编程序中的 label,汇编器 会自动根据 label 所在的地址计算出相对的偏移量赋予指令编码。

    到_mymain中后就会执行c代码中内容了。 执行完c代码后,会根据ra寄存器的值返回来执行下一句,l.j _LOOP。这里是为了让riscv不乱跑,设置这个循环。

     4.c代码

    C代码内容很简单,分别对0x1000这个地址写入次,第一次值100,第二次值0x202

    1. void write32(int addr,int value)
    2. {
    3. int *addr_value;
    4. addr_value = (int*)addr;
    5. *addr_value = value;
    6. }
    7. void mymain()
    8. {
    9. volatile int age=100;
    10. write32(0x1000,age);
    11. write32(0x1000,0x202);
    12. }

    C代码的汇编结果gcc -S:

    1. .file "firmware.c"
    2. .option nopic
    3. .text
    4. .align 2
    5. .globl _write32
    6. .type _write32, @function
    7. _write32:
    8. l.sw a1,0(a0)
    9. l.ret
    10. .size _write32, .-_write32
    11. .align 2
    12. .globl _mymain
    13. .type _mymain, @function
    14. _mymain:
    15. l.add sp,sp,-32
    16. l.li a5,100
    17. l.sw a5,12(sp)
    18. l.lw a1,12(sp)
    19. l.li a0,4096
    20. l.sw ra,28(sp)
    21. call _write32
    22. l.li a1,514
    23. l.li a0,4096
    24. call _write32
    25. l.lw ra,28(sp)
    26. l.add sp,sp,32
    27. l.jr ra
    28. .size _mymain, .-_mymain
    29. .ident "GCC: (GNU) 6.1.0"

    5.链接

    链接脚本

    1. MEMORY
    2. {
    3. flash : ORIGIN = 0x52040000, LENGTH = 0x00040000
    4. ram : ORIGIN = 0x5b000000, LENGTH = 0x00006000
    5. glb : ORIGIN = 0x52086000, LENGTH = 0x00032000
    6. rodata : ORIGIN = 0xa0000000, LENGTH = 0x00040000
    7. }
    8. SECTIONS
    9. {
    10. .text :
    11. {
    12. *(.text)
    13. } > flash
    14. .data :
    15. {
    16. *(.data)
    17. } > ram
    18. .bss :
    19. {
    20. *(.bss)
    21. } > ram
    22. .debug :
    23. {
    24. *(.debug_frame .zdebug_frame)
    25. *(.debug_abbrev)
    26. *(.debug_line)
    27. *(.debug_str)
    28. *(.debug_loc)
    29. *(.debug_macinfo)
    30. *(.debug_info)
    31. *(.debug_aranges)
    32. *(.debug_ranges)
    33. *(.comment)
    34. } > ram
    35. .rodata :
    36. {
    37. *(.rodata)
    38. } > rodata
    39. }

    链接结果,通过objdump工具进行反汇编注意使用-D选项,对所有段进行反汇编:

    1. isp_firmware: file format elf32-littleriscv
    2. Disassembly of section .text:
    3. 52040000 <_th0_reset>:
    4. 52040000: 0940006f l.jal zero,52040094 <_th0_main>
    5. 52040004: 00000013 l.addi zero,zero,0
    6. 52040008 <_LOOP>:
    7. 52040008: 0000006f l.jal zero,52040008 <_LOOP>
    8. ...
    9. 52040080 <_pack_version>:
    10. 52040080: 00000171 0x171
    11. 52040084 <_svn_version>:
    12. 52040084: 00367ad3 l.fadd.s fs5,fa2,ft3
    13. 52040088 <_build_date>:
    14. 52040088: 07e60701 0x7e60701
    15. 5204008c <_api_version>:
    16. 5204008c: 00000180 0x180
    17. 52040090 <_silicon_version>:
    18. 52040090: 000003e8 0x3e8
    19. 52040094 <_th0_main>:
    20. 52040094: 00000113 l.addi sp,zero,0
    21. 52040098: 00000193 l.addi gp,zero,0
    22. 5204009c: 00000213 l.addi tp,zero,0
    23. 520400a0: 00000293 l.addi t0,zero,0
    24. 520400a4: 00000313 l.addi t1,zero,0
    25. 520400a8: 00000393 l.addi t2,zero,0
    26. 520400ac: 00000413 l.addi s0,zero,0
    27. 520400b0: 00000493 l.addi s1,zero,0
    28. 520400b4: 00000513 l.addi a0,zero,0
    29. 520400b8: 00000593 l.addi a1,zero,0
    30. 520400bc: 00000613 l.addi a2,zero,0
    31. 520400c0: 00000693 l.addi a3,zero,0
    32. 520400c4: 00000713 l.addi a4,zero,0
    33. 520400c8: 00000793 l.addi a5,zero,0
    34. 520400cc: 00000813 l.addi a6,zero,0
    35. 520400d0: 00000893 l.addi a7,zero,0
    36. 520400d4: 00000913 l.addi s2,zero,0
    37. 520400d8: 00000993 l.addi s3,zero,0
    38. 520400dc: 00000a13 l.addi s4,zero,0
    39. 520400e0: 00000a93 l.addi s5,zero,0
    40. 520400e4: 00000b13 l.addi s6,zero,0
    41. 520400e8: 00000b93 l.addi s7,zero,0
    42. 520400ec: 00000c13 l.addi s8,zero,0
    43. 520400f0: 00000c93 l.addi s9,zero,0
    44. 520400f4: 00000d13 l.addi s10,zero,0
    45. 520400f8: 00000d93 l.addi s11,zero,0
    46. 520400fc: 00000e13 l.addi t3,zero,0
    47. 52040100: 00000e93 l.addi t4,zero,0
    48. 52040104: 00000f13 l.addi t5,zero,0
    49. 52040108: 00000f93 l.addi t6,zero,0
    50. 5204010c: 52086137 l.lui sp,0x52086
    51. 52040110 <_init_cmem_done_th0>:
    52. 52040110: 010000ef l.jal ra,52040120 <_mymain>
    53. 52040114: ef5ff06f l.jal zero,52040008 <_LOOP>
    54. 52040118 <_write32>:
    55. 52040118: 00b52023 l.sw a1,0(a0)
    56. 5204011c: 00008067 l.jalr zero,0(ra)
    57. 52040120 <_mymain>:
    58. 52040120: fe010113 l.addi sp,sp,-32 # 52085fe0 <_mymain+0x45ec0>
    59. 52040124: 06400793 l.addi a5,zero,100
    60. 52040128: 00f12623 l.sw a5,12(sp)
    61. 5204012c: 00c12583 l.lw a1,12(sp)
    62. 52040130: 00001537 l.lui a0,0x1
    63. 52040134: 00112e23 l.sw ra,28(sp)
    64. 52040138: fe1ff0ef l.jal ra,52040118 <_write32>
    65. 5204013c: 20200593 l.addi a1,zero,514
    66. 52040140: 00001537 l.lui a0,0x1
    67. 52040144: fd5ff0ef l.jal ra,52040118 <_write32>
    68. 52040148: 01c12083 l.lw ra,28(sp)
    69. 5204014c: 02010113 l.addi sp,sp,32
    70. 52040150: 00008067 l.jalr zero,0(ra)
    71. Disassembly of section .debug:
    72. 5b000000 <.debug>:
    73. 5b000000: 3a434347 l.fmsub.d ft6,ft6,ft4,ft7,rmm
    74. 5b000004: 4e472820 0x4e472820
    75. 5b000008: 36202955 l.c.setireg m18,m2,0x1b10
    76. 5b00000c: 302e312e 0x302e312e
    77. ...

     6.生成firmware

    然后使用python脚本将,对应需要的段的地址和指令编码dump出来。使用的python脚本如下,输入文件是上面的反汇编结果:

    1. #!/usr/bin/python
    2. import sys
    3. import re
    4. def replace_line(input_file, output_file):
    5. input_f = open(input_file, 'r')
    6. output_f = open(output_file, 'w')
    7. text=0;
    8. rodata=0;
    9. sdata=0;
    10. for line in input_f:
    11. line = line.rstrip() # removing right space
    12. #print(line)
    13. if("text" in line):
    14. text=1
    15. sdata=0
    16. rodata=0
    17. if("sdata" in line):
    18. sdata=1
    19. text=0
    20. rodata=0
    21. if("rodata" in line):
    22. rodata=1
    23. text=0
    24. sdata=0
    25. if(("debug" in line)):
    26. sdata=0;
    27. rodata=0;
    28. text=0;
    29. if (line.find(' l.') != -1)&(text==1) :
    30. line = line.replace (":", ",")
    31. words = line.split()
    32. output_f.write(words[0]+words[1]+'\n')
    33. if (re.findall(r'\d+:\s+\w+',line) != [])&(sdata==1) :
    34. line = line.replace (":", ",")
    35. words = line.split()
    36. output_f.write(words[0]+words[1]+'\n')
    37. if (re.findall(r'\d+:\s+\w+',line) != [])&(rodata==1) :
    38. line = line.replace (":", ",")
    39. words = line.split()
    40. output_f.write(words[0]+words[1]+'\n')
    41. arg_list = sys.argv
    42. print(arg_list[1])
    43. print(arg_list[2])
    44. if len(arg_list) != 3:
    45. print("need input file list")
    46. sys.exit()
    47. replace_line(arg_list[1], arg_list[2])

    dump出的firmware的文件如下,其中包含指令编码以及所放置的mem中的地址:

    1. 52040000,0940006f
    2. 52040004,00000013
    3. 52040008,0000006f
    4. 52040084,00367ad3
    5. 52040094,00000113
    6. 52040098,00000193
    7. 5204009c,00000213
    8. 520400a0,00000293
    9. 520400a4,00000313
    10. 520400a8,00000393
    11. 520400ac,00000413
    12. 520400b0,00000493
    13. 520400b4,00000513
    14. 520400b8,00000593
    15. 520400bc,00000613
    16. 520400c0,00000693
    17. 520400c4,00000713
    18. 520400c8,00000793
    19. 520400cc,00000813
    20. 520400d0,00000893
    21. 520400d4,00000913
    22. 520400d8,00000993
    23. 520400dc,00000a13
    24. 520400e0,00000a93
    25. 520400e4,00000b13
    26. 520400e8,00000b93
    27. 520400ec,00000c13
    28. 520400f0,00000c93
    29. 520400f4,00000d13
    30. 520400f8,00000d93
    31. 520400fc,00000e13
    32. 52040100,00000e93
    33. 52040104,00000f13
    34. 52040108,00000f93
    35. 5204010c,52086137
    36. 52040110,010000ef
    37. 52040114,ef5ff06f
    38. 52040118,00b52023
    39. 5204011c,00008067
    40. 52040120,fe010113
    41. 52040124,06400793
    42. 52040128,00f12623
    43. 5204012c,00c12583
    44. 52040130,00001537
    45. 52040134,00112e23
    46. 52040138,fe1ff0ef
    47. 5204013c,20200593
    48. 52040140,00001537
    49. 52040144,fd5ff0ef
    50. 52040148,01c12083
    51. 5204014c,02010113
    52. 52040150,00008067

     7.仿真结果

    将上面dump出来的结果,进行仿真。结果如下所示。可以看见和C代码内容一样分别对0x1000这个地址写入次,第一次值100(0x64),第二次值0x202

    pc指针的初始值值设置的是52040000,也就是.text的初始地址。

     

    参考:

    1.RISC-V架构与嵌入式开发快速入门

  • 相关阅读:
    QQd挂源码已更新最新加速项目程序全开源
    声学感知刻度(mel scale、Bark scale、ERB)与声学特征提取(MFCC、BFCC、GFCC)
    spring cloud gateway 入门
    uni-app项目由hbuilder项目转化为cli项目
    EasyExcel实现对excel文件读写
    不重装系统,如何将系统从SSD迁移到M2固态硬盘
    基于Python OpenCV的金铲铲自动进游戏、D牌...
    手部关键点识别易语言代码
    Redis底层核心数据结构详解
    知识图谱实体对齐2:基于GNN嵌入的方法
  • 原文地址:https://blog.csdn.net/geter_CS/article/details/127671194