diff --git a/.github/scripts/check-commit.sh b/.github/scripts/check-commit.sh index b0f16636..fe1de2bf 100755 --- a/.github/scripts/check-commit.sh +++ b/.github/scripts/check-commit.sh @@ -45,7 +45,7 @@ search () { done } -submodules=("cva6" "boom" "ibex" "hwacha" "icenet" "nvdla" "rocket-chip" "sha3" "sifive-blocks" "sifive-cache" "testchipip" "riscv-sodor" "mempress") +submodules=("cva6" "boom" "ibex" "gemmini" "hwacha" "icenet" "nvdla" "rocket-chip" "sha3" "sifive-blocks" "sifive-cache" "testchipip" "riscv-sodor" "mempress") dir="generators" branches=("master" "main" "dev") search diff --git a/.github/workflows/chipyard-run-tests.yml b/.github/workflows/chipyard-run-tests.yml index c3e77e8b..f7917e92 100644 --- a/.github/workflows/chipyard-run-tests.yml +++ b/.github/workflows/chipyard-run-tests.yml @@ -390,6 +390,35 @@ jobs: ########################################################################## + chipyard-spike-gemmini-run-tests: + name: chipyard-spike-gemmini-run-tests + needs: prepare-chipyard-accels # technically doesn't depend on RTL but should be after the build.sh for Gemmini + runs-on: ferry + steps: + - name: Delete old checkout + run: | + ls -alh . + rm -rf ${{ github.workspace }}/* || true + rm -rf ${{ github.workspace }}/.* || true + ls -alh . + - name: Checkout + uses: actions/checkout@v3 + - name: Git workaround + uses: ./.github/actions/git-workaround + - name: Create conda env + uses: ./.github/actions/create-conda-env + - name: Build Gemmini FireMarshal + run: | + conda activate ${{ env.conda-env-name-no-time }}-$(date --date "${{ env.workflow-timestamp }}" +%Y%m%d)-riscv-tools + cd ${{ github.workspace }} && ./scripts/init-submodules-no-riscv-tools.sh --force + cd ${{ github.workspace }} && source ./scripts/fix-open-files.sh + git submodule update --init software/firemarshal && cd software/firemarshal && ./init-submodules.sh + cd ${{ github.workspace }}/generators/gemmini/software && ${{ github.workspace }}/software/firemarshal/marshal -v -d build gemmini-smoke.json + - name: Running Gemmini FireMarshal smoke test + run: | + conda activate ${{ env.conda-env-name-no-time }}-$(date --date "${{ env.workflow-timestamp }}" +%Y%m%d)-riscv-tools + cd ${{ github.workspace }}/generators/gemmini/software && ${{ github.workspace }}/software/firemarshal/marshal -v -d launch -s gemmini-smoke.json + chipyard-rocket-run-tests: name: chipyard-rocket-run-tests needs: prepare-chipyard-cores diff --git a/docs/Software/Spike.rst b/docs/Software/Spike.rst index bdaa4750..79e41d6e 100644 --- a/docs/Software/Spike.rst +++ b/docs/Software/Spike.rst @@ -32,4 +32,21 @@ In this configuration, Spike is cache-coherent, and communicates with the uncore make CONFIG=SpikeConfig run-binary BINARY=hello.riscv +Spike-as-a-Tile also supports Tightly-Coupled-Memory (TCM) for the SpikeTile, in which the main system memory is entirely modeled +within the Spike tile, allowing for very fast simulatoin performance. +.. code-block:: shell + + make CONFIG=SpikeUltraFastConfig run-binary BINARY=hello.riscv + +Spike-as-a-Tile can be configured with custom IPC, commit logging, and other behaviors. Spike-specific flags can be added as plusargs to ``EXTRA_SIM_FLAGS`` + +.. code-block:: shell + + make CONFIG=SpikeUltraFastConfig run-binary-hex BINARY=hello.riscv EXTRA_SPIKE_FLAGS="+spike-ipc=10000 +spike-fast-clint +spike-debug" + + +* ``+spike-ipc=``: Sets the maximum number of instructions Spike can retire in a single "tick", or cycle of the uncore simulation. +* ``+spike-fast-clint``: Enables fast-forwarding through WFI stalls by generating fake timer interrupts +* ``+spike-debug``: Enables debug Spike logging +* ``+spike-verbose``: Enables Spike commit-log generation diff --git a/generators/boom b/generators/boom index deae9f70..051dbadb 160000 --- a/generators/boom +++ b/generators/boom @@ -1 +1 @@ -Subproject commit deae9f70469336a3787fa7fcc10135ffb93d21d9 +Subproject commit 051dbadb6d0e9018c5b1f843ac73cff4242a02f8 diff --git a/generators/chipyard/src/main/resources/csrc/spiketile.cc b/generators/chipyard/src/main/resources/csrc/spiketile.cc index 4d2bb8a5..f59e825a 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,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& 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 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 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(), - std::vector(), - 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(), + std::vector(), + 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); } } } 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/Subsystem.scala b/generators/chipyard/src/main/scala/Subsystem.scala index 34175d39..a2f81c0a 100644 --- a/generators/chipyard/src/main/scala/Subsystem.scala +++ b/generators/chipyard/src/main/scala/Subsystem.scala @@ -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 diff --git a/generators/chipyard/src/main/scala/config/AbstractConfig.scala b/generators/chipyard/src/main/scala/config/AbstractConfig.scala index b084845e..c13139bf 100644 --- a/generators/chipyard/src/main/scala/config/AbstractConfig.scala +++ b/generators/chipyard/src/main/scala/config/AbstractConfig.scala @@ -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 diff --git a/generators/chipyard/src/main/scala/config/SpikeConfigs.scala b/generators/chipyard/src/main/scala/config/SpikeConfigs.scala index b45245c0..cc6d0c90 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,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) diff --git a/generators/gemmini b/generators/gemmini index 686cb15d..4dd19f3e 160000 --- a/generators/gemmini +++ b/generators/gemmini @@ -1 +1 @@ -Subproject commit 686cb15dad756887db62460968bc616392bc4341 +Subproject commit 4dd19f3e93d2decc24048eb1776e53fb20855841 diff --git a/generators/sifive-blocks b/generators/sifive-blocks index 4273925f..3938f301 160000 --- a/generators/sifive-blocks +++ b/generators/sifive-blocks @@ -1 +1 @@ -Subproject commit 4273925fdd5d8872d6b6a8dec6cee3330b9a68c7 +Subproject commit 3938f301ce453c86e908211788017fd3a7e2765e diff --git a/software/firemarshal b/software/firemarshal index 12784a42..fb93e311 160000 --- a/software/firemarshal +++ b/software/firemarshal @@ -1 +1 @@ -Subproject commit 12784a42cb1b2188536ef5bfc123f800374d3177 +Subproject commit fb93e3116fed07191e669291b941e9eabb565ee3 diff --git a/tests/Makefile b/tests/Makefile index 54959bf0..8756350d 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -6,7 +6,8 @@ LDFLAGS= -static include libgloss.mk PROGRAMS = pwm blkdev accum charcount nic-loopback big-blkdev pingd \ - streaming-passthrough streaming-fir nvdla spiflashread spiflashwrite fft gcd + streaming-passthrough streaming-fir nvdla spiflashread spiflashwrite fft gcd \ + hello spiflash.img: spiflash.py python3 $< diff --git a/tests/hello.c b/tests/hello.c new file mode 100644 index 00000000..28d667e0 --- /dev/null +++ b/tests/hello.c @@ -0,0 +1,6 @@ +#include + +int main(void) { + printf("Hello world\n"); + return 0; +} diff --git a/toolchains/riscv-tools/riscv-isa-sim b/toolchains/riscv-tools/riscv-isa-sim index 34bebfe3..d70ea67d 160000 --- a/toolchains/riscv-tools/riscv-isa-sim +++ b/toolchains/riscv-tools/riscv-isa-sim @@ -1 +1 @@ -Subproject commit 34bebfe31183289b5428b9a363a4596750030d3f +Subproject commit d70ea67df7e85a8d92a8baa254afde67c33c43a9