2

我用哈佛架构构建了一个 32 位 RISC-V CPU,我想用 C 为它编写程序。我有一个 RISC-V 编译器集(https://xpack.github.io/riscv-none-embed-gcc / ) 可以做到这一点并且工作正常 - 对于大多数事情。当我想使用全局变量、全局数组等时,问题就开始了,因为这些类型在启动/重置时被启动脚本复制到 RAM。

这是我的 CPU 的框图:(稍后会很重要。请注意指令存储器 = FLASH 和数据存储器 = RAM) 我的 CPU 框图

(如果您对我的 CPU 感兴趣,我制作了一个关于它的视频:https ://www.youtube.com/watch?v=KzSaFFpBPDM )


例子:

一个典型的程序看起来像这样:

#include <stdint.h>

int static_var_1 = 2;
int static_var_2 = 4;

int main(void)
{
    int var = static_var_1 + static_var_2;
}

它的 objdump 是这样的:

/opt/xpack-riscv-none-embed-gcc-10.1.0-1.1/riscv-none-embed/bin/objdump build/APP.elf -D

build/APP.elf:     file format elf32-littleriscv


Disassembly of section .text:

00000000 <_start>:
   0:   00080137            lui sp,0x80
   4:   ffc10113            addi    sp,sp,-4 # 7fffc <_estack>
   8:   00c000ef            jal ra,14 <main>
   c:   0040006f            j   10 <_exit>

00000010 <_exit>:
  10:   0000006f            j   10 <_exit>

00000014 <main>:
  14:   fe010113            addi    sp,sp,-32
  18:   00812e23            sw  s0,28(sp)
  1c:   02010413            addi    s0,sp,32
  20:   00002703            lw  a4,0(zero) # 0 <_start>
  24:   00402783            lw  a5,4(zero) # 4 <static_var_2>
  28:   00f707b3            add a5,a4,a5
  2c:   fef42623            sw  a5,-20(s0)
  30:   00000793            li  a5,0
  34:   00078513            mv  a0,a5
  38:   01c12403            lw  s0,28(sp)
  3c:   02010113            addi    sp,sp,32
  40:   00008067            ret

Disassembly of section .data:

00000000 <static_var_1>:
   0:   0002                    c.slli64    zero
    ...

00000004 <static_var_2>:
   4:   0004                    0x4
    ...

Disassembly of section ._user_heap_stack:

00000008 <._user_heap_stack>:
    ...

<_start>是我的启动脚本的一部分,它将初始化堆栈指针)


问题:

以下是尝试加载全局变量的两条指令:

  20:   00002703            lw  a4,0(zero) # 0 <_start>
  24:   00402783            lw  a5,4(zero) # 4 <static_var_2>

但是有一个问题——它们从未被放入 RAM,因此 CPU 很可能最终会得到一些垃圾数据,这是不可接受的。


解决方案?

有人建议将链接器放松作为我之前的问题(RISC-V:全局变量)的一部分,同样,情况似乎并非如此,但我仍然可能是错的!

根据我的研究,大多数“经典”CPU 使用启动脚本,复制发生的地方,但由于这不是冯诺依曼架构,我没有将闪存映射到数据存储器,因此无法读取由程序(见上面的框图)。输出程序必须包含已解码为可执行指令的变量,例如,如果我们希望 RAM 中位置 0x0 处的值 0x4,则可以将其解码为:

addi t0, zero, 0x4
sw t0, 0(zero)

将我的 CPU 重新构建为 von-neuman 将需要更多的门和 IC,这是一个离散构建,每个 IC 都很重要。

如上所述,对我来说,用硬件来做是最糟糕的解决方案,所以如果它可以用软件来做,我完全赞成——它可以!显然,有一个解决方案,但迄今为止最丑陋的:编译代码,提取数据(使用python),使用python脚本解码的这些变量生成一个新的启动脚本,然后再次编译。

我真的不想走那条路,所以如果可以通过修改启动脚本、链接器等来完成,那就太好了。

AVR IC 基本上是哈佛架构(尽管经过修改),那么它们有什么不同的地方可以学习吗?

4

0 回答 0