这篇是介绍关于rocket-chip rom的内容,也叫bootrom。

bootrom的具体scala代码为:/rocket-chip/src/main/scala/devices/tilelink/BootROM.scala

在rocket-chip功能说明篇中,我生成了一个CPU,我打算按照我的配置,一点一点的说明这些功能是如何使用的,有些功能还会介绍如何修改相应的scala代码。

第一个介绍的是rom,也叫bootrom。我一开始写了rom的代码,想着让CPU从rom中正常启动,然后执行完rom的代码后跳转至sram中的。但在我写好rom的代码后,我发现了一个问题。那就是rocket-chip生成的rom是固化代码的,它是从/rocket-chip/bootrom目录中读取bootrom.img作为rom的原始代码,然后在chisel & firrtl生成代码时,将bootrom.img的内容写入到bootrom模块中。

那么我们的问题是:如何将我们自己写的rom 代码固化在bootrom中?
或者换一个思路:如何让rocket-chip从我们预想的地址中进行初始运行?

针对上面的问题,我想到了三个办法。也都分别做了实验,下面将对这三个办法一一说明。

  1. 修改/rocket-chip/bootrom/bootrom.img的内容,让rocket-chip从我们的代码开始运行。
  2. 修改rocket-chip的启动地址,让它不再从bootrom中启动,从其他地址进行启动。
  3. 修改 /rocket-chip/src/main/scala/devices/tilelink/BootROM.scala的代码,让bootrom中的代码内容可以被自由改写,且能灵活载入。

方法一:
需要修改/rocket-chip/bootrom/bootrom.img的内容,就要知道*.img是什么格式,从什么文件转换过来的。*.img是镜像的格式,可以从二进制文件中转换过来。大家查看/rocket-chip/bootrom/Makefile就能找到转换的命令。

至于二进制文件如何来?二进制文件从elf中来,elf的生成过程可以参考我之前的博客:
https://blog.csdn.net/a_weiming/article/details/89006615
而elf转bin的命令如下:

riscv32-unknown-elf-objcopy XXX.elf -O binary XXX.bin

而bin转img的命令如下:

dd if=XXX.bin of=XXX.img bs=128 count=3

dd指令的详解看这里:https://blog.csdn.net/yanyuan_smartisan/article/details/79543805

到这一步为止,得到了我们自己代码的XXX.img了,下一步就是让rocket-chip吃我们自己的XXX.img。

不修改scala代码的话,就直接命名为bootrom.img,然后覆盖到/rocket-chip/bootrom目录。
修改scala代码的话,可以修改 /home/x/rocket-chip/src/main/scala/subsystem/Configs.scala文件,第42行代码:

case BootROMParams => BootROMParams(contentFileName = "./bootrom/bootrom.img")

修改为:

case BootROMParams => BootROMParams(contentFileName = "./bootrom/XXX.img")

XXX.img就是你自己代码的img文件,然后最后一步就是进入vsim目录,运行make verilog命令生成带有你自己rom代码的RTL。

这是生成后的bootrom模块,我们对一下固化的代码和反汇编的情况。
rom.dump是我生成的反汇编文件,上面的是RTL固化的bootrom.img代码。
因为我采用了支持压缩指令的gcc去编译,所以编译出来的代码是支持16位的压缩代码的。
对比着看,可以看到地址为10000时,32bits的指令为41014081,下一个word的地址为10004,指令为42014181,都是能和反汇编一一对应的。
到这里,我们已经修改完了,可以直接用这份RTL去跑我们的程序了。
至于rom的代码内容是什么?大家可以参照我之前写的program.S
https://blog.csdn.net/a_weiming/article/details/89006615
rom代码就是这个program.S的内容,而rom的main函数中只有一条代码,那就是将PC跳转至0x8000_0000的位置。我设置sram的起始地址就是0x8000_0000。

方法二:
方法二是直接不使用bootrom,将rocket-chip的启动地址直接改为可配置的形式,具体是修改方法可以参考我之前的博客:
https://blog.csdn.net/a_weiming/article/details/93789311
这样修改后,我们就能自由配置rocket-chip的启动地址了,可以直接配置为0x8000_0000,直接从sram中启动,跳过了bootrom的启动过程。

方法三:
首先,我们来分析一下方法一,方法一可行,但每次改bootrom代码,我们都要重新生成bin,再转为img,并再次生成RTL,这个过程相当复杂,相当繁琐,当然你的bootrom code是固定好不再改了,那这种方式还是不错的。至于方法二,也可行,但没有了rom的特性,修改了启动地址后,可以随意指向哪个物理地址,如果指向的物理地址是一个sram,那么就是一个可读可写的空间,而rom的特性就是只读,不能改写,所以本质上还是有差别的。当然你可以在总线上挂一个自己编写的rom,然后将启动地址指向这个rom,这样就能解决这个问题,但额外的工作就是你要自己写一个符合总线协议的rom模块。
基于上面的两个分析,我想了第三个办法,既有rom的只读特性,又能灵活装载测试程序,不用每次都重新生成RTL代码。
方法就是修改 /rocket-chip/src/main/scala/devices/tilelink/BootROM.scala的代码,让bootrom中的代码内容可以被自由改写。修改的内容如下:

  lazy val module = new LazyModuleImp(this) {val contents = contentsDelayedval wrapSize = 1 << log2Ceil(contents.size)require (wrapSize <= size)val (in, edge) = node.in(0)val words = (contents ++ Seq.fill(wrapSize-contents.size)(0.toByte)).grouped(beatBytes).toSeqval bigs = words.map(_.foldRight(BigInt(0)){ case (x,y) => (x.toInt & 0xff) | y << 8})//val rom = Vec(bigs.map(x => UInt(x, width = 8*beatBytes)))//x_modifyval rom = Mem(4096,UInt(32.W))in.d.valid := in.a.validin.a.ready := in.d.readyval index = in.a.bits.address(log2Ceil(wrapSize)-1,log2Ceil(beatBytes))val high = if (wrapSize == size) UInt(0) else in.a.bits.address(log2Ceil(size)-1, log2Ceil(wrapSize))in.d.bits := edge.AccessAck(in.a.bits, Mux(high.orR, UInt(0), rom(index)))// Tie off unused channelsin.b.valid := Bool(false)in.c.ready := Bool(true)in.e.ready := Bool(true)}

我屏蔽了val rom = Vec(bigs.map(x => UInt(x, width = 8*beatBytes)))这一句,这一句是将bootrom.img的内容赋值只向量类型(Vec)。修改后为:val rom = Mem(4096,UInt(32.W))。
将rom的类型声明为存储器的类型(Mem)。就改这一句就可以了,其他都不用改。然后生成出来的代码是这样的:
rom的内容不是之前的那种固化的值,而是变为了reg类型。这样的话,我们就能在TB中对它自由赋值了,这样就能自由改变rom的代码而又不用每次都重新编译RTL。下面是我在TB中赋值的代码。
一条是赋值给sram的,一条是赋值给rom的。

最后我们来看一下rom代码运行的情况。
先看cpu从rom中读代码的总线行为:
cpu读rom的总线是Tilelink,具体的协议大家可以自行去查资料,后面有时间我也可能会出些说明。a接口是cpu->rom的,d接口是rom->cpu的,两个接口都是单向的,a接口是请求数据的,d接口是返回数据的,当然这里只是简单的说明,它们还有更复杂的用法。当a接口的ready&valid有效时,address和size是有效的,而且rom会单拍给出数据,也就是d接口会当拍给出a_address的数据,d接口也是当ready&和valid同时有效时,data输出有效,可以看到输出的数据和上面的反汇编是一致的。
然后我们看cpu读取数据后的运行情况:
可以看到读rom的操作在前,运行代码的操作在后,当读了数据后cpu才开始运行,因为宽度的原因,我不能再放大了,所以只能看到压缩的数据,但不难看出,第一个自行的io_pc为0x10000,而起指令io_inst_0为0x4081。还需要补充的是,io_pc & io_inst_0这两个信号都是在csr模块中的。
最后我们看一下rom代码执行完后,跳转至sram的过程:
首先我们看一下反汇编,在0x10104的指令是0x800007b7,将0x80000这个立即数赋值到a5的通用寄存器中(lui—将高20位的立即数赋值);在0x10108的指令是0x8782,跳转至寄存器a5中;在0x1010a的指令是0x8082,从main函数中返回(return),当然这条指令是不会被执行的,因为前一条就是一条跳转指令。
然后再看波形,io_pc 为0x10104和0x10108时,指令是对得上反汇编的。在0x10108后的io_pc变为了0x8000_0000,也就是跳转指令生效了,pc跳转至0x8000_0000这个位置进行执行。

到这里,关于rom的内容已经介绍完毕了,如果觉得还是有用的那就给个赞吧,谢谢。
还有,我尝试过上传方法一和方法三中的RTL,我本来想设置下载的积分为1的,但每次审核后,都会自动改为3了,所以我就不公开下载链接了,如果想要的朋友,可以私下找我,因为后面的一些功能说明也会按照这几份RTL进行说明的。

Rocket-Chip-Rom相关推荐

  1. Rocket Chip 介绍

    Rocket  Chip 是基于 Chisel 开发的一款开源的 SoC 生成器,具有可综合的RTL.通过配置可以生成两种基于 RISC-V 指令集的通用处理器就.Rocket-Chip 中有两种处理 ...

  2. chisel(Rocket Chip)中如何参数化芯片系统

    2021.9.5 有些地方添加了一点自己的理解!!! 0 绪论 前面已经介绍了chisel的初级和高级参数化. 如何把这些东西有效的在系统中组织起来呢?如何在系统中快捷的使用他们?这篇文章主要解决这个 ...

  3. 开源RISC-V 项目Freedom在Arty-7-100T开发板上的实现

    开源RISC-V 项目Freedom在Arty-7-100T开发板上的实现 1.获取Freedom项目源码 Freedom项目开源的地址为https://github.com/sifive/freed ...

  4. RISC-V架构总结1

    国产芯片能够自主一直是大家共同的期待!但无奈起步较晚,目前的通用计算平台已经是外国企业的天下.国产自主的芯片不仅仅是在工艺上还达不到目前商用芯片的水平,最底层的CPU指令集架构上也是处处受制于ARM, ...

  5. Xilinx Jtag Access/svf文件/BSCANE2

    可以在vivado安装bin目录使用xsdb.bat或xsct.bat调出命令行控制界面:[除了使用官方的usb-jtag接口,还可以使用open ocd的接口开发(不过,openocd可能不支持xi ...

  6. 芯片开发语言:Verilog 在左,Chisel 在右

    来源 | 老石谈芯 在最近召开的RISC-V中国峰会上,中科院计算所的包云岗研究员团队正式发布了名为"香山"的开源高性能处RISC-V处理器.前不久我有幸和包老师就这个事情做了一次 ...

  7. SOPC第一课 建立QSYS系统

    开发板:小梅哥AC620 软件:quartus 13.1 介绍 软核处理器代表:nios II Xilinx 的 microBlaze核 nios II提供强大的HAL系统库支持 2004年推出nio ...

  8. 片上总线协议学习(1)——SiFive的TileLink与ARM系列总线的概述与对比

    link 片上总线协议学习(1)--SiFive的TileLink与ARM系列总线的概述与对比 finally 27 人赞同了该文章 一.背景介绍 随着超大规模集成电路的迅速发展,半导体工业进入深亚微 ...

  9. 在“芯片庭院”培育一颗多核异构 RISC-V SOC种子

    1 文章导览 本文是简要性的导览chipyard官方手册内容,以及安装开发环境需要注意的的一些地方,最后运行几个简单的官方Demo,希望能对RISC-V有兴趣的小伙伴有所启发帮助,官方网址为https ...

  10. 降低芯片设计创新门槛——从互联网成功经验看开源芯片生态发展

    降低芯片设计创新门槛 --从互联网成功经验看开源芯片生态发展 中国科学院计算技术研究所研究员  包云岗 2018年,中国企业遭遇芯片禁售令而陷入困境,中国半导体产业的现状再次引起各界广泛关注.如何尽快 ...

最新文章

  1. C# Socket系列三 socket通信的封包和拆包
  2. X5同层播放器应用实践
  3. spring 启动加载数据_12个很棒的Spring数据教程来启动您的数据项目
  4. [转帖]公司内网机器病毒
  5. 爱奇艺回应遭做空;百度 App 部分频道停更;React Native 0.62 发布 | 极客头条
  6. xcode Cornerstone 拷贝项目 提示框架头文件找不到的问题
  7. 福州大学软件工程1916|W班 第10、11次作业成绩排名
  8. Active Directory证书服务
  9. mysql 查询建表详情_MySQL 查看数据表结构以及详情的方法
  10. 2020.01.18【NOIP提高组】模拟B 组——总结——探险者拉罗
  11. [渝粤教育] 南京森林警察学院 森林植物识别技术 ——珍稀植物识别 参考 资料
  12. 面试考点:逻辑思维面试题(软件测试)
  13. html好看的后台页面布局,25 个精美的后台管理界面模板和布局
  14. 解决Intel Edison 已连接Wifi但无法上网问题
  15. ELK集群部署报错(master not discovered yet, this node has not previously joined a bootstrapped )
  16. 手撸的一个快递查询系统,竟然阅读量过1.8w
  17. 又一巅峰!,Java开发实用必备的几款插件
  18. PS|002自制夸张表情包
  19. android 不能在子线程中更新ui的讨论和分析
  20. 【一起学Rust | 开源项目】效率提升工具espanso——在日常输入中使用代码提示

热门文章

  1. jquery中beforeSend和complete的使用 --- 提高用户体验
  2. QC协议+华为FCP+三星AFC快充取电5V9V芯片FS2601应用
  3. java计算机毕业设计贫困助学管理系统源程序+mysql+系统+lw文档+远程调试
  4. Java类类getMethod()方法及示例
  5. 跨校区无线WiFi组网解决方案
  6. w10添加蓝牙显示无法连接服务器失败,技术解答Win10系统下显示蓝牙已配对但未连接的修复方式...
  7. EXCEL函数LookUp, VLOOKUP及HLOOKUP函数
  8. android+kitchen最新优化版下载,Kitchen Story最新版下载
  9. python生成exe文件运行闪退解决方法
  10. # 腾讯云TcaplusDB X 大主宰·大千世界|万道争锋,独领其风