Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Test chip features #128

Merged
merged 6 commits into from
Apr 1, 2021
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 13 additions & 8 deletions src/main/resources/testchipip/bootrom/bootrom.S
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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

Expand Down
Binary file modified src/main/resources/testchipip/bootrom/bootrom.rv32.img
Binary file not shown.
Binary file modified src/main/resources/testchipip/bootrom/bootrom.rv64.img
Binary file not shown.
24 changes: 24 additions & 0 deletions src/main/resources/testchipip/csrc/testchip_tsi.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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<std::pair<uint64_t, uint32_t>>();
write_hart0_msip = true;

std::vector<std::string> 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;
}
}

Expand All @@ -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();
}
3 changes: 3 additions & 0 deletions src/main/resources/testchipip/csrc/testchip_tsi.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<std::pair<uint64_t, uint32_t>> init_writes;
};
#endif
38 changes: 38 additions & 0 deletions src/main/scala/BootAddrReg.scala
Original file line number Diff line number Diff line change
@@ -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)
abejgonzalez marked this conversation as resolved.
Show resolved Hide resolved
tlbus.toVariableWidthSlave(Some("boot-address-reg")) { node := TLBuffer() }
jerryz123 marked this conversation as resolved.
Show resolved Hide resolved
InModuleBody {
val bootAddrReg = RegInit(params.defaultBootAddress.U(p(XLen).W))
node.regmap(0 -> Seq(RegField(p(XLen), bootAddrReg)))
}
}
}
86 changes: 86 additions & 0 deletions src/main/scala/CustomBootPin.scala
Original file line number Diff line number Diff line change
@@ -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 = 0x10040) extends Config((site, here, up) => {
jerryz123 marked this conversation as resolved.
Show resolved Hide resolved
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 } }
jerryz123 marked this conversation as resolved.
Show resolved Hide resolved
}
custom_boot
}
}
val outer_io = InModuleBody {
val custom_boot = IO(Input(Bool())).suggestName("custom_boot")
inner_io := custom_boot
custom_boot
}
outer_io
}
}
4 changes: 2 additions & 2 deletions src/main/scala/TileResetCtrl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change still seems silly to me.
The only benefit seems to be the user doesn't need to know that state of the cores to affect a change, i.e. they can just write a 0 or 1 to a specific word without reading first or keeping of track of which cores are in reset.
The down side is the user cannot bring multiple cores out of reset at once. This can be problematic if the user has cores that are designed to come up together.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fact that byte-wide writes through TSI don't work is the real motivation for this change. This just seems safer for now, as its more intuitive to do a series of word-writes, instead of doing byte-mask manipulation.

Also if some cores are designed to come up together with reset, then some other widget should be used instead of this one. Even if we byte-packed them, this widget wouldn't support bringing them out of reset together if their hartids are more than 8 apart, or not aligned properly.

}): _*)

val tileMap = tile_prci_domains.zipWithIndex.map({ case (d, i) =>
Expand Down