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

如何建立自己的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工具链的编译与使用(https://blog.csdn.net/a_weiming/article/details/84801051)

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的说明。
在这里插入图片描述

注意,下文中使用“###”形式的均是我添加的注释,原代码中没有。

#*****************************************************************************
# 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

以下的定义在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)

接下来是仿真的波形分析。
在这里插入图片描述

  • 3
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值