Rocket——BootRom
Bootrom是嵌入处理器芯片内的一小块掩模ROM,包含处理器在上电或复位时执行的第一个代码。bootrom结构如下所示(图自10-02 晶片內建Boot Rom記憶體映設圖介紹_哔哩哔哩_bilibili):
rocket中的code bootrom.s是rocket-chip/bootrom.S at master · chipsalliance/rocket-chip (github.com),rocket-chip生成的rom是固化代码的,它是从/rocket-chip/bootrom目录中读取bootrom.img作为rom的原始代码,然后在chisel & firrtl生成代码时,将bootrom.img的内容写入到bootrom模块中。bootrom.s注释如下:
//定义dram起始地址是0x8000_0000 #define DRAM_BASE 0x80000000 .section .text.start, "ax", @progbits .globl _start //_start地址是0x10000 _start: csrwi 0x7c1, 0 // disable chicken bits li s0, DRAM_BASE csrr a0, mhartid la a1, _dtb //跳转到s0的地址,也就是8000_0000 jr s0 //_hang的地址是10040,其会等待debug模块发来的一个中断 .section .text.hang, "ax", @progbits .globl _hang _hang: csrwi 0x7c1, 0 // disable chicken bits csrr a0, mhartid la a1, _dtb csrwi mie, 0 1: wfi j 1b .section .rodata.dtb, "a", @progbits .globl _dtb .align 5, 0 _dtb: .ascii "DTB goes here"
可见,如果我们通过系统函数将自己的hex写入0x8000_0000开头的sram中,并让cpu执行,需要修改bootrom的resetvector,让其从复位后的0x10000地址开始执行,即可顺利跳转到0x8000_0000地址处。
1,修改src/main/scala/devices/tilelink/BootROM.scala中的case class BootROMParams,让hang: BigInt=0x10000
但经过测试发现系统并没有跳转到0x8000_0000执行,为此我们需要详细分析一下soc上电后执行rom代码的行为。首先看看rom的接口:
rom和cpu交互采用tilelink总线接口,关于tilelink部分的基础信息参加论文阅读:Diplomatic Design Patterns: A TileLink Case Study - Haowen_Zhao - 博客园 (cnblogs.com)
其ROM的TL接口信号如下:
a接口是cpu->rom的,d接口是rom->cpu的,两个接口都是单向的,a接口是请求数据的,d接口是返回数据的。
而经过检查发现bootrom的载入是没问题的。那么我们看看cpu读取到rom数据后的行为。
经过debug,发现是rocket-chip/bootrom/bootrom.img官方镜像的问题,经过修改重新生成rtl,成功从0x8000_0000启动: