参考的这本书《基于FPGA与RISC-V的嵌入式系统设计》
modelsim仿真
首先在arduino里面写好代码,编译:
然后将elf文件复制到modelsim文件夹下,运行python脚本:
python dram_dat_gen.py test1.ino.elf > sdram_ISSI_SDRAM_test_component.dat
然后打开modelsim运行下面的代码就行了。
do build_lib.do
do build_soc.do
do run_sim.do
run 100us
这里我们用riscv gcc工具链对elf文件反汇编:
riscv-none-embed-objdump.exe -D test1.ino.elf > test1.ino.s
显示某一个段内容:https://blog.csdn.net/whatday/article/details/99154104
riscv-none-embed-objdump.exe -j .data -d test1.ino.elf
riscv启动过程
Register | ABI | Use by convention | Preserved? |
---|---|---|---|
x0 | zero | hardwired to 0, ignores writes | n/a |
x1 | ra | return address for jumps | no |
x2 | sp | stack pointer | yes |
x3 | gp | global pointer | n/a |
x4 | tp | thread pointer | n/a |
x5 | t0 | temporary register 0 | no |
x6 | t1 | temporary register 1 | no |
x7 | t2 | temporary register 2 | no |
x8 | s0 or fp | saved register 0 or frame pointer | yes |
x9 | s1 | saved register 1 | yes |
x10 | a0 | return value or function argument 0 | no |
x11 | a1 | return value or function argument 1 | no |
x12 | a2 | function argument 2 | no |
x13 | a3 | function argument 3 | no |
x14 | a4 | function argument 4 | no |
x15 | a5 | function argument 5 | no |
x16 | a6 | function argument 6 | no |
x17 | a7 | function argument 7 | no |
x18 | s2 | saved register 2 | yes |
x19 | s3 | saved register 3 | yes |
x20 | s4 | saved register 4 | yes |
x21 | s5 | saved register 5 | yes |
x22 | s6 | saved register 6 | yes |
x23 | s7 | saved register 7 | yes |
x24 | s8 | saved register 8 | yes |
x25 | s9 | saved register 9 | yes |
x26 | s10 | saved register 10 | yes |
x27 | s11 | saved register 11 | yes |
x28 | t3 | temporary register 3 | no |
x29 | t4 | temporary register 4 | no |
x30 | t5 | temporary register 5 | no |
x31 | t6 | temporary register 6 | no |
pc | (none) | program counter | n/a |
sp指针:8M空间:为什么少了8字节?
initial可以被综合吗
gp指针
arduino源码分析
第一条质量地址是0,但是sdram的总线地址是0x80000000。
可以看elf文件头也有入口地址:
arduino初始化代码
test1.ino.elf: file format elf32-littleriscv
Disassembly of section .text:
80000000 <_start>:
80000000: 00002197 auipc gp,0x2 #0x2000=8KB空间
80000004: c3818193 addi gp,gp,-968 # 80001c38 <__global_pointer$>
80000008: 80c18513 addi a0,gp,-2036 # 80001444 <_edata>
8000000c: 87018613 addi a2,gp,-1936 # 800014a8 <_end>
80000010: 40a60633 sub a2,a2,a0
80000014: 00000593 li a1,0 #立即数加载,x[a1]=0
#void *memset(void *s, int ch, size_t n);
80000018: 7e8000ef jal ra,80000800 <memset> #参数情况:a0=80001444,a1=0,a2=64
8000001c: 00000517 auipc a0,0x0
80000020: 6ec50513 addi a0,a0,1772 # 80000708 <__libc_fini_array>
80000024: 698000ef jal ra,800006bc <atexit>
80000028: 740000ef jal ra,80000768 <__libc_init_array>
8000002c: 00012503 lw a0,0(sp)
80000030: 00410593 addi a1,sp,4
80000034: 00000613 li a2,0
80000038: 294000ef jal ra,800002cc <main>
8000003c: 6940006f j 800006d0 <exit>
第一次ra指针
pc指针:
注意,上面汇编一次增加4字节,而16位bus的sdram地址一次增加2字节,因此sdram地址和pc地址有这样的关系:
sdram addr = (pc addr - 0x80000000)/4 * 2;
16位sdram数据合并成32位数据是用移位寄存器实现的。如上图所示。
memset跳转:
__do_global_dtors_aux和__do_global_ctors_aux
80000308 <main>:
80000308: ff010113 addi sp,sp,-16
8000030c: 00112623 sw ra,12(sp)
80000310: 2e4000ef jal ra,800005f4 <_Z12noInterruptsv>
80000314: 0001c5b7 lui a1,0x1c
80000318: 20058593 addi a1,a1,512 # 1c200 <_start-0x7ffe3e00>
8000031c: 83418513 addi a0,gp,-1996 # 80001494 <Serial>
80000320: 06c000ef jal ra,8000038c <_ZN14HardwareSerial5beginEm>
80000324: 800007b7 lui a5,0x80000
80000328: 19078793 addi a5,a5,400 # 80000190 <__global_pointer$+0xffffe530>
8000032c: 30579073 csrw mtvec,a5
80000330: e05ff0ef jal ra,80000134 <_Z5setupv> #setup
80000334: e05ff0ef jal ra,80000138 <_Z4loopv> #loop
80000338: ffdff06f j 80000334 <main+0x2c> #jump to loop
总结
总结一下,reindeer的内存管理还是比较简单的,而且因为使用串口配合python脚本,使得启动代码也十分简单。虽然还没有尝试过arduino下载程序运行,不过大致原理应该一样。
下一步尝试将其移植到vivado平台上。