NANO 9K玩转RISCV之ARDUINO开发环境

news2024/11/14 13:48:09

一、前言

在从0-1探索RISCV指令集的路上,我们用百元不到的NANO 9K开发板一步步的实现: 

1)最小的内核架构

2)取值,译码和执行的过程(电路实现ISA指令集)

3)存储空间的实现(寄存器,RAM, ROM的寻址)和数据搬移

4) 外设的电路实现

  至此,我们有了一个自己用数字电路实现的CPU精简内核,而且实现了RISCV的ISA指令集的一部分,虽然是很小的一部分! 

  看看我们之前的软件编写方式,

1)用什么语言?首先要用机器码二进制来实现,汇编都不行。

2)软件怎么装载和运行?只能是写死到ROM里,没法更新,下载?更不用想了。 

       所以这个简洁到简陋的"MCU"和我们平常用的8051,STM32相比,缺什么? 

1)编译器和反编译器。 编译器用来把C或者汇编编译成机器语言(二进制)然后可以加载执行;

2)支持交互编程的IDE集成开发环境,最好能一键下载,最好不需要专用的烧录器,比如串口下载。 

         MCU是工具芯片,能否用起来,用的好,依赖于开发者生态, 很多性能优异的MCU设计出来推广的不好都是因为开发环境“反人类”, 工程师/开发者“不喜欢”,从而制约了发展,越没人用越无法迭代, 越迭代慢越没人用,从而陷入僵局。

        反观市场上的“当红炸子鸡”,除了芯片本身的性价比外,简单易用,稳定可靠的IDE环境,便宜易获得的下载工具都为人津津乐道,前有AVR/MCS51, 后有ESP32, STM32,所以设计MCU一定要有关注开发环境和融入生态的思路和提前规划, 这些就是本次内容要解决的问题! 

 二、解决方案

        导入简洁而不简单的IDE , ARDUINO开发环境, 实现开发环境的闭环。 

        常见的生态: 

        8位机: 8051/STM8+IAR,  STM32+KEIL......还有像STC以及其他厂商推出的各类IDE,或者基于eclipse\codeblock\vscode扩展的各种插件。 

        如果我们平时玩过电子制作,对arduino不会模式,经常用来做电子积木,逻辑简单而功能强大,生态极为丰富,只要是成熟的外设,不管是温湿度传感器,陀螺仪,气压计,还是OLED屏,SPI屏,甚至蓝牙,wifi都不在话下,不但有硬件生态,还有丰富的软件生态,各种库几乎能满足平常电子制作甚至专业快速开发的一切需求。 

   先看看我们的成果: 

在arduino里导入了我们的精简内核(用nano 9k的板子实现的软核),并且支持直接一键编译,串口下载,是不是完美解决了我们上面的困扰。 当然,由于内核实现的指令集过于简单,这个软核的能编写的应用软件很局限,但至少也可以把流水灯点起来,bink,blink.......

分步骤实现:

1)修改内核,加载到板子上;形成我们自己的"MCU开发板"

硬件设计的增量----内核在前面项目基础上,增加: 

  • 模块--HWLoader实现
  • 模块--双口RAM实现
    • A口-HWLoader
    • B口-core
  • core修改TOP层引用,增加了端口调用,MUX端口选择
  • core修改地址译码电路

综合,下载,这里注意要设置下systemverilog语言支持,不然综合会报错。 

报错信息: 

 

设置位置: project->configuration 

 

  

2)配置arduino开发环境;

包括必要的三件套: 硬件支持包+环境配置文件,编译器,下载工具软件

 环境配置: 

获取压缩包arduino_riscvgcc_tools ” riscv.rar下载,解压到Arduino安装目录的hardware子目录下(如“C:\Arduino\hardware\”)

工具链配置(编译+下载): 

tools下的gcc.rar解压。得到两个工具链的两个要素: 编译器gcc+下载器

查看配置文件: C:\arduino-1.8.19\hardware\riscv\tangnano9k\boards.txt

 

```
TANG.name=TANG Nano9k Board (Gaoyun GW1NR)

TANG.platform=riscv-gcc
TANG.build.board=_BOARD_TANG_NANO9K_

TANG.build.extra_flags = -march=rv32i -mabi=ilp32 
TANG.compiler.c.extra_flags= 
TANG.compiler.cpp.extra_flags= 
TANG.ld.extra_flags = 

TANG.upload.maximum_size=4096
TANG.upload.speed=115200
TANG.upload.tool=Reindeer_upload

TANG.build.mcu=tiny
TANG.build.core=riscv
TANG.build.variant=generic
```

platform.txt

```
name=Lanzhoo RISC-V (TANG Nano9k)

compiler.path           = {runtime.platform.path}/tools/gcc/bin/

compiler.define= -DIDE=Arduino "-I{compiler.path}../riscv-none-elf/include"

build.extra_flags       =
build.flags             = 

compiler.c.cmd          = riscv-none-elf-gcc
compiler.c.flags        =  -W -c --specs=nosys.specs -O1 -fdata-sections -ffunction-sections -fno-exceptions -fno-unwind-tables 
compiler.c.extra_flags  =
compiler.elf.flags      =
compiler.elf.cmd        = riscv-none-elf-gcc

compiler.ld.cmd = riscv-none-elf-gcc
compiler.ld.flags= -Wl,--gc-sections -static -lm --specs=nosys.specs
compiler.ld.extra_flags=
compiler.ldscript=Reindeer.ld

compiler.ar.cmd=riscv-none-elf-ar
compiler.ar.flags=rcs

compiler.objcopy.cmd=riscv-none-elf-objcopy

compiler.elf2hex.cmd=riscv-none-elf-objcopy

compiler.size.path = {runtime.platform.path}/tools/gcc/bin/
compiler.size.cmd = riscv-none-elf-size

build.variant=generic
build.ldscript.path={build.variant.path}

core.header=Arduino.h

compiler.c.elf.extra_flags= -I{build.core.path}
compiler.S.extra_flags=
compiler.cpp.extra_flags=
compiler.ar.extra_flags=

compiler.objcopy.eep.flags = -O binary
compiler.objcopy.eep.extra_flags=

compiler.elf2hex.flags = -O ihex
compiler.elf2hex.extra_flags=

recipe.c.o.pattern="{compiler.path}{compiler.c.cmd}" {build.flags} {compiler.c.flags} {compiler.define} {compiler.c.extra_flags} {build.extra_flags} -I{build.path}/sketch {includes} "{source_file}" -o "{object_file}"

recipe.cpp.o.pattern="{compiler.path}{compiler.c.cmd}" {build.flags} {compiler.c.flags} {compiler.define} {compiler.c.extra_flags} {build.extra_flags} -I{build.path}/sketch {includes} "{source_file}" -o "{object_file}"

recipe.ar.pattern="{compiler.path}{compiler.ar.cmd}"  {compiler.ar.flags} {compiler.ar.extra_flags} "{archive_file_path}"  "{object_file}"

recipe.c.combine.pattern="{compiler.path}{compiler.ld.cmd}" -T {build.ldscript.path}/{compiler.ldscript} {build.flags} {compiler.ld.flags} {build.extra_flags} -o "{build.path}/{build.project_name}.elf" {object_files} "{build.path}/{archive_file}"

recipe.objcopy.hex.pattern="{compiler.path}{compiler.elf2hex.cmd}" {compiler.elf2hex.flags} {compiler.elf2hex.extra_flags} "{build.path}/{build.project_name}.elf"  "{build.path}/{build.project_name}.hex"

recipe.output.tmp_file={build.project_name}.hex
recipe.output.save_file={build.project_name}.{build.variant}.hex

recipe.size.pattern="{compiler.size.path}/{compiler.size.cmd}"  "{build.path}/{build.project_name}.hex"
recipe.size.regex=Total\s+([0-9]+).*
 
# up loader
tools.Reindeer_upload.cmd=reindeer_config
tools.Reindeer_upload.path={runtime.platform.path}/tools

tools.Reindeer_upload.upload.params.verbose=
tools.Reindeer_upload.upload.params.quiet=
tools.Reindeer_upload.upload.protocol=UART

tools.Reindeer_upload.upload.pattern="{path}/{cmd}" --reset --run --port={serial.port} --baud=115200 "--image={build.path}/{build.project_name}.hex"
```

 

 链接link配置脚本, 路径: C:\arduino-1.8.19\hardware\riscv\tangnano9k\variants\generic\Reindeer.ld

内容: 

/* Script for -z combreloc: combine and sort reloc sections */
/* Copyright (C) 2014-2018 Free Software Foundation, Inc.
   Copying and distribution of this script, with or without modification,
   are permitted in any medium without royalty provided the copyright
   notice and this notice are preserved.  */
OUTPUT_FORMAT("elf32-littleriscv", "elf32-littleriscv",
              "elf32-littleriscv")
OUTPUT_ARCH(riscv)
ENTRY(_start)
/*
SEARCH_DIR("=/Host/Work/riscv-none-gcc-8.1.0-2/install/win64/riscv-none-gcc/riscv-none-embed/lib"); 
SEARCH_DIR("=/usr/local/lib"); 
SEARCH_DIR("=/lib"); 
SEARCH_DIR("=/usr/lib");
*/
SECTIONS
{
  /* Read-only sections, merged into text segment: */
/*  PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x80000000)); . = SEGMENT_START("text-segment", 0x80000000); 
*/
  PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x80002000)); . = SEGMENT_START("text-segment", 0x80002000);
/*  PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x00002000)); . = SEGMENT_START("text-segment", 0x00002000); 
*/
/* hzheng. 2022.11.19 */
  .interp         : { *(.interp) }
  .note.gnu.build-id : { *(.note.gnu.build-id) }
  .hash           : { *(.hash) }
  .gnu.hash       : { *(.gnu.hash) }
  .dynsym         : { *(.dynsym) }
  .dynstr         : { *(.dynstr) }
  .gnu.version    : { *(.gnu.version) }
  .gnu.version_d  : { *(.gnu.version_d) }
  .gnu.version_r  : { *(.gnu.version_r) }
  .rela.dyn       :
    {
      *(.rela.init)
      *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
      *(.rela.fini)
      *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
      *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
      *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
      *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
      *(.rela.ctors)
      *(.rela.dtors)
      *(.rela.got)
      *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*)
      *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*)
      *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*)
      *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*)
      *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
      PROVIDE_HIDDEN (__rela_iplt_start = .);
      *(.rela.iplt)
      PROVIDE_HIDDEN (__rela_iplt_end = .);
    }
  .rela.plt       :
    {
      *(.rela.plt)
    }
  .init           :
  {
    KEEP (*(SORT_NONE(.init)))
  }
  .plt            : { *(.plt) }
  .iplt           : { *(.iplt) }
  .text           :
  {
    *(.text .stub .text.* .gnu.linkonce.t.*)
    *(.text.startup .text.startup.*)
    *(.text.unlikely .text.*_unlikely .text.unlikely.*)
    *(.text.exit .text.exit.*)
    *(.text.hot .text.hot.*)
    /* .gnu.warning sections are handled specially by elf32.em.  */
    *(.gnu.warning)
  }
  .fini           :
  {
    KEEP (*(SORT_NONE(.fini)))
  }
  PROVIDE (__etext = .);
  PROVIDE (_etext = .);
  PROVIDE (etext = .);
  .rodata         : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
  .rodata1        : { *(.rodata1) }
  .sdata2         :
  {
    *(.sdata2 .sdata2.* .gnu.linkonce.s2.*)
  }
  .sbss2          : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) }
  .eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) }
  .eh_frame       : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) }
  .gcc_except_table   : ONLY_IF_RO { *(.gcc_except_table
  .gcc_except_table.*) }
  .gnu_extab   : ONLY_IF_RO { *(.gnu_extab*) }
  /* These sections are generated by the Sun/Oracle C++ compiler.  */
  .exception_ranges   : ONLY_IF_RO { *(.exception_ranges
  .exception_ranges*) }
  /* Adjust the address for the data segment.  We want to adjust up to
     the same address within the page on the next page up.  */
  . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE));
  /* Exception handling  */
  
 /* . = SEGMENT_START("data-segment", 0x80002000);
 */ 
/*   . = SEGMENT_START("data-segment", 0x80001000);
 */
   . = SEGMENT_START("data-segment", 0x00000400);
 
/*   . = SEGMENT_START("data-segment", 0x00000400);
 */
 /* hzheng. 2022.11.19 */  
 
  .eh_frame       : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) }
  .gnu_extab      : ONLY_IF_RW { *(.gnu_extab) }
  .gcc_except_table   : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
  .exception_ranges   : ONLY_IF_RW { *(.exception_ranges .exception_ranges*) }
  /* Thread Local Storage sections  */
  .tdata          : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
  .tbss           : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
  .preinit_array     :
  {
    PROVIDE_HIDDEN (__preinit_array_start = .);
    KEEP (*(.preinit_array))
    PROVIDE_HIDDEN (__preinit_array_end = .);
  }
  .init_array     :
  {
    PROVIDE_HIDDEN (__init_array_start = .);
    KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
    KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
    PROVIDE_HIDDEN (__init_array_end = .);
  }
  .fini_array     :
  {
    PROVIDE_HIDDEN (__fini_array_start = .);
    KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
    KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
    PROVIDE_HIDDEN (__fini_array_end = .);
  }
  .ctors          :
  {
    /* gcc uses crtbegin.o to find the start of
       the constructors, so we make sure it is
       first.  Because this is a wildcard, it
       doesn't matter if the user does not
       actually link against crtbegin.o; the
       linker won't look for a file to match a
       wildcard.  The wildcard also means that it
       doesn't matter which directory crtbegin.o
       is in.  */
    KEEP (*crtbegin.o(.ctors))
    KEEP (*crtbegin?.o(.ctors))
    /* We don't want to include the .ctor section from
       the crtend.o file until after the sorted ctors.
       The .ctor section from the crtend file contains the
       end of ctors marker and it must be last */
    KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
    KEEP (*(SORT(.ctors.*)))
    KEEP (*(.ctors))
  }
  .dtors          :
  {
    KEEP (*crtbegin.o(.dtors))
    KEEP (*crtbegin?.o(.dtors))
    KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
    KEEP (*(SORT(.dtors.*)))
    KEEP (*(.dtors))
  }
  .jcr            : { KEEP (*(.jcr)) }
  .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data .rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) }
  .dynamic        : { *(.dynamic) }
  . = DATA_SEGMENT_RELRO_END (0, .);
  .data           :
  {
    *(.data .data.* .gnu.linkonce.d.*)
    SORT(CONSTRUCTORS)
  }
  .data1          : { *(.data1) }
  .got            : { *(.got.plt) *(.igot.plt) *(.got) *(.igot) }
  /* We want the small data sections together, so single-instruction offsets
     can access them all, and initialized data all before uninitialized, so
     we can shorten the on-disk segment size.  */
  .sdata          :
  {
    __global_pointer$ = . + 0x800;
    *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) *(.srodata .srodata.*)
    *(.sdata .sdata.* .gnu.linkonce.s.*)
  }
  _edata = .; PROVIDE (edata = .);
  . = .;
  __bss_start = .;
  .sbss           :
  {
    *(.dynsbss)
    *(.sbss .sbss.* .gnu.linkonce.sb.*)
    *(.scommon)
  }
  .bss            :
  {
   *(.dynbss)
   *(.bss .bss.* .gnu.linkonce.b.*)
   *(COMMON)
   /* Align here to ensure that the .bss section occupies space up to
      _end.  Align after .bss to ensure correct alignment even if the
      .bss section disappears because there are no input sections.
      FIXME: Why do we need it? When there is no .bss section, we don't
      pad the .data section.  */
   . = ALIGN(. != 0 ? 32 / 8 : 1);
  }
  . = ALIGN(32 / 8);
  . = SEGMENT_START("ldata-segment", .);
  . = ALIGN(32 / 8);
  _end = .; PROVIDE (end = .);
  . = DATA_SEGMENT_END (.);
  /* Stabs debugging sections.  */
  .stab          0 : { *(.stab) }
  .stabstr       0 : { *(.stabstr) }
  .stab.excl     0 : { *(.stab.excl) }
  .stab.exclstr  0 : { *(.stab.exclstr) }
  .stab.index    0 : { *(.stab.index) }
  .stab.indexstr 0 : { *(.stab.indexstr) }
  .comment       0 : { *(.comment) }
  /* DWARF debug sections.
     Symbols in the DWARF debugging sections are relative to the beginning
     of the section so we begin them at 0.  */
  /* DWARF 1 */
  .debug          0 : { *(.debug) }
  .line           0 : { *(.line) }
  /* GNU DWARF 1 extensions */
  .debug_srcinfo  0 : { *(.debug_srcinfo) }
  .debug_sfnames  0 : { *(.debug_sfnames) }
  /* DWARF 1.1 and DWARF 2 */
  .debug_aranges  0 : { *(.debug_aranges) }
  .debug_pubnames 0 : { *(.debug_pubnames) }
  /* DWARF 2 */
  .debug_info     0 : { *(.debug_info .gnu.linkonce.wi.*) }
  .debug_abbrev   0 : { *(.debug_abbrev) }
  .debug_line     0 : { *(.debug_line .debug_line.* .debug_line_end ) }
  .debug_frame    0 : { *(.debug_frame) }
  .debug_str      0 : { *(.debug_str) }
  .debug_loc      0 : { *(.debug_loc) }
  .debug_macinfo  0 : { *(.debug_macinfo) }
  /* SGI/MIPS DWARF 2 extensions */
  .debug_weaknames 0 : { *(.debug_weaknames) }
  .debug_funcnames 0 : { *(.debug_funcnames) }
  .debug_typenames 0 : { *(.debug_typenames) }
  .debug_varnames  0 : { *(.debug_varnames) }
  /* DWARF 3 */
  .debug_pubtypes 0 : { *(.debug_pubtypes) }
  .debug_ranges   0 : { *(.debug_ranges) }
  /* DWARF Extension.  */
  .debug_macro    0 : { *(.debug_macro) }
  .debug_addr     0 : { *(.debug_addr) }
  .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
  /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) }
}

3)编写主程序代码和头文件

main.cpp

 

```
#include "Arduino.h"
int main(){          
    setup();
    while (1) {
        loop();
    } 
    return 0;
}
```

头文件arduino.h: 

 


```
#ifndef _ARDUINO_H
#define _ARDUINO_H

#ifdef  __cplusplus
extern "C" {
#endif

extern void setup();
extern void loop();

#ifdef  __cplusplus
}
#endif

#endif
```

(注:这里涉及.c和.cpp中函数相互调用的链接问题。如果Arduino.h中不加“#ifdef  __cplusplus”相关语句,则main.c中的main()在链接时找不到.ino.cpp中实现的setup()和loop()。(把main.c改名为main.cpp就可以))

 

4)编写arduino 应用,查看编译下载日志, 熟悉工作流程

 

C:\arduino-1.8.19\arduino-builder -dump-prefs -logger=machine -hardware C:\arduino-1.8.19\hardware -hardware C:\Users\hy\AppData\Local\Arduino15\packages -tools C:\arduino-1.8.19\tools-builder -tools C:\arduino-1.8.19\hardware\tools\avr -tools C:\Users\hy\AppData\Local\Arduino15\packages -built-in-libraries C:\arduino-1.8.19\libraries -libraries C:\Users\hy\Documents\Arduino\libraries -fqbn=riscv:tangnano9k:TANG -vid-pid=0403_6010 -ide-version=10819 -build-path C:\Users\hy\AppData\Local\Temp\arduino_build_815823 -warnings=none -build-cache C:\Users\hy\AppData\Local\Temp\arduino_cache_966892 -prefs=build.warn_data_percentage=75 -verbose C:\Gowin\TangNano9k_Tutorial\04_arduino_step01\arduino01\arduino01.ino
C:\arduino-1.8.19\arduino-builder -compile -logger=machine -hardware C:\arduino-1.8.19\hardware -hardware C:\Users\hy\AppData\Local\Arduino15\packages -tools C:\arduino-1.8.19\tools-builder -tools C:\arduino-1.8.19\hardware\tools\avr -tools C:\Users\hy\AppData\Local\Arduino15\packages -built-in-libraries C:\arduino-1.8.19\libraries -libraries C:\Users\hy\Documents\Arduino\libraries -fqbn=riscv:tangnano9k:TANG -vid-pid=0403_6010 -ide-version=10819 -build-path C:\Users\hy\AppData\Local\Temp\arduino_build_815823 -warnings=none -build-cache C:\Users\hy\AppData\Local\Temp\arduino_cache_966892 -prefs=build.warn_data_percentage=75 -verbose C:\Gowin\TangNano9k_Tutorial\04_arduino_step01\arduino01\arduino01.ino
---------------------------------------------
Using board 'TANG' from platform in folder: C:\arduino-1.8.19\hardware\riscv\tangnano9k
Using core 'riscv' from platform in folder: C:\arduino-1.8.19\hardware\riscv\tangnano9k
-------------------------------------------------
Detecting libraries used...
"C:\\arduino-1.8.19\\hardware\\riscv\\tangnano9k/tools/gcc/bin/riscv-none-elf-gcc" -W -c --specs=nosys.specs -O1 -fdata-sections -ffunction-sections -fno-exceptions -fno-unwind-tables -DIDE=Arduino "-IC:\\arduino-1.8.19\\hardware\\riscv\\tangnano9k/tools/gcc/bin/../riscv-none-elf/include" -march=rv32i -mabi=ilp32 "-IC:\\Users\\hy\\AppData\\Local\\Temp\\arduino_build_815823/sketch" "-IC:\\arduino-1.8.19\\hardware\\riscv\\tangnano9k\\cores\\riscv" "-IC:\\arduino-1.8.19\\hardware\\riscv\\tangnano9k\\variants\\generic" "C:\\Users\\hy\\AppData\\Local\\Temp\\arduino_build_815823\\sketch\\arduino01.ino.cpp" -o nul
----------------------------------------------------
Generating function prototypes...
"C:\\arduino-1.8.19\\hardware\\riscv\\tangnano9k/tools/gcc/bin/riscv-none-elf-gcc" -W -c --specs=nosys.specs -O1 -fdata-sections -ffunction-sections -fno-exceptions -fno-unwind-tables -DIDE=Arduino "-IC:\\arduino-1.8.19\\hardware\\riscv\\tangnano9k/tools/gcc/bin/../riscv-none-elf/include" -march=rv32i -mabi=ilp32 "-IC:\\Users\\hy\\AppData\\Local\\Temp\\arduino_build_815823/sketch" "-IC:\\arduino-1.8.19\\hardware\\riscv\\tangnano9k\\cores\\riscv" "-IC:\\arduino-1.8.19\\hardware\\riscv\\tangnano9k\\variants\\generic" "C:\\Users\\hy\\AppData\\Local\\Temp\\arduino_build_815823\\sketch\\arduino01.ino.cpp" -o "C:\\Users\\hy\\AppData\\Local\\Temp\\arduino_build_815823\\preproc\\ctags_target_for_gcc_minus_e.cpp"
"C:\\arduino-1.8.19\\tools-builder\\ctags\\5.8-arduino11/ctags" -u --language-force=c++ -f - --c++-kinds=svpf --fields=KSTtzns --line-directives "C:\\Users\\hy\\AppData\\Local\\Temp\\arduino_build_815823\\preproc\\ctags_target_for_gcc_minus_e.cpp"
----------------------------------------------------
正在编译项目...
"C:\\arduino-1.8.19\\hardware\\riscv\\tangnano9k/tools/gcc/bin/riscv-none-elf-gcc" -W -c --specs=nosys.specs -O1 -fdata-sections -ffunction-sections -fno-exceptions -fno-unwind-tables -DIDE=Arduino "-IC:\\arduino-1.8.19\\hardware\\riscv\\tangnano9k/tools/gcc/bin/../riscv-none-elf/include" -march=rv32i -mabi=ilp32 "-IC:\\Users\\hy\\AppData\\Local\\Temp\\arduino_build_815823/sketch" "-IC:\\arduino-1.8.19\\hardware\\riscv\\tangnano9k\\cores\\riscv" "-IC:\\arduino-1.8.19\\hardware\\riscv\\tangnano9k\\variants\\generic" "C:\\Users\\hy\\AppData\\Local\\Temp\\arduino_build_815823\\sketch\\arduino01.ino.cpp" -o "C:\\Users\\hy\\AppData\\Local\\Temp\\arduino_build_815823\\sketch\\arduino01.ino.cpp.o"
Compiling libraries...
Compiling core...
"C:\\arduino-1.8.19\\hardware\\riscv\\tangnano9k/tools/gcc/bin/riscv-none-elf-gcc" -W -c --specs=nosys.specs -O1 -fdata-sections -ffunction-sections -fno-exceptions -fno-unwind-tables -DIDE=Arduino "-IC:\\arduino-1.8.19\\hardware\\riscv\\tangnano9k/tools/gcc/bin/../riscv-none-elf/include" -march=rv32i -mabi=ilp32 "-IC:\\Users\\hy\\AppData\\Local\\Temp\\arduino_build_815823/sketch" "-IC:\\arduino-1.8.19\\hardware\\riscv\\tangnano9k\\cores\\riscv" "-IC:\\arduino-1.8.19\\hardware\\riscv\\tangnano9k\\variants\\generic" "C:\\arduino-1.8.19\\hardware\\riscv\\tangnano9k\\cores\\riscv\\main.c" -o "C:\\Users\\hy\\AppData\\Local\\Temp\\arduino_build_815823\\core\\main.c.o"
"C:\\arduino-1.8.19\\hardware\\riscv\\tangnano9k/tools/gcc/bin/riscv-none-elf-ar" rcs "C:\\Users\\hy\\AppData\\Local\\Temp\\arduino_build_815823\\core\\core.a" "C:\\Users\\hy\\AppData\\Local\\Temp\\arduino_build_815823\\core\\main.c.o"
Archiving built core (caching) in: C:\Users\hy\AppData\Local\Temp\arduino_cache_966892\core\core_riscv_tangnano9k_TANG_e2890981838dae9eb3ff54af2f115652.a
--------------------------------------------
Linking everything together...
"C:\\arduino-1.8.19\\hardware\\riscv\\tangnano9k/tools/gcc/bin/riscv-none-elf-gcc" -T "C:\\arduino-1.8.19\\hardware\\riscv\\tangnano9k\\variants\\generic/Reindeer.ld" -Wl,--gc-sections -static -lm --specs=nosys.specs -march=rv32i -mabi=ilp32 -o "C:\\Users\\hy\\AppData\\Local\\Temp\\arduino_build_815823/arduino01.ino.elf" "C:\\Users\\hy\\AppData\\Local\\Temp\\arduino_build_815823\\sketch\\arduino01.ino.cpp.o" "C:\\Users\\hy\\AppData\\Local\\Temp\\arduino_build_815823/core\\core.a"
"C:\\arduino-1.8.19\\hardware\\riscv\\tangnano9k/tools/gcc/bin/riscv-none-elf-objcopy" -O ihex "C:\\Users\\hy\\AppData\\Local\\Temp\\arduino_build_815823/arduino01.ino.elf" "C:\\Users\\hy\\AppData\\Local\\Temp\\arduino_build_815823/arduino01.ino.hex"
"C:\\arduino-1.8.19\\hardware\\riscv\\tangnano9k/tools/gcc/bin//riscv-none-elf-size" "C:\\Users\\hy\\AppData\\Local\\Temp\\arduino_build_815823/arduino01.ino.hex"
项目使用了 0 字节,占用了 (0%) 程序存储空间。最大为 4096 字节。
------------------------------------------------------------------
C:\arduino-1.8.19\hardware\riscv\tangnano9k/tools/reindeer_config --reset --run --port=COM53 --baud=115200 --image=C:\Users\hy\AppData\Local\Temp\arduino_build_815823/arduino01.ino.hex 
===============================================================================
# Copyright (c) 2019, PulseRain Technology LLC 
# Reindeer Configuration Utility, Version 2.1
===============================================================================
baud_rate  =  115200
com_port   =  COM53
toolchain  =  riscv-none-embed-
===============================================================================
Reseting CPU ...
Loading  C:\Users\hy\AppData\Local\Temp\arduino_build_815823/arduino01.ino.hex

===================> start the CPU, entry point = 0x80002000
 

生成的.hex文件将用于烧写。

生成的.elf文件可以通过riscv-none-elf-objdump.exe反编译为汇编。

 

5)通过反编译,深入探索

文件路径: C:\Users\hy\AppData\Local\Temp\arduino_build_815823

 反编译命令: 

-D arduino01.ino.elf  > code.txt

得到反编译的汇编代码: 

-D arduino01.ino.elf  > code.txt


arduino01.ino.elf:     file format elf32-littleriscv


Disassembly of section .text:

80002000 <_start>:
80002000:	00001137          	lui	sp,0x1
80002004:	0240006f          	j	80002028 <main>
_start函数先设置堆栈指针gp也就是sp的值,然后调用若干函数初始化变量,然后跳转main函数。

80002008 <_fini>:
80002008:	0000006f          	j	80002008 <_fini>

8000200c <setup>:
8000200c:	00008067          	ret

80002010 <loop>:
80002010:	00180813          	addi	a6,a6,1
80002014:	00a00793          	li	a5,10
80002018:	00000013          	nop
8000201c:	fff78793          	addi	a5,a5,-1
80002020:	fe079ce3          	bnez	a5,80002018 <loop+0x8>
80002024:	00008067          	ret

80002028 <main>:
80002028:	ff010113          	addi	sp,sp,-16 # ff0 <__global_pointer$+0x3ec>
8000202c:	00112623          	sw	ra,12(sp)
80002030:	fddff0ef          	jal	ra,8000200c <setup>
80002034:	fddff0ef          	jal	ra,80002010 <loop>
80002038:	ffdff06f          	j	80002034 <main+0xc>

Disassembly of section .eh_frame:

00000400 <__FRAME_END__>:
 400:	0000                	.2byte	0x0
	...

Disassembly of section .comment:

00000000 <.comment>:
   0:	3a434347          	.4byte	0x3a434347
   4:	2820                	.2byte	0x2820
   6:	5078                	.2byte	0x5078
   8:	6361                	.2byte	0x6361
   a:	4e47206b          	.4byte	0x4e47206b
   e:	2055                	.2byte	0x2055
  10:	4952                	.2byte	0x4952
  12:	562d4353          	.4byte	0x562d4353
  16:	4520                	.2byte	0x4520
  18:	626d                	.2byte	0x626d
  1a:	6465                	.2byte	0x6465
  1c:	6564                	.2byte	0x6564
  1e:	2064                	.2byte	0x2064
  20:	20434347          	.4byte	0x20434347
  24:	3878                	.2byte	0x3878
  26:	5f36                	.2byte	0x5f36
  28:	3436                	.2byte	0x3436
  2a:	2029                	.2byte	0x2029
  2c:	3231                	.2byte	0x3231
  2e:	312e                	.2byte	0x312e
  30:	302e                	.2byte	0x302e
	...

Disassembly of section .riscv.attributes:

00000000 <.riscv.attributes>:
   0:	1b41                	.2byte	0x1b41
   2:	0000                	.2byte	0x0
   4:	7200                	.2byte	0x7200
   6:	7369                	.2byte	0x7369
   8:	01007663          	bgeu	zero,a6,14 <__FRAME_END__-0x3ec>
   c:	0011                	.2byte	0x11
   e:	0000                	.2byte	0x0
  10:	1004                	.2byte	0x1004
  12:	7205                	.2byte	0x7205
  14:	3376                	.2byte	0x3376
  16:	6932                	.2byte	0x6932
  18:	7032                	.2byte	0x7032
  1a:	0031                	.2byte	0x31

 - 其它函数还包括:deregister_tm_clones、register_tm_clones、__do_global_dtors_aux、frame_dummy、atexit、exit、__libc_fini_array、__libc_init_array、memset、__register_exitproc、__call_exitprocs、_exit。

总共代码量是0x052c,约2.4kB。

另外还占用了约2点多kB的数据区。

三、运行结果观察

下载程序前: 

Arduino未下载程序前,core运行的程序是rom_data.mi中的指令。

观察led的值:

```

00, 0000

||: (循环)

01, 0100

10, 1000

11, 1000

00, 1011

:||

```

和以下指令(addr[3:2], code[5:2])是一一对应的:

rom_data.mi

#File_format=Hex
#Address_depth=1024
#Data_width=32
00002783
00178813
01002023
81002823
ff5ff06f
00000000
00000000
00000000

 

#### 下载程序后的现象

观察led的值:

```

00, 1101

01, 1011

10, 0100

11, 1000

00, 1011

||: (循环)

11, 1001

00, 0100

01, 0100

10, 0100

11, 0100

00, 1000

01, 1001

10, 0100

11, 1000

00, 1011

:||

```

 观察反编译的代码

对照反汇编指令,是一致的:
```
80002000 <_start>:
80002000:	00001137          	lui	sp,0x1
80002004:	0240006f          	j	80002028 <main>
80002028 <main>:
80002028:	ff010113          	addi	sp,sp,-16 # ff0 <__global_pointer$+0x3ec>
8000202c:	00112623          	sw	ra,12(sp)
80002030:	fddff0ef          	jal	ra,8000200c <_Z5setupv>
||: (循环)
8000200c <_Z5setupv>:
8000200c:	00008067          	ret
80002010 <_Z4loopv>:
80002010:	00180813          	addi	a6,a6,1
80002014:	00a00793          	li	a5,10
80002018:	00000013          	nop
8000201c:	fff78793          	addi	a5,a5,-1
80002020:	fe079ce3          	bnez	a5,80002018 <_Z4loopv+0x8>
80002024:	00008067          	ret
80002028 <main>:
80002028:	ff010113          	addi	sp,sp,-16 # ff0 <__global_pointer$+0x3ec>
8000202c:	00112623          	sw	ra,12(sp)
80002030:	fddff0ef          	jal	ra,8000200c <_Z5setupv>
:||


```
由于没有实现ret指令和bnez指令,所以只有jal和j进行了跳转,其它都是顺序执行。

四、小结

通过这样的IDE+TOOLCHAIN组合,我们建立了自研CPU核的小生态闭环

内核实现,外设,指令集,开发工具,编译环境。 

没错,商用的MCU也是这些,只是规模和复杂度增加了几个数量级,但是原理基本一致。 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2144922.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

使用神经网络拟合6项参数

使用神经网络拟合6项参数 1. 数据预处理1.1 添加参数解析1.2 数据预处理逻辑1.3 数据归一化及划分1.4 数据标签处理逻辑1.5 数据转torch 2. 定义model2.1 CNN_LSTM2.2 Transformer 3. 定义train脚本3.1 loss和optimizer3.2 train3.3 predict 1. 数据预处理 1.1 添加参数解析 …

Vue+nodejs+express汽车配件商城销售管理系统 i9cgz

目录 技术栈具体实现截图系统设计思路技术可行性nodejs类核心代码部分展示可行性论证研究方法解决的思路Express框架介绍源码获取/联系我 技术栈 该系统将采用B/S结构模式&#xff0c;开发软件有很多种可以用&#xff0c;本次开发用到的软件是vscode&#xff0c;用到的数据库是…

动态分析基础

实验一 Lab03-01.exe文件中发现的恶意代码 问题&#xff1a; 1.找出这个恶意代码的导入函数与字符串列表? 2.这个恶意代码在主机上的感染迹象特征是什么? 3.这个恶意代码是否存在一些有用的网络特征码?如果存在&#xff0c;它们是什么? 解答&#xff1a; 1.找出这个恶意代…

上调铁矿石产量预期后,淡水河谷股价能否重振?

猛兽财经的核心观点&#xff1a; &#xff08;1&#xff09;尽管市场面临挑战&#xff0c;但淡水河谷(VALE)还是上调了2024年的铁矿石产量预期。 &#xff08;2&#xff09;第二季度业绩喜忧参半;收入减少&#xff0c;但铁矿石出货量却很强劲。 &#xff08;3&#xff09;投资者…

【渗透测试】-vulnhub源码框架漏洞-Os-hackNos-1

vulnhub源码框架漏洞中的CVE-2018-7600-Drupal 7.57 文章目录  前言 1.靶场搭建&#xff1a; 2.信息搜集&#xff1a; 主机探测&#xff1a; 端口扫描&#xff1a; 目录扫描&#xff1a; 3.分析&#xff1a; 4.步骤&#xff1a; 1.下载CVE-2018-7600的exp 2.执行exp: 3.写入木…

QCustomPlot笔记(一)

文章目录 简介将帮助文档添加到Qt Creator中编译共享库cmake工程编译提示ui_mainwindow.h找不到qcustomplot.h文件 环境:windowsQt Creator 10.0.1cmake 简介 QT中用于绘制曲线的第三方工具 下载地址&#xff1a;https://www.qcustomplot.com/index.php/download 第一个压缩…

心觉:不能成事的根本原因

很多人一直都很努力&#xff0c;每天都很忙 每天都学习很多东西&#xff0c;学习各种道&#xff0c;各种方法论 但是许多年过去了依然一事无成 自己的目标没有达成&#xff0c;梦想没有实现 为什么呢 关键是没有开悟 那么什么是开悟呢 现在很多人都在讲开悟 貌似开悟很…

Docker Registry API best practice 【Docker Registry API 最佳实践】

文章目录 1. 安装 docker2. 配置 docker4. 配置域名解析5. 部署 registry6. Registry API 管理7. 批量清理镜像8. 其他 &#x1f44b; 这篇文章内容&#xff1a;实现shell 脚本批量清理docker registry的镜像。 &#x1f514;&#xff1a;你可以在这里阅读&#xff1a;https:/…

《深度学习》—— PyTorch的神经网络模块中常用的损失函数

文章目录 前言一、回归模型中常用的损失函数1、平均绝对误差损失&#xff08;L1Loss&#xff09;2、均方误差损失&#xff08;MSELoss也称L2Loss&#xff09;3、SmoothL1Loss 二、分类模型中常用的损失函数1、负对数似然损失&#xff08;NLLLoss&#xff09;2、二元交叉熵损失&…

XML映射器-动态sql

01-动态sql 1.实现动态条件SQL 第一种方法在sql语句中加入where 11其他条件都加and就行,这样就可以根据if条件来判断要传递的参数可以有几个 第二种方法用where标签给if语句包起来 where标签的作用如下图 第三种方法用trim标签解释如下图 用choose也可以实现条件查询如下图,…

【数据结构与算法 | 灵神题单 | 自底向上DFS篇】力扣508, 1026, 951

1. 力扣508&#xff1a;出现次数最多的子树元素和 1.1 题目&#xff1a; 给你一个二叉树的根结点 root &#xff0c;请返回出现次数最多的子树元素和。如果有多个元素出现的次数相同&#xff0c;返回所有出现次数最多的子树元素和&#xff08;不限顺序&#xff09;。 一个结…

在Ubuntu中编译含有JSON的文件出现报错

在ubuntu中进行JSON相关学习的时候&#xff0c;我发现了一些小问题&#xff0c;决定与大家进行分享&#xff0c;减少踩坑时候出现不必要的时间耗费 截取部分含有JSON部分的代码进行展示 char *str "{ \"title\":\"JSON Example\", \"author\&…

Web植物管理系统-下位机部分

本节主要展示上位机部分&#xff0c;采用BSP编程&#xff0c;不附带BSP中各个头文件的说明&#xff0c;仅仅是对main逻辑进行解释 main.c 上下位机通信 通过串口通信&#xff0c;有两位数据验证头&#xff08;verify数组中保存对应的数据头 0xAA55) 通信格式 上位发送11字节…

保护您的企业免受网络犯罪分子侵害的四个技巧

在这个日益数字化的时代&#xff0c;小型企业越来越容易受到网络犯罪的威胁。网络犯罪分子不断调整策略&#xff0c;并使用人工智能来推动攻击。随着技术的进步&#xff0c;您的敏感数据面临的风险也在增加。 风险的不断增大意味着&#xff0c;做好基本工作比以往任何时候都更…

Java--stream流、方法引用

Stream流 - Stream流的好处 - 直接阅读代码的字面意思即可完美展示无关逻辑方式的语义 - Stream流把真正的函数式编程风格引入到Java中 - 代码简洁 - Stream流的三类方法 - 获取Stream流 - 创建一条流水线,并把数据放到流水线上准备进行操作 - 中间方法 - 流水线上的操作 - 一次…

【代码随想录训练营第42期 Day60打卡 - 图论Part10 - Bellman_ford算法系列运用

目录 一、Bellman_ford算法的应用 二、题目与题解 题目一&#xff1a;卡码网 94. 城市间货物运输 I 题目链接 题解&#xff1a;队列优化Bellman-Ford算法&#xff08;SPFA&#xff09; 题目二&#xff1a;卡码网 95. 城市间货物运输 II 题目链接 题解&#xff1a; 队列优…

MySQL高阶1783-大满贯数量

题目 找出每一个球员赢得大满贯比赛的次数。结果不包含没有赢得比赛的球员的ID 。 结果集 无顺序要求 。 准备数据 Create table If Not Exists Players (player_id int, player_name varchar(20)); Create table If Not Exists Championships (year int, Wimbledon int, F…

Unity 高亮插件HighlightPlus介绍

仅对官方文档进行了翻译 注意:官方文档本身就落后实际,但对入门仍很有帮助,核心并没有较大改变,有的功能有差异,以实际为准.(目前我已校正了大部分差异,后续我会继续维护该文档) 为什么为该插件做翻译?功能强大,使用简单,且还在维护. 基于此版本的内置渲染管线文档 快速开始…

C语言之预处理详解(完结撒花)

目录 前言 一、预定义符号 二、#define 定义常量 三、#define定义宏 四、宏与函数的对比 五、#和## 运算符 六、命名约定 七、#undef 八、条件编译 九、头文件的包含 总结 前言 本文为我的C语言系列的最后一篇文章&#xff0c;主要讲述了#define定义和宏、#和##运算符、各种条件…

9.18作业

提示并输入一个字符串&#xff0c;统计该字符串中字母、数字、空格、其他字符的个数并输出 代码展示 #include <iostream>using namespace std;int main() {string str;int countc 0; // 字母计数int countn 0; // 数字计数int count 0; // 空格计数int counto 0;…