diff --git a/src/main/resources/testchipip/bootrom/bootrom.S b/src/main/resources/testchipip/bootrom/bootrom.S index be0c3bc8..dc899567 100644 --- a/src/main/resources/testchipip/bootrom/bootrom.S +++ b/src/main/resources/testchipip/bootrom/bootrom.S @@ -1,4 +1,4 @@ -#define DRAM_BASE 0x80000000 +#define BOOTADDR_REG 0x4000 // boot all cores (only hart 0) and jump to main program execution .section .text.start, "ax", @progbits @@ -43,13 +43,18 @@ boot_core: bnez t0, boot_core // block until hart 0 clears own MSIP sll a0, a0, 2 // offset for hart MSIP add a1, a0, a1 -boot_core_hart0: // begin executing code at DRAM_BASE - sw zero, 0(a1) // clear the interrupt - li a0, DRAM_BASE // program reset vector - csrw mepc, a0 // return from interrupt to start of user program - csrr a0, mhartid // hartid for next level bootloader - la a1, _dtb // dtb address for next level bootloader - li a2, 0x80 // set mstatus MPIE to 0 +boot_core_hart0: // begin executing code at DRAM_BASE + sw zero, 0(a1) // clear the interrupt + li a0, BOOTADDR_REG // program reset vector +#if __riscv_xlen == 32 + lw a0, 0(a0) // get boot address from bootaddr_reg SCR +#else + ld a0, 0(a0) // get boot address from bootaddr_reg SCR +#endif + csrw mepc, a0 // return from interrupt to start of user program + csrr a0, mhartid // hartid for next level bootloader + la a1, _dtb // dtb address for next level bootloader + li a2, 0x80 // set mstatus MPIE to 0 csrc mstatus, a2 mret diff --git a/src/main/resources/testchipip/bootrom/bootrom.rv32.img b/src/main/resources/testchipip/bootrom/bootrom.rv32.img index 12a9111d..801bdb50 100755 Binary files a/src/main/resources/testchipip/bootrom/bootrom.rv32.img and b/src/main/resources/testchipip/bootrom/bootrom.rv32.img differ diff --git a/src/main/resources/testchipip/bootrom/bootrom.rv64.img b/src/main/resources/testchipip/bootrom/bootrom.rv64.img index f746c2db..d42dfb22 100755 Binary files a/src/main/resources/testchipip/bootrom/bootrom.rv64.img and b/src/main/resources/testchipip/bootrom/bootrom.rv64.img differ diff --git a/src/main/resources/testchipip/csrc/testchip_tsi.cc b/src/main/resources/testchipip/csrc/testchip_tsi.cc index ecec1a02..9ad47cd3 100644 --- a/src/main/resources/testchipip/csrc/testchip_tsi.cc +++ b/src/main/resources/testchipip/csrc/testchip_tsi.cc @@ -3,10 +3,25 @@ testchip_tsi_t::testchip_tsi_t(int argc, char** argv, bool can_have_loadmem) : tsi_t(argc, argv) { has_loadmem = false; + init_writes = std::vector>(); + write_hart0_msip = true; + std::vector args(argv + 1, argv + argc); for (auto& arg : args) { if (arg.find("+loadmem=") == 0) has_loadmem = can_have_loadmem; + if (arg.find("+init_write=0x") == 0) { + auto d = arg.find(":0x"); + if (d == std::string::npos) { + throw std::invalid_argument("Improperly formatted +init_write argument"); + } + uint64_t addr = strtoull(arg.substr(14, d - 14).c_str(), 0, 16); + uint32_t val = strtoull(arg.substr(d + 3).c_str(), 0, 16); + + init_writes.push_back(std::make_pair(addr, val)); + } + if (arg.find("+no_hart0_msip") == 0) + write_hart0_msip = false; } } @@ -28,3 +43,12 @@ void testchip_tsi_t::read_chunk(addr_t taddr, size_t nbytes, void* dst) tsi_t::read_chunk(taddr, nbytes, dst); } } + +void testchip_tsi_t::reset() +{ + for (auto p : init_writes) { + write_chunk(p.first, sizeof(uint32_t), &p.second); + } + if (write_hart0_msip) + tsi_t::reset(); +} diff --git a/src/main/resources/testchipip/csrc/testchip_tsi.h b/src/main/resources/testchipip/csrc/testchip_tsi.h index cc90810c..94d7ac45 100644 --- a/src/main/resources/testchipip/csrc/testchip_tsi.h +++ b/src/main/resources/testchipip/csrc/testchip_tsi.h @@ -22,10 +22,13 @@ class testchip_tsi_t : public tsi_t protected: virtual void load_mem_write(addr_t taddr, size_t nbytes, const void* src) { }; virtual void load_mem_read(addr_t taddr, size_t nbytes, void* dst) { }; + void reset() override; bool has_loadmem; private: bool is_loadmem; + bool write_hart0_msip; + std::vector> init_writes; }; #endif diff --git a/src/main/scala/BootAddrReg.scala b/src/main/scala/BootAddrReg.scala new file mode 100644 index 00000000..43c33972 --- /dev/null +++ b/src/main/scala/BootAddrReg.scala @@ -0,0 +1,38 @@ +package testchipip + +import chisel3._ +import chisel3.experimental.{IO} +import freechips.rocketchip.config.{Parameters, Field} +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.tilelink._ +import freechips.rocketchip.devices.tilelink._ +import freechips.rocketchip.regmapper._ +import freechips.rocketchip.subsystem._ +import freechips.rocketchip.util._ +import freechips.rocketchip.tile._ +import freechips.rocketchip.prci._ + + +case class BootAddrRegParams( + defaultBootAddress: BigInt = 0x80000000L, // This should be DRAM_BASE + bootRegAddress: BigInt = 0x4000, + slaveWhere: TLBusWrapperLocation = PBUS +) +case object BootAddrRegKey extends Field[BootAddrRegParams](BootAddrRegParams()) + +trait HasPeripheryBootAddrReg { this: BaseSubsystem => + val params = p(BootAddrRegKey) + + val tlbus = locateTLBusWrapper(params.slaveWhere) + + val device = new SimpleDevice("boot-address-reg", Nil) + + tlbus { + val node = TLRegisterNode(Seq(AddressSet(params.bootRegAddress, 4096-1)), device, "reg/control", beatBytes=tlbus.beatBytes) + tlbus.toVariableWidthSlave(Some("boot-address-reg")) { node } + InModuleBody { + val bootAddrReg = RegInit(params.defaultBootAddress.U(p(XLen).W)) + node.regmap(0 -> RegField.bytes(bootAddrReg)) + } + } +} diff --git a/src/main/scala/CustomBootPin.scala b/src/main/scala/CustomBootPin.scala new file mode 100644 index 00000000..3e17df6d --- /dev/null +++ b/src/main/scala/CustomBootPin.scala @@ -0,0 +1,86 @@ +package testchipip + +import chisel3._ +import chisel3.util._ +import chisel3.experimental.{IO} +import freechips.rocketchip.config._ +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.tilelink._ +import freechips.rocketchip.devices.tilelink._ +import freechips.rocketchip.regmapper._ +import freechips.rocketchip.subsystem._ +import freechips.rocketchip.util._ +import freechips.rocketchip.tile._ +import freechips.rocketchip.prci._ + +case class CustomBootPinParams( + customBootAddress: BigInt = 0x80000000L, // Default is DRAM_BASE + masterWhere: TLBusWrapperLocation = CBUS // This needs to write to clint and bootaddrreg, which are on CBUS/PBUS +) + +case object CustomBootPinKey extends Field[Option[CustomBootPinParams]](Some(CustomBootPinParams())) + +class WithCustomBootPinAltAddr(address: BigInt) extends Config((site, here, up) => { + case CustomBootPinKey => up(CustomBootPinKey, site).map(p => p.copy(customBootAddress = address)) +}) + +trait CanHavePeripheryCustomBootPin { this: BaseSubsystem => + val custom_boot_pin = p(CustomBootPinKey).map { params => + val tlbus = locateTLBusWrapper(params.masterWhere) + val clientParams = TLMasterPortParameters.v1( + clients = Seq(TLMasterParameters.v1( + name = "custom-boot", + sourceId = IdRange(0, 1), + )), + minLatency = 1 + ) + + val inner_io = tlbus { + val node = TLClientNode(Seq(clientParams)) + tlbus.coupleFrom(s"port_named_custom_boot_pin") ({ _ := node }) + + InModuleBody { + val custom_boot = IO(Input(Bool())).suggestName("custom_boot") + val (tl, edge) = node.out(0) + val inactive :: waiting_bootaddr_reg_a :: waiting_bootaddr_reg_d :: waiting_msip_a :: waiting_msip_d :: dead :: Nil = Enum(6) + val state = RegInit(inactive) + tl.a.valid := false.B + tl.a.bits := DontCare + tl.d.ready := true.B + switch (state) { + is (inactive) { when (custom_boot) { state := waiting_bootaddr_reg_a } } + is (waiting_bootaddr_reg_a) { + tl.a.valid := true.B + tl.a.bits := edge.Put( + toAddress = p(BootAddrRegKey).bootRegAddress.U, + fromSource = 0.U, + lgSize = 2.U, + data = params.customBootAddress.U + )._2 + when (tl.a.fire()) { state := waiting_bootaddr_reg_d } + } + is (waiting_bootaddr_reg_d) { when (tl.d.fire()) { state := waiting_msip_a } } + is (waiting_msip_a) { + tl.a.valid := true.B + tl.a.bits := edge.Put( + toAddress = (p(CLINTKey).get.baseAddress + CLINTConsts.msipOffset(0)).U, // msip for hart0 + fromSource = 0.U, + lgSize = log2Ceil(CLINTConsts.msipBytes).U, + data = 1.U + )._2 + when (tl.a.fire()) { state := waiting_msip_d } + } + is (waiting_msip_d) { when (tl.d.fire()) { state := dead } } + is (dead) { when (!custom_boot) { state := inactive } } + } + custom_boot + } + } + val outer_io = InModuleBody { + val custom_boot = IO(Input(Bool())).suggestName("custom_boot") + inner_io := custom_boot + custom_boot + } + outer_io + } +} diff --git a/src/main/scala/TileResetCtrl.scala b/src/main/scala/TileResetCtrl.scala index e18a0d35..e9c55932 100644 --- a/src/main/scala/TileResetCtrl.scala +++ b/src/main/scala/TileResetCtrl.scala @@ -38,14 +38,14 @@ class TLTileResetCtrl(w: Int, params: TileResetCtrlParams, tile_prci_domains: Se lazy val module = new LazyModuleImp(this) { val nTiles = p(TilesLocated(InSubsystem)).size - require (nTiles <= 4096) + require (nTiles <= 4096 / 4) val r_tile_resets = (0 until nTiles).map({ i => withReset (asyncResetSinkNode.in.head._1.reset) { Module(new AsyncResetRegVec(w=1, init=(if (params.initResetHarts.contains(i)) 1 else 0))) } }) node.regmap((0 until nTiles).map({ i => - i -> Seq(RegField.rwReg(1, r_tile_resets(i).io)), + i * 4 -> Seq(RegField.rwReg(1, r_tile_resets(i).io)), }): _*) val tileMap = tile_prci_domains.zipWithIndex.map({ case (d, i) =>