1.riscv基本的寄存器列表
这里只关注32个通用寄存器x0-x31

2.引导程序代码
- # 1 "iriscvboot.casm"
- # 1 "
" - # 1 "
" - # 1 "/usr/include/stdc-predef.h" 1 3 4
- # 1 "
" 2 - # 1 "iriscvboot.casm"
-
- ###define 0x52080000 0
- # 29 "iriscvboot.casm"
- .section .text
- .org 0x0
-
- _th0_reset:
- l.j _th0_main
- l.nop
-
- _LOOP:
- l.j _LOOP
-
- ## === version info start at 0x80 ==
- .org 0x80
- .global _pack_version
- .global _build_date
- .global _api_version
- _pack_version:
- .word 0x0171
- _svn_version:
- .word 0x0367ad3
- _build_date:
- .word 0x07e60701
- _api_version:
- .word 0x0180
- _silicon_version:
- .word 1000
- ## === version info end ===
- ###################################################################
-
- _th0_main:
- l.addi x2,x0,0x0
- l.addi x3,x0,0x0
- l.addi x4,x0,0x0
- l.addi x5,x0,0x0
- l.addi x6,x0,0x0
- l.addi x7,x0,0x0
- l.addi x8,x0,0x0
- l.addi x9,x0,0x0
- l.addi x10,x0,0x0
- l.addi x11,x0,0x0
- l.addi x12,x0,0x0
- l.addi x13,x0,0x0
- l.addi x14,x0,0x0
- l.addi x15,x0,0x0
- l.addi x16,x0,0x0
- l.addi x17,x0,0x0
- l.addi x18,x0,0x0
- l.addi x19,x0,0x0
- l.addi x20,x0,0x0
- l.addi x21,x0,0x0
- l.addi x22,x0,0x0
- l.addi x23,x0,0x0
- l.addi x24,x0,0x0
- l.addi x25,x0,0x0
- l.addi x26,x0,0x0
- l.addi x27,x0,0x0
- l.addi x28,x0,0x0
- l.addi x29,x0,0x0
- l.addi x30,x0,0x0
- l.addi x31,x0,0x0
- l.lui x2,0x52086
-
-
- _init_cmem_done_th0:
- l.jal _mymain
- 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
- void write32(int addr,int value)
- {
- int *addr_value;
- addr_value = (int*)addr;
- *addr_value = value;
- }
-
- void mymain()
- {
- volatile int age=100;
- write32(0x1000,age);
- write32(0x1000,0x202);
- }
C代码的汇编结果gcc -S:
- .file "firmware.c"
- .option nopic
- .text
- .align 2
- .globl _write32
- .type _write32, @function
- _write32:
- l.sw a1,0(a0)
- l.ret
- .size _write32, .-_write32
- .align 2
- .globl _mymain
- .type _mymain, @function
- _mymain:
- l.add sp,sp,-32
- l.li a5,100
- l.sw a5,12(sp)
- l.lw a1,12(sp)
- l.li a0,4096
- l.sw ra,28(sp)
- call _write32
- l.li a1,514
- l.li a0,4096
- call _write32
- l.lw ra,28(sp)
- l.add sp,sp,32
- l.jr ra
- .size _mymain, .-_mymain
- .ident "GCC: (GNU) 6.1.0"
5.链接
链接脚本
- MEMORY
- {
- flash : ORIGIN = 0x52040000, LENGTH = 0x00040000
- ram : ORIGIN = 0x5b000000, LENGTH = 0x00006000
- glb : ORIGIN = 0x52086000, LENGTH = 0x00032000
- rodata : ORIGIN = 0xa0000000, LENGTH = 0x00040000
- }
-
- SECTIONS
- {
- .text :
- {
- *(.text)
- } > flash
- .data :
- {
- *(.data)
- } > ram
- .bss :
- {
- *(.bss)
- } > ram
-
- .debug :
- {
- *(.debug_frame .zdebug_frame)
- *(.debug_abbrev)
- *(.debug_line)
- *(.debug_str)
- *(.debug_loc)
- *(.debug_macinfo)
- *(.debug_info)
- *(.debug_aranges)
- *(.debug_ranges)
- *(.comment)
- } > ram
- .rodata :
- {
- *(.rodata)
- } > rodata
- }
链接结果,通过objdump工具进行反汇编注意使用-D选项,对所有段进行反汇编:
-
- isp_firmware: file format elf32-littleriscv
-
-
- Disassembly of section .text:
-
- 52040000 <_th0_reset>:
- 52040000: 0940006f l.jal zero,52040094 <_th0_main>
- 52040004: 00000013 l.addi zero,zero,0
-
- 52040008 <_LOOP>:
- 52040008: 0000006f l.jal zero,52040008 <_LOOP>
- ...
-
- 52040080 <_pack_version>:
- 52040080: 00000171 0x171
-
- 52040084 <_svn_version>:
- 52040084: 00367ad3 l.fadd.s fs5,fa2,ft3
-
- 52040088 <_build_date>:
- 52040088: 07e60701 0x7e60701
-
- 5204008c <_api_version>:
- 5204008c: 00000180 0x180
-
- 52040090 <_silicon_version>:
- 52040090: 000003e8 0x3e8
-
- 52040094 <_th0_main>:
- 52040094: 00000113 l.addi sp,zero,0
- 52040098: 00000193 l.addi gp,zero,0
- 5204009c: 00000213 l.addi tp,zero,0
- 520400a0: 00000293 l.addi t0,zero,0
- 520400a4: 00000313 l.addi t1,zero,0
- 520400a8: 00000393 l.addi t2,zero,0
- 520400ac: 00000413 l.addi s0,zero,0
- 520400b0: 00000493 l.addi s1,zero,0
- 520400b4: 00000513 l.addi a0,zero,0
- 520400b8: 00000593 l.addi a1,zero,0
- 520400bc: 00000613 l.addi a2,zero,0
- 520400c0: 00000693 l.addi a3,zero,0
- 520400c4: 00000713 l.addi a4,zero,0
- 520400c8: 00000793 l.addi a5,zero,0
- 520400cc: 00000813 l.addi a6,zero,0
- 520400d0: 00000893 l.addi a7,zero,0
- 520400d4: 00000913 l.addi s2,zero,0
- 520400d8: 00000993 l.addi s3,zero,0
- 520400dc: 00000a13 l.addi s4,zero,0
- 520400e0: 00000a93 l.addi s5,zero,0
- 520400e4: 00000b13 l.addi s6,zero,0
- 520400e8: 00000b93 l.addi s7,zero,0
- 520400ec: 00000c13 l.addi s8,zero,0
- 520400f0: 00000c93 l.addi s9,zero,0
- 520400f4: 00000d13 l.addi s10,zero,0
- 520400f8: 00000d93 l.addi s11,zero,0
- 520400fc: 00000e13 l.addi t3,zero,0
- 52040100: 00000e93 l.addi t4,zero,0
- 52040104: 00000f13 l.addi t5,zero,0
- 52040108: 00000f93 l.addi t6,zero,0
- 5204010c: 52086137 l.lui sp,0x52086
-
- 52040110 <_init_cmem_done_th0>:
- 52040110: 010000ef l.jal ra,52040120 <_mymain>
- 52040114: ef5ff06f l.jal zero,52040008 <_LOOP>
-
- 52040118 <_write32>:
- 52040118: 00b52023 l.sw a1,0(a0)
- 5204011c: 00008067 l.jalr zero,0(ra)
-
- 52040120 <_mymain>:
- 52040120: fe010113 l.addi sp,sp,-32 # 52085fe0 <_mymain+0x45ec0>
- 52040124: 06400793 l.addi a5,zero,100
- 52040128: 00f12623 l.sw a5,12(sp)
- 5204012c: 00c12583 l.lw a1,12(sp)
- 52040130: 00001537 l.lui a0,0x1
- 52040134: 00112e23 l.sw ra,28(sp)
- 52040138: fe1ff0ef l.jal ra,52040118 <_write32>
- 5204013c: 20200593 l.addi a1,zero,514
- 52040140: 00001537 l.lui a0,0x1
- 52040144: fd5ff0ef l.jal ra,52040118 <_write32>
- 52040148: 01c12083 l.lw ra,28(sp)
- 5204014c: 02010113 l.addi sp,sp,32
- 52040150: 00008067 l.jalr zero,0(ra)
-
- Disassembly of section .debug:
-
- 5b000000 <.debug>:
- 5b000000: 3a434347 l.fmsub.d ft6,ft6,ft4,ft7,rmm
- 5b000004: 4e472820 0x4e472820
- 5b000008: 36202955 l.c.setireg m18,m2,0x1b10
- 5b00000c: 302e312e 0x302e312e
- ...
6.生成firmware
然后使用python脚本将,对应需要的段的地址和指令编码dump出来。使用的python脚本如下,输入文件是上面的反汇编结果:
- #!/usr/bin/python
- import sys
- import re
- def replace_line(input_file, output_file):
- input_f = open(input_file, 'r')
- output_f = open(output_file, 'w')
- text=0;
- rodata=0;
- sdata=0;
- for line in input_f:
- line = line.rstrip() # removing right space
- #print(line)
-
- if("text" in line):
- text=1
- sdata=0
- rodata=0
- if("sdata" in line):
- sdata=1
- text=0
- rodata=0
- if("rodata" in line):
- rodata=1
- text=0
- sdata=0
- if(("debug" in line)):
- sdata=0;
- rodata=0;
- text=0;
-
- if (line.find(' l.') != -1)&(text==1) :
- line = line.replace (":", ",")
- words = line.split()
- output_f.write(words[0]+words[1]+'\n')
-
- if (re.findall(r'\d+:\s+\w+',line) != [])&(sdata==1) :
- line = line.replace (":", ",")
- words = line.split()
- output_f.write(words[0]+words[1]+'\n')
-
- if (re.findall(r'\d+:\s+\w+',line) != [])&(rodata==1) :
- line = line.replace (":", ",")
- words = line.split()
- output_f.write(words[0]+words[1]+'\n')
-
-
-
- arg_list = sys.argv
- print(arg_list[1])
- print(arg_list[2])
-
- if len(arg_list) != 3:
- print("need input file list")
- sys.exit()
-
- replace_line(arg_list[1], arg_list[2])
dump出的firmware的文件如下,其中包含指令编码以及所放置的mem中的地址:
- 52040000,0940006f
- 52040004,00000013
- 52040008,0000006f
- 52040084,00367ad3
- 52040094,00000113
- 52040098,00000193
- 5204009c,00000213
- 520400a0,00000293
- 520400a4,00000313
- 520400a8,00000393
- 520400ac,00000413
- 520400b0,00000493
- 520400b4,00000513
- 520400b8,00000593
- 520400bc,00000613
- 520400c0,00000693
- 520400c4,00000713
- 520400c8,00000793
- 520400cc,00000813
- 520400d0,00000893
- 520400d4,00000913
- 520400d8,00000993
- 520400dc,00000a13
- 520400e0,00000a93
- 520400e4,00000b13
- 520400e8,00000b93
- 520400ec,00000c13
- 520400f0,00000c93
- 520400f4,00000d13
- 520400f8,00000d93
- 520400fc,00000e13
- 52040100,00000e93
- 52040104,00000f13
- 52040108,00000f93
- 5204010c,52086137
- 52040110,010000ef
- 52040114,ef5ff06f
- 52040118,00b52023
- 5204011c,00008067
- 52040120,fe010113
- 52040124,06400793
- 52040128,00f12623
- 5204012c,00c12583
- 52040130,00001537
- 52040134,00112e23
- 52040138,fe1ff0ef
- 5204013c,20200593
- 52040140,00001537
- 52040144,fd5ff0ef
- 52040148,01c12083
- 5204014c,02010113
- 52040150,00008067
7.仿真结果
将上面dump出来的结果,进行仿真。结果如下所示。可以看见和C代码内容一样分别对0x1000这个地址写入次,第一次值100(0x64),第二次值0x202

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

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