Merge remote-tracking branch 'upstream/main' into graphics

This commit is contained in:
Hansung Kim
2023-04-05 13:12:57 -07:00
23 changed files with 605 additions and 95 deletions

View File

@@ -6,6 +6,9 @@
#include <sstream>
#include <vpi_user.h>
#include <svdpi.h>
#include "testchip_tsi.h"
extern testchip_tsi_t* tsi;
enum transfer_t {
NToB,
@@ -73,9 +76,18 @@ public:
void dcache_b(uint64_t address, uint64_t source, int param);
bool dcache_c(uint64_t *address, uint64_t* source, int* param, unsigned char* voluntary, unsigned char* has_data, uint64_t* data[8]);
void dcache_d(uint64_t sourceid, uint64_t data[8], unsigned char has_data, unsigned char grantack);
void tcm_a(uint64_t address, uint64_t data, uint32_t mask, uint32_t opcode, uint32_t size);
bool tcm_d(uint64_t *data);
void loadmem(const char* fname);
void drain_stq();
bool stq_empty() { return st_q.size() == 0; };
const cfg_t &get_cfg() const { return cfg; }
const std::map<size_t, processor_t*>& get_harts() const { return harts; }
~chipyard_simif_t() { };
chipyard_simif_t(size_t icache_ways,
size_t icache_sets,
@@ -86,9 +98,17 @@ public:
char* readonly_uncacheable,
char* executable,
size_t icache_sourceids,
size_t dcache_sourceids);
size_t dcache_sourceids,
size_t tcm_base,
size_t tcm_size,
const char* isastr,
size_t pmpregions);
uint64_t cycle;
bool use_stq;
htif_t *htif;
bool fast_clint;
cfg_t cfg;
std::map<size_t, processor_t*> harts;
private:
bool handle_cache_access(reg_t addr, size_t len,
uint8_t* load_bytes,
@@ -133,6 +153,11 @@ private:
uint64_t mmio_stdata;
size_t mmio_len;
uint64_t mmio_lddata;
uint64_t tcm_base;
uint64_t tcm_size;
uint8_t* tcm;
std::vector<uint64_t> tcm_q;
};
class tile_t {
@@ -163,6 +188,7 @@ extern "C" void spike_tile(int hartid, char* isa,
int dcache_sets, int dcache_ways,
char* cacheable, char* uncacheable, char* readonly_uncacheable, char* executable,
int icache_sourceids, int dcache_sourceids,
long long int tcm_base, long long int tcm_size,
long long int reset_vector,
long long int ipc,
long long int cycle,
@@ -237,7 +263,18 @@ extern "C" void spike_tile(int hartid, char* isa,
int* mmio_a_size,
unsigned char mmio_d_valid,
long long int mmio_d_data
long long int mmio_d_data,
unsigned char tcm_a_valid,
long long int tcm_a_address,
long long int tcm_a_data,
int tcm_a_mask,
int tcm_a_opcode,
int tcm_a_size,
unsigned char* tcm_d_valid,
unsigned char tcm_d_ready,
long long int* tcm_d_data
)
{
if (!host) {
@@ -248,36 +285,26 @@ extern "C" void spike_tile(int hartid, char* isa,
if (tiles.find(hartid) == tiles.end()) {
printf("Constructing spike processor_t\n");
isa_parser_t *isa_parser = new isa_parser_t(isa, "MSU");
std::string* isastr = new std::string(isa);
chipyard_simif_t* simif = new chipyard_simif_t(icache_ways, icache_sets,
dcache_ways, dcache_sets,
cacheable, uncacheable, readonly_uncacheable, executable,
icache_sourceids, dcache_sourceids);
std::string* isastr = new std::string(isa);
cfg_t* cfg = new cfg_t(std::make_pair(0, 0),
nullptr,
isastr->c_str(),
"MSU",
"vlen:128,elen:64",
false,
endianness_little,
pmpregions,
std::vector<mem_cfg_t>(),
std::vector<size_t>(),
false,
0);
icache_sourceids, dcache_sourceids,
tcm_base, tcm_size,
isastr->c_str(), pmpregions);
processor_t* p = new processor_t(isa_parser,
cfg,
&simif->get_cfg(),
simif,
hartid,
false,
log_file->get(),
sout);
p->enable_log_commits();
simif->harts[hartid] = p;
s_vpi_vlog_info vinfo;
if (!vpi_get_vlog_info(&vinfo))
abort();
std::string loadmem_file = "";
for (int i = 1; i < vinfo.argc; i++) {
std::string arg(vinfo.argv[i]);
if (arg == "+spike-debug") {
@@ -286,7 +313,18 @@ extern "C" void spike_tile(int hartid, char* isa,
if (arg == "+spike-stq") {
simif->use_stq = true;
}
if (arg.find("+loadmem=") == 0) {
loadmem_file = arg.substr(strlen("+loadmem="));
}
if (arg == "+spike-fast-clint") {
simif->fast_clint = true;
}
if (arg == "+spike-verbose") {
p->enable_log_commits();
}
}
if (loadmem_file != "" && tcm_size > 0)
simif->loadmem(loadmem_file.c_str());
p->reset();
p->get_state()->pc = reset_vector;
@@ -296,6 +334,9 @@ extern "C" void spike_tile(int hartid, char* isa,
tile_t* tile = tiles[hartid];
chipyard_simif_t* simif = tile->simif;
processor_t* proc = tile->proc;
if (!simif->htif && tsi) {
simif->htif = (htif_t*) tsi;
}
simif->cycle = cycle;
if (debug) {
@@ -357,6 +398,13 @@ extern "C" void spike_tile(int hartid, char* isa,
if (mmio_d_valid) {
simif->mmio_d(mmio_d_data);
}
if (tcm_a_valid) {
simif->tcm_a(tcm_a_address, tcm_a_data, tcm_a_mask, tcm_a_opcode, tcm_a_size);
}
if (tcm_d_ready) {
*tcm_d_valid = simif->tcm_d((uint64_t*)tcm_d_data);
}
}
@@ -369,14 +417,34 @@ chipyard_simif_t::chipyard_simif_t(size_t icache_ways,
char* readonly_uncacheable,
char* executable,
size_t ic_sourceids,
size_t dc_sourceids
size_t dc_sourceids,
size_t tcm_base,
size_t tcm_size,
const char* isastr,
size_t pmpregions
) :
cycle(0),
use_stq(false),
htif(nullptr),
fast_clint(false),
cfg(std::make_pair(0, 0),
nullptr,
isastr,
"MSU",
"vlen:128,elen:64",
false,
endianness_little,
pmpregions,
std::vector<mem_cfg_t>(),
std::vector<size_t>(),
false,
0),
icache_ways(icache_ways),
icache_sets(icache_sets),
dcache_ways(dcache_ways),
dcache_sets(dcache_sets),
tcm_base(tcm_base),
tcm_size(tcm_size),
mmio_valid(false),
mmio_inflight(false)
{
@@ -432,6 +500,8 @@ chipyard_simif_t::chipyard_simif_t(size_t icache_ways,
uint64_t size_int = std::stoul(size);
executables.push_back(mem_region_t { base_int, size_int });
}
tcm = (uint8_t*)malloc(tcm_size);
}
bool chipyard_simif_t::reservable(reg_t addr) {
@@ -440,12 +510,20 @@ bool chipyard_simif_t::reservable(reg_t addr) {
return true;
}
}
if (addr >= tcm_base && addr < tcm_base + tcm_size) {
return true;
}
return false;
}
bool chipyard_simif_t::mmio_fetch(reg_t addr, size_t len, uint8_t* bytes) {
bool executable = false;
if (addr >= tcm_base && addr < tcm_base + tcm_size) {
memcpy(bytes, tcm + addr - tcm_base, len);
return true;
}
for (auto& r: executables) {
if (addr >= r.base && addr + len <= r.base + r.size) {
executable = true;
@@ -466,6 +544,10 @@ bool chipyard_simif_t::mmio_load(reg_t addr, size_t len, uint8_t* bytes) {
bool found = false;
bool cacheable = false;
bool readonly = false;
if (addr >= tcm_base && addr < tcm_base + tcm_size) {
memcpy(bytes, tcm + addr - tcm_base, len);
return true;
}
for (auto& r: cacheables) {
if (addr >= r.base && addr + len <= r.base + r.size) {
cacheable = true;
@@ -829,9 +911,14 @@ bool chipyard_simif_t::dcache_c(uint64_t* address, uint64_t* source, int* param,
}
bool chipyard_simif_t::mmio_store(reg_t addr, size_t len, const uint8_t* bytes) {
if (addr >= tcm_base && addr < tcm_base + tcm_size) {
memcpy(tcm + addr - tcm_base, bytes, len);
return true;
}
bool found = false;
bool cacheable = false;
for (auto& r: cacheables) {
for (auto& r: cacheables) {
if (addr >= r.base && addr + len <= r.base + r.size) {
cacheable = true;
found = true;
@@ -899,27 +986,108 @@ void chipyard_simif_t::dcache_d(uint64_t sourceid, uint64_t data[8], unsigned ch
}
}
void chipyard_simif_t::tcm_a(uint64_t address, uint64_t data, uint32_t mask, uint32_t opcode, uint32_t size) {
bool load = opcode == 4;
uint64_t rdata = 0;
memcpy(&rdata, tcm + address - tcm_base, 8);
tcm_q.push_back(rdata);
if (!load) {
for (size_t i = 0; i < 8; i++) {
if ((mask >> i) & 1) {
memcpy(tcm + address - tcm_base + i, ((uint8_t*)&data) + i, 1);
}
}
}
}
bool chipyard_simif_t::tcm_d(uint64_t* data) {
if (tcm_q.size() == 0)
return false;
*data = tcm_q[0];
tcm_q.erase(tcm_q.begin());
return true;
}
#define parse_nibble(c) ((c) >= 'a' ? (c)-'a'+10 : (c)-'0')
void chipyard_simif_t::loadmem(const char* fname) {
std::ifstream in(fname);
std::string line;
if (!in.is_open()) {
printf("SpikeTile couldn't open loadmem file %s\n", fname);
abort();
}
size_t fsize = 0;
size_t start = 0;
while (std::getline(in, line)) {
for (ssize_t i = line.length()-2, j = 0; i >= 0; i -= 2, j++) {
char byte = (parse_nibble(line[i]) << 4) | parse_nibble(line[i+1]);
ssize_t addr = (start + j) % tcm_size;
tcm[addr] = (uint8_t)byte;
}
start += line.length()/2;
fsize += line.length()/2;
if (fsize > tcm_size) {
fprintf(stderr, "Loadmem file is too large\n");
abort();
}
}
}
bool insn_should_fence(uint64_t bits) {
uint8_t opcode = bits & 0x7f;
return opcode == 0b0101111 || opcode == 0b0001111;
}
bool insn_is_wfi(uint64_t bits) {
return bits == 0x10500073;
}
void spike_thread_main(void* arg)
{
tile_t* tile = (tile_t*) arg;
processor_t* proc = tile->proc;
chipyard_simif_t* simif = tile->simif;
state_t* state = proc->get_state();
while (true) {
while (tile->max_insns == 0) {
host->switch_to();
}
while (tile->max_insns != 0) {
// TODO: Fences don't work
// uint64_t last_bits = tile->proc->get_last_bits();
// if (insn_should_fence(last_bits) && !tile->simif->stq_empty()) {
//uint64_t last_bits = proc->get_last_bits();
// if (insn_should_fence(last_bits) && !simif->stq_empty()) {
// host->switch_to();
// }
tile->proc->step(1);
proc->step(1);
tile->max_insns--;
tile->proc->get_state()->mcycle->write(tile->simif->cycle);
if (proc->is_waiting_for_interrupt()) {
if (simif->fast_clint) {
// uint64_t mip = state->mip->read();
// uint64_t mie = state->mie->read();
//printf("Setting MTIP %x %x %x %x %lx\n", simif->cycle, old_minstret, mip, mie,
// state->pc);
state->mip->backdoor_write_with_mask(MIP_MTIP, MIP_MTIP);
tile->max_insns = tile->max_insns <= 1 ? 0 : 1;
} else {
//printf("SpikeTile in WFI\n");
tile->max_insns = 0;
}
}
if (tile->max_insns % 100 == 0) {
uint64_t old_minstret = state->minstret->read();
uint64_t tohost_addr = simif->htif ? simif->htif->get_tohost_addr() : 0;
uint64_t fromhost_addr = simif->htif ? simif->htif->get_fromhost_addr() : 0;
auto& mem_read = state->log_mem_read;
reg_t mem_read_addr = mem_read.empty() ? 0 : std::get<0>(mem_read[0]);
if ((old_minstret == state->minstret->read()) ||
(tohost_addr && mem_read_addr == tohost_addr) ||
(fromhost_addr && mem_read_addr == fromhost_addr)) {
tile->max_insns == 0;
}
}
state->mcycle->write(simif->cycle);
}
}
}

View File

@@ -13,6 +13,8 @@ import "DPI-C" function void spike_tile(input int hartid,
input string executable,
input int icache_sourceids,
input int dcache_sourceids,
input longint tcm_base,
input longint tcm_size,
input longint reset_vector,
input longint ipc,
input longint cycle,
@@ -89,7 +91,18 @@ import "DPI-C" function void spike_tile(input int hartid,
output int mmio_a_size,
input bit mmio_d_valid,
input longint mmio_d_data
input longint mmio_d_data,
input bit tcm_a_valid,
input longint tcm_a_address,
input longint tcm_a_data,
input int tcm_a_mask,
input int tcm_a_opcode,
input int tcm_a_size,
output bit tcm_d_valid,
input bit tcm_d_ready,
output longint tcm_d_data
);
@@ -106,7 +119,9 @@ module SpikeBlackBox #(
parameter READONLY_UNCACHEABLE,
parameter EXECUTABLE,
parameter ICACHE_SOURCEIDS,
parameter DCACHE_SOURCEIDS )(
parameter DCACHE_SOURCEIDS,
parameter TCM_BASE,
parameter TCM_SIZE)(
input clock,
input reset,
input [63:0] reset_vector,
@@ -185,7 +200,18 @@ module SpikeBlackBox #(
output [31:0] mmio_a_size,
input mmio_d_valid,
input [63:0] mmio_d_data
input [63:0] mmio_d_data,
input tcm_a_valid,
input [63:0] tcm_a_address,
input [63:0] tcm_a_data,
input [31:0] tcm_a_mask,
input [31:0] tcm_a_opcode,
input [31:0] tcm_a_size,
output tcm_d_valid,
input tcm_d_ready,
output [63:0] tcm_d_data
);
longint __insns_retired;
@@ -257,7 +283,13 @@ module SpikeBlackBox #(
reg [63:0] __dcache_c_data_6_reg;
reg [63:0] __dcache_c_data_7_reg;
wire __tcm_d_ready;
bit __tcm_d_valid;
longint __tcm_d_data;
reg __tcm_d_valid_reg;
reg [63:0] __tcm_d_data_reg;
always @(posedge clock) begin
@@ -322,12 +354,18 @@ module SpikeBlackBox #(
__dcache_c_data_6_reg <= 64'h0;
__dcache_c_data_7 = 64'h0;
__dcache_c_data_7_reg <= 64'h0;
__tcm_d_valid = 1'b0;
__tcm_d_valid_reg <= 1'b0;
__tcm_d_data = 64'h0;
__tcm_d_data_reg <= 64'h0;
spike_tile_reset(HARTID);
end else begin
spike_tile(HARTID, ISA, PMPREGIONS,
ICACHE_SETS, ICACHE_WAYS, DCACHE_SETS, DCACHE_WAYS,
CACHEABLE, UNCACHEABLE, READONLY_UNCACHEABLE, EXECUTABLE,
ICACHE_SOURCEIDS, DCACHE_SOURCEIDS,
TCM_BASE, TCM_SIZE,
reset_vector, ipc, cycle, __insns_retired,
debug, mtip, msip, meip, seip,
@@ -350,7 +388,10 @@ module SpikeBlackBox #(
dcache_d_data_4, dcache_d_data_5, dcache_d_data_6, dcache_d_data_7,
__mmio_a_ready, __mmio_a_valid, __mmio_a_address, __mmio_a_data, __mmio_a_store, __mmio_a_size,
mmio_d_valid, mmio_d_data
mmio_d_valid, mmio_d_data,
tcm_a_valid, tcm_a_address, tcm_a_data, tcm_a_mask, tcm_a_opcode, tcm_a_size,
__tcm_d_valid, __tcm_d_ready, __tcm_d_data
);
__insns_retired_reg <= __insns_retired;
@@ -385,6 +426,10 @@ module SpikeBlackBox #(
__mmio_a_data_reg <= __mmio_a_data;
__mmio_a_store_reg <= __mmio_a_store;
__mmio_a_size_reg <= __mmio_a_size;
__tcm_d_valid_reg <= __tcm_d_valid;
__tcm_d_data_reg <= __tcm_d_data;
end
end // always @ (posedge clock)
assign insns_retired = __insns_retired_reg;
@@ -424,6 +469,8 @@ module SpikeBlackBox #(
assign mmio_a_size = __mmio_a_size_reg;
assign __mmio_a_ready = mmio_a_ready;
assign tcm_d_valid = __tcm_d_valid_reg;
assign tcm_d_data = __tcm_d_data_reg;
assign __tcm_d_ready = tcm_d_ready;
endmodule;

View File

@@ -51,6 +51,12 @@ case object IOBinders extends Field[Map[String, Seq[IOBinderFunction]]](
Map[String, Seq[IOBinderFunction]]().withDefaultValue(Nil)
)
case object DontTouchIOBindersPorts extends Field[Boolean](true)
class WithDontTouchIOBinders(b: Boolean = true) extends Config((site, here, up) => {
case DontTouchIOBindersPorts => b
})
abstract trait HasIOBinders { this: LazyModule =>
val lazySystem: LazyModule
private val iobinders = p(IOBinders)
@@ -67,10 +73,33 @@ abstract trait HasIOBinders { this: LazyModule =>
})
// A publicly accessible list of IO cells (useful for a floorplanning tool, for example)
lazy val iocells = (lzyFlattened.values ++ impFlattened.values).unzip._2.flatten.toBuffer
val iocells = InModuleBody { (lzyFlattened.values ++ impFlattened.values).unzip._2.flatten.toBuffer }
// A mapping between stringified DigitalSystem traits and their corresponding ChipTop ports
lazy val portMap = iobinders.keys.map(k => k -> (lzyFlattened(k)._1 ++ impFlattened(k)._1)).toMap
val portMap = InModuleBody { iobinders.keys.map(k => k -> (lzyFlattened(k)._1 ++ impFlattened(k)._1)).toMap }
// A mapping between stringified DigitalSystem traits and their corresponding ChipTop iocells
val iocellMap = InModuleBody { iobinders.keys.map(k => k -> (lzyFlattened(k)._2 ++ impFlattened(k)._2)).toMap }
InModuleBody {
if (p(DontTouchIOBindersPorts)) {
portMap.values.foreach(_.foreach(dontTouch(_)))
}
println("IOCells generated by IOBinders:")
for ((k, v) <- iocellMap) {
if (!v.isEmpty) {
val cells = v.map(_.getClass.getSimpleName).groupBy(identity).mapValues(_.size)
println(s" IOBinder for $k generated:")
for ((t, c) <- cells) { println(s" $c X $t") }
}
}
println()
val totals = iocells.map(_.getClass.getSimpleName).groupBy(identity).mapValues(_.size)
println(s" Total generated ${iocells.size} IOCells:")
for ((t, c) <- totals) { println(s" $c X $t") }
}
}
// Note: The parameters instance is accessible only through LazyModule

View File

@@ -15,8 +15,7 @@ import freechips.rocketchip.util._
import freechips.rocketchip.tile._
import freechips.rocketchip.prci.ClockSinkParameters
case class SpikeCoreParams(
) extends CoreParams {
case class SpikeCoreParams() extends CoreParams {
val useVM = true
val useHypervisor = false
val useSupervisor = true
@@ -79,7 +78,8 @@ case class SpikeTileParams(
hartId: Int = 0,
val core: SpikeCoreParams = SpikeCoreParams(),
icacheParams: ICacheParams = ICacheParams(nWays = 32),
dcacheParams: DCacheParams = DCacheParams(nWays = 32)
dcacheParams: DCacheParams = DCacheParams(nWays = 32),
tcmParams: Option[MasterPortParams] = None // tightly coupled memory
) extends InstantiableTileParams[SpikeTile]
{
val name = Some("spike_tile")
@@ -145,6 +145,27 @@ class SpikeTile(
sourceId = IdRange(0, 1),
requestFifo = true))))))
tlSlaveXbar.node :*= slaveNode
val tcmNode = spikeTileParams.tcmParams.map { tcmP =>
val device = new MemoryDevice
val base = AddressSet.misaligned(tcmP.base, tcmP.size)
val tcmNode = TLManagerNode(Seq(TLSlavePortParameters.v1(
managers = Seq(TLSlaveParameters.v1(
address = base,
resources = device.reg,
regionType = RegionType.IDEMPOTENT, // not cacheable
executable = true,
supportsGet = TransferSizes(1, 8),
supportsPutFull = TransferSizes(1, 8),
supportsPutPartial = TransferSizes(1, 8),
fifoId = Some(0)
)),
beatBytes = 8
)))
connectTLSlave(tcmNode := TLBuffer(), 8)
tcmNode
}
tlOtherMastersNode := TLBuffer() := tlMasterXbar.node
masterNode :=* tlOtherMastersNode
tlMasterXbar.node := TLWidthWidget(64) := TLBuffer():= icacheNode
@@ -166,7 +187,9 @@ class SpikeBlackBox(
cacheable_regions: String,
uncacheable_regions: String,
readonly_uncacheable_regions: String,
executable_regions: String) extends BlackBox(Map(
executable_regions: String,
tcm_base: BigInt,
tcm_size: BigInt) extends BlackBox(Map(
"HARTID" -> IntParam(hartId),
"ISA" -> StringParam(isa),
"PMPREGIONS" -> IntParam(pmpregions),
@@ -179,7 +202,9 @@ class SpikeBlackBox(
"UNCACHEABLE" -> StringParam(uncacheable_regions),
"READONLY_UNCACHEABLE" -> StringParam(readonly_uncacheable_regions),
"CACHEABLE" -> StringParam(cacheable_regions),
"EXECUTABLE" -> StringParam(executable_regions)
"EXECUTABLE" -> StringParam(executable_regions),
"TCM_BASE" -> IntParam(tcm_base),
"TCM_SIZE" -> IntParam(tcm_size)
)) with HasBlackBoxResource {
val io = IO(new Bundle {
@@ -258,6 +283,22 @@ class SpikeBlackBox(
val data = Input(UInt(64.W))
}
}
val tcm = new Bundle {
val a = new Bundle {
val valid = Input(Bool())
val address = Input(UInt(64.W))
val data = Input(UInt(64.W))
val mask = Input(UInt(32.W))
val opcode = Input(UInt(32.W))
val size = Input(UInt(32.W))
}
val d = new Bundle {
val valid = Output(Bool())
val ready = Input(Bool())
val data = Output(UInt(64.W))
}
}
})
addResource("/vsrc/spiketile.v")
addResource("/csrc/spiketile.cc")
@@ -289,7 +330,10 @@ class SpikeTileModuleImp(outer: SpikeTile) extends BaseTileModuleImp(outer) {
tileParams.icache.get.nSets, tileParams.icache.get.nWays,
tileParams.dcache.get.nSets, tileParams.dcache.get.nWays,
tileParams.dcache.get.nMSHRs,
cacheable_regions, uncacheable_regions, readonly_uncacheable_regions, executable_regions))
cacheable_regions, uncacheable_regions, readonly_uncacheable_regions, executable_regions,
outer.spikeTileParams.tcmParams.map(_.base).getOrElse(0),
outer.spikeTileParams.tcmParams.map(_.size).getOrElse(0)
))
spike.io.clock := clock.asBool
val cycle = RegInit(0.U(64.W))
cycle := cycle + 1.U
@@ -304,64 +348,63 @@ class SpikeTileModuleImp(outer: SpikeTile) extends BaseTileModuleImp(outer) {
spike.io.msip := int_bundle.msip
spike.io.meip := int_bundle.meip
spike.io.seip := int_bundle.seip.get
spike.io.ipc := PlusArg("spike-ipc", 10000, width=64)
spike.io.ipc := PlusArg("spike-ipc", width=32, default=10000)
val blockBits = log2Ceil(p(CacheBlockBytes))
val icache_a_q = Module(new Queue(new TLBundleA(icacheEdge.bundle), 1, flow=true, pipe=true))
spike.io.icache.a.ready := icache_a_q.io.enq.ready && icache_a_q.io.count === 0.U
icache_tl.a <> icache_a_q.io.deq
icache_a_q.io.enq.valid := spike.io.icache.a.valid
icache_a_q.io.enq.bits := icacheEdge.Get(
spike.io.icache.a.ready := icache_tl.a.ready
icache_tl.a.valid := spike.io.icache.a.valid
icache_tl.a.bits := icacheEdge.Get(
fromSource = spike.io.icache.a.sourceid,
toAddress = (spike.io.icache.a.address >> blockBits) << blockBits,
lgSize = blockBits.U)._2
icache_tl.d.ready := true.B
spike.io.icache.d.valid := icache_tl.d.valid
spike.io.icache.d.sourceid := icache_tl.d.bits.source
spike.io.icache.d.data := icache_tl.d.bits.data.asTypeOf(Vec(8, UInt(64.W)))
val dcache_a_q = Module(new Queue(new TLBundleA(dcacheEdge.bundle), 1, flow=true, pipe=true))
spike.io.dcache.a.ready := dcache_a_q.io.enq.ready && dcache_a_q.io.count === 0.U
dcache_tl.a <> dcache_a_q.io.deq
dcache_a_q.io.enq.valid := spike.io.dcache.a.valid
dcache_a_q.io.enq.bits := dcacheEdge.AcquireBlock(
fromSource = spike.io.dcache.a.sourceid,
toAddress = (spike.io.dcache.a.address >> blockBits) << blockBits,
lgSize = blockBits.U,
growPermissions = Mux(spike.io.dcache.a.state_old, 2.U, Mux(spike.io.dcache.a.state_new, 1.U, 0.U)))._2
spike.io.dcache.a.ready := dcache_tl.a.ready
dcache_tl.a.valid := spike.io.dcache.a.valid
if (dcacheEdge.manager.anySupportAcquireB) {
dcache_tl.a.bits := dcacheEdge.AcquireBlock(
fromSource = spike.io.dcache.a.sourceid,
toAddress = (spike.io.dcache.a.address >> blockBits) << blockBits,
lgSize = blockBits.U,
growPermissions = Mux(spike.io.dcache.a.state_old, 2.U, Mux(spike.io.dcache.a.state_new, 1.U, 0.U)))._2
} else {
dcache_tl.a.bits := DontCare
}
dcache_tl.b.ready := true.B
spike.io.dcache.b.valid := dcache_tl.b.valid
spike.io.dcache.b.address := dcache_tl.b.bits.address
spike.io.dcache.b.source := dcache_tl.b.bits.source
spike.io.dcache.b.param := dcache_tl.b.bits.param
val dcache_c_q = Module(new Queue(new TLBundleC(dcacheEdge.bundle), 1, flow=true, pipe=true))
spike.io.dcache.c.ready := dcache_c_q.io.enq.ready && dcache_c_q.io.count === 0.U
dcache_tl.c <> dcache_c_q.io.deq
dcache_c_q.io.enq.valid := spike.io.dcache.c.valid
dcache_c_q.io.enq.bits := Mux(spike.io.dcache.c.voluntary,
dcacheEdge.Release(
fromSource = spike.io.dcache.c.sourceid,
toAddress = spike.io.dcache.c.address,
lgSize = blockBits.U,
shrinkPermissions = spike.io.dcache.c.param,
data = spike.io.dcache.c.data.asUInt)._2,
Mux(spike.io.dcache.c.has_data,
dcacheEdge.ProbeAck(
spike.io.dcache.c.ready := dcache_tl.c.ready
dcache_tl.c.valid := spike.io.dcache.c.valid
if (dcacheEdge.manager.anySupportAcquireB) {
dcache_tl.c.bits := Mux(spike.io.dcache.c.voluntary,
dcacheEdge.Release(
fromSource = spike.io.dcache.c.sourceid,
toAddress = spike.io.dcache.c.address,
lgSize = blockBits.U,
reportPermissions = spike.io.dcache.c.param,
data = spike.io.dcache.c.data.asUInt),
dcacheEdge.ProbeAck(
fromSource = spike.io.dcache.c.sourceid,
toAddress = spike.io.dcache.c.address,
lgSize = blockBits.U,
reportPermissions = spike.io.dcache.c.param)
))
shrinkPermissions = spike.io.dcache.c.param,
data = spike.io.dcache.c.data.asUInt)._2,
Mux(spike.io.dcache.c.has_data,
dcacheEdge.ProbeAck(
fromSource = spike.io.dcache.c.sourceid,
toAddress = spike.io.dcache.c.address,
lgSize = blockBits.U,
reportPermissions = spike.io.dcache.c.param,
data = spike.io.dcache.c.data.asUInt),
dcacheEdge.ProbeAck(
fromSource = spike.io.dcache.c.sourceid,
toAddress = spike.io.dcache.c.address,
lgSize = blockBits.U,
reportPermissions = spike.io.dcache.c.param)
))
} else {
dcache_tl.c.bits := DontCare
}
val has_data = dcacheEdge.hasData(dcache_tl.d.bits)
val should_finish = dcacheEdge.isRequest(dcache_tl.d.bits)
@@ -376,12 +419,10 @@ class SpikeTileModuleImp(outer: SpikeTile) extends BaseTileModuleImp(outer) {
dcache_tl.e.valid := dcache_tl.d.valid && should_finish
dcache_tl.e.bits := dcacheEdge.GrantAck(dcache_tl.d.bits)
val mmio_a_q = Module(new Queue(new TLBundleA(mmioEdge.bundle), 1, flow=true, pipe=true))
spike.io.mmio.a.ready := mmio_a_q.io.enq.ready && mmio_a_q.io.count === 0.U
mmio_tl.a <> mmio_a_q.io.deq
mmio_a_q.io.enq.valid := spike.io.mmio.a.valid
spike.io.mmio.a.ready := mmio_tl.a.ready
mmio_tl.a.valid := spike.io.mmio.a.valid
val log_size = MuxCase(0.U, (0 until 3).map { i => (spike.io.mmio.a.size === (1 << i).U) -> i.U })
mmio_a_q.io.enq.bits := Mux(spike.io.mmio.a.store,
mmio_tl.a.bits := Mux(spike.io.mmio.a.store,
mmioEdge.Put(0.U, spike.io.mmio.a.address, log_size, spike.io.mmio.a.data)._2,
mmioEdge.Get(0.U, spike.io.mmio.a.address, log_size)._2)
@@ -389,9 +430,33 @@ class SpikeTileModuleImp(outer: SpikeTile) extends BaseTileModuleImp(outer) {
spike.io.mmio.d.valid := mmio_tl.d.valid
spike.io.mmio.d.data := mmio_tl.d.bits.data
spike.io.tcm := DontCare
spike.io.tcm.a.valid := false.B
spike.io.tcm.d.ready := true.B
outer.tcmNode.map { tcmNode =>
val (tcm_tl, tcmEdge) = tcmNode.in(0)
val debug_tcm_tl = WireInit(tcm_tl)
dontTouch(debug_tcm_tl)
tcm_tl.a.ready := true.B
spike.io.tcm.a.valid := tcm_tl.a.valid
spike.io.tcm.a.address := tcm_tl.a.bits.address
spike.io.tcm.a.data := tcm_tl.a.bits.data
spike.io.tcm.a.mask := tcm_tl.a.bits.mask
spike.io.tcm.a.opcode := tcm_tl.a.bits.opcode
spike.io.tcm.a.size := tcm_tl.a.bits.size
spike.io.tcm.d.ready := tcm_tl.d.ready
tcm_tl.d.bits := tcmEdge.AccessAck(RegNext(tcm_tl.a.bits))
when (RegNext(tcm_tl.a.bits.opcode === TLMessages.Get)) {
tcm_tl.d.bits.opcode := TLMessages.AccessAckData
}
tcm_tl.d.valid := spike.io.tcm.d.valid
tcm_tl.d.bits.data := spike.io.tcm.d.data
}
}
class WithNSpikeCores(n: Int = 1, overrideIdOffset: Option[Int] = None) extends Config((site, here, up) => {
class WithNSpikeCores(n: Int = 1, tileParams: SpikeTileParams = SpikeTileParams(),
overrideIdOffset: Option[Int] = None) extends Config((site, here, up) => {
case TilesLocated(InSubsystem) => {
// Calculate the next available hart ID (since hart ID cannot be duplicated)
val prev = up(TilesLocated(InSubsystem), site)
@@ -399,8 +464,21 @@ class WithNSpikeCores(n: Int = 1, overrideIdOffset: Option[Int] = None) extends
// Create TileAttachParams for every core to be instantiated
(0 until n).map { i =>
SpikeTileAttachParams(
tileParams = SpikeTileParams(hartId = i + idOffset)
tileParams = tileParams.copy(hartId = i + idOffset)
)
} ++ prev
}
})
class WithSpikeTCM extends Config((site, here, up) => {
case TilesLocated(InSubsystem) => {
val prev = up(TilesLocated(InSubsystem))
require(prev.size == 1)
val spike = prev(0).asInstanceOf[SpikeTileAttachParams]
Seq(spike.copy(tileParams = spike.tileParams.copy(
tcmParams = Some(up(ExtMem).get.master)
)))
}
case ExtMem => None
case BankedL2Key => up(BankedL2Key).copy(nBanks = 0)
})

View File

@@ -12,6 +12,7 @@ import freechips.rocketchip.prci._
import freechips.rocketchip.config.{Field, Parameters}
import freechips.rocketchip.devices.tilelink._
import freechips.rocketchip.devices.debug.{HasPeripheryDebug, HasPeripheryDebugModuleImp, ExportDebug, DebugModuleKey}
import sifive.blocks.devices.uart.{HasPeripheryUART, PeripheryUARTKey}
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.tile._
import freechips.rocketchip.tilelink._
@@ -45,9 +46,33 @@ trait CanHaveHTIF { this: BaseSubsystem =>
}
}
// This trait adds the "chosen" node to DTS, which
// can be used to pass information to OS about the earlycon
case object ChosenInDTS extends Field[Boolean](true)
trait CanHaveChosenInDTS { this: BaseSubsystem =>
if (p(ChosenInDTS)) {
this match {
case t: HasPeripheryUART if (!p(PeripheryUARTKey).isEmpty) => {
val chosen = new Device {
def describe(resources: ResourceBindings): Description = {
val stdout = resources("stdout").map(_.value)
Description("chosen", resources("uart").headOption.map { case Binding(_, value) =>
"stdout-path" -> Seq(value)
}.toMap)
}
}
ResourceBinding {
t.uarts.foreach(u => Resource(chosen, "uart").bind(ResourceAlias(u.device.label)))
}
}
}
}
}
class ChipyardSubsystem(implicit p: Parameters) extends BaseSubsystem
with HasTiles
with CanHaveHTIF
with CanHaveChosenInDTS
{
def coreMonitorBundles = tiles.map {
case r: RocketTile => r.module.core.rocketImpl.coreMonitorBundle

View File

@@ -60,4 +60,5 @@ class AbstractConfig extends Config(
new freechips.rocketchip.subsystem.WithNExtTopInterrupts(0) ++ // no external interrupts
new freechips.rocketchip.subsystem.WithDontDriveBusClocksFromSBus ++ // leave the bus clocks undriven by sbus
new freechips.rocketchip.subsystem.WithCoherentBusTopology ++ // hierarchical buses including sbus/mbus/pbus/fbus/cbus/l2
new freechips.rocketchip.subsystem.WithDTS("ucb-bar,chipyard", Nil) ++ // custom device name for DTS
new freechips.rocketchip.system.BaseConfig) // "base" rocketchip system

View File

@@ -9,6 +9,7 @@ import freechips.rocketchip.diplomacy.{AsynchronousCrossing}
// DOC include start: FFTRocketConfig
class FFTRocketConfig extends Config(
new chipyard.iobinders.WithDontTouchIOBinders(false) ++ // TODO: hack around dontTouch not working in SFC
new fftgenerator.WithFFTGenerator(numPoints=8, width=16, decPt=8) ++ // add 8-point mmio fft at the default addr (0x2400) with 16bit fixed-point numbers.
new freechips.rocketchip.subsystem.WithNBigCores(1) ++
new chipyard.config.AbstractConfig)
@@ -58,6 +59,7 @@ class LargeNVDLARocketConfig extends Config(
new chipyard.config.AbstractConfig)
class ManyMMIOAcceleratorRocketConfig extends Config(
new chipyard.iobinders.WithDontTouchIOBinders(false) ++ // TODO: hack around dontTouch not working in SFC
new fftgenerator.WithFFTGenerator(numPoints=8, width=16, decPt=8) ++ // add 8-point mmio fft at the default addr (0x2400) with 16bit fixed-point numbers.
new nvidia.blocks.dla.WithNVDLA("small") ++ // add a small NVDLA
new chipyard.example.WithStreamingPassthrough ++ // use top with tilelink-controlled streaming passthrough

View File

@@ -12,6 +12,7 @@ class RocketConfig extends Config(
new chipyard.config.AbstractConfig)
class TinyRocketConfig extends Config(
new chipyard.iobinders.WithDontTouchIOBinders(false) ++ // TODO FIX: Don't dontTouch the ports
new chipyard.config.WithTLSerialLocation(
freechips.rocketchip.subsystem.FBUS,
freechips.rocketchip.subsystem.PBUS) ++ // attach TL serial adapter to f/p busses
@@ -130,3 +131,9 @@ class MulticlockAXIOverSerialConfig extends Config(
new freechips.rocketchip.subsystem.WithNBigCores(2) ++
new chipyard.config.AbstractConfig)
// DOC include end: MulticlockAXIOverSerialConfig
class CustomIOChipTopRocketConfig extends Config(
new chipyard.example.WithCustomChipTop ++
new chipyard.example.WithCustomIOCells ++
new freechips.rocketchip.subsystem.WithNBigCores(1) ++ // single rocket-core
new chipyard.config.AbstractConfig)

View File

@@ -1,6 +1,7 @@
package chipyard
import freechips.rocketchip.config.{Config}
import freechips.rocketchip.rocket.{DCacheParams}
// Configs which instantiate a Spike-simulated
// tile that interacts with the Chipyard SoC
@@ -14,6 +15,33 @@ class SpikeConfig extends Config(
class SpikeFastUARTConfig extends Config(
new chipyard.WithNSpikeCores(1) ++
new chipyard.config.WithUARTFIFOEntries(128, 128) ++
new chipyard.config.WithMemoryBusFrequency(1) ++
new chipyard.config.WithPeripheryBusFrequency(1) ++
new chipyard.config.WithMemoryBusFrequency(2) ++
new chipyard.config.WithPeripheryBusFrequency(2) ++
new chipyard.config.AbstractConfig)
// Makes the UART fast, also builds no L2 and a ludicrous L1D
class SpikeUltraFastConfig extends Config(
new chipyard.WithSpikeTCM ++
new chipyard.WithNSpikeCores(1) ++
new testchipip.WithSerialPBusMem ++
new chipyard.config.WithUARTFIFOEntries(128, 128) ++
new chipyard.config.WithMemoryBusFrequency(2) ++
new chipyard.config.WithPeripheryBusFrequency(2) ++
new chipyard.config.WithBroadcastManager ++
new chipyard.config.AbstractConfig)
// Add the default firechip devices
class SpikeUltraFastDevicesConfig extends Config(
new chipyard.harness.WithSimBlockDevice ++
new chipyard.harness.WithLoopbackNIC ++
new icenet.WithIceNIC ++
new testchipip.WithBlockDevice ++
new chipyard.WithSpikeTCM ++
new chipyard.WithNSpikeCores(1) ++
new testchipip.WithSerialPBusMem ++
new chipyard.config.WithUARTFIFOEntries(128, 128) ++
new chipyard.config.WithMemoryBusFrequency(2) ++
new chipyard.config.WithPeripheryBusFrequency(2) ++
new chipyard.config.WithBroadcastManager ++
new chipyard.config.AbstractConfig)

View File

@@ -77,6 +77,7 @@ class TutorialSha3BlackBoxConfig extends Config(
// Tutorial Phase 5: Map a multicore heterogeneous SoC with multiple cores and memory-mapped accelerators
class TutorialNoCConfig extends Config(
new chipyard.iobinders.WithDontTouchIOBinders(false) ++
// Try changing the dimensions of the Mesh topology
new constellation.soc.WithGlobalNoC(constellation.soc.GlobalNoCParams(
NoCParams(

View File

@@ -0,0 +1,64 @@
package chipyard.example
import chisel3._
import chipyard.iobinders._
import freechips.rocketchip.config._
import freechips.rocketchip.diplomacy.{InModuleBody}
import barstools.iocell.chisel._
import chipyard._
// A "custom" IOCell with additional I/O
// The IO don't do anything here in this example
class CustomDigitalInIOCellBundle extends DigitalInIOCellBundle {
val custom_out = Output(Bool())
val custom_in = Input(Bool())
}
// Using a custom digital in iocell instead of the default one
class CustomDigitalInIOCell extends RawModule with DigitalInIOCell {
val io = IO(new CustomDigitalInIOCellBundle)
io.i := io.pad
io.custom_out := io.pad
}
case class CustomIOCellParams() extends IOCellTypeParams {
def analog() = Module(new GenericAnalogIOCell)
def gpio() = Module(new GenericDigitalGPIOCell)
def input() = Module(new CustomDigitalInIOCell)
def output() = Module(new GenericDigitalOutIOCell)
}
class CustomChipTop(implicit p: Parameters) extends ChipTop {
// making the module name ChipTop instead of CustomChipTop means
// we don't have to set the TOP make variable to CustomChipTop
override lazy val desiredName = "ChipTop"
// InModuleBody blocks are executed within the LazyModuleImp of this block
InModuleBody {
iocellMap.foreach { case (interface, cells) => {
cells.foreach { _ match {
case c: CustomDigitalInIOCell => {
c.io.custom_in := false.B
}
case c: GenericDigitalOutIOCell => {
// do nothing
}
case c => {
require(false, "Unsupported iocell type ${c.getClass}")
}
}}
}}
// demonstrate accessing the iocellMap directly
val serialTLIOCells = iocellMap("interface testchipip.CanHavePeripheryTLSerial")
}
}
class WithCustomIOCells extends Config((site, here, up) => {
case IOCellKey => CustomIOCellParams()
})
class WithCustomChipTop extends Config((site, here, up) => {
case BuildTop => (p: Parameters) => new CustomChipTop()(p)
})