Rocket-Chip复位向量的修改

rocket-chip复位向量的修改

rocket-chip系统复位后是从bootrom中进行启动的,这章我们将详细分析rocket-chip是如何调用bootrom模块的,最后还会对复位向量进行修改,即让rocket-chip不再从bootrom开始启动,而是从我们想要的地址进行启动。

bootrom模块的调用:
首先关注的scala文件是 /src/main/scala/system/ExampleRocketSystem.scala

package freechips.rocketchip.system

import Chisel._
import freechips.rocketchip.config.Parameters
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.tilelink._
import freechips.rocketchip.subsystem._
import freechips.rocketchip.devices.tilelink._
import freechips.rocketchip.util.DontTouch

/** Example Top with periphery devices and ports, and a Rocket subsystem */
class ExampleRocketSystem(implicit p: Parameters) extends RocketSubsystem
    with HasAsyncExtInterrupts
    with CanHaveMasterAXI4MemPort
    with CanHaveMasterAXI4MMIOPort
    with CanHaveSlaveAXI4Port
    with HasPeripheryBootROM {
  override lazy val module = new ExampleRocketSystemModuleImp(this)

  // Error device used for testing and to NACK invalid front port transactions
  val error = LazyModule(new TLError(p(ErrorDeviceKey), sbus.beatBytes))
  // always buffer the error device because no one cares about its latency
  sbus.coupleTo("slave_named_error"){ error.node := TLBuffer() := _ }
}

class ExampleRocketSystemModuleImp[+L <: ExampleRocketSystem](_outer: L) extends RocketSubsystemModuleImp(_outer)
    with HasRTCModuleImp
    with HasExtInterruptsModuleImp
    with CanHaveMasterAXI4MemPortModuleImp
    with CanHaveMasterAXI4MMIOPortModuleImp
    with CanHaveSlaveAXI4PortModuleImp
    with HasPeripheryBootROMModuleImp
with DontTouch

HasPeripheryBootROM & HasPeripheryBootROMModuleImp就是调用bootrom的地方。
在哪个地方可以找到呢?
答案就是 /src/main/scala/devices/tilelink/BootROM.scala

package freechips.rocketchip.devices.tilelink

import Chisel._
import freechips.rocketchip.config.{Field, Parameters}
import freechips.rocketchip.subsystem.{BaseSubsystem, HasResetVectorWire}
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.tilelink._
import freechips.rocketchip.util._

import java.nio.{ByteBuffer, ByteOrder}
import java.nio.file.{Files, Paths}

/** Size, location and contents of the boot rom. */
case class BootROMParams(
  address: BigInt = 0x10000,
  size: Int = 0x10000,
  hang: BigInt = 0x10040,
  contentFileName: String)
case object BootROMParams extends Field[BootROMParams]

class TLROM(val base: BigInt, val size: Int, contentsDelayed: => Seq[Byte], executable: Boolean = true, beatBytes: Int = 4,
  resources: Seq[Resource] = new SimpleDevice("rom", Seq("sifive,rom0")).reg("mem"))(implicit p: Parameters) extends LazyModule
{
  val node = TLManagerNode(Seq(TLManagerPortParameters(
    Seq(TLManagerParameters(
      address     = List(AddressSet(base, size-1)),
      resources   = resources,
      regionType  = RegionType.UNCACHED,
      executable  = executable,
      supportsGet = TransferSizes(1, beatBytes),
      fifoId      = Some(0))),
    beatBytes = beatBytes)))

  lazy val module = new LazyModuleImp(this) {
    val contents = contentsDelayed
    val 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).toSeq
    val 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)))

    in.d.valid := in.a.valid
    in.a.ready := in.d.ready

    val 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 channels
    in.b.valid := Bool(false)
    in.c.ready := Bool(true)
    in.e.ready := Bool(true)
  }
}

/** Adds a boot ROM that contains the DTB describing the system's subsystem. */
trait HasPeripheryBootROM { this: BaseSubsystem =>
  val dtb: DTB
  private val params = p(BootROMParams)
  private lazy val contents = {
    val romdata = Files.readAllBytes(Paths.get(params.contentFileName))
    val rom = ByteBuffer.wrap(romdata)
    rom.array() ++ dtb.contents
  }
  def resetVector: BigInt = params.hang

  val bootrom = LazyModule(new TLROM(params.address, params.size, contents, true, sbus.control_bus.beatBytes))

  sbus.control_bus.toVariableWidthSlave(Some("bootrom")){ bootrom.node }
}

/** Subsystem will power-on running at 0x10040 (BootROM) */
trait HasPeripheryBootROMModuleImp extends LazyModuleImp
    with HasResetVectorWire {
  val outer: HasPeripheryBootROM
  global_reset_vector := outer.resetVector.U
}

由上面代码可以知道,在HasPeripheryBootROMModuleImp中有global_reset_vector := outer.resetVector.U,而在HasPeripheryBootROM中,定义的方法是def resetVector: BigInt = params.hang,最后追到params.hang是在BootROMParams中定义的,hang=0x10040。简化点就是global_reset_vector = resetVector = params.hang = 0x10040。0x10040就是bootrom的起始地址,将这个值传给了global_reset_vector,那么global_reset_vector在哪里找到呢?

答案是 /src/main/scala/subsystem/ResetVector.scala

package freechips.rocketchip.subsystem

import Chisel._

/** A single place for all tiles to find out the reset vector */
trait HasResetVectorWire {
  def resetVectorBits: Int
  val global_reset_vector = Wire(UInt(width = resetVectorBits))
}

那么global_reset_vector是怎么传到cpu内部的呢?
答案是 /src/main/scala/subsystem/RocketSubsystem.scala

//只复制了部分代码
class RocketSubsystemModuleImp[+L <: RocketSubsystem](_outer: L) extends BaseSubsystemModuleImp(_outer)
    with HasRocketTilesModuleImp {
  tile_inputs.zip(outer.hartIdList).foreach { case(wire, i) =>
    wire.clock := clock
    wire.reset := reset
    wire.hartid := UInt(i)
    wire.reset_vector := global_reset_vector
  }
}

wire.reset_vector会将global_reset_vector的值传到cpu core的内部。
到这里rocket-chip从bootrom启动的大致情况已经说明完毕,下面介绍的是我自己修改的复位向量。代码修改如下,修改文件为(/src/main/scala/subsystem/RocketSubsystem.scala):

class RocketSubsystemModuleImp[+L <: RocketSubsystem](_outer: L) extends BaseSubsystemModuleImp(_outer)
    with HasRocketTilesModuleImp {
  tile_inputs.zip(outer.hartIdList).foreach { case(wire, i) =>
    wire.clock := clock
    wire.reset := reset
    wire.hartid := UInt(i)
    wire.reset_vector := global_reset_vector
  }
 
  //xhunter_modify
  //在模块顶层声明一个为reset_vector的信号,Uint类型,input,32位
  val reset_vector = IO(UInt(INPUT, width = 32))
  //将reset_vector的值赋给global_reset_vector
  //同时屏蔽/src/main/scala/system/ExampleRocketSystem.scala中的HasPeripheryBootROM & HasPeripheryBootROMModuleImp
  global_reset_vector := reset_vector
}

用上面的方法就能使rocket-chip不再从bootrom中启动,而是从我们输入的reset_vector开始启动。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值