有人预言,RISC-V或将是继Intel和Arm之后的第三大主流处理器体系。欢迎访问全球首家只专注于RISC-V单片机行业应用的中文网站
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
本帖最后由 新ちゃん 于 2020-8-20 22:18 编辑
如何建立自己的RISC-V编译环境–汇编?
1.RISC-V编译环境框架
这是我RISC-V编译环境的架构: - 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的说明。
注意,下文中使用“###”形式的均是我添加的注释,原代码中没有。
- <font size="3">#*****************************************************************************
- # add.S
- #-----------------------------------------------------------------------------
- #
- # Test add instructions.
- #
- #屏蔽了原来的include "riscv_test.h"
- ######include "riscv_test.h"
- #使用我自己的asm.h
- #include "asm.h"
- ###使用RVTEST_RV32U段内容
- RVTEST_RV32U
- ###使用RVTEST_CODE_BEGIN段内容
- RVTEST_CODE_BEGIN
- ###按2^2字节(4字节)数据对齐
- .align 2
- ###“.option push”伪操作暂时将当前的选项设置保存起来,
- ###从而允许之后使用.option伪操作指定新的选项;
- ###而“.option pop”伪操作将最近保存的选项设置恢复出来重新生效。
- ###通过“.option push”和“.option pop”的组合,便可以在汇编程序中在不影响全
- ###局选项设置的情况下,为其中嵌入的某一段代码特别地设置不同的选项。
- ###意思就是:
- ###在add.S这个汇编文件中,将前面其他.S/.h文件中的配置选项保存起来,
- ###然后在add.S文件中设置一些新的选项,新的选项就是下面的.option norvc
- .option push
- ###伪操作表示接下来的汇编程序不可以被汇编生成16位宽的压缩指令。
- .option norvc
- ###定义标签asm_start
- asm_start:
- ###将0xAAAAAAAA赋给a1
- li a1, 0xAAAAAAAA
- ###将0x22222222赋给a1
- li a0, 0x22222222
- ###将a0和a1相加,并出入a2中
- add a2, a1, a0
- ###将0x7000_0000存入a4中
- lui a4, 0x70000
- ###将a4的值+4并存入a6中
- addi a6, a4, 4
- ###将a2的结果存到总线为0x7000_0004的memory中
- sw a2, 0(a6)
- ###将0xFF存到a5中
- li a5, 255
- ###将a5的结果存到总线为0x7000_0000的memory中,用于停止VCS仿真
- sw a5, 0(a4)
- ###恢复原选项配置
- .option pop
- ###使用RVTEST_CODE_END段内容
- RVTEST_CODE_END
-
- ###数据段.data:已初始化的C程序全局变量和静态局部变量。
- .data
- ###使用RVTEST_DATA_BEGIN段内容
- RVTEST_DATA_BEGIN
- ###使用RVTEST_DATA_END段内容
- 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
- // See LICENSE for license details.
- #ifndef _ENV_PHYSICAL_SINGLE_CORE_H
- #define _ENV_PHYSICAL_SINGLE_CORE_H
- #include "./encoding.h"
- //-----------------------------------------------------------------------
- // Begin Macro
- //-----------------------------------------------------------------------
- ###定义宏init
- #define RVTEST_RV64U \
- .macro init; \
- .endm
- ###定义宏init,同时运行RVTEST_FP_ENABLE段
- #define RVTEST_RV64UF \
- .macro init; \
- RVTEST_FP_ENABLE; \
- .endm
- ###定义宏init
- #define RVTEST_RV32U \
- .macro init; \
- .endm
- ###定义宏init,同时运行RVTEST_FP_ENABLE段
- #define RVTEST_RV32UF \
- .macro init; \
- RVTEST_FP_ENABLE; \
- .endm
- ###定义宏init
- #define RVTEST_RV64M \
- .macro init; \
- RVTEST_ENABLE_MACHINE; \
- .endm
- ###定义宏init,同时运行RVTEST_ENABLE_SUPERVISOR段
- #define RVTEST_RV64S \
- .macro init; \
- RVTEST_ENABLE_SUPERVISOR; \
- .endm
- ###定义宏init,同时运行RVTEST_ENABLE_MACHINE段
- #define RVTEST_RV32M \
- .macro init; \
- RVTEST_ENABLE_MACHINE; \
- .endm
- ###定义宏init,同时运行RVTEST_ENABLE_SUPERVISOR段
- #define RVTEST_RV32S \
- .macro init; \
- RVTEST_ENABLE_SUPERVISOR; \
- .endm
- ###运行CHECK_XLEN段
- #if __riscv_xlen == 64
- ###将1装入a0;将a0的值进行逻辑左移31位;如果a0的值≥0,跳转至标志为1的地方;
- ###运行RVTEST_PASS段;标志1的位置。
- ###1f的意思是向前找第一个数字为1的标志,即往下面的行找
- # define CHECK_XLEN li a0, 1; slli a0, a0, 31; bgez a0, 1f; RVTEST_PASS; 1:
- #else
- ###将1装入a0;将a0的值进行逻辑左移31位;如果a0的值<0,跳转至标志为1的地方;
- ###运行RVTEST_PASS段;标志1的位置。
- # define CHECK_XLEN li a0, 1; slli a0, a0, 31; bltz a0, 1f; RVTEST_PASS; 1:
- #endif
- ###定义INIT_PMP段的内容
- #define INIT_PMP \
- ###将标志1的PC赋值给t0
- la t0, 1f; \
- ###将t0的值赋值给mtvec
- csrw mtvec, t0; \
- ###将-1赋值给t0,实际上是赋0xFFFF_FFFF给t0
- li t0, -1; /* Set up a PMP to permit all accesses */ \
- ###将t0的值写入pmpaddr0 CSR寄存器中
- csrw pmpaddr0, t0; \
- ###将PMP_NAPOT | PMP_R | PMP_W | PMP_X的值赋给t0,这些值在encoding.h中定义
- li t0, PMP_NAPOT | PMP_R | PMP_W | PMP_X; \
- ###将t0的值写入pmpcfg0 CSR寄存器中
- csrw pmpcfg0, t0; \
- ###按2^2字节(4字节)数据对齐
- .align 2; \
- ###标志1的具体位置
- 1:
- /*Configure MMU*/
- /*SATP:Supervisor Address Translation and Protection (satp) Register*/
- #define INIT_SATP \
- ###将标志1的PC赋值给t0
- la t0, 1f; \
- ###t0的值赋给mtvec
- csrw mtvec, t0; \
- ###写CSR寄存器sptrb为0
- csrwi sptbr, 0; \
- ###按2^2字节(4字节)数据对齐
- .align 2; \
- ###标志1的具体位置
- 1:
- ###定义DELEGATE_NO_TRAPS段的内容,这是对应多模式情况下的
- ###将中断权限分配到其他模式中,不单单机器模式可以处理中断
- #define DELEGATE_NO_TRAPS \
- ###将标志1的PC赋值给t0
- la t0, 1f; \
- ###t0的值赋给mtvec
- csrw mtvec, t0; \
- ###写CSR寄存器medeleg(异常)为0,如果没有这个CSR寄存器会产生异常
- csrwi medeleg, 0; \
- ###写CSR寄存器mideleg(中断)为0,如果没有这个CSR寄存器会产生异常
- csrwi mideleg, 0; \
- ###写CSR寄存器mie为0,清除中断使能
- csrwi mie, 0; \
- ###按2^2字节(4字节)数据对齐
- .align 2; \
- ###标志1的具体位置
- 1:
- ###定义RVTEST_ENABLE_SUPERVISOR段的内容
- ###SUPERVISOR模式的定义
- #define RVTEST_ENABLE_SUPERVISOR \
- li a0, MSTATUS_MPP & (MSTATUS_MPP >> 1); \
- csrs mstatus, a0; \
- ###将SIP_SSIP | SIP_STIP赋给a0
- li a0, SIP_SSIP | SIP_STIP; \
- ###将a0赋值给mideleg CSR寄存器,用于授权SUPERVISOR模式可以处理中断
- csrs mideleg, a0; \
- ###定义RVTEST_ENABLE_MACHINE段的内容
- ### MACHINE模式的定义
- #define RVTEST_ENABLE_MACHINE \
- ###将MSTATUS_MPP赋给a0,MSTATUS_MPP在encoding.h中定义
- li a0, MSTATUS_MPP; \
- ###将a0的值赋给mstatus
- csrs mstatus, a0; \
- ###定义VTEST_FP_ENABLE段的内容
- ###浮点模式的定义
- #define RVTEST_FP_ENABLE \
- ###将MSTATUS_FS & (MSTATUS_FS >> 1)赋给a0
- li a0, MSTATUS_FS & (MSTATUS_FS >> 1); \
- ###将a0赋给mstatus
- csrs mstatus, a0; \
- ###将0写入到fcsr CSR寄存器中,如果核没有支持浮点功能,则不会存在fcsr,
- ###写fcsr的行为会报异常
- csrwi fcsr, 0
- ###定义RISCV_MULTICORE_DISABLE段的内容
- ###不使用多核的配置
- #define RISCV_MULTICORE_DISABLE \
- ###读mhartid CSR寄存器的值,并赋给a0
- csrr a0, mhartid; \
- ###判断a0的值,如果不等于0,则一直保持在标志1的位置,即多核情况下,
- ###一直保持在标志1的位置,1b为向后找第一个数字为1的标志,也就是这条指令
- ###若等于0,则为单核,可以进行下面的指令执行
- 1: bnez a0, 1b
- ###定义EXTRA_TVEC_USER、EXTRA_TVEC_MACHINE、
- ###EXTRA_INIT和EXTRA_INIT_TIMER,这些段虽然定义了,但没有内容,
- ###需要用到的自己补充汇编内容
- #define EXTRA_TVEC_USER
- #define EXTRA_TVEC_MACHINE
- #define EXTRA_INIT
- #define EXTRA_INIT_TIMER
- ###定义NTERRUPT_HANDLER段内容,将跳到other_exception函数中
- #define INTERRUPT_HANDLER j other_exception /* No interrupts should occur */
- ###定义RVTEST_CODE_BEGIN段的内容
- #define RVTEST_CODE_BEGIN \
- ###指令代码段.text
- .section .text.init; \
- ###按2^6(64字节)对齐
- .align 6; \
- ###占个位置,后面有对stvec_handler定义的,就会覆盖
- .weak stvec_handler; \
- ###占个位置,后面有对mtvec_handler定义的,就会覆盖
- .weak mtvec_handler; \
- ### .global和.globl伪操作用于定义一个全局的符号,使得链接器能够全
- ###局识别它,即一个程序文件中定义的符号能够被所有
- ###其他程序文件可见。指定汇编程序入口为_start,即代码的最开始地方。
- .globl _start; \
- _start: \
- /* reset vector */ \
- ###跳到reset_vector函数中
- j reset_vector; \
- ###跳到asm_start函数中,这是我自己改的,不用那么多繁琐的步骤,直接跳
- /* j asm_start; */ \
- ###按2^2(4字节)对齐
- .align 2; \
- trap_vector: \
- /* test whether the test came from pass/fail */ \
- ###将mcasue的值赋给t5
- csrr t5, mcause; \
- ###将CAUSE_USER_ECALL值赋给t6
- li t6, CAUSE_USER_ECALL; \
- ###如果t5和t6相等,则跳到write_tohost函数中
- beq t5, t6, write_tohost; \
- ###将CAUSE_SUPERVISOR_ECALL值赋给t6
- li t6, CAUSE_SUPERVISOR_ECALL; \
- ###如果t5和t6相等,则跳到write_tohost函数中
- beq t5, t6, write_tohost; \
- ###将CAUSE_MACHINE_ECALL值赋给t6
- li t6, CAUSE_MACHINE_ECALL; \
- ###如果t5和t6相等,则跳到write_tohost函数中
- beq t5, t6, write_tohost; \
- /* if an mtvec_handler is defined, jump to it */ \
- la t5, mtvec_handler; \
- ###如果没有定义mtvec_handler函数,则mtvec_handler为0,等于0则跳到标志1
- beqz t5, 1f; \
- jr t5; \
- /* was it an interrupt or an exception? */ \
- ###前面的异常/中断都不符合了,才跳到这,对mcause的值到t5中
- 1: csrr t5, mcause; \
- ###如果t5≥0,则跳到handle_exception中
- bgez t5, handle_exception; \
- ###如果连handle_exception都不是,那就跳到other_exception中
- INTERRUPT_HANDLER; \
- handle_exception: \
- /* we don't know how to handle whatever the exception was */ \
- ###意思就是,这里需要你自己补充,如果想用的话
- other_exception: \
- /* some unhandlable exception occurred */ \
- ###意思就是,这里需要你自己补充,如果想用的话
- ###利用TESTNUM和立即数1337进行或操作
- 1: ori TESTNUM, TESTNUM, 1337; \
- ### write_tohost函数
- write_tohost: \
- ###将TESTNUM的值存到tohost的位置上
- sw TESTNUM, tohost, t5; \
- ###PC一直保持在当前位置,进入死循环
- j write_tohost; \
- reset_vector: \
- ###运行RISCV_MULTICORE_DISABLE的内容
- RISCV_MULTICORE_DISABLE; \
- ###运行INIT_SATP的内容,因为我生成的没有MMU,所以屏蔽了这句
- ###如果不屏蔽,会产生异常,但也没有影响,因为异常处理的PC就是接下来的指令
- /*INIT_SATP;*/ \
- ###运行INIT_PMP的内容
- INIT_PMP; \
- ###运行DELEGATE_NO_TRAPS的内容
- DELEGATE_NO_TRAPS; \
- ###因为运行DELEGATE_NO_TRAPS时产生了异常,所以下一句清除异常
- csrw mcause, 0; \
- ###将0赋值给TESTNUM(gp)
- li TESTNUM, 0; \
- ###将trap_vector的物理地址赋值给t0
- la t0, trap_vector; \
- ###将t0赋值给mtvec CSR寄存器
- csrw mtvec, t0; \
- ###运行CHECK_XLEN的内容
- CHECK_XLEN; \
- /* if an stvec_handler is defined, delegate exceptions to it */ \
- ###这里如果有定义stvec_handler就会进入下面的指令,没有就跳到标志1
- la t0, stvec_handler; \
- beqz t0, 1f; \
- csrw stvec, t0; \
- ###将一些特殊的中断或者异常,MMU相关,授权给其他模式处理
- li t0, (1 << CAUSE_LOAD_PAGE_FAULT) | \
- (1 << CAUSE_STORE_PAGE_FAULT) | \
- (1 << CAUSE_FETCH_PAGE_FAULT) | \
- (1 << CAUSE_MISALIGNED_FETCH) | \
- (1 << CAUSE_USER_ECALL) | \
- (1 << CAUSE_BREAKPOINT); \
- csrw medeleg, t0; \
- csrr t1, medeleg; \
- bne t0, t1, other_exception; \
- ###将0写入mstatus CSR寄存器中
- 1: csrwi mstatus, 0; \
- ###这句编译出来的是auipc t0,0x0
- init; \
- ###这个没有定义,所以是空的
- EXTRA_INIT; \
- ###这个没有定义,所以是空的
- EXTRA_INIT_TIMER; \
- ###跳到标志1的位置赋值给t0
- la t0, 1f; \
- ###将t0赋值给mepc
- csrw mepc, t0; \
- ###将mhartid的值赋值给a0
- csrr a0, mhartid; \
- ###M模式return
- mret; \
- 1:
- //-----------------------------------------------------------------------
- // End Macro
- //-----------------------------------------------------------------------
- #define RVTEST_CODE_END \
- ###UNIMP : C0001073. This is an alias for CSRRW x0, cycle, x0. Since cycle is a
- ###read-only CSR, then #(whether this CSR exists or not) an attempt to write into
- ###it will generate an illegal instruction #exception. This 32-bit form of UNIMP is
- ###emitted when targeting a system without the C #extension, or when the .option
- ###norvc directive is used.
- unimp
- //-----------------------------------------------------------------------
- // Pass/Fail Macro
- //-----------------------------------------------------------------------
- #define RVTEST_PASS \
- ###执行fence指令,可以清楚ICache内容;将1赋值给gp;最后执行ecall
- fence; \
- li TESTNUM, 1; \
- ecall
- #define TESTNUM gp
- #define RVTEST_FAIL \
- ###执行fence指令
- fence; \
- ###如何TESTNUM等于0,则一直停在这,不为0则执行下面的程序
- 1: beqz TESTNUM, 1b; \
- ###将TESTNUM的值逻辑左移1位,并重新赋值给TESTNUM
- sll TESTNUM, TESTNUM, 1; \
- ###将TESTNUM的值与1或,并重新赋值给TESTNUM
- or TESTNUM, TESTNUM, 1; \
- ecall
- //-----------------------------------------------------------------------
- // Data Section Macro
- //-----------------------------------------------------------------------
- ###定义了EXTRA_DATA,但是是空的
- #define EXTRA_DATA
- ###此段基本是空的,需要用到的,要自己添加内容
- #define RVTEST_DATA_BEGIN \
- EXTRA_DATA \
- ###将之前的段设置保存,并将当前的段设置改名.tohost
- .pushsection .tohost,"aw",@progbits; \
- .align 6; .global tohost; tohost: .dword 0; \
- .align 6; .global fromhost; fromhost: .dword 0; \
- ###恢复之前的段设置
- .popsection; \
- .align 4; .global begin_signature; begin_signature:
- #define RVTEST_DATA_END .align 4; .global end_signature; end_signature:
- #endif
复制代码
2.3.3 asm.lk:这个文件就是/riscv-tests/env/p/link.ld文件,只是我改了名字。 - SECTIONS
- {
- /*. = 0x80000000;*/
- ###这里我修改了,因为我想它从我的ROM直接执行,我的ROM地址是0x10000
- . = 0x00010000;
- .text.init : { *(.text.init) }
- . = ALIGN(0x1000);
- .tohost : { *(.tohost) }
- . = ALIGN(0x1000);
- .text : { *(.text) }
- . = ALIGN(0x1000);
- .data : { *(.data) }
- .bss : { *(.bss) }
- _end = .;
- }
复制代码
2.4 bulid:这个目录最主要的是Makefile脚本,用于调用工具链编译asm。我只贴部分代码,是生成elf的代码,生成bin、hex和dump的方法大家参考/riscv-tests/benchmarks/Makefile。
部分代码:
- #--------------------------------------------------------------------
- # author : x
- # data : 2019.4.2
- # name : project compiler for rocket-chip
- #--------------------------------------------------------------------
- proj_name ?= add
- #--------------------------------------------------------------------
- # Build rules
- #--------------------------------------------------------------------
- RISCV_PREFIX ?= ../toolchain/bin/riscv32-unknown-elf-
- RISCV_GCC ?= $(RISCV_PREFIX)gcc
- RISCV_GCC_OPTS ?= -DPREALLOCATE=1 -mcmodel=medany -static -std=gnu99 -O2 -ffast-math -fno-common -fno-builtin-printf
- RISCV_LINK_OPTS ?= -static -nostdlib -nostartfiles -lm -lgcc -T ../common/asm.ld
- SOURCE_FILE ?= ../common ../asm/$(proj_name)/*.S
- #--------------------------------------------------------------------
- # Object
- #--------------------------------------------------------------------
- default:
- make all
- elf:
- $(RISCV_GCC) $(RISCV_GCC_OPTS) -o $(proj_name)/$(proj_name).elf $(SOURCE_FILE) $(RISCV_LINK_OPTS)
- all: elf
复制代码
3.反汇编文件
- add/add.elf: file format elf32-littleriscv
- Disassembly of section .text.init:
- 00010000 <_start>:
- _start():
- 10000: a081 j 10040 <reset_vector>
- 10002: 0001 nop
- 00010004 <trap_vector>:
- trap_vector():
- 10004: 34202f73 csrr t5,mcause
- 10008: 4fa1 li t6,8
- 1000a: 03ff0663 beq t5,t6,10036 <write_tohost>
- 1000e: 4fa5 li t6,9
- 10010: 03ff0363 beq t5,t6,10036 <write_tohost>
- 10014: 4fad li t6,11
- 10016: 03ff0063 beq t5,t6,10036 <write_tohost>
- 1001a: ffff0f17 auipc t5,0xffff0
- 1001e: fe6f0f13 addi t5,t5,-26 # 0 <_start-0x10000>
- 10022: 000f0363 beqz t5,10028 <trap_vector+0x24>
- 10026: 8f02 jr t5
- 10028: 34202f73 csrr t5,mcause
- 1002c: 000f5363 bgez t5,10032 <handle_exception>
- 10030: a009 j 10032 <handle_exception>
- 00010032 <handle_exception>:
- handle_exception():
- 10032: 5391e193 ori gp,gp,1337
- 00010036 <write_tohost>:
- write_tohost():
- 10036: 00001f17 auipc t5,0x1
- 1003a: fc3f2523 sw gp,-54(t5) # 11000 <tohost>
- 1003e: bfe5 j 10036 <write_tohost>
- 00010040 <reset_vector>:
- reset_vector():
- 10040: f1402573 csrr a0,mhartid
- 10044: e101 bnez a0,10044 <reset_vector+0x4>
- 10046: 00000297 auipc t0,0x0
- 1004a: 01a28293 addi t0,t0,26 # 10060 <reset_vector+0x20>
- 1004e: 30529073 csrw mtvec,t0
- 10052: 52fd li t0,-1
- 10054: 3b029073 csrw pmpaddr0,t0
- 10058: 42fd li t0,31
- 1005a: 3a029073 csrw pmpcfg0,t0
- 1005e: 0001 nop
- 10060: 00000297 auipc t0,0x0
- 10064: 01828293 addi t0,t0,24 # 10078 <reset_vector+0x38>
- 10068: 30529073 csrw mtvec,t0
- 1006c: 30205073 csrwi medeleg,0
- 10070: 30305073 csrwi mideleg,0
- 10074: 30405073 csrwi mie,0
- 10078: 34205073 csrwi mcause,0
- 1007c: 4181 li gp,0
- 1007e: 00000297 auipc t0,0x0
- 10082: f8628293 addi t0,t0,-122 # 10004 <trap_vector>
- 10086: 30529073 csrw mtvec,t0
- 1008a: 4505 li a0,1
- 1008c: 057e slli a0,a0,0x1f
- 1008e: 00054763 bltz a0,1009c <reset_vector+0x5c>
- 10092: 0ff0000f fence
- 10096: 4185 li gp,1
- 10098: 00000073 ecall
- 1009c: ffff0297 auipc t0,0xffff0
- 100a0: f6428293 addi t0,t0,-156 # 0 <_start-0x10000>
- 100a4: 00028e63 beqz t0,100c0 <reset_vector+0x80>
- 100a8: 10529073 csrw stvec,t0
- 100ac: 0000b2b7 lui t0,0xb
- 100b0: 10928293 addi t0,t0,265 # b109 <_start-0x4ef7>
- 100b4: 30229073 csrw medeleg,t0
- 100b8: 30202373 csrr t1,medeleg
- 100bc: f6629be3 bne t0,t1,10032 <handle_exception>
- 100c0: 30005073 csrwi mstatus,0
- 100c4: 00000297 auipc t0,0x0
- 100c8: 01428293 addi t0,t0,20 # 100d8 <asm_start>
- 100cc: 34129073 csrw mepc,t0
- 100d0: f1402573 csrr a0,mhartid
- 100d4: 30200073 mret
- 000100d8 <asm_start>:
- asm_start():
- 100d8: aaaab5b7 lui a1,0xaaaab
- 100dc: aaa58593 addi a1,a1,-1366 # aaaaaaaa <_end+0xaaa98aaa>
- 100e0: 22222537 lui a0,0x22222
- 100e4: 22250513 addi a0,a0,546 # 22222222 <_end+0x22210222>
- 100e8: 00a58633 add a2,a1,a0
- 100ec: 70000737 lui a4,0x70000
- 100f0: 00470813 addi a6,a4,4 # 70000004 <_end+0x6ffee004>
- 100f4: 00c82023 sw a2,0(a6)
- 100f8: 0ff00793 li a5,255
- 100fc: 00f72023 sw a5,0(a4)
- ...
- Disassembly of section .tohost:
- 00011000 <tohost>:
- ...
- 00011040 <fromhost>:
复制代码
4.仿真测试
在说明仿真前,先贴部分TB中的代码,此代码用于自动停止VCS仿真。
具体的操作是CPU利用总线往0x7000_0000的地址写0xFF的值,然后TB就会执行$finish。
TB的代码是:
- /**************************/
- /* download memory */
- /**************************/
- initial begin
- #100 $readmemh("../compiler/build/add/add.hex",ldut.bootrom.rom);
- end
- /**************************/
- /* capture finish */
- /**************************/
- always @* begin
- 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
- #10 $finish(2);
- end
- end
复制代码
汇编中对应的代码是: - lui a4, 0x70000
- li a5, 255
- sw a5, 0(a4)
复制代码
接下来是仿真的波形分析。
本篇完,感谢关注:RISC-V单片机中文网
|