From 298aadafc5383a151a2fb61d55be191699a143f3 Mon Sep 17 00:00:00 2001 From: Jerry Zhao Date: Sat, 25 Mar 2023 21:41:40 -0700 Subject: [PATCH] Add support for TightlyCoupledMemory for SpikeTile --- .../src/main/resources/csrc/spiketile.cc | 160 ++++++++++++++- .../src/main/resources/vsrc/spiketile.v | 59 +++++- .../chipyard/src/main/scala/SpikeTile.scala | 182 +++++++++++++----- .../src/main/scala/config/SpikeConfigs.scala | 17 +- 4 files changed, 351 insertions(+), 67 deletions(-) diff --git a/generators/chipyard/src/main/resources/csrc/spiketile.cc b/generators/chipyard/src/main/resources/csrc/spiketile.cc index 4d2bb8a5..9942364f 100644 --- a/generators/chipyard/src/main/resources/csrc/spiketile.cc +++ b/generators/chipyard/src/main/resources/csrc/spiketile.cc @@ -6,6 +6,9 @@ #include #include #include +#include "testchip_tsi.h" + +extern testchip_tsi_t* tsi; enum transfer_t { NToB, @@ -73,6 +76,12 @@ 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; }; @@ -86,9 +95,13 @@ 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); uint64_t cycle; bool use_stq; + htif_t *htif; + bool fast_clint; private: bool handle_cache_access(reg_t addr, size_t len, uint8_t* load_bytes, @@ -133,6 +146,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 tcm_q; }; class tile_t { @@ -163,6 +181,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 +256,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) { @@ -251,7 +281,8 @@ extern "C" void spike_tile(int hartid, char* 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); + icache_sourceids, dcache_sourceids, + tcm_base, tcm_size); std::string* isastr = new std::string(isa); cfg_t* cfg = new cfg_t(std::make_pair(0, 0), nullptr, @@ -264,7 +295,7 @@ extern "C" void spike_tile(int hartid, char* isa, std::vector(), std::vector(), false, - 0); + 0); processor_t* p = new processor_t(isa_parser, cfg, simif, @@ -278,6 +309,7 @@ extern "C" void spike_tile(int hartid, char* isa, 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 +318,15 @@ 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 (loadmem_file != "" && tcm_size > 0) + simif->loadmem(loadmem_file.c_str()); p->reset(); p->get_state()->pc = reset_vector; @@ -296,6 +336,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 +400,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 +419,20 @@ 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 ) : cycle(0), use_stq(false), + htif(nullptr), + fast_clint(false), 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 +488,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 +498,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 +532,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 +899,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,11 +974,64 @@ 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; @@ -913,12 +1041,30 @@ void spike_thread_main(void* arg) } while (tile->max_insns != 0) { // TODO: Fences don't work - // uint64_t last_bits = tile->proc->get_last_bits(); + //uint64_t last_bits = tile->proc->get_last_bits(); // if (insn_should_fence(last_bits) && !tile->simif->stq_empty()) { // host->switch_to(); // } + uint64_t old_minstret = tile->proc->get_state()->minstret->read(); tile->proc->step(1); tile->max_insns--; + if (tile->proc->is_waiting_for_interrupt()) { + if (tile->simif->fast_clint) { + tile->proc->get_state()->mip->backdoor_write_with_mask(MIP_MTIP, MIP_MTIP); + } + tile->max_insns = 0; + } + if (tile->max_insns % 100 == 0) { + uint64_t tohost_addr = tile->simif->htif ? tile->simif->htif->get_tohost_addr() : 0; + uint64_t fromhost_addr = tile->simif->htif ? tile->simif->htif->get_fromhost_addr() : 0; + auto& mem_read = tile->proc->get_state()->log_mem_read; + reg_t mem_read_addr = mem_read.empty() ? 0 : std::get<0>(mem_read[0]); + if ((old_minstret == tile->proc->get_state()->minstret->read()) || + (tohost_addr && mem_read_addr == tohost_addr) || + (fromhost_addr && mem_read_addr == fromhost_addr)) { + tile->max_insns == 0; + } + } tile->proc->get_state()->mcycle->write(tile->simif->cycle); } } diff --git a/generators/chipyard/src/main/resources/vsrc/spiketile.v b/generators/chipyard/src/main/resources/vsrc/spiketile.v index 87254e35..c78d7a0f 100644 --- a/generators/chipyard/src/main/resources/vsrc/spiketile.v +++ b/generators/chipyard/src/main/resources/vsrc/spiketile.v @@ -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; diff --git a/generators/chipyard/src/main/scala/SpikeTile.scala b/generators/chipyard/src/main/scala/SpikeTile.scala index c7e5b69d..98c750ce 100644 --- a/generators/chipyard/src/main/scala/SpikeTile.scala +++ b/generators/chipyard/src/main/scala/SpikeTile.scala @@ -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) +}) diff --git a/generators/chipyard/src/main/scala/config/SpikeConfigs.scala b/generators/chipyard/src/main/scala/config/SpikeConfigs.scala index b45245c0..0d9972a9 100644 --- a/generators/chipyard/src/main/scala/config/SpikeConfigs.scala +++ b/generators/chipyard/src/main/scala/config/SpikeConfigs.scala @@ -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,18 @@ 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) +