新ちゃん 发表于 2020-8-19 12:06:26

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

本帖最后由 新ちゃん 于 2020-8-20 22:18 编辑

如何建立自己的RISC-V编译环境–汇编?
1.RISC-V编译环境框架
这是我RISC-V编译环境的架构:buildcasecommontoolchain


一级目录二级目录说明
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中
adda2, a1, a0
###将0x7000_0000存入a4中
luia4, 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字节)对齐
      .align6;                                                      \
      ###占个位置,后面有对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



汇编中对应的代码是: luia4, 0x70000
li   a5, 255
sw   a5, 0(a4)

接下来是仿真的波形分析。





本篇完,感谢关注:RISC-V单片机中文网
页: [1]
查看完整版本: 如何建立自己的RISC-V编译环境--汇编?