diff --git a/.github/scripts/ci_repo_lock.sh b/.github/scripts/ci_repo_lock.sh index 78443d932..32805b5f0 100755 --- a/.github/scripts/ci_repo_lock.sh +++ b/.github/scripts/ci_repo_lock.sh @@ -23,19 +23,22 @@ exec 9>"${LOCK_FILE}" repo_reset() { cd "${repo}" + + # buckyball repository it self never depend on submodules in submodules unless llvm in buddy-mlir git fetch --force --prune origin "${want_sha}" - git checkout --detach "${want_sha}" + git checkout --detach --force "${want_sha}" git reset --hard "${want_sha}" git clean -ffd - # rm -rf arch/out + + rm -rf arch/out rm -rf compiler/thirdparty/buddy-mlir/llvm/build rm -rf compiler/thirdparty/buddy-mlir/build + git submodule sync git submodule update --init --force - for submodule in bbdev bebop compiler/thirdparty/buddy-mlir; do - git -C "${repo}/${submodule}" reset --hard - git -C "${repo}/${submodule}" clean -ffd - done + git -C compiler/thirdparty/buddy-mlir submodule sync + git -C compiler/thirdparty/buddy-mlir submodule update --init --force -- llvm + git submodule foreach 'git clean -ffd' have_sha="$(git rev-parse HEAD)" if [[ "${have_sha}" != "${want_sha}" ]]; then echo "ERROR: checkout is ${have_sha}, expected ${want_sha}" >&2 diff --git a/.github/workflows/check.yaml b/.github/workflows/check.yaml index c4a2d06ef..fc38b0386 100644 --- a/.github/workflows/check.yaml +++ b/.github/workflows/check.yaml @@ -43,9 +43,19 @@ jobs: set -euo pipefail root=~/Code/buckyball source "${root}/.github/scripts/setproxy.sh" - bash "${root}/.github/scripts/ci_repo_lock.sh" \ + cd "${root}" + + # fetch first to ensure if we modify ci_repo_lock.sh, we still use the old version to checkout. + git fetch --force --prune origin "${CHECKOUT_SHA}" + git show "${CHECKOUT_SHA}:.github/scripts/ci_repo_lock.sh" | bash -s -- \ prepare "${CHECKOUT_SHA}" "${root}" "${CHECKOUT_REF}" + nix build + cd "${root}/bbdev" + nix develop -c true + cd "${root}/bebop" + nix develop -c true + - name: Check pre-commit shell: zsh {0} run: | @@ -111,7 +121,9 @@ jobs: set -euo pipefail root="${BB_ROOT/#\~/$HOME}" source "${root}/.github/scripts/setproxy.sh" - bash "${root}/.github/scripts/ci_repo_lock.sh" \ + cd "${root}" + git fetch --force --prune origin "${CHECKOUT_SHA}" + git show "${CHECKOUT_SHA}:.github/scripts/ci_repo_lock.sh" | bash -s -- \ enter "${CHECKOUT_SHA}" "${root}" "${CHECKOUT_REF}" - name: Nix build @@ -158,9 +170,9 @@ jobs: root="${BB_ROOT/#\~/$HOME}" cd "${root}" nix develop -c bbdev bebop-verilator --clean '--chip ${{ matrix.chip }}' - nix develop -c bbdev bebop-verilator --verilog '--chip ${{ matrix.chip }}' - nix develop -c bbdev bebop-verilator --build '--jobs 16 --chip ${{ matrix.chip }}' - nix develop -c bbdev bebop-verilator --batch '--chip ${{ matrix.chip }} --test elf-tests --clean-before' + nix develop -c bbdev bebop-verilator --verilog '--chip ${{ matrix.chip }} --diff' + nix develop -c bbdev bebop-verilator --build '--jobs 16 --chip ${{ matrix.chip }} --diff' + nix develop -c bbdev bebop-verilator --batch '--chip ${{ matrix.chip }} --test elf-tests --diff --clean-before' - name: rushB batch if: matrix.enable_rushb && matrix.run_bemu_elf_tests && matrix.run_bemu_pk_tests && matrix.run_verilator_batch_tests diff --git a/.github/workflows/regression.yml b/.github/workflows/regression.yml index cc5c709b4..a630d7735 100644 --- a/.github/workflows/regression.yml +++ b/.github/workflows/regression.yml @@ -44,8 +44,15 @@ jobs: set -euo pipefail root="${BB_ROOT/#\~/$HOME}" source "${root}/.github/scripts/setproxy.sh" - bash "${root}/.github/scripts/ci_repo_lock.sh" \ + cd "${root}" + git fetch --force --prune origin "${CHECKOUT_SHA}" + git show "${CHECKOUT_SHA}:.github/scripts/ci_repo_lock.sh" | bash -s -- \ prepare "${CHECKOUT_SHA}" "${root}" "${CHECKOUT_REF}" + nix build + cd "${root}/bbdev" + nix develop -c true + cd "${root}/bebop" + nix develop -c true - name: Install config shell: zsh {0} @@ -89,7 +96,9 @@ jobs: set -euo pipefail root="${BB_ROOT/#\~/$HOME}" source "${root}/.github/scripts/setproxy.sh" - bash "${root}/.github/scripts/ci_repo_lock.sh" \ + cd "${root}" + git fetch --force --prune origin "${CHECKOUT_SHA}" + git show "${CHECKOUT_SHA}:.github/scripts/ci_repo_lock.sh" | bash -s -- \ enter "${CHECKOUT_SHA}" "${root}" "${CHECKOUT_REF}" - name: DC area @@ -155,7 +164,9 @@ jobs: set -euo pipefail root="${BB_ROOT/#\~/$HOME}" source "${root}/.github/scripts/setproxy.sh" - bash "${root}/.github/scripts/ci_repo_lock.sh" \ + cd "${root}" + git fetch --force --prune origin "${CHECKOUT_SHA}" + git show "${CHECKOUT_SHA}:.github/scripts/ci_repo_lock.sh" | bash -s -- \ enter "${CHECKOUT_SHA}" "${root}" "${CHECKOUT_REF}" - name: Chip UVM @@ -183,6 +194,7 @@ jobs: name: fpga-bitstream-${{ matrix.chip }} needs: gate runs-on: check + timeout-minutes: 720 strategy: fail-fast: false matrix: @@ -207,7 +219,9 @@ jobs: set -euo pipefail root="${BB_ROOT/#\~/$HOME}" source "${root}/.github/scripts/setproxy.sh" - bash "${root}/.github/scripts/ci_repo_lock.sh" \ + cd "${root}" + git fetch --force --prune origin "${CHECKOUT_SHA}" + git show "${CHECKOUT_SHA}:.github/scripts/ci_repo_lock.sh" | bash -s -- \ enter "${CHECKOUT_SHA}" "${root}" "${CHECKOUT_REF}" - name: FPGA buildbitstream @@ -217,9 +231,11 @@ jobs: set -euo pipefail root="${BB_ROOT/#\~/$HOME}" cd "${root}" - rm -rf "${root}"/bebop/build/"${{ matrix.chip }}"-*/ - nix develop -c bbdev bebop-p2e --verilog '--chip ${{ matrix.chip }}' - nix develop -c bbdev bebop-p2e --buildbitstream '--chip ${{ matrix.chip }}' + for build_dir in "${root}"/bebop/build/"${{ matrix.chip }}"-*(N); do + rm -rf "${build_dir}" + done + nix develop -c bbdev bebop-p2e --verilog '--chip ${{ matrix.chip }} --diff' + nix develop -c bbdev bebop-p2e --buildbitstream '--chip ${{ matrix.chip }} --diff' bits=("${root}"/bebop/build/"${{ matrix.chip }}"-*/fpgaCompDir/bitstream.bit(N)) if (( ${#bits} != 1 )); then echo "ERROR: expected exactly 1 bitstream.bit for ${{ matrix.chip }}, got ${#bits}" >&2 @@ -246,30 +262,37 @@ jobs: matrix: include: - chip: toy - run_fpga_check: true + run_fpga_elf: true + run_fpga_pk: true - chip: pebble - run_fpga_check: true + run_fpga_elf: true + run_fpga_pk: true - chip: goban - run_fpga_check: true + run_fpga_elf: true + run_fpga_pk: false - chip: poly - run_fpga_check: true + run_fpga_elf: true + run_fpga_pk: false - chip: multi-rocket - run_fpga_check: true + run_fpga_elf: true + run_fpga_pk: false env: BB_ROOT: ~/Code/buckyball steps: - name: Enter repo lock - if: matrix.run_fpga_check + if: matrix.run_fpga_elf || matrix.run_fpga_pk shell: zsh {0} run: | set -euo pipefail root="${BB_ROOT/#\~/$HOME}" source "${root}/.github/scripts/setproxy.sh" - bash "${root}/.github/scripts/ci_repo_lock.sh" \ + cd "${root}" + git fetch --force --prune origin "${CHECKOUT_SHA}" + git show "${CHECKOUT_SHA}:.github/scripts/ci_repo_lock.sh" | bash -s -- \ enter "${CHECKOUT_SHA}" "${root}" "${CHECKOUT_REF}" - name: FPGA check - if: matrix.run_fpga_check + if: matrix.run_fpga_elf || matrix.run_fpga_pk shell: zsh {0} run: | set -euo pipefail @@ -281,13 +304,21 @@ jobs: printf '%s\n' "${bits[@]}" >&2 exit 1 fi - nix develop -c bbdev workload --build "--chip ${{ matrix.chip }}" - nix develop -c bbdev workload --tohex "--chip ${{ matrix.chip }}" - nix develop -c bbdev bebop-p2e --batch "--chip ${{ matrix.chip }} --bitstream ${bits[1]} --test elf-tests" - nix develop -c bbdev bebop-p2e --batch "--chip ${{ matrix.chip }} --bitstream ${bits[1]} --test pk-tests" + + if [[ "${{ matrix.run_fpga_elf }}" == "true" ]]; then + nix develop -c bbdev compiler --build "--chip ${{ matrix.chip }}" + nix develop -c bbdev workload --build "--chip ${{ matrix.chip }}" + nix develop -c bbdev workload --tohex "--chip ${{ matrix.chip }}" + nix develop -c bbdev bebop-p2e --batch "--chip ${{ matrix.chip }} --bitstream ${bits[1]} --test elf-tests --diff" + fi + + if [[ "${{ matrix.run_fpga_pk }}" == "true" ]]; then + nix develop -c bbdev kernel --build "--chip ${{ matrix.chip }}" + nix develop -c bbdev bebop-p2e --batch "--chip ${{ matrix.chip }} --bitstream ${bits[1]} --test pk-tests --diff" + fi - name: Exit repo lock - if: always() && matrix.run_fpga_check + if: always() && (matrix.run_fpga_elf || matrix.run_fpga_pk) shell: zsh {0} run: | set -euo pipefail @@ -307,10 +338,10 @@ jobs: model: lenet - chip: pebble model: mobilenet - - chip: pebble - model: resnet - - chip: pebble - model: yolo + # - chip: pebble + # model: resnet + # - chip: pebble + # model: yolo env: BB_ROOT: ~/Code/buckyball steps: @@ -320,7 +351,9 @@ jobs: set -euo pipefail root="${BB_ROOT/#\~/$HOME}" source "${root}/.github/scripts/setproxy.sh" - bash "${root}/.github/scripts/ci_repo_lock.sh" \ + cd "${root}" + git fetch --force --prune origin "${CHECKOUT_SHA}" + git show "${CHECKOUT_SHA}:.github/scripts/ci_repo_lock.sh" | bash -s -- \ enter "${CHECKOUT_SHA}" "${root}" "${CHECKOUT_REF}" - name: Model build @@ -333,6 +366,7 @@ jobs: echo "ERROR: eval-performance requires a real model, got model=none" >&2 exit 1 fi + nix develop -c bbdev compiler --build "--chip ${{ matrix.chip }}" nix develop -c bbdev workload --build "--chip ${{ matrix.chip }} --model ${{ matrix.model }}" nix develop -c bbdev kernel --build "--chip ${{ matrix.chip }} --model ${{ matrix.model }}" diff --git a/arch/build.sc b/arch/build.sc index 897103115..4f01ca4bb 100644 --- a/arch/build.sc +++ b/arch/build.sc @@ -11,12 +11,13 @@ object protoJava extends JavaModule { os.pwd / os.up / "bbdev" / "api" / "steps" / "config" / "scripts" / "proto" } + def protoSources = T.sources { + Seq(PathRef(protoDir() / "chip.proto")) + } + def generatedSources = T { val dir = protoDir() - val proto = dir / "chip.proto" - if (!os.exists(proto)) { - throw new Exception(s"missing chip.proto: $proto") - } + val proto = protoSources().head.path os.proc("protoc", s"-I$dir", s"--java_out=${T.dest}", proto).call() Seq(PathRef(T.dest)) } @@ -53,14 +54,9 @@ object bank extends FrameworkModule { override def moduleDeps = Seq(axis) } -object cache extends FrameworkModule { - override def moduleRoot = frameworkRoot / "mem-core" / "cache" - override def moduleDeps = Seq(chi) -} - object coherence extends FrameworkModule { override def moduleRoot = frameworkRoot / "mem-core" / "coherence" - override def moduleDeps = Seq(chi, cache) + override def moduleDeps = Seq(chi) } object rvv extends FrameworkModule { @@ -75,7 +71,7 @@ object seed extends FrameworkModule { object root_chip extends FrameworkModule { override def moduleRoot = frameworkRoot / "root" / "root-chip" - override def moduleDeps = Seq(axis, chi, bank, coherence, cache) + override def moduleDeps = Seq(axis, chi, bank, coherence) } object root_core extends FrameworkModule { @@ -109,7 +105,6 @@ object buckyball extends SbtModule { m => chi, bank, coherence, - cache, rvv, seed, root_chip, diff --git a/arch/src/csrc/include/monitor/trace.h b/arch/src/csrc/include/monitor/trace.h index 055b6ab14..dab0b5f1c 100644 --- a/arch/src/csrc/include/monitor/trace.h +++ b/arch/src/csrc/include/monitor/trace.h @@ -13,10 +13,13 @@ void dpi_bdb_set_clk(unsigned long long c); // DPI-C function for instruction trace (itrace) // Called from GlobalROB when instructions are allocated/issued/completed -void dpi_itrace(unsigned char is_issue, // 2 = alloc, 1 = issue, 0 = complete - unsigned int rob_id, unsigned int domain_id, unsigned int funct, - unsigned long long pc, unsigned long long rs1, - unsigned long long rs2, unsigned char bank_enable); +void dpi_itrace(unsigned int is_issue, // 2 = alloc, 1 = issue, 0 = complete + unsigned int hart_id_lo, unsigned int hart_id_hi, + unsigned int rob_id, unsigned int inst_id_lo, + unsigned int inst_id_hi, unsigned int domain_id, + unsigned int funct, unsigned int pc_lo, unsigned int pc_hi, + unsigned int rs1_lo, unsigned int rs1_hi, unsigned int rs2_lo, + unsigned int rs2_hi); // DPI-C function for memory trace (mtrace) // Called from MemBackend when read/write requests are made diff --git a/arch/src/csrc/src/monitor/trace/itrace.cc b/arch/src/csrc/src/monitor/trace/itrace.cc index 4262d322c..34f78a3b3 100644 --- a/arch/src/csrc/src/monitor/trace/itrace.cc +++ b/arch/src/csrc/src/monitor/trace/itrace.cc @@ -18,26 +18,6 @@ static void init_itrace() { } } -// bank_enable encoding (funct7[6:4]): -// 000 = none, 001 = 1rd, 010 = 1wr, 011 = 1rd+1wr, 100 = 2rd+1wr -// 101/110/111 = none (extended opcode space) -static const char *bank_enable_str(unsigned char enable) { - switch (enable) { - case 0: - return "---"; - case 1: - return "R--"; - case 2: - return "--W"; - case 3: - return "R-W"; - case 4: - return "RRW"; - default: - return "---"; // 5,6,7 = no bank access (extended) - } -} - static void u64_hex(char *buf, size_t n, unsigned long long v) { int ret = snprintf(buf, n, "0x%016llx", v); if (ret < 0 || (size_t)ret >= n) { @@ -48,16 +28,25 @@ static void u64_hex(char *buf, size_t n, unsigned long long v) { // DPI-C function for instruction trace (itrace) // Called when an instruction is allocated/issued/completed in GlobalROB extern "C" void -dpi_itrace(unsigned char is_issue, // 2 = alloc, 1 = issue, 0 = complete - unsigned int rob_id, unsigned int domain_id, unsigned int funct, - unsigned long long pc, unsigned long long rs1, - unsigned long long rs2, unsigned char bank_enable) { +dpi_itrace(unsigned int is_issue, // 2 = alloc, 1 = issue, 0 = complete + unsigned int hart_id_lo, unsigned int hart_id_hi, + unsigned int rob_id, unsigned int inst_id_lo, + unsigned int inst_id_hi, unsigned int domain_id, unsigned int funct, + unsigned int pc_lo, unsigned int pc_hi, unsigned int rs1_lo, + unsigned int rs1_hi, unsigned int rs2_lo, unsigned int rs2_hi) { if (!bdb_trace_on(BDB_TR_ITRACE)) { return; } init_itrace(); if (itrace_fp) { + unsigned long long hart_id = + ((unsigned long long)hart_id_hi << 32) | hart_id_lo; + unsigned long long inst_id = + ((unsigned long long)inst_id_hi << 32) | inst_id_lo; + unsigned long long pc = ((unsigned long long)pc_hi << 32) | pc_lo; + unsigned long long rs1 = ((unsigned long long)rs1_hi << 32) | rs1_lo; + unsigned long long rs2 = ((unsigned long long)rs2_hi << 32) | rs2_lo; char pc_hex[19]; char rs1_hex[19]; char rs2_hex[19]; @@ -65,29 +54,31 @@ dpi_itrace(unsigned char is_issue, // 2 = alloc, 1 = issue, 0 = complete u64_hex(rs1_hex, sizeof(rs1_hex), rs1); u64_hex(rs2_hex, sizeof(rs2_hex), rs2); if (is_issue == 2) { - fprintf( - itrace_fp, - "{\"type\":\"itrace\",\"clk\":%llu,\"event\":\"alloc\",\"rob_id\":%u," - "\"domain_id\":%u,\"funct\":\"0x%02x\",\"bank_enable\":%u," - "\"bank\":\"%s\",\"pc\":\"%s\",\"rs1\":\"%s\",\"rs2\":\"%s\"}\n", - (unsigned long long)bdb_rtl_clk, rob_id, domain_id, funct, - bank_enable, bank_enable_str(bank_enable), pc_hex, rs1_hex, rs2_hex); + fprintf(itrace_fp, + "{\"type\":\"itrace\",\"clk\":%llu,\"event\":\"alloc\",\"hart_" + "id\":%llu," + "\"rob_id\":%u,\"inst_id\":%llu,\"domain_id\":%u,\"funct\":\"0x%" + "02x\"," + "\"pc\":\"%s\",\"rs1\":\"%s\",\"rs2\":\"%s\"}\n", + (unsigned long long)bdb_rtl_clk, hart_id, rob_id, inst_id, + domain_id, funct, pc_hex, rs1_hex, rs2_hex); } else if (is_issue == 1) { + fprintf(itrace_fp, + "{\"type\":\"itrace\",\"clk\":%llu,\"event\":\"issue\",\"hart_" + "id\":%llu," + "\"rob_id\":%u,\"inst_id\":%llu,\"domain_id\":%u,\"funct\":\"0x%" + "02x\"," + "\"pc\":\"%s\",\"rs1\":\"%s\",\"rs2\":\"%s\"}\n", + (unsigned long long)bdb_rtl_clk, hart_id, rob_id, inst_id, + domain_id, funct, pc_hex, rs1_hex, rs2_hex); + } else { fprintf( itrace_fp, - "{\"type\":\"itrace\",\"clk\":%llu,\"event\":\"issue\",\"rob_id\":%u," - "\"domain_id\":%u,\"funct\":\"0x%02x\",\"bank_enable\":%u," - "\"bank\":\"%s\",\"pc\":\"%s\",\"rs1\":\"%s\",\"rs2\":\"%s\"}\n", - (unsigned long long)bdb_rtl_clk, rob_id, domain_id, funct, - bank_enable, bank_enable_str(bank_enable), pc_hex, rs1_hex, rs2_hex); - } else { - fprintf(itrace_fp, - "{\"type\":\"itrace\",\"clk\":%llu,\"event\":\"complete\",\"rob_" - "id\":%u," - "\"domain_id\":%u,\"funct\":\"0x%02x\",\"bank_enable\":%u," - "\"bank\":\"%s\",\"pc\":\"%s\"}\n", - (unsigned long long)bdb_rtl_clk, rob_id, domain_id, funct, - bank_enable, bank_enable_str(bank_enable), pc_hex); + "{\"type\":\"itrace\",\"clk\":%llu,\"event\":\"complete\"," + "\"hart_id\":%llu,\"rob_id\":%u,\"inst_id\":%llu,\"domain_id\":%u," + "\"funct\":\"0x%02x\",\"pc\":\"%s\"}\n", + (unsigned long long)bdb_rtl_clk, hart_id, rob_id, inst_id, domain_id, + funct, pc_hex); } fflush(itrace_fp); } diff --git a/arch/src/csrc/src/monitor/trace/mtrace.cc b/arch/src/csrc/src/monitor/trace/mtrace.cc index 2c4058817..319d3bb5d 100644 --- a/arch/src/csrc/src/monitor/trace/mtrace.cc +++ b/arch/src/csrc/src/monitor/trace/mtrace.cc @@ -63,28 +63,3 @@ extern "C" void dpi_mtrace(unsigned char is_write, // 1 = write, 0 = read fflush(mtrace_fp); } } - -// DPI-C function for memory trace issue (mtrace_issue) -// Called when MemMidend issues memory operations -extern "C" void dpi_mtrace_issue(unsigned int hart_id_lo, - unsigned int hart_id_hi, - unsigned char is_shared, unsigned int rob_id, - unsigned int vbank_id, unsigned int group_id) { - if (!bdb_trace_on(BDB_TR_MTRACE)) { - return; - } - init_mtrace(); - - unsigned long long hart_id = - ((unsigned long long)hart_id_hi << 32) | hart_id_lo; - - if (mtrace_fp) { - fprintf(mtrace_fp, - "{\"type\":\"mtrace_issue\",\"clk\":%llu,\"event\":\"issue\"," - "\"hart_id\":%llu,\"is_shared\":%u,\"rob_id\":%u,\"vbank_id\":%u," - "\"group_id\":%u}\n", - (unsigned long long)bdb_rtl_clk, hart_id, is_shared, rob_id, - vbank_id, group_id); - fflush(mtrace_fp); - } -} diff --git a/arch/src/main/scala/framework/balldomain/blink/bank.scala b/arch/src/main/scala/framework/balldomain/blink/bank.scala index 65f1dd551..8bfedeafc 100644 --- a/arch/src/main/scala/framework/balldomain/blink/bank.scala +++ b/arch/src/main/scala/framework/balldomain/blink/bank.scala @@ -23,7 +23,7 @@ trait HasBallId { trait HasAccGroupId { val b: GlobalConfig - val group_id = Input(UInt(log2Up(b.memDomain.bankNum).W)) + val group_id = Input(UInt(b.memDomain.groupIdWidth.W)) } class BankRead(val b: GlobalConfig) extends Bundle with HasBankId with HasRobId with HasBallId with HasAccGroupId { diff --git a/arch/src/main/scala/framework/balldomain/decoder/BallDecodeCmd.scala b/arch/src/main/scala/framework/balldomain/decoder/BallDecodeCmd.scala index 6519643b8..e34e6f580 100644 --- a/arch/src/main/scala/framework/balldomain/decoder/BallDecodeCmd.scala +++ b/arch/src/main/scala/framework/balldomain/decoder/BallDecodeCmd.scala @@ -8,7 +8,7 @@ import chisel3.util._ * and framework infrastructure (BallReservationStation, BBus). The * concrete decode logic (funct7 → BID/operands) lives in user code. */ -class BallDecodeCmd(numBanks: Int, iterLen: Int) extends Bundle { +class BallDecodeCmd(numBanks: Int, iterLen: Int, groupCountWidth: Int) extends Bundle { val bid = UInt(5.W) val funct7 = UInt(7.W) val iter = UInt(iterLen.W) @@ -23,9 +23,9 @@ class BallDecodeCmd(numBanks: Int, iterLen: Int) extends Bundle { val op1_bank = UInt(log2Up(numBanks).W) val op2_bank = UInt(log2Up(numBanks).W) val wr_bank = UInt(log2Up(numBanks).W) - val op1_col = UInt(5.W) - val op2_col = UInt(5.W) - val wr_col = UInt(5.W) + val op1_col = UInt(groupCountWidth.W) + val op2_col = UInt(groupCountWidth.W) + val wr_col = UInt(groupCountWidth.W) // MMIO metadata bank: which main bank's MMIO region to access val meta_bank = UInt(log2Up(numBanks).W) diff --git a/arch/src/main/scala/framework/balldomain/decoder/BallDomainDecoder.scala b/arch/src/main/scala/framework/balldomain/decoder/BallDomainDecoder.scala index e195bd7c2..ca6db292d 100644 --- a/arch/src/main/scala/framework/balldomain/decoder/BallDomainDecoder.scala +++ b/arch/src/main/scala/framework/balldomain/decoder/BallDomainDecoder.scala @@ -22,9 +22,11 @@ class BallDomainDecoder(val b: GlobalConfig) extends Module { val iterLen = b.frontend.iter_len @public - val cmd_i = IO(Flipped(Decoupled(new PostGDCmd(b)))) + val cmd_i = IO(Flipped(Decoupled(new PostGDCmd(b)))) + @public - val ball_decode_cmd_o = IO(Decoupled(new BallDecodeCmd(b.memDomain.virtualBankCount, iterLen))) + val ball_decode_cmd_o = + IO(Decoupled(new BallDecodeCmd(b.memDomain.virtualBankCount, iterLen, b.memDomain.groupCountWidth))) cmd_i.ready := ball_decode_cmd_o.ready diff --git a/arch/src/main/scala/framework/balldomain/rs/reservationStation.scala b/arch/src/main/scala/framework/balldomain/rs/reservationStation.scala index e8fbf5abe..5557170bc 100644 --- a/arch/src/main/scala/framework/balldomain/rs/reservationStation.scala +++ b/arch/src/main/scala/framework/balldomain/rs/reservationStation.scala @@ -8,7 +8,7 @@ import framework.balldomain.decoder.BallDecodeCmd // Ball domain issue interface - includes global rob_id class BallRsIssue(b: GlobalConfig) extends Bundle { - val cmd = new BallDecodeCmd(b.memDomain.virtualBankCount, b.frontend.iter_len) + val cmd = new BallDecodeCmd(b.memDomain.virtualBankCount, b.frontend.iter_len, b.memDomain.groupCountWidth) // Global ROB ID val rob_id = UInt(log2Up(b.frontend.rob_entries).W) val is_sub = Bool() @@ -38,7 +38,7 @@ class BallReservationStation(val b: GlobalConfig) extends Module { @public val ball_decode_cmd_i = IO(Flipped(new DecoupledIO(new Bundle { - val cmd = new BallDecodeCmd(b.memDomain.virtualBankCount, b.frontend.iter_len) + val cmd = new BallDecodeCmd(b.memDomain.virtualBankCount, b.frontend.iter_len, b.memDomain.groupCountWidth) // Global ROB ID val rob_id = UInt(log2Up(b.frontend.rob_entries).W) val is_sub = Bool() @@ -59,7 +59,7 @@ class BallReservationStation(val b: GlobalConfig) extends Module { // Simple FIFO queue, only for buffering val fifo = Module(new Queue( new Bundle { - val cmd = new BallDecodeCmd(b.memDomain.virtualBankCount, b.frontend.iter_len) + val cmd = new BallDecodeCmd(b.memDomain.virtualBankCount, b.frontend.iter_len, b.memDomain.groupCountWidth) val rob_id = UInt(log2Up(b.frontend.rob_entries).W) val is_sub = Bool() val sub_rob_id = UInt(log2Up(b.frontend.sub_rob_depth * 4).W) @@ -131,4 +131,5 @@ class BallReservationStation(val b: GlobalConfig) extends Module { complete_o.valid := completeArb.io.out.valid complete_o.bits := completeArb.io.out.bits completeArb.io.out.ready := complete_o.ready + } diff --git a/arch/src/main/scala/framework/dpi/DpiGuard.scala b/arch/src/main/scala/framework/dpi/DpiGuard.scala index 1df92506f..f85a18c32 100644 --- a/arch/src/main/scala/framework/dpi/DpiGuard.scala +++ b/arch/src/main/scala/framework/dpi/DpiGuard.scala @@ -19,6 +19,9 @@ object DpiGuard { def wrapMTrace(body: String): String = wrapTraceKind("BUCKYBALL_DISABLE_MTRACE_DPI", body) + def wrapBTrace(body: String): String = + wrapTraceKind("BUCKYBALL_DISABLE_BTRACE_DPI", body) + def wrapPMCTrace(body: String): String = wrapTraceKind("BUCKYBALL_DISABLE_PMCTRACE_DPI", body) } diff --git a/arch/src/main/scala/framework/frontend/Frontend.scala b/arch/src/main/scala/framework/frontend/Frontend.scala index 2d669abbf..2a9156a43 100644 --- a/arch/src/main/scala/framework/frontend/Frontend.scala +++ b/arch/src/main/scala/framework/frontend/Frontend.scala @@ -9,6 +9,8 @@ import framework.frontend.globalrs.{GlobalSchedComplete, GlobalSchedIssue, Globa import framework.top.GlobalConfig import framework.system.core.rocket.{RoCCCommandBB, RoCCResponseBB} import framework.balldomain.blink.SubRobRow +import framework.memdomain.backend.banks.btrace.PhysicalBankHash +import framework.memdomain.backend.shared.SharedMemLayout /** * Frontend Module @@ -17,12 +19,15 @@ import framework.balldomain.blink.SubRobRow @instantiable class Frontend(val b: GlobalConfig) extends Module { + val sharedHashCount = if (b.memDomain.sharedEnable) SharedMemLayout.totalBank(b) else 0 + @public val io = IO(new Bundle { + val hartid = Input(UInt(b.tile.xLen.W)) // RoCC command input val cmd = Flipped(Decoupled(new Bundle { - val cmd = new RoCCCommandBB(b.core.xLen) + val cmd = new RoCCCommandBB(b.tile.xLen) })) // Issue to domains @@ -36,9 +41,17 @@ class Frontend(val b: GlobalConfig) extends Module { // Ball -> SubROB request passthrough val ball_subrob_req_i = Flipped(Vec(b.ballDomain.ballNum, Decoupled(new SubRobRow(b)))) + val inst_ids = Output(Vec(b.frontend.rob_entries, UInt(64.W))) + + val bank_hashes = + if (b.sim.diffTest) { + Some(Input(Vec(b.memDomain.bankNum + sharedHashCount, new PhysicalBankHash(b)))) + } else { + None + } // RoCC response - val resp = Decoupled(new RoCCResponseBB(b.core.xLen)) + val resp = Decoupled(new RoCCResponseBB(b.tile.xLen)) val busy = Output(Bool()) // Propagates the Global ROB retirement pulse to the host bridge. val retired = Output(Bool()) @@ -62,10 +75,13 @@ class Frontend(val b: GlobalConfig) extends Module { io.cmd.ready := !boot.io.active && gDecoder.io.id_i.ready scheduler.io.decode_cmd_i <> gDecoder.io.id_o + scheduler.io.hart_id := io.hartid + scheduler.io.bank_hashes.foreach(_ := io.bank_hashes.get) io.ball_issue_o <> scheduler.io.ball_issue_o io.mem_issue_o <> scheduler.io.mem_issue_o io.gp_issue_o <> scheduler.io.gp_issue_o + io.inst_ids := scheduler.io.inst_ids scheduler.io.ball_complete_i <> io.ball_complete_i scheduler.io.mem_complete_i <> io.mem_complete_i diff --git a/arch/src/main/scala/framework/frontend/boot/Boot.scala b/arch/src/main/scala/framework/frontend/boot/Boot.scala index 695f67861..a40aab6a4 100644 --- a/arch/src/main/scala/framework/frontend/boot/Boot.scala +++ b/arch/src/main/scala/framework/frontend/boot/Boot.scala @@ -15,7 +15,7 @@ class BootRom(val b: GlobalConfig) extends Module { val io = IO(new Bundle { val cmd = Decoupled(new Bundle { - val cmd = new RoCCCommandBB(b.core.xLen) + val cmd = new RoCCCommandBB(b.tile.xLen) }) val schedulerIdle = Input(Bool()) @@ -31,8 +31,8 @@ class BootRom(val b: GlobalConfig) extends Module { Seq.empty[BuckyballCommand] private val bootFuncts = VecInit(bootRecords.map(r => r.funct.U(7.W))) - private val bootRs1Data = VecInit(bootRecords.map(r => r.rs1.U(b.core.xLen.W))) - private val bootRs2Data = VecInit(bootRecords.map(r => r.rs2.U(b.core.xLen.W))) + val bootRs1Data = VecInit(bootRecords.map(r => r.rs1.U(b.tile.xLen.W))) + val bootRs2Data = VecInit(bootRecords.map(r => r.rs2.U(b.tile.xLen.W))) private val bootPcWidth = math.max(1, log2Ceil(bootRecords.length + 1)) private val active = RegInit(true.B) @@ -42,8 +42,8 @@ class BootRom(val b: GlobalConfig) extends Module { private val atEnd = pc === bootRecords.length.U(bootPcWidth.W) - private val current = Wire(new RoCCCommandBB(b.core.xLen)) - current := 0.U.asTypeOf(new RoCCCommandBB(b.core.xLen)) + val current = Wire(new RoCCCommandBB(b.tile.xLen)) + current := 0.U.asTypeOf(new RoCCCommandBB(b.tile.xLen)) current.funct := Mux(atEnd, 0.U, bootFuncts(pc)) current.funct3 := BuckyballCommand.Custom3Funct3.U current.opcode := BuckyballCommand.Custom3Opcode.U diff --git a/arch/src/main/scala/framework/frontend/decoder/GobalDecoder.scala b/arch/src/main/scala/framework/frontend/decoder/GobalDecoder.scala index 854e12f60..7bf9a41fb 100644 --- a/arch/src/main/scala/framework/frontend/decoder/GobalDecoder.scala +++ b/arch/src/main/scala/framework/frontend/decoder/GobalDecoder.scala @@ -16,17 +16,17 @@ import framework.frontend.scoreboard.BankAccessInfo import framework.system.core.rocket.RoCCCommandBB class BuckyballRawCmd(val b: GlobalConfig) extends Bundle { - val cmd = new RoCCCommandBB(b.core.xLen) + val cmd = new RoCCCommandBB(b.tile.xLen) } class PostGDCmd(val b: GlobalConfig) extends Bundle { val domain_id = UInt(4.W) val ball_bid = UInt(5.W) - val cmd = new RoCCCommandBB(b.core.xLen) + val cmd = new RoCCCommandBB(b.tile.xLen) val bankAccess = new BankAccessInfo(b.frontend.bank_id_len) - val op1_col = UInt(log2Up(b.memDomain.bankNum + 1).W) - val op2_col = UInt(log2Up(b.memDomain.bankNum + 1).W) - val wr_col = UInt(log2Up(b.memDomain.bankNum + 1).W) + val op1_col = UInt(b.memDomain.groupCountWidth.W) + val op2_col = UInt(b.memDomain.groupCountWidth.W) + val wr_col = UInt(b.memDomain.groupCountWidth.W) val isFence = Bool() val isBarrier = Bool() } @@ -40,7 +40,7 @@ class GlobalDecoder(val b: GlobalConfig) extends Module { val io = IO(new Bundle { val id_i = Flipped(Decoupled(new Bundle { - val cmd = new RoCCCommandBB(b.core.xLen) + val cmd = new RoCCCommandBB(b.tile.xLen) })) val id_o = Decoupled(new PostGDCmd(b)) @@ -86,7 +86,7 @@ class GlobalDecoder(val b: GlobalConfig) extends Module { // Bank access info extraction — enable flags from funct7[6:4] // // Unified rs1 layout (defined in isa.h): - // rs1[9:0] = bank_0 (rd_bank_0 or wr_bank for MVIN/MSET) + // rs1[9:0] = bank_0 (rd_bank_0 or MSET config bank) // rs1[19:10] = bank_1 (rd_bank_1, dual-operand only) // rs1[29:20] = bank_2 (wr_bank for Ball instructions) // rs1[63:30] = iter (34-bit) @@ -105,7 +105,7 @@ class GlobalDecoder(val b: GlobalConfig) extends Module { // Decode enable from funct7[6:4] val hasRd0 = enableBits === 1.U || enableBits === 3.U || enableBits === 4.U val hasRd1 = enableBits === 4.U - val hasWr = enableBits === 2.U || enableBits === 3.U || enableBits === 4.U + val hasWr = (enableBits === 2.U || enableBits === 3.U || enableBits === 4.U) && func7 =/= MVIN_MMIO_BITPAT val ballBid = WireDefault(0.U(5.W)) b.ballDomain.ballISA.foreach { entry => @@ -119,9 +119,7 @@ class GlobalDecoder(val b: GlobalConfig) extends Module { bankAccess.rd_bank_1_valid := hasRd1 bankAccess.rd_bank_1_id := rs1(bankIdLen + 9, 10) bankAccess.wr_bank_valid := hasWr - // For Mem instructions (MVIN/MSET), wr_bank is bank_0 (rs1[9:0]) - // For Ball instructions, wr_bank is bank_2 (rs1[29:20]) - bankAccess.wr_bank_id := Mux(is_mem_inst, rs1(bankIdLen - 1, 0), rs1(bankIdLen + 19, 20)) + bankAccess.wr_bank_id := Mux(func7 === MSET_BITPAT, rs1(bankIdLen - 1, 0), rs1(bankIdLen + 19, 20)) private def legalBank(raw: UInt): Bool = raw <= b.frontend.vbank_id_upper_bound.U || diff --git a/arch/src/main/scala/framework/frontend/globalrs/GlobalROB.scala b/arch/src/main/scala/framework/frontend/globalrs/GlobalROB.scala index 656e1511f..67907f48a 100644 --- a/arch/src/main/scala/framework/frontend/globalrs/GlobalROB.scala +++ b/arch/src/main/scala/framework/frontend/globalrs/GlobalROB.scala @@ -8,13 +8,17 @@ import framework.top.GlobalConfig import framework.frontend.decoder.{DomainId, PostGDCmd} import framework.frontend.scoreboard.{BankAccessInfo, BankAliasTable, BankScoreboard} import framework.memdomain.frontend.cmd.decoder.DISA.MSET_BITPAT +import framework.memdomain.backend.shared.SharedMemLayout +import framework.memdomain.backend.banks.btrace.{BTraceDPI, PhysicalBankHash} @instantiable class GlobalROB(val b: GlobalConfig) extends Module { - val robDepth = b.frontend.rob_entries - val idWidth = log2Up(robDepth) - val scoreBankNum = b.memDomain.virtualBankCount + robDepth + val robDepth = b.frontend.rob_entries + val idWidth = log2Up(robDepth) + val scoreBankNum = b.memDomain.virtualBankCount + robDepth + val sharedHashCount = if (b.memDomain.sharedEnable) SharedMemLayout.totalBank(b) else 0 + val physicalBankCount = b.memDomain.bankNum + sharedHashCount require( b.frontend.vbank_id_upper_bound < b.memDomain.virtualBankCount, @@ -23,6 +27,7 @@ class GlobalROB(val b: GlobalConfig) extends Module { @public val io = IO(new Bundle { + val hart_id = Input(UInt(b.tile.xLen.W)) val alloc = Flipped(new DecoupledIO(new PostGDCmd(b))) val issue = new DecoupledIO(new GlobalRobEntry(b)) val complete = Flipped(new DecoupledIO(UInt(idWidth.W))) @@ -35,6 +40,15 @@ class GlobalROB(val b: GlobalConfig) extends Module { val entry_complete = Output(Vec(robDepth, Bool())) val subRobActive = Input(Bool()) + val inst_ids = Output(Vec(robDepth, UInt(64.W))) + + val bank_hashes = + if (b.sim.diffTest) { + Some(Input(Vec(physicalBankCount, new PhysicalBankHash(b)))) + } else { + None + } + }) // --------------------------------------------------------------------------- @@ -59,19 +73,18 @@ class GlobalROB(val b: GlobalConfig) extends Module { val itraceComp = Module(new ITraceDPI) for (t <- Seq(itraceAlloc, itraceIssue, itraceComp)) { - t.io.clock := clock - t.io.reset := reset.asBool - t.io.is_issue := 0.U - t.io.rob_id := 0.U - t.io.domain_id := 0.U - t.io.funct := 0.U - t.io.pc := 0.U - t.io.rs1_idx := 0.U - t.io.rs2_idx := 0.U - t.io.rs1_data := 0.U - t.io.rs2_data := 0.U - t.io.bank_enable := 0.U - t.io.enable := false.B + t.io.clock := clock + t.io.reset := reset.asBool + t.io.is_issue := 0.U + t.io.hart_id := io.hart_id + t.io.rob_id := 0.U + t.io.inst_id := 0.U + t.io.domain_id := 0.U + t.io.funct := 0.U + t.io.pc := 0.U + t.io.rs1_data := 0.U + t.io.rs2_data := 0.U + t.io.enable := false.B } // --------------------------------------------------------------------------- @@ -81,11 +94,23 @@ class GlobalROB(val b: GlobalConfig) extends Module { val robValid = RegInit(VecInit(Seq.fill(robDepth)(false.B))) val robIssued = RegInit(VecInit(Seq.fill(robDepth)(false.B))) val robComplete = RegInit(VecInit(Seq.fill(robDepth)(false.B))) + val instIds = RegInit(VecInit(Seq.fill(robDepth)(0.U(64.W)))) + val nextInstId = RegInit(1.U(64.W)) + + val statusHashes = + if (b.sim.diffTest) { + Some(RegInit(VecInit(Seq.fill(robDepth)(VecInit(Seq.fill(3)(0.U(32.W))))))) + } else { + None + } + + io.inst_ids := instIds val headPtr = RegInit(0.U(idWidth.W)) val tailPtr = RegInit(0.U(idWidth.W)) val issuedCount = RegInit(0.U(log2Up(robDepth + 1).W)) - val bankCols = RegInit(VecInit(Seq.fill(b.memDomain.virtualBankCount)(0.U(log2Up(b.memDomain.bankNum + 1).W)))) + private val bankColWidth = b.memDomain.groupCountWidth + val bankCols = RegInit(VecInit(Seq.fill(b.memDomain.virtualBankCount)(0.U(bankColWidth.W)))) // In-flight ownership is tracked in the architectural vbank namespace. private val vbankMaskWidth = b.memDomain.virtualBankCount val vbankBusy = RegInit(0.U(vbankMaskWidth.W)) @@ -158,7 +183,7 @@ class GlobalROB(val b: GlobalConfig) extends Module { for (i <- 0 until robDepth) { val ptr = robIdx(wrapPtr(headPtr + i.U)) commitScan(i) := commitKeep(i) && robValid(ptr) && robComplete(ptr) - commitKeep(i + 1) := commitScan(i) + commitKeep(i + 1) := (if (b.sim.diffTest) false.B else commitScan(i)) } val hasCommit = commitScan.asUInt.orR val tailAlias = Wire(UInt(b.frontend.bank_id_len.W)) @@ -205,8 +230,8 @@ class GlobalROB(val b: GlobalConfig) extends Module { val olderUseMask = entryRawReads(older) | entryRawWrites(older) val rawConflict = ((allocReadMask & entryRawWrites(older)) | (allocWriteMask & olderUseMask)).orR - val configConflict = (allocIsConfig || entryIsConfig(older)) && - ((allocReadMask | allocWriteMask) & olderUseMask).orR + val configConflict = (allocIsConfig && entryIsConfig(older)) || + ((allocIsConfig || entryIsConfig(older)) && ((allocReadMask | allocWriteMask) & olderUseMask).orR) val sameBall = allocIsBall && robEntries(older).cmd.domain_id === DomainId.BALL && robEntries(older).cmd.ball_bid === io.alloc.bits.ball_bid @@ -217,33 +242,110 @@ class GlobalROB(val b: GlobalConfig) extends Module { (robValid(older) && configConflict) } val allocDependencies = allocDependencyBits.asUInt + val allocUsesInstId = io.alloc.bits.cmd.pc =/= 0.U when(io.alloc.fire) { - itraceAlloc.io.is_issue := 2.U - itraceAlloc.io.rob_id := tailPtr - itraceAlloc.io.domain_id := io.alloc.bits.domain_id - itraceAlloc.io.funct := io.alloc.bits.cmd.funct - itraceAlloc.io.pc := io.alloc.bits.cmd.pc - itraceAlloc.io.rs1_idx := io.alloc.bits.cmd.rs1 - itraceAlloc.io.rs2_idx := io.alloc.bits.cmd.rs2 - itraceAlloc.io.rs1_data := io.alloc.bits.cmd.rs1Data - itraceAlloc.io.rs2_data := io.alloc.bits.cmd.rs2Data - itraceAlloc.io.bank_enable := io.alloc.bits.cmd.funct(6, 4) - itraceAlloc.io.enable := true.B + itraceAlloc.io.is_issue := 2.U + itraceAlloc.io.rob_id := tailPtr + itraceAlloc.io.inst_id := Mux(allocUsesInstId, nextInstId, 0.U) + itraceAlloc.io.domain_id := io.alloc.bits.domain_id + itraceAlloc.io.funct := io.alloc.bits.cmd.funct + itraceAlloc.io.pc := io.alloc.bits.cmd.pc + itraceAlloc.io.rs1_data := io.alloc.bits.cmd.rs1Data + itraceAlloc.io.rs2_data := io.alloc.bits.cmd.rs2Data + itraceAlloc.io.enable := true.B robEntries(tailPtr).cmd := io.alloc.bits robEntries(tailPtr).renamedBankAccess := bat.io.alloc_renamed robEntries(tailPtr).rob_id := tailPtr + instIds(tailPtr) := Mux(allocUsesInstId, nextInstId, 0.U) robValid(tailPtr) := true.B robIssued(tailPtr) := false.B robComplete(tailPtr) := false.B + statusHashes.foreach { hashes => + for (slot <- 0 until 3) { + hashes(tailPtr)(slot) := 0.U + } + } tailPtr := nextPtr(tailPtr) + when(allocUsesInstId) { + nextInstId := nextInstId + 1.U + } } // --------------------------------------------------------------------------- // Complete: mark entry as completed, release scoreboard resources // --------------------------------------------------------------------------- - io.complete.ready := true.B + if (b.sim.diffTest) { + val collecting = RegInit(false.B) + val collectCid = Reg(UInt(idWidth.W)) + val collectSlot = Reg(UInt(2.W)) + val collectGroup = Reg(UInt(32.W)) + val currentHash = Reg(UInt(32.W)) + val hashReady = RegInit(false.B) + val hashCid = Reg(UInt(idWidth.W)) + + val incomingAccess = robEntries(io.complete.bits).cmd.bankAccess + val incomingNeedsHash = instIds(io.complete.bits) =/= 0.U && !isMappingConfig(robEntries(io.complete.bits)) && + (incomingAccess.rd_bank_0_valid || incomingAccess.rd_bank_1_valid || incomingAccess.wr_bank_valid) + io.complete.ready := !incomingNeedsHash || (hashReady && hashCid === io.complete.bits) + + when(!collecting && !hashReady && io.complete.valid && incomingNeedsHash) { + collecting := true.B + collectCid := io.complete.bits + collectSlot := Mux(incomingAccess.rd_bank_0_valid, 0.U, Mux(incomingAccess.rd_bank_1_valid, 1.U, 2.U)) + collectGroup := 0.U + currentHash := 0.U + } + + val access = robEntries(collectCid).cmd.bankAccess + val vbank = MuxLookup(collectSlot, access.wr_bank_id)(Seq( + 0.U -> access.rd_bank_0_id, + 1.U -> access.rd_bank_1_id, + 2.U -> access.wr_bank_id + )) + val hasNextSlot = MuxLookup(collectSlot, false.B)(Seq( + 0.U -> (access.rd_bank_1_valid || access.wr_bank_valid), + 1.U -> access.wr_bank_valid + )) + val nextSlot = Mux(collectSlot === 0.U && access.rd_bank_1_valid, 1.U, 2.U) + val matches = VecInit(io.bank_hashes.get.map { state => + state.valid && state.hartId === io.hart_id && state.vbankId === vbank && state.groupId === collectGroup + }) + val nextMatches = VecInit(io.bank_hashes.get.map { state => + state.valid && state.hartId === io.hart_id && state.vbankId === vbank && state.groupId === collectGroup + 1.U + }) + val physical = Mux1H(matches, io.bank_hashes.get) + def rotateLeft(value: UInt, amount: Int): UInt = Cat(value(31 - amount, 0), value(31, 32 - amount)) + + val mixed = physical.statusHash ^ rotateLeft(physical.groupId, 7) ^ "h9e3779b9".U + val nextHash = rotateLeft(currentHash, 5) ^ mixed ^ rotateLeft(mixed, 13) + + when(collecting) { + assert(PopCount(matches) === 1.U, "BTrace requires exactly one physical bank per vbank group") + when(nextMatches.asUInt.orR) { + currentHash := nextHash + collectGroup := collectGroup + 1.U + }.otherwise { + statusHashes.get(collectCid)(collectSlot) := nextHash + when(hasNextSlot) { + collectSlot := nextSlot + collectGroup := 0.U + currentHash := 0.U + }.otherwise { + collecting := false.B + hashReady := true.B + hashCid := collectCid + } + } + } + + when(io.complete.fire) { + hashReady := false.B + } + } else { + io.complete.ready := true.B + } scoreboard.complete.valid := false.B scoreboard.complete.bits := 0.U.asTypeOf(scoreboard.complete.bits) @@ -257,17 +359,15 @@ class GlobalROB(val b: GlobalConfig) extends Module { scoreboard.complete.valid := true.B scoreboard.complete.bits := robEntries(cid).renamedBankAccess - itraceComp.io.is_issue := 0.U - itraceComp.io.rob_id := cid - itraceComp.io.domain_id := robEntries(cid).cmd.domain_id - itraceComp.io.funct := robEntries(cid).cmd.cmd.funct - itraceComp.io.pc := robEntries(cid).cmd.cmd.pc - itraceComp.io.rs1_idx := robEntries(cid).cmd.cmd.rs1 - itraceComp.io.rs2_idx := robEntries(cid).cmd.cmd.rs2 - itraceComp.io.rs1_data := robEntries(cid).cmd.cmd.rs1Data - itraceComp.io.rs2_data := robEntries(cid).cmd.cmd.rs2Data - itraceComp.io.bank_enable := robEntries(cid).cmd.cmd.funct(6, 4) - itraceComp.io.enable := true.B + itraceComp.io.is_issue := 0.U + itraceComp.io.rob_id := cid + itraceComp.io.inst_id := instIds(cid) + itraceComp.io.domain_id := robEntries(cid).cmd.domain_id + itraceComp.io.funct := robEntries(cid).cmd.cmd.funct + itraceComp.io.pc := robEntries(cid).cmd.cmd.pc + itraceComp.io.rs1_data := robEntries(cid).cmd.cmd.rs1Data + itraceComp.io.rs2_data := robEntries(cid).cmd.cmd.rs2Data + itraceComp.io.enable := true.B } val completedBitMask = Mux( @@ -364,17 +464,15 @@ class GlobalROB(val b: GlobalConfig) extends Module { scoreboard.issue.valid := true.B scoreboard.issue.bits := robEntries(actualIssuePtr).renamedBankAccess - itraceIssue.io.is_issue := 1.U - itraceIssue.io.rob_id := robEntries(actualIssuePtr).rob_id - itraceIssue.io.domain_id := robEntries(actualIssuePtr).cmd.domain_id - itraceIssue.io.funct := robEntries(actualIssuePtr).cmd.cmd.funct - itraceIssue.io.pc := robEntries(actualIssuePtr).cmd.cmd.pc - itraceIssue.io.rs1_idx := robEntries(actualIssuePtr).cmd.cmd.rs1 - itraceIssue.io.rs2_idx := robEntries(actualIssuePtr).cmd.cmd.rs2 - itraceIssue.io.rs1_data := robEntries(actualIssuePtr).cmd.cmd.rs1Data - itraceIssue.io.rs2_data := robEntries(actualIssuePtr).cmd.cmd.rs2Data - itraceIssue.io.bank_enable := robEntries(actualIssuePtr).cmd.cmd.funct(6, 4) - itraceIssue.io.enable := true.B + itraceIssue.io.is_issue := 1.U + itraceIssue.io.rob_id := robEntries(actualIssuePtr).rob_id + itraceIssue.io.inst_id := instIds(actualIssuePtr) + itraceIssue.io.domain_id := robEntries(actualIssuePtr).cmd.domain_id + itraceIssue.io.funct := robEntries(actualIssuePtr).cmd.cmd.funct + itraceIssue.io.pc := robEntries(actualIssuePtr).cmd.cmd.pc + itraceIssue.io.rs1_data := robEntries(actualIssuePtr).cmd.cmd.rs1Data + itraceIssue.io.rs2_data := robEntries(actualIssuePtr).cmd.cmd.rs2Data + itraceIssue.io.enable := true.B } // Preserve the original update ordering when issue and complete coincide: @@ -401,10 +499,21 @@ class GlobalROB(val b: GlobalConfig) extends Module { commitMask(i) := hits.reduce(_ || _) when(commitMask(i)) { when(robEntries(i).cmd.domain_id === DomainId.MEM && robEntries(i).cmd.cmd.funct === MSET_BITPAT) { - val bank = robEntries(i).cmd.bankAccess.wr_bank_id(b.memDomain.vbankIdWidth - 1, 0) - val col = robEntries(i).cmd.cmd.rs2Data(9, 5) + val bankId = robEntries(i).cmd.bankAccess.wr_bank_id + val bank = bankId(b.memDomain.vbankIdWidth - 1, 0) + val col = robEntries(i).cmd.cmd.rs2Data(9, 5) when(robEntries(i).cmd.cmd.rs2Data(10)) { - bankCols(bank) := Mux(col === 0.U, b.memDomain.bankNum.U, col) + val fullCol = + if (b.memDomain.sharedEnable) { + Mux( + bankId >= b.frontend.shared_bank_id_base.U && bankId < b.memDomain.virtualBankCount.U, + SharedMemLayout.totalBank(b).U(bankColWidth.W), + b.memDomain.bankNum.U(bankColWidth.W) + ) + } else { + b.memDomain.bankNum.U(bankColWidth.W) + } + bankCols(bank) := Mux(col === 0.U, fullCol, col) }.otherwise { bankCols(bank) := 0.U } @@ -415,6 +524,25 @@ class GlobalROB(val b: GlobalConfig) extends Module { } } + if (b.sim.diffTest) { + val commitIndex = PriorityEncoder(commitMask.asUInt) + val commitAccess = robEntries(commitIndex).cmd.bankAccess + val invalidVbank = "hffffffff".U(32.W) + val btrace = Module(new BTraceDPI) + btrace.io.clock := clock + btrace.io.reset := reset.asBool + btrace.io.instId := instIds(commitIndex) + btrace.io.hartId := io.hart_id + btrace.io.r0Vbank := Mux(commitAccess.rd_bank_0_valid, commitAccess.rd_bank_0_id, invalidVbank) + btrace.io.r0Hash := Mux(commitAccess.rd_bank_0_valid, statusHashes.get(commitIndex)(0), 0.U) + btrace.io.r1Vbank := Mux(commitAccess.rd_bank_1_valid, commitAccess.rd_bank_1_id, invalidVbank) + btrace.io.r1Hash := Mux(commitAccess.rd_bank_1_valid, statusHashes.get(commitIndex)(1), 0.U) + btrace.io.w0Vbank := Mux(commitAccess.wr_bank_valid, commitAccess.wr_bank_id, invalidVbank) + btrace.io.w0Hash := Mux(commitAccess.wr_bank_valid, statusHashes.get(commitIndex)(2), 0.U) + btrace.io.fire := hasCommit && instIds(commitIndex) =/= 0.U && !isMappingConfig(robEntries(commitIndex)) && + (commitAccess.rd_bank_0_valid || commitAccess.rd_bank_1_valid || commitAccess.wr_bank_valid) + } + // Maintain dependency masks at the same architectural events that gate the // issue scan. A dependency involving a config entry (on either side) clears // only at commit; all other dependencies clear at complete. This is the @@ -446,4 +574,5 @@ class GlobalROB(val b: GlobalConfig) extends Module { io.issued_count := issuedCount io.entry_valid := robValid io.entry_complete := robComplete + } diff --git a/arch/src/main/scala/framework/frontend/globalrs/GlobalScheduler.scala b/arch/src/main/scala/framework/frontend/globalrs/GlobalScheduler.scala index b30a377f3..43bfab495 100644 --- a/arch/src/main/scala/framework/frontend/globalrs/GlobalScheduler.scala +++ b/arch/src/main/scala/framework/frontend/globalrs/GlobalScheduler.scala @@ -10,6 +10,8 @@ import framework.frontend.decoder.GISA._ import framework.frontend.scoreboard.BankAccessInfo import framework.system.core.rocket.RoCCResponseBB import framework.balldomain.blink.SubRobRow +import framework.memdomain.backend.banks.btrace.PhysicalBankHash +import framework.memdomain.backend.shared.SharedMemLayout class GlobalRobEntry(val b: GlobalConfig) extends Bundle { val cmd = new PostGDCmd(b) @@ -31,8 +33,11 @@ class GlobalSchedComplete(b: GlobalConfig) extends Bundle { @instantiable class GlobalScheduler(val b: GlobalConfig) extends Module { + val sharedHashCount = if (b.memDomain.sharedEnable) SharedMemLayout.totalBank(b) else 0 + @public val io = IO(new Bundle { + val hart_id = Input(UInt(b.tile.xLen.W)) val decode_cmd_i = Flipped(new DecoupledIO(new PostGDCmd(b))) val ball_issue_o = Decoupled(new GlobalSchedIssue(b)) val mem_issue_o = Decoupled(new GlobalSchedIssue(b)) @@ -41,9 +46,17 @@ class GlobalScheduler(val b: GlobalConfig) extends Module { val mem_complete_i = Flipped(Decoupled(new GlobalSchedComplete(b))) val gp_complete_i = Flipped(Decoupled(new GlobalSchedComplete(b))) val ball_subrob_req_i = Flipped(Vec(b.ballDomain.ballNum, Decoupled(new SubRobRow(b)))) + val inst_ids = Output(Vec(b.frontend.rob_entries, UInt(64.W))) + + val bank_hashes = + if (b.sim.diffTest) { + Some(Input(Vec(b.memDomain.bankNum + sharedHashCount, new PhysicalBankHash(b)))) + } else { + None + } val scheduler_rocc_o = new Bundle { - val resp = new DecoupledIO(new RoCCResponseBB(b.core.xLen)) + val resp = new DecoupledIO(new RoCCResponseBB(b.tile.xLen)) val busy = Output(Bool()) } @@ -56,6 +69,9 @@ class GlobalScheduler(val b: GlobalConfig) extends Module { }) val rob: Instance[GlobalROB] = Instantiate(new GlobalROB(b)) + rob.io.hart_id := io.hart_id + rob.io.bank_hashes.foreach(_ := io.bank_hashes.get) + io.inst_ids := rob.io.inst_ids val isFenceCmd = io.decode_cmd_i.valid && io.decode_cmd_i.bits.isFence val fenceActive = RegInit(false.B) @@ -102,7 +118,9 @@ class GlobalScheduler(val b: GlobalConfig) extends Module { mainIssueEntry.is_sub := false.B mainIssueEntry.sub_rob_id := 0.U - val completeArb = Module(new Arbiter(new GlobalSchedComplete(b), 3)) + val completeArb = Module(new Arbiter(new GlobalSchedComplete(b), 3)) + val completeQueue = Module(new Queue(UInt(log2Up(b.frontend.rob_entries).W), b.frontend.rob_entries)) + rob.io.complete <> completeQueue.io.deq completeArb.io.in(0).valid := io.ball_complete_i.valid completeArb.io.in(0).bits := io.ball_complete_i.bits io.ball_complete_i.ready := completeArb.io.in(0).ready @@ -171,29 +189,22 @@ class GlobalScheduler(val b: GlobalConfig) extends Module { ) rob.io.subRobActive := subRobIssueValid - subRob.io.subComplete.valid := completeArb.io.out.valid && completeBits.is_sub - subRob.io.subComplete.bits := completeBits.sub_rob_id - subRob.io.masterComplete.ready := true.B + subRob.io.subComplete.valid := completeArb.io.out.valid && completeBits.is_sub + subRob.io.subComplete.bits := completeBits.sub_rob_id val normalComplete = completeArb.io.out.valid && !completeBits.is_sub - if (b.frontend.rs_out_of_order_response) { - rob.io.complete.valid := normalComplete || subRob.io.masterComplete.valid - rob.io.complete.bits := Mux(subRob.io.masterComplete.valid, subRob.io.masterComplete.bits, completeBits.rob_id) - } else { - val isHeadComplete = Mux( - subRob.io.masterComplete.valid, - subRob.io.masterComplete.bits === rob.io.head_ptr, - completeBits.rob_id === rob.io.head_ptr - ) - rob.io.complete.valid := (normalComplete || subRob.io.masterComplete.valid) && isHeadComplete - rob.io.complete.bits := Mux(subRob.io.masterComplete.valid, subRob.io.masterComplete.bits, completeBits.rob_id) - } - completeArb.io.out.ready := Mux( + val masterComplete = subRob.io.masterComplete.valid + val completeRobId = Mux(masterComplete, subRob.io.masterComplete.bits, completeBits.rob_id) + + completeQueue.io.enq.valid := masterComplete || normalComplete + completeQueue.io.enq.bits := completeRobId + subRob.io.masterComplete.ready := masterComplete && completeQueue.io.enq.ready + completeArb.io.out.ready := Mux( completeBits.is_sub, subRob.io.subComplete.ready, - rob.io.complete.ready + !masterComplete && completeQueue.io.enq.ready ) - io.idle := rob.io.empty && !fenceActive && !barrierWaitROB && !barrierWaitRelease && !subRob.io.occupied + io.idle := rob.io.empty && !fenceActive && !barrierWaitROB && !barrierWaitRelease && !subRob.io.occupied } else { for (i <- 0 until b.ballDomain.ballNum) { io.ball_subrob_req_i(i).ready := false.B @@ -214,14 +225,10 @@ class GlobalScheduler(val b: GlobalConfig) extends Module { when(completeArb.io.out.valid) { assert(!completeBits.is_sub, "SubROB completion observed when frontend.sub_rob_enable=false") } - if (b.frontend.rs_out_of_order_response) { - rob.io.complete.valid := completeArb.io.out.valid - } else { - rob.io.complete.valid := completeArb.io.out.valid && completeBits.rob_id === rob.io.head_ptr - } - rob.io.complete.bits := completeBits.rob_id - completeArb.io.out.ready := rob.io.complete.ready - io.idle := rob.io.empty && !fenceActive && !barrierWaitROB && !barrierWaitRelease + completeQueue.io.enq.valid := completeArb.io.out.valid + completeQueue.io.enq.bits := completeBits.rob_id + completeArb.io.out.ready := completeQueue.io.enq.ready + io.idle := rob.io.empty && !fenceActive && !barrierWaitROB && !barrierWaitRelease } io.scheduler_rocc_o.resp.valid := false.B @@ -229,4 +236,5 @@ class GlobalScheduler(val b: GlobalConfig) extends Module { io.scheduler_rocc_o.resp.bits.data := 0.U io.scheduler_rocc_o.busy := rob.io.full || fenceActive || barrierWaitROB || barrierWaitRelease io.retired := rob.io.complete.fire && rob.io.entry_valid(rob.io.complete.bits) + } diff --git a/arch/src/main/scala/framework/frontend/globalrs/ITraceDPI.scala b/arch/src/main/scala/framework/frontend/globalrs/ITraceDPI.scala index fec614ce6..08126e6c6 100644 --- a/arch/src/main/scala/framework/frontend/globalrs/ITraceDPI.scala +++ b/arch/src/main/scala/framework/frontend/globalrs/ITraceDPI.scala @@ -7,19 +7,18 @@ import framework.dpi.DpiGuard class ITraceDPI extends BlackBox with HasBlackBoxInline { val io = IO(new Bundle { - val clock = Input(Clock()) - val reset = Input(Bool()) - val is_issue = Input(UInt(8.W)) - val rob_id = Input(UInt(32.W)) - val domain_id = Input(UInt(32.W)) - val funct = Input(UInt(32.W)) - val pc = Input(UInt(64.W)) - val rs1_idx = Input(UInt(64.W)) - val rs2_idx = Input(UInt(64.W)) - val rs1_data = Input(UInt(64.W)) - val rs2_data = Input(UInt(64.W)) - val bank_enable = Input(UInt(8.W)) - val enable = Input(Bool()) + val clock = Input(Clock()) + val reset = Input(Bool()) + val is_issue = Input(UInt(8.W)) + val hart_id = Input(UInt(64.W)) + val rob_id = Input(UInt(32.W)) + val inst_id = Input(UInt(64.W)) + val domain_id = Input(UInt(32.W)) + val funct = Input(UInt(32.W)) + val pc = Input(UInt(64.W)) + val rs1_data = Input(UInt(64.W)) + val rs2_data = Input(UInt(64.W)) + val enable = Input(Bool()) }) setInline( @@ -29,45 +28,42 @@ class ITraceDPI extends BlackBox with HasBlackBoxInline { | input clock, | input reset, | input [7:0] is_issue, + | input [63:0] hart_id, | input [31:0] rob_id, + | input [63:0] inst_id, | input [31:0] domain_id, | input [31:0] funct, | input [63:0] pc, - | input [63:0] rs1_idx, - | input [63:0] rs2_idx, | input [63:0] rs1_data, | input [63:0] rs2_data, - | input [7:0] bank_enable, | input enable |); |""".stripMargin + DpiGuard.wrapITrace(""" | import "DPI-C" context function void dpi_itrace( | input int unsigned is_issue, + | input int unsigned hart_id_lo, + | input int unsigned hart_id_hi, | input int unsigned rob_id, + | input int unsigned inst_id_lo, + | input int unsigned inst_id_hi, | input int unsigned domain_id, | input int unsigned funct, | input int unsigned pc_lo, | input int unsigned pc_hi, - | input int unsigned rs1_idx_lo, - | input int unsigned rs1_idx_hi, - | input int unsigned rs2_idx_lo, - | input int unsigned rs2_idx_hi, | input int unsigned rs1_data_lo, | input int unsigned rs1_data_hi, | input int unsigned rs2_data_lo, - | input int unsigned rs2_data_hi, - | input int unsigned bank_enable + | input int unsigned rs2_data_hi | ); | reg [7:0] is_issue_reg; + | reg [63:0] hart_id_reg; | reg [31:0] rob_id_reg; + | reg [63:0] inst_id_reg; | reg [31:0] domain_id_reg; | reg [31:0] funct_reg; | reg [63:0] pc_reg; - | reg [63:0] rs1_idx_reg; - | reg [63:0] rs2_idx_reg; | reg [63:0] rs1_data_reg; | reg [63:0] rs2_data_reg; - | reg [7:0] bank_enable_reg; | reg valid_reg; | | always @(posedge clock) begin @@ -75,21 +71,20 @@ class ITraceDPI extends BlackBox with HasBlackBoxInline { | valid_reg <= 1'b0; | end else begin | if (valid_reg) begin - | dpi_itrace(is_issue_reg, rob_id_reg, domain_id_reg, funct_reg, pc_reg[31:0], pc_reg[63:32], rs1_idx_reg[31:0], rs1_idx_reg[63:32], rs2_idx_reg[31:0], rs2_idx_reg[63:32], rs1_data_reg[31:0], rs1_data_reg[63:32], rs2_data_reg[31:0], rs2_data_reg[63:32], bank_enable_reg); + | dpi_itrace(is_issue_reg, hart_id_reg[31:0], hart_id_reg[63:32], rob_id_reg, inst_id_reg[31:0], inst_id_reg[63:32], domain_id_reg, funct_reg, pc_reg[31:0], pc_reg[63:32], rs1_data_reg[31:0], rs1_data_reg[63:32], rs2_data_reg[31:0], rs2_data_reg[63:32]); | end | | valid_reg <= enable; | if (enable) begin | is_issue_reg <= is_issue; + | hart_id_reg <= hart_id; | rob_id_reg <= rob_id; + | inst_id_reg <= inst_id; | domain_id_reg <= domain_id; | funct_reg <= funct; | pc_reg <= pc; - | rs1_idx_reg <= rs1_idx; - | rs2_idx_reg <= rs2_idx; | rs1_data_reg <= rs1_data; | rs2_data_reg <= rs2_data; - | bank_enable_reg <= bank_enable; | end | end | end diff --git a/arch/src/main/scala/framework/gpdomain/sequencer/decoder/DomainDecoder.scala b/arch/src/main/scala/framework/gpdomain/sequencer/decoder/DomainDecoder.scala index 15847d82a..533c72b34 100644 --- a/arch/src/main/scala/framework/gpdomain/sequencer/decoder/DomainDecoder.scala +++ b/arch/src/main/scala/framework/gpdomain/sequencer/decoder/DomainDecoder.scala @@ -30,7 +30,7 @@ object DomainDecoderParameter { * Domain Decoder IO */ class DomainDecoderIO(b: GlobalConfig) extends Bundle { - val inst_i = Input(new RoCCCommandBB(b.core.xLen)) + val inst_i = Input(new RoCCCommandBB(b.tile.xLen)) val decoded_o = Decoder.bundle(DomainDecoderParameter.decoderParam).cloneType } diff --git a/arch/src/main/scala/framework/mem-core/axis/src/main/resources/arbiter_checker.svh b/arch/src/main/scala/framework/mem-core/axis/src/main/resources/arbiter_checker.svh index ba85d6fe2..a11f577cd 100644 --- a/arch/src/main/scala/framework/mem-core/axis/src/main/resources/arbiter_checker.svh +++ b/arch/src/main/scala/framework/mem-core/axis/src/main/resources/arbiter_checker.svh @@ -1,5 +1,5 @@ -class checker extends uvm_component; - `uvm_component_utils(checker) +class arbiter_checker extends uvm_component; + `uvm_component_utils(arbiter_checker) virtual arbiter_if vif; chandle model; diff --git a/arch/src/main/scala/framework/mem-core/axis/src/main/resources/arbiter_driver.svh b/arch/src/main/scala/framework/mem-core/axis/src/main/resources/arbiter_driver.svh index 87692aad5..9b8240145 100644 --- a/arch/src/main/scala/framework/mem-core/axis/src/main/resources/arbiter_driver.svh +++ b/arch/src/main/scala/framework/mem-core/axis/src/main/resources/arbiter_driver.svh @@ -18,8 +18,8 @@ class driver extends uvm_component; task run_phase(uvm_phase phase); bit [31:0] data0[3] = '{32'h00000000, 32'hffffffff, 32'haaaaaaaa}; bit [31:0] data1[3] = '{32'hffffffff, 32'h00000000, 32'h55555555}; - bit [ 3:0] keep0[3] = '{4'h1, 4'hf, 4'h5}; - bit [ 3:0] keep1[3] = '{4'hf, 4'h1, 4'ha}; + bit [3:0] keep0[3] = '{4'h1, 4'hf, 4'h5}; + bit [3:0] keep1[3] = '{4'hf, 4'h1, 4'ha}; int unsigned index0 = 0; int unsigned index1 = 0; int unsigned cycle = 0; @@ -36,13 +36,13 @@ class driver extends uvm_component; while (index0 < 3 || index1 < 3) begin vif.in_valid[0] <= index0 < 3; vif.in_valid[1] <= index1 < 3; - vif.in_data[0] <= data0[index0 < 3 ? index0 : 2]; - vif.in_data[1] <= data1[index1 < 3 ? index1 : 2]; - vif.in_keep[0] <= keep0[index0 < 3 ? index0 : 2]; - vif.in_keep[1] <= keep1[index1 < 3 ? index1 : 2]; - vif.in_last[0] <= index0 == 2; - vif.in_last[1] <= index1 == 2; - vif.out_ready <= cycle % 3 != 0; + vif.in_data[0] <= data0[index0<3?index0 : 2]; + vif.in_data[1] <= data1[index1<3?index1 : 2]; + vif.in_keep[0] <= keep0[index0<3?index0 : 2]; + vif.in_keep[1] <= keep1[index1<3?index1 : 2]; + vif.in_last[0] <= index0 == 2; + vif.in_last[1] <= index1 == 2; + vif.out_ready <= cycle % 3 != 0; @(posedge vif.clock); if (vif.in_valid[0] && vif.in_ready[0]) index0++; if (vif.in_valid[1] && vif.in_ready[1]) index1++; diff --git a/arch/src/main/scala/framework/mem-core/axis/src/main/resources/arbiter_interface.sv b/arch/src/main/scala/framework/mem-core/axis/src/main/resources/arbiter_interface.sv index 4c05081bf..45f3ad70b 100644 --- a/arch/src/main/scala/framework/mem-core/axis/src/main/resources/arbiter_interface.sv +++ b/arch/src/main/scala/framework/mem-core/axis/src/main/resources/arbiter_interface.sv @@ -1,9 +1,11 @@ -interface arbiter_if(input logic clock); +interface arbiter_if ( + input logic clock +); logic reset; logic [ 1:0] in_valid; logic [ 1:0] in_ready; - logic [31:0] in_data[2]; - logic [ 3:0] in_keep[2]; + logic [31:0] in_data [2]; + logic [ 3:0] in_keep [2]; logic [ 1:0] in_last; logic out_valid; logic out_ready; @@ -13,7 +15,9 @@ interface arbiter_if(input logic clock); assert property (@(posedge clock) disable iff (reset) $onehot0(in_ready)); assert property (@(posedge clock) disable iff (reset) - out_valid && !out_ready |=> out_valid && $stable({out_data, out_keep, out_last})); + out_valid && !out_ready |=> out_valid && $stable( + {out_data, out_keep, out_last} + )); cover property (@(posedge clock) disable iff (reset) &in_valid); cover property (@(posedge clock) disable iff (reset) in_valid[0] && in_ready[0]); diff --git a/arch/src/main/scala/framework/mem-core/axis/src/main/resources/arbiter_tb.sv b/arch/src/main/scala/framework/mem-core/axis/src/main/resources/arbiter_tb.sv index b827a6861..9d8516136 100644 --- a/arch/src/main/scala/framework/mem-core/axis/src/main/resources/arbiter_tb.sv +++ b/arch/src/main/scala/framework/mem-core/axis/src/main/resources/arbiter_tb.sv @@ -6,27 +6,27 @@ module arbiter_tb; logic reset = 1'b0; always #5 clock = ~clock; - arbiter_if source_if(clock); + arbiter_if source_if (clock); assign source_if.reset = reset; PacketArbiter dut ( - .clock(clock), - .reset(reset), - .io_in_0_ready(source_if.in_ready[0]), - .io_in_0_valid(source_if.in_valid[0]), - .io_in_0_bits_tdata(source_if.in_data[0]), - .io_in_0_bits_tkeep(source_if.in_keep[0]), - .io_in_0_bits_tlast(source_if.in_last[0]), - .io_in_1_ready(source_if.in_ready[1]), - .io_in_1_valid(source_if.in_valid[1]), - .io_in_1_bits_tdata(source_if.in_data[1]), - .io_in_1_bits_tkeep(source_if.in_keep[1]), - .io_in_1_bits_tlast(source_if.in_last[1]), - .io_out_ready(source_if.out_ready), - .io_out_valid(source_if.out_valid), - .io_out_bits_tdata(source_if.out_data), - .io_out_bits_tkeep(source_if.out_keep), - .io_out_bits_tlast(source_if.out_last) + .clock(clock), + .reset(reset), + .io_in_0_ready(source_if.in_ready[0]), + .io_in_0_valid(source_if.in_valid[0]), + .io_in_0_bits_tdata(source_if.in_data[0]), + .io_in_0_bits_tkeep(source_if.in_keep[0]), + .io_in_0_bits_tlast(source_if.in_last[0]), + .io_in_1_ready(source_if.in_ready[1]), + .io_in_1_valid(source_if.in_valid[1]), + .io_in_1_bits_tdata(source_if.in_data[1]), + .io_in_1_bits_tkeep(source_if.in_keep[1]), + .io_in_1_bits_tlast(source_if.in_last[1]), + .io_out_ready(source_if.out_ready), + .io_out_valid(source_if.out_valid), + .io_out_bits_tdata(source_if.out_data), + .io_out_bits_tkeep(source_if.out_keep), + .io_out_bits_tlast(source_if.out_last) ); initial begin diff --git a/arch/src/main/scala/framework/mem-core/axis/src/main/resources/arbiter_test.svh b/arch/src/main/scala/framework/mem-core/axis/src/main/resources/arbiter_test.svh index 89db5b424..76f8ec6a7 100644 --- a/arch/src/main/scala/framework/mem-core/axis/src/main/resources/arbiter_test.svh +++ b/arch/src/main/scala/framework/mem-core/axis/src/main/resources/arbiter_test.svh @@ -2,7 +2,7 @@ class env extends uvm_env; `uvm_component_utils(env) driver source; - checker monitor; + arbiter_checker monitor; function new(string name, uvm_component parent); super.new(name, parent); @@ -10,8 +10,8 @@ class env extends uvm_env; function void build_phase(uvm_phase phase); super.build_phase(phase); - source = driver::type_id::create("source", this); - monitor = checker::type_id::create("monitor", this); + source = driver::type_id::create("source", this); + monitor = arbiter_checker::type_id::create("monitor", this); endfunction endclass diff --git a/arch/src/main/scala/framework/mem-core/axis/src/main/resources/interface.sv b/arch/src/main/scala/framework/mem-core/axis/src/main/resources/interface.sv index 2e75047f9..b8f0e35a5 100644 --- a/arch/src/main/scala/framework/mem-core/axis/src/main/resources/interface.sv +++ b/arch/src/main/scala/framework/mem-core/axis/src/main/resources/interface.sv @@ -1,4 +1,6 @@ -interface axis_if(input logic clock); +interface axis_if ( + input logic clock +); logic reset; logic tvalid; logic tready; @@ -7,8 +9,9 @@ interface axis_if(input logic clock); logic tlast; property payload_stable_during_stall; - @(posedge clock) disable iff (reset) - tvalid && !tready |=> tvalid && $stable({tdata, tkeep, tlast}); + @(posedge clock) disable iff (reset) tvalid && !tready |=> tvalid && $stable( + {tdata, tkeep, tlast} + ); endproperty assert property (payload_stable_during_stall); diff --git a/arch/src/main/scala/framework/mem-core/axis/src/main/resources/master_tb.sv b/arch/src/main/scala/framework/mem-core/axis/src/main/resources/master_tb.sv index 5fb2d0aef..746daee03 100644 --- a/arch/src/main/scala/framework/mem-core/axis/src/main/resources/master_tb.sv +++ b/arch/src/main/scala/framework/mem-core/axis/src/main/resources/master_tb.sv @@ -6,25 +6,25 @@ module master_tb; logic reset = 1'b0; always #5 clock = ~clock; - axis_if source_if(clock); - axis_if sink_if(clock); + axis_if source_if (clock); + axis_if sink_if (clock); assign source_if.reset = reset; assign sink_if.reset = reset; Master dut ( - .clock(clock), - .reset(reset), - .io_in_ready(source_if.tready), - .io_in_valid(source_if.tvalid), - .io_in_bits_tdata(source_if.tdata), - .io_in_bits_tkeep(source_if.tkeep), - .io_in_bits_tlast(source_if.tlast), - .io_axis_tvalid(sink_if.tvalid), - .io_axis_tready(sink_if.tready), - .io_axis_tdata(sink_if.tdata), - .io_axis_tkeep(sink_if.tkeep), - .io_axis_tlast(sink_if.tlast) + .clock(clock), + .reset(reset), + .io_in_ready(source_if.tready), + .io_in_valid(source_if.tvalid), + .io_in_bits_tdata(source_if.tdata), + .io_in_bits_tkeep(source_if.tkeep), + .io_in_bits_tlast(source_if.tlast), + .io_axis_tvalid(sink_if.tvalid), + .io_axis_tready(sink_if.tready), + .io_axis_tdata(sink_if.tdata), + .io_axis_tkeep(sink_if.tkeep), + .io_axis_tlast(sink_if.tlast) ); initial begin diff --git a/arch/src/main/scala/framework/mem-core/axis/src/main/resources/slave_tb.sv b/arch/src/main/scala/framework/mem-core/axis/src/main/resources/slave_tb.sv index 33a90a377..aceba229b 100644 --- a/arch/src/main/scala/framework/mem-core/axis/src/main/resources/slave_tb.sv +++ b/arch/src/main/scala/framework/mem-core/axis/src/main/resources/slave_tb.sv @@ -6,25 +6,25 @@ module slave_tb; logic reset = 1'b0; always #5 clock = ~clock; - axis_if source_if(clock); - axis_if sink_if(clock); + axis_if source_if (clock); + axis_if sink_if (clock); assign source_if.reset = reset; assign sink_if.reset = reset; Slave dut ( - .clock(clock), - .reset(reset), - .io_axis_tvalid(source_if.tvalid), - .io_axis_tready(source_if.tready), - .io_axis_tdata(source_if.tdata), - .io_axis_tkeep(source_if.tkeep), - .io_axis_tlast(source_if.tlast), - .io_out_ready(sink_if.tready), - .io_out_valid(sink_if.tvalid), - .io_out_bits_tdata(sink_if.tdata), - .io_out_bits_tkeep(sink_if.tkeep), - .io_out_bits_tlast(sink_if.tlast) + .clock(clock), + .reset(reset), + .io_axis_tvalid(source_if.tvalid), + .io_axis_tready(source_if.tready), + .io_axis_tdata(source_if.tdata), + .io_axis_tkeep(source_if.tkeep), + .io_axis_tlast(source_if.tlast), + .io_out_ready(sink_if.tready), + .io_out_valid(sink_if.tvalid), + .io_out_bits_tdata(sink_if.tdata), + .io_out_bits_tkeep(sink_if.tkeep), + .io_out_bits_tlast(sink_if.tlast) ); initial begin diff --git a/arch/src/main/scala/framework/mem-core/cache/build.sc b/arch/src/main/scala/framework/mem-core/cache/build.sc deleted file mode 100644 index e512a5cee..000000000 --- a/arch/src/main/scala/framework/mem-core/cache/build.sc +++ /dev/null @@ -1,21 +0,0 @@ -import mill._ -import mill.scalalib._ - -trait ChiselModule extends SbtModule { - def moduleRoot: os.Path - - override def millSourcePath = moduleRoot - override def scalaVersion = "2.13.16" - override def ivyDeps = Agg(ivy"org.chipsalliance::chisel:6.7.0") - override def scalacPluginIvyDeps = Agg(ivy"org.chipsalliance:::chisel-plugin:6.7.0") - override def scalacOptions = Seq("-deprecation", "-feature", "-language:reflectiveCalls", "-Ymacro-annotations") -} - -object chi extends ChiselModule { - override def moduleRoot = os.pwd / os.up / "chi" -} - -object cache extends ChiselModule { - override def moduleRoot = os.pwd - override def moduleDeps = Seq(chi) -} diff --git a/arch/src/main/scala/framework/mem-core/cache/src/csrc/README.md b/arch/src/main/scala/framework/mem-core/cache/src/csrc/README.md deleted file mode 100644 index e69de29bb..000000000 diff --git a/arch/src/main/scala/framework/mem-core/cache/src/main/resources/README.md b/arch/src/main/scala/framework/mem-core/cache/src/main/resources/README.md deleted file mode 100644 index e69de29bb..000000000 diff --git a/arch/src/main/scala/framework/mem-core/chi/src/main/scala/Emit.scala b/arch/src/main/scala/framework/mem-core/chi/src/main/scala/Emit.scala index 25292e34c..53b5b7fc4 100644 --- a/arch/src/main/scala/framework/mem-core/chi/src/main/scala/Emit.scala +++ b/arch/src/main/scala/framework/mem-core/chi/src/main/scala/Emit.scala @@ -1,5 +1,7 @@ package memcore.bus.chi +import memcore.bus.chi.snf.SramEndpoint + object Emit extends App { val p = Params() require((new RequestFlit(p)).flitWidth == 137) diff --git a/arch/src/main/scala/framework/mem-core/coherence/src/main/scala/ChiHome.scala b/arch/src/main/scala/framework/mem-core/chi/src/main/scala/hnf/ChiHome.scala similarity index 99% rename from arch/src/main/scala/framework/mem-core/coherence/src/main/scala/ChiHome.scala rename to arch/src/main/scala/framework/mem-core/chi/src/main/scala/hnf/ChiHome.scala index 504fe2bce..1483d9e23 100644 --- a/arch/src/main/scala/framework/mem-core/coherence/src/main/scala/ChiHome.scala +++ b/arch/src/main/scala/framework/mem-core/chi/src/main/scala/hnf/ChiHome.scala @@ -1,8 +1,9 @@ -package memcore.memory.coherence +package memcore.bus.chi.hnf import chisel3._ import chisel3.util._ import memcore.bus.chi._ +import memcore.bus.chi.snf.{LineRequest, LineResponse} // A finite-address, precise-directory Home. One serialized transaction per Home; // CompAck closes a read grant before another request can observe its directory state. diff --git a/arch/src/main/scala/framework/mem-core/cache/src/main/scala/BankedChiCache.scala b/arch/src/main/scala/framework/mem-core/chi/src/main/scala/rnf/BankedChiCache.scala similarity index 99% rename from arch/src/main/scala/framework/mem-core/cache/src/main/scala/BankedChiCache.scala rename to arch/src/main/scala/framework/mem-core/chi/src/main/scala/rnf/BankedChiCache.scala index cf18cdbc9..52a9ab56e 100644 --- a/arch/src/main/scala/framework/mem-core/cache/src/main/scala/BankedChiCache.scala +++ b/arch/src/main/scala/framework/mem-core/chi/src/main/scala/rnf/BankedChiCache.scala @@ -1,4 +1,4 @@ -package memcore.memory.cache +package memcore.bus.chi.rnf import chisel3._ import chisel3.util._ diff --git a/arch/src/main/scala/framework/mem-core/cache/src/main/scala/CachePort.scala b/arch/src/main/scala/framework/mem-core/chi/src/main/scala/rnf/CachePort.scala similarity index 96% rename from arch/src/main/scala/framework/mem-core/cache/src/main/scala/CachePort.scala rename to arch/src/main/scala/framework/mem-core/chi/src/main/scala/rnf/CachePort.scala index f30681c15..1efe22868 100644 --- a/arch/src/main/scala/framework/mem-core/cache/src/main/scala/CachePort.scala +++ b/arch/src/main/scala/framework/mem-core/chi/src/main/scala/rnf/CachePort.scala @@ -1,4 +1,4 @@ -package memcore.memory.cache +package memcore.bus.chi.rnf import chisel3._ import memcore.bus.chi.Params diff --git a/arch/src/main/scala/framework/mem-core/cache/src/main/scala/ChiCache.scala b/arch/src/main/scala/framework/mem-core/chi/src/main/scala/rnf/ChiCache.scala similarity index 99% rename from arch/src/main/scala/framework/mem-core/cache/src/main/scala/ChiCache.scala rename to arch/src/main/scala/framework/mem-core/chi/src/main/scala/rnf/ChiCache.scala index bcf49abd2..c96bb7b4a 100644 --- a/arch/src/main/scala/framework/mem-core/cache/src/main/scala/ChiCache.scala +++ b/arch/src/main/scala/framework/mem-core/chi/src/main/scala/rnf/ChiCache.scala @@ -1,4 +1,4 @@ -package memcore.memory.cache +package memcore.bus.chi.rnf import chisel3._ import chisel3.util._ diff --git a/arch/src/main/scala/framework/mem-core/coherence/src/main/scala/NpuRegion.scala b/arch/src/main/scala/framework/mem-core/chi/src/main/scala/rni/NpuRegion.scala similarity index 99% rename from arch/src/main/scala/framework/mem-core/coherence/src/main/scala/NpuRegion.scala rename to arch/src/main/scala/framework/mem-core/chi/src/main/scala/rni/NpuRegion.scala index ba3cb4025..38174b713 100644 --- a/arch/src/main/scala/framework/mem-core/coherence/src/main/scala/NpuRegion.scala +++ b/arch/src/main/scala/framework/mem-core/chi/src/main/scala/rni/NpuRegion.scala @@ -1,4 +1,4 @@ -package memcore.memory.coherence +package memcore.bus.chi.rni import chisel3._ import chisel3.util._ diff --git a/arch/src/main/scala/framework/mem-core/chi/src/main/scala/MemoryNode.scala b/arch/src/main/scala/framework/mem-core/chi/src/main/scala/snf/MemoryNode.scala similarity index 99% rename from arch/src/main/scala/framework/mem-core/chi/src/main/scala/MemoryNode.scala rename to arch/src/main/scala/framework/mem-core/chi/src/main/scala/snf/MemoryNode.scala index 17e8528e9..ba965640c 100644 --- a/arch/src/main/scala/framework/mem-core/chi/src/main/scala/MemoryNode.scala +++ b/arch/src/main/scala/framework/mem-core/chi/src/main/scala/snf/MemoryNode.scala @@ -1,8 +1,9 @@ -package memcore.bus.chi +package memcore.bus.chi.snf import chisel3._ import chisel3.util._ import chisel3.experimental.hierarchy.{instantiable, public} +import memcore.bus.chi._ class LineRequest(p: Params) extends Bundle { val id = UInt(p.txnIdBits.W) diff --git a/arch/src/main/scala/framework/mem-core/chi/src/main/scala/SramEndpoint.scala b/arch/src/main/scala/framework/mem-core/chi/src/main/scala/snf/SramEndpoint.scala similarity index 98% rename from arch/src/main/scala/framework/mem-core/chi/src/main/scala/SramEndpoint.scala rename to arch/src/main/scala/framework/mem-core/chi/src/main/scala/snf/SramEndpoint.scala index c58575546..98a103d7b 100644 --- a/arch/src/main/scala/framework/mem-core/chi/src/main/scala/SramEndpoint.scala +++ b/arch/src/main/scala/framework/mem-core/chi/src/main/scala/snf/SramEndpoint.scala @@ -1,8 +1,9 @@ -package memcore.bus.chi +package memcore.bus.chi.snf import chisel3._ import chisel3.util._ import chisel3.experimental.hierarchy.{instantiable, public, Instance, Instantiate} +import memcore.bus.chi._ class SnPort(p: Params) extends Bundle { val rxReq = Flipped(new Channel((new RequestFlit(p)).flitWidth)) diff --git a/arch/src/main/scala/framework/mem-core/coherence/build.sc b/arch/src/main/scala/framework/mem-core/coherence/build.sc index 1ef19e7ba..856e64cc6 100644 --- a/arch/src/main/scala/framework/mem-core/coherence/build.sc +++ b/arch/src/main/scala/framework/mem-core/coherence/build.sc @@ -15,12 +15,7 @@ object chi extends ChiselModule { override def moduleRoot = os.pwd / os.up / "chi" } -object cache extends ChiselModule { - override def moduleRoot = os.pwd / os.up / "cache" - override def moduleDeps = Seq(chi) -} - object coherence extends ChiselModule { override def moduleRoot = os.pwd - override def moduleDeps = Seq(chi, cache) + override def moduleDeps = Seq(chi) } diff --git a/arch/src/main/scala/framework/mem-core/coherence/src/main/scala/CoherentSystem.scala b/arch/src/main/scala/framework/mem-core/coherence/src/main/scala/CoherentSystem.scala index a02872a1b..3b576c44e 100644 --- a/arch/src/main/scala/framework/mem-core/coherence/src/main/scala/CoherentSystem.scala +++ b/arch/src/main/scala/framework/mem-core/coherence/src/main/scala/CoherentSystem.scala @@ -4,7 +4,10 @@ import chisel3._ import chisel3.util._ import chisel3.experimental.hierarchy.{Instance, Instantiate} import memcore.bus.chi._ -import memcore.memory.cache._ +import memcore.bus.chi.hnf.ChiHome +import memcore.bus.chi.rnf.{BankedChiCache, CacheAccess, CacheResult} +import memcore.bus.chi.rni.{NpuBeat, NpuCommand, NpuRegionAgent, RegionDirectory, RegionEntry} +import memcore.bus.chi.snf.{LineRequest, LineResponse, LineSram} // Standalone multicore cache + Home + memory. Every protocol direction crosses // a real CHI credit channel; the crossbar routes flits by destination NodeID. diff --git a/arch/src/main/scala/framework/mem-core/coherence/src/main/scala/RootPageTableWalker.scala b/arch/src/main/scala/framework/mem-core/coherence/src/main/scala/RootPageTableWalker.scala index a5e99171a..d3ba61455 100644 --- a/arch/src/main/scala/framework/mem-core/coherence/src/main/scala/RootPageTableWalker.scala +++ b/arch/src/main/scala/framework/mem-core/coherence/src/main/scala/RootPageTableWalker.scala @@ -4,7 +4,7 @@ import chisel3._ import chisel3.util._ import memcore.bus.chi.Params -import memcore.memory.cache.{CacheAccess, CacheAtomic, CacheResult} +import memcore.bus.chi.rnf.{CacheAccess, CacheAtomic, CacheResult} /** Virtual-memory request used by the ROOT-native DTLB/ITLB path. */ class RootTranslationRequest extends Bundle { diff --git a/arch/src/main/scala/framework/memdomain/MemDomain.scala b/arch/src/main/scala/framework/memdomain/MemDomain.scala index f8821fdb4..ed8e90073 100644 --- a/arch/src/main/scala/framework/memdomain/MemDomain.scala +++ b/arch/src/main/scala/framework/memdomain/MemDomain.scala @@ -17,13 +17,15 @@ import framework.memdomain.frontend.mem.{MemConfigerIO} import framework.memdomain.frontend.mem.tlb.{BBTLBExceptionIO, BBTLBPTWIO} import framework.memdomain.midend.MemMidend import framework.memdomain.backend.MemBackend +import framework.memdomain.backend.banks.btrace.PhysicalBankHash @instantiable class MemDomain(val b: GlobalConfig)(edge: TLEdgeOut) extends Module { - val totalMmioRead = b.ballDomain.ballIdMappings.map(_.mmioReadBW).sum - val totalMmioWrite = b.ballDomain.ballIdMappings.map(_.mmioWriteBW).sum - val totalBallRead = b.ballDomain.ballIdMappings.map(_.inBW).sum - val totalBallWrite = b.ballDomain.ballIdMappings.map(_.outBW).sum + val totalMmioRead = b.ballDomain.ballIdMappings.map(_.mmioReadBW).sum + val totalMmioWrite = b.ballDomain.ballIdMappings.map(_.mmioWriteBW).sum + val totalBallRead = b.ballDomain.ballIdMappings.map(_.inBW).sum + val totalBallWrite = b.ballDomain.ballIdMappings.map(_.outBW).sum + val sharedHashCount = if (b.memDomain.sharedEnable) SharedMemLayout.totalBank(b) else 0 @public val io = IO(new Bundle { @@ -31,6 +33,7 @@ class MemDomain(val b: GlobalConfig)(edge: TLEdgeOut) extends Module { val global_issue_i = Flipped(Decoupled(new GlobalSchedIssue(b))) val global_complete_o = Decoupled(new GlobalSchedComplete(b)) val busy = Output(Bool()) + val inst_ids = Input(Vec(b.frontend.rob_entries, UInt(64.W))) // Inside Channel val ballChannelActive = Input(Vec(b.ballDomain.ballNum, Bool())) @@ -48,25 +51,44 @@ class MemDomain(val b: GlobalConfig)(edge: TLEdgeOut) extends Module { val tlbExp = Vec(1, new BBTLBExceptionIO) val tl_reader = new TLBundle(edge.bundle) val tl_writer = new TLBundle(edge.bundle) - val hartid = Input(UInt(b.core.xLen.W)) + val hartid = Input(UInt(b.tile.xLen.W)) // Shared memory path val shared_mem_req = Vec(SharedMemLayout.channelPerHart(b), new MemRequestIO(b)) val shared_config = Decoupled(new MemConfigerIO(b)) val shared_query_valid = Output(Bool()) val shared_query_vbank_id = Output(UInt(b.memDomain.vbankIdWidth.W)) - val shared_query_group_count = Input(UInt(log2Up(b.memDomain.bankNum + 1).W)) + val shared_query_group_count = Input(UInt(b.memDomain.groupCountWidth.W)) + + val bank_hashes = + if (b.sim.diffTest) { + Some(Output(Vec(b.memDomain.bankNum + sharedHashCount, new PhysicalBankHash(b)))) + } else { + None + } + + val shared_bank_hashes = + if (b.sim.diffTest && b.memDomain.sharedEnable) { + Some(Input(Vec(sharedHashCount, new PhysicalBankHash(b)))) + } else { + None + } + }) val frontend: Instance[MemFrontend] = Instantiate(new MemFrontend(b)(edge)) val midend: Instance[MemMidend] = Instantiate(new MemMidend(b)) val backend: Instance[MemBackend] = Instantiate(new MemBackend(b)) + io.bank_hashes.foreach(_ := backend.io.bank_hashes.get) + backend.io.shared_bank_hashes.foreach(_ := io.shared_bank_hashes.get) + // Connect query interface from frontend to backend backend.io.query_vbank_id := frontend.io.query_vbank_id backend.io.query_is_shared := frontend.io.query_is_shared frontend.io.query_group_count := backend.io.query_group_count frontend.io.hartid := io.hartid + midend.io.inst_ids := io.inst_ids // Shared query: backend delegates shared query to external SharedMemBackend backend.io.shared_query_group_count := io.shared_query_group_count diff --git a/arch/src/main/scala/framework/memdomain/backend/MTrace.scala b/arch/src/main/scala/framework/memdomain/backend/MTrace.scala index 3414f8212..f8c551536 100644 --- a/arch/src/main/scala/framework/memdomain/backend/MTrace.scala +++ b/arch/src/main/scala/framework/memdomain/backend/MTrace.scala @@ -14,6 +14,7 @@ class MTraceDPI extends BlackBox with HasBlackBoxInline { val channel = Input(UInt(32.W)) val hart_id = Input(UInt(64.W)) val rob_id = Input(UInt(32.W)) + val inst_id = Input(UInt(64.W)) val vbank_id = Input(UInt(32.W)) val pbank_id = Input(UInt(32.W)) val group_id = Input(UInt(32.W)) @@ -35,6 +36,7 @@ class MTraceDPI extends BlackBox with HasBlackBoxInline { | input [31:0] channel, | input [63:0] hart_id, | input [31:0] rob_id, + | input [63:0] inst_id, | input [31:0] vbank_id, | input [31:0] pbank_id, | input [31:0] group_id, @@ -52,6 +54,8 @@ class MTraceDPI extends BlackBox with HasBlackBoxInline { | input int unsigned hart_id_lo, | input int unsigned hart_id_hi, | input int unsigned rob_id, + | input int unsigned inst_id_lo, + | input int unsigned inst_id_hi, | input int unsigned vbank_id, | input int unsigned pbank_id, | input int unsigned group_id, @@ -67,6 +71,7 @@ class MTraceDPI extends BlackBox with HasBlackBoxInline { | reg [31:0] channel_reg; | reg [63:0] hart_id_reg; | reg [31:0] rob_id_reg; + | reg [63:0] inst_id_reg; | reg [31:0] vbank_id_reg; | reg [31:0] pbank_id_reg; | reg [31:0] group_id_reg; @@ -81,7 +86,7 @@ class MTraceDPI extends BlackBox with HasBlackBoxInline { | valid_reg <= 1'b0; | end else begin | if (valid_reg) begin - | dpi_mtrace(is_write_reg, is_shared_reg, channel_reg, hart_id_reg[31:0], hart_id_reg[63:32], rob_id_reg, vbank_id_reg, pbank_id_reg, group_id_reg, addr_reg, write_mask_reg, data_lo_reg[31:0], data_lo_reg[63:32], data_hi_reg[31:0], data_hi_reg[63:32]); + | dpi_mtrace(is_write_reg, is_shared_reg, channel_reg, hart_id_reg[31:0], hart_id_reg[63:32], rob_id_reg, inst_id_reg[31:0], inst_id_reg[63:32], vbank_id_reg, pbank_id_reg, group_id_reg, addr_reg, write_mask_reg, data_lo_reg[31:0], data_lo_reg[63:32], data_hi_reg[31:0], data_hi_reg[63:32]); | end | | valid_reg <= enable; @@ -91,6 +96,7 @@ class MTraceDPI extends BlackBox with HasBlackBoxInline { | channel_reg <= channel; | hart_id_reg <= hart_id; | rob_id_reg <= rob_id; + | inst_id_reg <= inst_id; | vbank_id_reg <= vbank_id; | pbank_id_reg <= pbank_id; | group_id_reg <= group_id; @@ -107,69 +113,3 @@ class MTraceDPI extends BlackBox with HasBlackBoxInline { """.stripMargin ) } - -class MTraceIssueDPI extends BlackBox with HasBlackBoxInline { - - val io = IO(new Bundle { - val clock = Input(Clock()) - val reset = Input(Bool()) - val hart_id = Input(UInt(64.W)) - val is_shared = Input(UInt(8.W)) - val rob_id = Input(UInt(32.W)) - val vbank_id = Input(UInt(32.W)) - val group_id = Input(UInt(32.W)) - val enable = Input(Bool()) - }) - - setInline( - "MTraceIssueDPI.v", - """ - |module MTraceIssueDPI( - | input clock, - | input reset, - | input [63:0] hart_id, - | input [7:0] is_shared, - | input [31:0] rob_id, - | input [31:0] vbank_id, - | input [31:0] group_id, - | input enable - |); - |""".stripMargin + DpiGuard.wrapMTrace(""" - | import "DPI-C" context function void dpi_mtrace_issue( - | input int unsigned hart_id_lo, - | input int unsigned hart_id_hi, - | input int unsigned is_shared, - | input int unsigned rob_id, - | input int unsigned vbank_id, - | input int unsigned group_id - | ); - | reg [63:0] hart_id_reg; - | reg [7:0] is_shared_reg; - | reg [31:0] rob_id_reg; - | reg [31:0] vbank_id_reg; - | reg [31:0] group_id_reg; - | reg valid_reg; - | - | always @(posedge clock) begin - | if (reset) begin - | valid_reg <= 1'b0; - | end else begin - | if (valid_reg) begin - | dpi_mtrace_issue(hart_id_reg[31:0], hart_id_reg[63:32], is_shared_reg, rob_id_reg, vbank_id_reg, group_id_reg); - | end - | valid_reg <= enable; - | if (enable) begin - | hart_id_reg <= hart_id; - | is_shared_reg <= is_shared; - | rob_id_reg <= rob_id; - | vbank_id_reg <= vbank_id; - | group_id_reg <= group_id; - | end - | end - | end - |""".stripMargin) + - """ - |endmodule - """.stripMargin - ) -} diff --git a/arch/src/main/scala/framework/memdomain/backend/MemBackend.scala b/arch/src/main/scala/framework/memdomain/backend/MemBackend.scala index af056433f..528163815 100644 --- a/arch/src/main/scala/framework/memdomain/backend/MemBackend.scala +++ b/arch/src/main/scala/framework/memdomain/backend/MemBackend.scala @@ -7,10 +7,13 @@ import framework.memdomain.frontend.mem.MemConfigerIO import framework.top.GlobalConfig import framework.memdomain.backend.privatepath.PrivateMemBackend import framework.memdomain.backend.shared.SharedMemLayout +import framework.memdomain.backend.banks.btrace.PhysicalBankHash @instantiable class MemBackend(val b: GlobalConfig) extends Module { + val sharedHashCount = if (b.memDomain.sharedEnable) SharedMemLayout.totalBank(b) else 0 + @public val io = IO(new Bundle { val mem_req = Vec(b.memDomain.bankChannel, Flipped(new MemRequestIO(b))) @@ -24,18 +27,42 @@ class MemBackend(val b: GlobalConfig) extends Module { // Query interface: shared query goes out, private query handled internally. val shared_query_valid = Output(Bool()) val shared_query_vbank_id = Output(UInt(b.memDomain.vbankIdWidth.W)) - val shared_query_group_count = Input(UInt(log2Up(b.memDomain.bankNum + 1).W)) + val shared_query_group_count = Input(UInt(b.memDomain.groupCountWidth.W)) // Original query interface from frontend val query_vbank_id = Input(UInt(b.memDomain.vbankIdWidth.W)) val query_is_shared = Input(Bool()) - val query_group_count = Output(UInt(log2Up(b.memDomain.bankNum + 1).W)) + val query_group_count = Output(UInt(b.memDomain.groupCountWidth.W)) + + val bank_hashes = + if (b.sim.diffTest) { + Some(Output(Vec(b.memDomain.bankNum + sharedHashCount, new PhysicalBankHash(b)))) + } else { + None + } + + val shared_bank_hashes = + if (b.sim.diffTest && b.memDomain.sharedEnable) { + Some(Input(Vec(SharedMemLayout.totalBank(b), new PhysicalBankHash(b)))) + } else { + None + } + }) // Keep the private backend datapath unchanged and isolate it in a dedicated module. val privateBackend: Instance[PrivateMemBackend] = Instantiate(new PrivateMemBackend(b)) private val sharedChannelPerHart = SharedMemLayout.channelPerHart(b) + io.bank_hashes.foreach { states => + for (i <- 0 until b.memDomain.bankNum) { + states(i) := privateBackend.io.bank_hashes.get(i) + } + for (i <- 0 until sharedHashCount) { + states(b.memDomain.bankNum + i) := io.shared_bank_hashes.get(i) + } + } + // Route config to the selected backend only. val cfgToShared = io.config.bits.is_shared privateBackend.io.config.valid := io.config.valid && !cfgToShared @@ -79,6 +106,7 @@ class MemBackend(val b: GlobalConfig) extends Module { io.shared_mem_req(i).is_shared := false.B io.shared_mem_req(i).hart_id := 0.U io.shared_mem_req(i).rob_id := 0.U + io.shared_mem_req(i).inst_id := 0.U io.shared_mem_req(i).read.req.valid := false.B io.shared_mem_req(i).read.req.bits := DontCare @@ -126,6 +154,7 @@ class MemBackend(val b: GlobalConfig) extends Module { privateBackend.io.mem_req(i).is_shared := useSharedReq privateBackend.io.mem_req(i).hart_id := io.mem_req(i).hart_id privateBackend.io.mem_req(i).rob_id := io.mem_req(i).rob_id + privateBackend.io.mem_req(i).inst_id := io.mem_req(i).inst_id // Read request route privateBackend.io.mem_req(i).read.req.valid := io.mem_req(i).read.req.valid && !useSharedReq @@ -145,6 +174,7 @@ class MemBackend(val b: GlobalConfig) extends Module { io.shared_mem_req(i).is_shared := useSharedReq io.shared_mem_req(i).hart_id := io.mem_req(i).hart_id io.shared_mem_req(i).rob_id := io.mem_req(i).rob_id + io.shared_mem_req(i).inst_id := io.mem_req(i).inst_id io.shared_mem_req(i).read.req.valid := io.mem_req(i).read.req.valid && useSharedReq io.shared_mem_req(i).read.req.bits := io.mem_req(i).read.req.bits @@ -206,6 +236,7 @@ class MemBackend(val b: GlobalConfig) extends Module { io.shared_mem_req(i).is_shared := false.B io.shared_mem_req(i).hart_id := 0.U io.shared_mem_req(i).rob_id := 0.U + io.shared_mem_req(i).inst_id := 0.U io.shared_mem_req(i).read.req.valid := false.B io.shared_mem_req(i).read.req.bits := DontCare io.shared_mem_req(i).read.resp.ready := false.B @@ -215,19 +246,18 @@ class MemBackend(val b: GlobalConfig) extends Module { } for (i <- 0 until b.memDomain.bankChannel) { - privateBackend.io.mem_req(i).bank_id := io.mem_req(i).bank_id - privateBackend.io.mem_req(i).group_id := io.mem_req(i).group_id - privateBackend.io.mem_req(i).is_shared := false.B - privateBackend.io.mem_req(i).hart_id := io.mem_req(i).hart_id - privateBackend.io.mem_req(i).rob_id := io.mem_req(i).rob_id - - privateBackend.io.mem_req(i).read.req.valid := io.mem_req(i).read.req.valid - privateBackend.io.mem_req(i).read.req.bits := io.mem_req(i).read.req.bits - privateBackend.io.mem_req(i).read.resp.ready := io.mem_req(i).read.resp.ready - io.mem_req(i).read.req.ready := privateBackend.io.mem_req(i).read.req.ready - io.mem_req(i).read.resp.valid := privateBackend.io.mem_req(i).read.resp.valid - io.mem_req(i).read.resp.bits := privateBackend.io.mem_req(i).read.resp.bits - + privateBackend.io.mem_req(i).bank_id := io.mem_req(i).bank_id + privateBackend.io.mem_req(i).group_id := io.mem_req(i).group_id + privateBackend.io.mem_req(i).is_shared := false.B + privateBackend.io.mem_req(i).hart_id := io.mem_req(i).hart_id + privateBackend.io.mem_req(i).rob_id := io.mem_req(i).rob_id + privateBackend.io.mem_req(i).inst_id := io.mem_req(i).inst_id + privateBackend.io.mem_req(i).read.req.valid := io.mem_req(i).read.req.valid + privateBackend.io.mem_req(i).read.req.bits := io.mem_req(i).read.req.bits + privateBackend.io.mem_req(i).read.resp.ready := io.mem_req(i).read.resp.ready + io.mem_req(i).read.req.ready := privateBackend.io.mem_req(i).read.req.ready + io.mem_req(i).read.resp.valid := privateBackend.io.mem_req(i).read.resp.valid + io.mem_req(i).read.resp.bits := privateBackend.io.mem_req(i).read.resp.bits privateBackend.io.mem_req(i).write.req.valid := io.mem_req(i).write.req.valid privateBackend.io.mem_req(i).write.req.bits := io.mem_req(i).write.req.bits privateBackend.io.mem_req(i).write.resp.ready := io.mem_req(i).write.resp.ready diff --git a/arch/src/main/scala/framework/memdomain/backend/MemBackendTypes.scala b/arch/src/main/scala/framework/memdomain/backend/MemBackendTypes.scala index e0c4dd780..6d1fea61e 100644 --- a/arch/src/main/scala/framework/memdomain/backend/MemBackendTypes.scala +++ b/arch/src/main/scala/framework/memdomain/backend/MemBackendTypes.scala @@ -9,8 +9,9 @@ class MemRequestIO(b: GlobalConfig) extends Bundle { val write = Flipped(new SramWriteIO(b)) // midend sends write req into backend val read = Flipped(new SramReadIO(b)) // midend sends read req into backend val bank_id = Output(UInt(b.memDomain.vbankIdWidth.W)) - val group_id = Output(UInt(log2Up(b.memDomain.bankNum).W)) + val group_id = Output(UInt(b.memDomain.groupIdWidth.W)) val is_shared = Output(Bool()) - val hart_id = Output(UInt(b.core.xLen.W)) + val hart_id = Output(UInt(b.tile.xLen.W)) val rob_id = Output(UInt(log2Up(b.frontend.rob_entries).W)) + val inst_id = Output(UInt(64.W)) } diff --git a/arch/src/main/scala/framework/memdomain/backend/accpipe/AccPipe.scala b/arch/src/main/scala/framework/memdomain/backend/accpipe/AccPipe.scala index f591ce7a0..0650e7922 100644 --- a/arch/src/main/scala/framework/memdomain/backend/accpipe/AccPipe.scala +++ b/arch/src/main/scala/framework/memdomain/backend/accpipe/AccPipe.scala @@ -20,9 +20,9 @@ class AccPipe(val b: GlobalConfig) extends Module { val is_multi = Input(Bool()) val busy = Output(Bool()) - val group_id = Output(UInt(log2Up(b.memDomain.bankNum).W)) + val group_id = Output(UInt(b.memDomain.groupIdWidth.W)) val bank_id = Output(UInt(b.memDomain.vbankIdWidth.W)) - val hart_id = Output(UInt(b.core.xLen.W)) + val hart_id = Output(UInt(b.tile.xLen.W)) }) // Each group has its own physical bank, so no address shifting is needed. @@ -30,13 +30,13 @@ class AccPipe(val b: GlobalConfig) extends Module { // to access wrong physical addresses while matmul writes used unshifted addresses. //group_id output - val group_id_reg = RegInit(0.U(log2Up(b.memDomain.bankNum).W)) + val group_id_reg = RegInit(0.U(b.memDomain.groupIdWidth.W)) io.group_id := group_id_reg //Bank_id output val bank_id_reg = RegInit(0.U(b.memDomain.vbankIdWidth.W)) io.bank_id := bank_id_reg - val hart_id_reg = RegInit(0.U(b.core.xLen.W)) + val hart_id_reg = RegInit(0.U(b.tile.xLen.W)) io.hart_id := hart_id_reg val rd_hold = RegInit(false.B) diff --git a/arch/src/main/scala/framework/memdomain/backend/banks/btrace/BTraceDPI.scala b/arch/src/main/scala/framework/memdomain/backend/banks/btrace/BTraceDPI.scala new file mode 100644 index 000000000..217b2a29b --- /dev/null +++ b/arch/src/main/scala/framework/memdomain/backend/banks/btrace/BTraceDPI.scala @@ -0,0 +1,64 @@ +package framework.memdomain.backend.banks.btrace + +import chisel3._ +import chisel3.util._ +import framework.dpi.DpiGuard + +class BTraceDPI extends BlackBox with HasBlackBoxInline { + + val io = IO(new Bundle { + val clock = Input(Clock()) + val reset = Input(Bool()) + val instId = Input(UInt(64.W)) + val hartId = Input(UInt(64.W)) + val r0Vbank = Input(UInt(32.W)) + val r0Hash = Input(UInt(32.W)) + val r1Vbank = Input(UInt(32.W)) + val r1Hash = Input(UInt(32.W)) + val w0Vbank = Input(UInt(32.W)) + val w0Hash = Input(UInt(32.W)) + val fire = Input(Bool()) + }) + + setInline( + "BTraceDPI.v", + """ + |module BTraceDPI( + | input clock, + | input reset, + | input [63:0] instId, + | input [63:0] hartId, + | input [31:0] r0Vbank, + | input [31:0] r0Hash, + | input [31:0] r1Vbank, + | input [31:0] r1Hash, + | input [31:0] w0Vbank, + | input [31:0] w0Hash, + | input fire + |); + |""".stripMargin + DpiGuard.wrapBTrace( + """ + | import "DPI-C" context function void dpi_btrace( + | input int unsigned inst_id_lo, + | input int unsigned inst_id_hi, + | input int unsigned hart_id_lo, + | input int unsigned hart_id_hi, + | input int unsigned r0_vbank, + | input int unsigned r0_hash, + | input int unsigned r1_vbank, + | input int unsigned r1_hash, + | input int unsigned w0_vbank, + | input int unsigned w0_hash + | ); + | always @(posedge clock) begin + | if (!reset && fire) begin + | dpi_btrace(instId[31:0], instId[63:32], hartId[31:0], hartId[63:32], r0Vbank, r0Hash, r1Vbank, r1Hash, w0Vbank, w0Hash); + | end + | end + |""".stripMargin + ) + + """ + |endmodule + |""".stripMargin + ) +} diff --git a/arch/src/main/scala/framework/memdomain/backend/banks/btrace/BTraceTypes.scala b/arch/src/main/scala/framework/memdomain/backend/banks/btrace/BTraceTypes.scala new file mode 100644 index 000000000..f4f7ce093 --- /dev/null +++ b/arch/src/main/scala/framework/memdomain/backend/banks/btrace/BTraceTypes.scala @@ -0,0 +1,13 @@ +package framework.memdomain.backend.banks.btrace + +import chisel3._ +import framework.top.GlobalConfig + +class PhysicalBankHash(val b: GlobalConfig) extends Bundle { + val valid = Bool() + val hartId = UInt(b.tile.xLen.W) + val vbankId = UInt(b.memDomain.vbankIdWidth.W) + val pbankId = UInt(32.W) + val groupId = UInt(32.W) + val statusHash = UInt(32.W) +} diff --git a/arch/src/main/scala/framework/memdomain/backend/privatepath/PrivateMemBackend.scala b/arch/src/main/scala/framework/memdomain/backend/privatepath/PrivateMemBackend.scala index bb5aea192..c80b46001 100644 --- a/arch/src/main/scala/framework/memdomain/backend/privatepath/PrivateMemBackend.scala +++ b/arch/src/main/scala/framework/memdomain/backend/privatepath/PrivateMemBackend.scala @@ -5,8 +5,10 @@ import chisel3.util._ import chisel3.experimental.hierarchy.{instantiable, public, Instance, Instantiate} import framework.memdomain.frontend.mem.MemConfigerIO import framework.memdomain.backend.{MTraceDPI, MemRequestIO} +import sims.hash.BankHashMonitor import framework.memdomain.backend.accpipe.AccPipe import framework.memdomain.backend.banks.SramBank +import framework.memdomain.backend.banks.btrace.PhysicalBankHash import framework.top.GlobalConfig @instantiable @@ -19,12 +21,20 @@ class PrivateMemBackend(val b: GlobalConfig) extends Module { // Query interface for frontend to get group count val query_vbank_id = Input(UInt(b.memDomain.vbankIdWidth.W)) - val query_group_count = Output(UInt(log2Up(b.memDomain.bankNum + 1).W)) + val query_group_count = Output(UInt(b.memDomain.groupCountWidth.W)) + val bank_hashes = if (b.sim.diffTest) Some(Output(Vec(b.memDomain.bankNum, new PhysicalBankHash(b)))) else None }) val banks: Seq[Instance[SramBank]] = Seq.fill(b.memDomain.bankNum)(Instantiate(new SramBank(b))) val accPipes: Seq[Instance[AccPipe]] = Seq.fill(b.memDomain.bankChannel)(Instantiate(new AccPipe(b))) + val hashMonitors = + if (b.sim.diffTest) { + Some(Seq.fill(b.memDomain.bankNum)(Instantiate(new BankHashMonitor(b)))) + } else { + None + } + // Per-channel memory trace DPI-C modules to avoid losing simultaneous events val mtraces = Seq.fill(b.memDomain.bankChannel)(Module(new MTraceDPI)) for (mt <- mtraces) { @@ -35,6 +45,7 @@ class PrivateMemBackend(val b: GlobalConfig) extends Module { mt.io.channel := 0.U mt.io.hart_id := 0.U mt.io.rob_id := 0.U + mt.io.inst_id := 0.U mt.io.vbank_id := 0.U mt.io.pbank_id := 0.U mt.io.group_id := 0.U @@ -50,9 +61,10 @@ class PrivateMemBackend(val b: GlobalConfig) extends Module { // ----------------------------------------------------------------------------- class MappingTableEntry extends Bundle { val valid = Bool() + val hart_id = UInt(b.tile.xLen.W) val vbank_id = UInt(b.memDomain.vbankIdWidth.W) val is_multi = Bool() - val group_id = UInt(log2Up(b.memDomain.bankNum).W) + val group_id = UInt(b.memDomain.groupIdWidth.W) } val mappingTable = RegInit(VecInit(Seq.fill(b.memDomain.bankNum)(0.U.asTypeOf(new MappingTableEntry)))) @@ -81,10 +93,11 @@ class PrivateMemBackend(val b: GlobalConfig) extends Module { // The private namespace is bounded by the frontend contract, while // multi-bank groups remain represented individually in mappingTable. val groupCountByVbank = RegInit( - VecInit(Seq.fill(privateVbankCount)(0.U(log2Up(b.memDomain.bankNum + 1).W))) + VecInit(Seq.fill(privateVbankCount)(0.U(b.memDomain.groupCountWidth.W))) ) def addEntry( + hart_id: UInt, vbank_id: UInt, pbank_id: UInt, is_multi: Bool, @@ -92,6 +105,7 @@ class PrivateMemBackend(val b: GlobalConfig) extends Module { ): Unit = { val entry = mappingTable(pbank_id) entry.valid := true.B + entry.hart_id := hart_id entry.vbank_id := vbank_id entry.is_multi := is_multi entry.group_id := group_id @@ -105,15 +119,6 @@ class PrivateMemBackend(val b: GlobalConfig) extends Module { } } - def getFreePbankId(): UInt = { - val hasFree = mappingTable.map(_.valid === false.B).reduce(_ || _) - when(!hasFree) { - assert(false.B, "PrivateMemBackend allocation failed: no free physical bank\n") - } - val freePbankId = mappingTable.indexWhere(_.valid === false.B) - freePbankId - } - // ----------------------------------------------------------------------------- // Default Value // ----------------------------------------------------------------------------- @@ -126,6 +131,7 @@ class PrivateMemBackend(val b: GlobalConfig) extends Module { accPipes(i).io.mem_req.is_shared := io.mem_req(i).is_shared accPipes(i).io.mem_req.hart_id := io.mem_req(i).hart_id accPipes(i).io.mem_req.rob_id := io.mem_req(i).rob_id + accPipes(i).io.mem_req.inst_id := io.mem_req(i).inst_id // Bank-side defaults (only driven when a bank is actually connected) accPipes(i).io.sramRead.req.ready := false.B @@ -150,17 +156,31 @@ class PrivateMemBackend(val b: GlobalConfig) extends Module { bank.io.sramWrite.resp.ready := true.B } - io.config.ready := true.B + val realloc = io.config.bits.group_id === 0.U + val freePbankMask = + VecInit(mappingTable.map(entry => !entry.valid || (realloc && entry.vbank_id === io.config.bits.vbank_id))) + val hasFreePbank = freePbankMask.asUInt.orR + io.config.ready := !io.config.bits.alloc || hasFreePbank + when(io.config.valid && io.config.bits.alloc && !hasFreePbank) { + assert(false.B, "PrivateMemBackend allocation failed: no free physical bank\n") + } // ----------------------------------------------------------------------------- // Bank Alloc/Release // ----------------------------------------------------------------------------- + hashMonitors.foreach(_.foreach(_.io.bind := false.B)) + when(io.config.fire) { val vbank = io.config.bits.vbank_id val vbankIdx = vbank(privateVbankIdWidth - 1, 0) when(io.config.bits.alloc) { - val freePbank = getFreePbankId() + val freePbank = PriorityEncoder(freePbankMask) + hashMonitors.foreach { hashes => + for (i <- 0 until b.memDomain.bankNum) { + hashes(i).io.bind := freePbank === i.U + } + } // Match bemu mset: realloc of the same vbank frees prior physical banks first. // MemConfiger emits one fire per group; only group 0 drops the old mapping. when(io.config.bits.group_id === 0.U) { @@ -168,6 +188,7 @@ class PrivateMemBackend(val b: GlobalConfig) extends Module { singleRouteValid(vbankIdx) := false.B } addEntry( + io.config.bits.hart_id, io.config.bits.vbank_id, freePbank, io.config.bits.is_multi, @@ -210,6 +231,7 @@ class PrivateMemBackend(val b: GlobalConfig) extends Module { mtraces(ch).io.channel := ch.U mtraces(ch).io.hart_id := io.mem_req(ch).hart_id mtraces(ch).io.rob_id := io.mem_req(ch).rob_id + mtraces(ch).io.inst_id := io.mem_req(ch).inst_id mtraces(ch).io.vbank_id := io.mem_req(ch).bank_id mtraces(ch).io.pbank_id := pbankId mtraces(ch).io.group_id := io.mem_req(ch).group_id @@ -229,6 +251,10 @@ class PrivateMemBackend(val b: GlobalConfig) extends Module { val channelReqAddr = Seq.fill(b.memDomain.bankChannel)(Wire(UInt(log2Ceil(b.memDomain.bankEntries).W))) val channelReqData = Seq.fill(b.memDomain.bankChannel)(Wire(UInt(b.memDomain.bankWidth.W))) val channelReqMask = Seq.fill(b.memDomain.bankChannel)(Wire(Vec(b.memDomain.bankMaskLen, Bool()))) + val channelHartId = Seq.fill(b.memDomain.bankChannel)(Wire(UInt(b.tile.xLen.W))) + val channelInstId = Seq.fill(b.memDomain.bankChannel)(Wire(UInt(64.W))) + val channelVbankId = Seq.fill(b.memDomain.bankChannel)(Wire(UInt(b.memDomain.vbankIdWidth.W))) + val channelGroupId = Seq.fill(b.memDomain.bankChannel)(Wire(UInt(b.memDomain.groupIdWidth.W))) for (i <- 0 until b.memDomain.bankChannel) { val routePbankReg = RegInit(0.U(pbankIndexWidth.W)) @@ -270,6 +296,10 @@ class PrivateMemBackend(val b: GlobalConfig) extends Module { ) channelReqData(i) := accPipes(i).io.sramWrite.req.bits.data channelReqMask(i) := accPipes(i).io.sramWrite.req.bits.mask + channelHartId(i) := io.mem_req(i).hart_id + channelInstId(i) := io.mem_req(i).inst_id + channelVbankId(i) := io.mem_req(i).bank_id + channelGroupId(i) := io.mem_req(i).group_id // SramBank is a pure single-port SRAM: the selected operation is always // accepted when its route is active. Using the held route directly avoids @@ -332,6 +362,10 @@ class PrivateMemBackend(val b: GlobalConfig) extends Module { val selectedReqMask = VecInit((0 until b.memDomain.bankMaskLen).map { k => oneHotOr(1, channelReqMask.map(_(k))).asBool }) + val selectedHartId = oneHotOr(b.tile.xLen, channelHartId) + val selectedInstId = oneHotOr(64, channelInstId) + val selectedVbankId = oneHotOr(b.memDomain.vbankIdWidth, channelVbankId) + val selectedGroupId = oneHotOr(b.memDomain.groupIdWidth, channelGroupId) banks(j).io.sramRead.req.valid := selectedReqValid && !selectedReqIsWrite banks(j).io.sramRead.req.bits.addr := selectedReqAddr @@ -340,6 +374,14 @@ class PrivateMemBackend(val b: GlobalConfig) extends Module { banks(j).io.sramWrite.req.bits.data := selectedReqData banks(j).io.sramWrite.req.bits.mask := selectedReqMask + hashMonitors.foreach { hashes => + val monitor = hashes(j) + monitor.io.write.valid := banks(j).io.sramWrite.req.fire + monitor.io.write.bits.addr := selectedReqAddr + monitor.io.write.bits.mask := selectedReqMask + monitor.io.write.bits.data := selectedReqData + } + // Only the channel holding this bank can consume its one-cycle response. banks(j).io.sramRead.resp.ready := VecInit((0 until b.memDomain.bankChannel).map { i => activeRouteOHs(i)(j) && accPipes(i).io.sramRead.resp.ready @@ -366,4 +408,15 @@ class PrivateMemBackend(val b: GlobalConfig) extends Module { accPipes(i).io.sramWrite.resp.valid := writeRespSel.orR accPipes(i).io.sramWrite.resp.bits.ok := writeRespSel.orR } + + io.bank_hashes.foreach { states => + for (i <- 0 until b.memDomain.bankNum) { + states(i).valid := mappingTable(i).valid + states(i).hartId := mappingTable(i).hart_id + states(i).vbankId := mappingTable(i).vbank_id + states(i).pbankId := i.U + states(i).groupId := mappingTable(i).group_id + states(i).statusHash := hashMonitors.get(i).io.statusHash + } + } } diff --git a/arch/src/main/scala/framework/memdomain/backend/shared/SharedMem.scala b/arch/src/main/scala/framework/memdomain/backend/shared/SharedMem.scala index e791a5f2f..91dc4cfeb 100644 --- a/arch/src/main/scala/framework/memdomain/backend/shared/SharedMem.scala +++ b/arch/src/main/scala/framework/memdomain/backend/shared/SharedMem.scala @@ -10,34 +10,30 @@ object SharedMemLayout { def totalBank(b: GlobalConfig): Int = { require(b.memDomain.sharedEnable, "shared memory is disabled") - require(b.memDomain.sharedEntries > 0, "sharedEntries must be > 0") - require( - b.memDomain.sharedEntries % b.memDomain.bankEntries == 0, - s"sharedEntries(${b.memDomain.sharedEntries}) must be divisible by bankEntries(${b.memDomain.bankEntries})" - ) - b.memDomain.sharedEntries / b.memDomain.bankEntries + require(b.memDomain.sharedBankNum > 0, "sharedBankNum must be > 0") + b.memDomain.sharedBankNum } def channelPerHart(b: GlobalConfig): Int = { if (!b.memDomain.sharedEnable) { return 0 } - require(b.top.nCores > 0, s"nCores(${b.top.nCores}) must be > 0") + require(b.memDomain.nCores > 0, s"nCores(${b.memDomain.nCores}) must be > 0") require( b.memDomain.sharedInputChannels > 0, s"sharedInputChannels(${b.memDomain.sharedInputChannels}) must be > 0" ) require( - b.memDomain.sharedInputChannels % b.top.nCores == 0, - s"sharedInputChannels(${b.memDomain.sharedInputChannels}) must be divisible by nCores(${b.top.nCores})" + b.memDomain.sharedInputChannels % b.memDomain.nCores == 0, + s"sharedInputChannels(${b.memDomain.sharedInputChannels}) must be divisible by nCores(${b.memDomain.nCores})" ) if (b.memDomain.sharedInputChannels > 32) { require( - b.memDomain.sharedInputChannels == b.top.nCores, - s"sharedInputChannels(${b.memDomain.sharedInputChannels}) must equal nCores(${b.top.nCores}) when > 32" + b.memDomain.sharedInputChannels == b.memDomain.nCores, + s"sharedInputChannels(${b.memDomain.sharedInputChannels}) must equal nCores(${b.memDomain.nCores}) when > 32" ) } - val ch = b.memDomain.sharedInputChannels / b.top.nCores + val ch = b.memDomain.sharedInputChannels / b.memDomain.nCores require(ch > 0, s"channelPerHart($ch) must be > 0") ch } @@ -46,16 +42,16 @@ object SharedMemLayout { } class SharedMemReadReq(val b: GlobalConfig) extends Bundle { - val hartid = UInt(b.core.xLen.W) + val hartid = UInt(b.tile.xLen.W) val pbank_id = UInt(log2Ceil(SharedMemLayout.totalBank(b)).W) - val group_id = UInt(log2Up(b.memDomain.bankNum).W) + val group_id = UInt(b.memDomain.groupIdWidth.W) val addr = UInt(log2Ceil(b.memDomain.bankEntries).W) } class SharedMemWriteReq(val b: GlobalConfig) extends Bundle { - val hartid = UInt(b.core.xLen.W) + val hartid = UInt(b.tile.xLen.W) val pbank_id = UInt(log2Ceil(SharedMemLayout.totalBank(b)).W) - val group_id = UInt(log2Up(b.memDomain.bankNum).W) + val group_id = UInt(b.memDomain.groupIdWidth.W) val addr = UInt(log2Ceil(b.memDomain.bankEntries).W) val mask = Vec(b.memDomain.bankMaskLen, Bool()) val data = UInt(b.memDomain.bankWidth.W) diff --git a/arch/src/main/scala/framework/memdomain/backend/shared/SharedMemBackend.scala b/arch/src/main/scala/framework/memdomain/backend/shared/SharedMemBackend.scala index 8e2570052..addf9f01b 100644 --- a/arch/src/main/scala/framework/memdomain/backend/shared/SharedMemBackend.scala +++ b/arch/src/main/scala/framework/memdomain/backend/shared/SharedMemBackend.scala @@ -4,14 +4,16 @@ import chisel3._ import chisel3.util._ import chisel3.experimental.hierarchy.{instantiable, public, Instance, Instantiate} import framework.memdomain.backend.{MTraceDPI, MemRequestIO} +import sims.hash.BankHashMonitor import framework.memdomain.backend.accpipe.AccPipe import framework.memdomain.backend.banks.SramBank +import framework.memdomain.backend.banks.btrace.PhysicalBankHash import framework.memdomain.frontend.mem.MemConfigerIO import framework.top.GlobalConfig @instantiable class SharedMemBackend(val b: GlobalConfig) extends Module { - private val nCores = b.top.nCores + val nCores = b.memDomain.nCores private val totalBanks = SharedMemLayout.totalBank(b) private val totalChannel = SharedMemLayout.totalChannel(b) @@ -22,14 +24,22 @@ class SharedMemBackend(val b: GlobalConfig) extends Module { // Query interface for frontend to get group count val query_valid = Input(Vec(nCores, Bool())) - val query_hart_id = Input(Vec(nCores, UInt(b.core.xLen.W))) + val query_hart_id = Input(Vec(nCores, UInt(b.tile.xLen.W))) val query_vbank_id = Input(Vec(nCores, UInt(b.memDomain.vbankIdWidth.W))) - val query_group_count = Output(Vec(nCores, UInt(log2Up(b.memDomain.bankNum + 1).W))) + val query_group_count = Output(Vec(nCores, UInt(b.memDomain.groupCountWidth.W))) + val bank_hashes = if (b.sim.diffTest) Some(Output(Vec(totalBanks, new PhysicalBankHash(b)))) else None }) val banks: Seq[Instance[SramBank]] = Seq.fill(totalBanks)(Instantiate(new SramBank(b))) val accPipes: Seq[Instance[AccPipe]] = Seq.fill(totalChannel)(Instantiate(new AccPipe(b))) + val hashMonitors = + if (b.sim.diffTest) { + Some(Seq.fill(totalBanks)(Instantiate(new BankHashMonitor(b)))) + } else { + None + } + // Per-channel memory trace DPI-C modules to avoid losing simultaneous events val mtraces = Seq.fill(totalChannel)(Module(new MTraceDPI)) for (mt <- mtraces) { @@ -40,6 +50,7 @@ class SharedMemBackend(val b: GlobalConfig) extends Module { mt.io.channel := 0.U mt.io.hart_id := 0.U mt.io.rob_id := 0.U + mt.io.inst_id := 0.U mt.io.vbank_id := 0.U mt.io.pbank_id := 0.U mt.io.group_id := 0.U @@ -55,10 +66,10 @@ class SharedMemBackend(val b: GlobalConfig) extends Module { // ----------------------------------------------------------------------------- class MappingTableEntry extends Bundle { val valid = Bool() - val hart_id = UInt(b.core.xLen.W) + val hart_id = UInt(b.tile.xLen.W) val vbank_id = UInt(b.memDomain.vbankIdWidth.W) val is_multi = Bool() - val group_id = UInt(log2Up(b.memDomain.bankNum).W) + val group_id = UInt(b.memDomain.groupIdWidth.W) } val mappingTable = RegInit(VecInit(Seq.fill(totalBanks)(0.U.asTypeOf(new MappingTableEntry)))) @@ -77,6 +88,7 @@ class SharedMemBackend(val b: GlobalConfig) extends Module { ): Unit = { val duplicate = mappingTable.map(entry => entry.valid && + !(group_id === 0.U && entry.hart_id === hart_id && entry.vbank_id === vbank_id) && (entry.hart_id === hart_id) && (entry.vbank_id === vbank_id) && (entry.group_id === group_id) @@ -110,16 +122,6 @@ class SharedMemBackend(val b: GlobalConfig) extends Module { } } - def getFreePbankId(): UInt = { - val hasFree = mappingTable.map(_.valid === false.B).reduce(_ || _) - when(!hasFree) { - assert(false.B, "SharedMemBackend allocation failed: no free physical shared bank\n") - } - - val freePbankId = mappingTable.indexWhere(_.valid === false.B) - freePbankId - } - // ----------------------------------------------------------------------------- // Default Value // ----------------------------------------------------------------------------- @@ -132,6 +134,7 @@ class SharedMemBackend(val b: GlobalConfig) extends Module { accPipes(i).io.mem_req.is_shared := io.mem_req(i).is_shared accPipes(i).io.mem_req.hart_id := io.mem_req(i).hart_id accPipes(i).io.mem_req.rob_id := io.mem_req(i).rob_id + accPipes(i).io.mem_req.inst_id := io.mem_req(i).inst_id // Bank-side defaults (only driven when a bank is actually connected) accPipes(i).io.sramRead.req.ready := false.B @@ -156,18 +159,36 @@ class SharedMemBackend(val b: GlobalConfig) extends Module { bank.io.sramWrite.resp.ready := true.B } - io.config.ready := true.B + val realloc = io.config.bits.group_id === 0.U + + val freePbankMask = VecInit(mappingTable.map(entry => + !entry.valid || + (realloc && entry.hart_id === io.config.bits.hart_id && entry.vbank_id === io.config.bits.vbank_id) + )) + + val hasFreePbank = freePbankMask.asUInt.orR + io.config.ready := !io.config.bits.alloc || hasFreePbank + when(io.config.valid && io.config.bits.alloc && !hasFreePbank) { + assert(false.B, "SharedMemBackend allocation failed: no free physical shared bank\n") + } // ----------------------------------------------------------------------------- // Bank Alloc/Release // ----------------------------------------------------------------------------- + hashMonitors.foreach(_.foreach(_.io.bind := false.B)) + when(io.config.fire) { when(io.config.bits.alloc) { when(io.config.bits.group_id === 0.U) { clearVbank(io.config.bits.hart_id, io.config.bits.vbank_id) } - val pbankId = getFreePbankId() + val pbankId = PriorityEncoder(freePbankMask) + hashMonitors.foreach { hashes => + for (i <- 0 until totalBanks) { + hashes(i).io.bind := pbankId === i.U + } + } printf( p"[SharedMemBackend][ALLOC] hart=${io.config.bits.hart_id} vbank=0x${Hexadecimal(io.config.bits.vbank_id)} " + p"group=${io.config.bits.group_id} pbank=$pbankId is_multi=${io.config.bits.is_multi}\n" @@ -231,6 +252,7 @@ class SharedMemBackend(val b: GlobalConfig) extends Module { mtraces(ch).io.channel := ch.U mtraces(ch).io.hart_id := io.mem_req(ch).hart_id mtraces(ch).io.rob_id := io.mem_req(ch).rob_id + mtraces(ch).io.inst_id := io.mem_req(ch).inst_id mtraces(ch).io.vbank_id := io.mem_req(ch).bank_id mtraces(ch).io.pbank_id := pbankId mtraces(ch).io.group_id := io.mem_req(ch).group_id @@ -292,4 +314,37 @@ class SharedMemBackend(val b: GlobalConfig) extends Module { } } } + + hashMonitors.foreach { hashes => + for (j <- 0 until totalBanks) { + val writeHits = VecInit((0 until totalChannel).map { i => + val activeHart = Mux(accPipes(i).io.busy, accPipes(i).io.hart_id, io.mem_req(i).hart_id) + val activeBank = Mux(accPipes(i).io.busy, accPipes(i).io.bank_id, io.mem_req(i).bank_id) + val activeGroup = Mux(accPipes(i).io.busy, accPipes(i).io.group_id, io.mem_req(i).group_id) + mappingTable(j).valid && + mappingTable(j).hart_id === activeHart && + mappingTable(j).vbank_id === activeBank && + (!mappingTable(j).is_multi || mappingTable(j).group_id === activeGroup) && + accPipes(i).io.sramWrite.req.fire + }) + val writeValid = writeHits.asUInt.orR + val monitor = hashes(j) + + monitor.io.write.valid := writeValid + monitor.io.write.bits.addr := banks(j).io.sramWrite.req.bits.addr + monitor.io.write.bits.mask := banks(j).io.sramWrite.req.bits.mask + monitor.io.write.bits.data := banks(j).io.sramWrite.req.bits.data + } + } + + io.bank_hashes.foreach { states => + for (i <- 0 until totalBanks) { + states(i).valid := mappingTable(i).valid + states(i).hartId := mappingTable(i).hart_id + states(i).vbankId := mappingTable(i).vbank_id + states(i).pbankId := i.U + states(i).groupId := mappingTable(i).group_id + states(i).statusHash := hashMonitors.get(i).io.statusHash + } + } } diff --git a/arch/src/main/scala/framework/memdomain/configs/MemDomainParam.scala b/arch/src/main/scala/framework/memdomain/configs/MemDomainParam.scala index 96d7cb237..015045b60 100644 --- a/arch/src/main/scala/framework/memdomain/configs/MemDomainParam.scala +++ b/arch/src/main/scala/framework/memdomain/configs/MemDomainParam.scala @@ -17,8 +17,10 @@ case class MemDomainParam( virtualBankCount: Int, sharedEnable: Boolean, sharedEntries: Int, + sharedBankNum: Int, sharedInputChannels: Int, sharedDefaultGroupCount: Int, + nCores: Int, tlb_size: Int, dma_n_xacts: Int, dma_burst_maxbytes: Int, @@ -35,9 +37,12 @@ case class MemDomainParam( mmioReadWidth: Int) { // MMIO derived values - val mmioBankBytes: Int = mmioBankEntries * (mmioBankWidth / 8) - val mmioTotalBytes: Int = mmioBankNum * mmioBankBytes - val vbankIdWidth: Int = chisel3.util.log2Up(virtualBankCount) + val mmioBankBytes: Int = mmioBankEntries * (mmioBankWidth / 8) + val mmioTotalBytes: Int = mmioBankNum * mmioBankBytes + val vbankIdWidth: Int = chisel3.util.log2Up(virtualBankCount) + val maxGroupCount: Int = math.max(bankNum, if (sharedEnable) sharedBankNum else bankNum) + val groupCountWidth: Int = chisel3.util.log2Up(maxGroupCount + 1) + val groupIdWidth: Int = chisel3.util.log2Up(maxGroupCount) } object MemDomainParam { @@ -52,8 +57,10 @@ object MemDomainParam { virtualBankCount = 0, sharedEnable = false, sharedEntries = 0, + sharedBankNum = 0, sharedInputChannels = 0, sharedDefaultGroupCount = 0, + nCores = 0, tlb_size = 0, dma_n_xacts = 0, dma_burst_maxbytes = 0, diff --git a/arch/src/main/scala/framework/memdomain/frontend/MemFrontend.scala b/arch/src/main/scala/framework/memdomain/frontend/MemFrontend.scala index 070215e86..7b13f75a4 100644 --- a/arch/src/main/scala/framework/memdomain/frontend/MemFrontend.scala +++ b/arch/src/main/scala/framework/memdomain/frontend/MemFrontend.scala @@ -58,9 +58,9 @@ class MemFrontend(val b: GlobalConfig)(edge: TLEdgeOut) extends Module { // Query interface to backend for group count val query_vbank_id = Output(UInt(b.memDomain.vbankIdWidth.W)) val query_is_shared = Output(Bool()) - val query_group_count = Input(UInt(log2Up(b.memDomain.bankNum + 1).W)) + val query_group_count = Input(UInt(b.memDomain.groupCountWidth.W)) - val hartid = Input(UInt(b.core.xLen.W)) + val hartid = Input(UInt(b.tile.xLen.W)) // Busy signal val busy = Output(Bool()) diff --git a/arch/src/main/scala/framework/memdomain/frontend/cmd/decoder/DomainDecoder.scala b/arch/src/main/scala/framework/memdomain/frontend/cmd/decoder/DomainDecoder.scala index dcd6140c9..336a7e229 100644 --- a/arch/src/main/scala/framework/memdomain/frontend/cmd/decoder/DomainDecoder.scala +++ b/arch/src/main/scala/framework/memdomain/frontend/cmd/decoder/DomainDecoder.scala @@ -74,7 +74,8 @@ class MemDomainDecoder(val b: GlobalConfig) extends Module { val rs2 = io.cmd_i.bits.cmd.rs2Data // Unified encoding: - // rs1[9:0] = bank_id (BANK0) + // rs1[9:0] = read/config bank (BANK0) + // rs1[29:20] = write bank (BANK2) // rs1[63:30] = iter (34-bit) // funct7[6:4] = enable (bank access flags, decoded by GlobalDecoder) // rs2[38:0] = mem_addr (for MVIN/MVOUT, 39-bit) @@ -85,8 +86,8 @@ class MemDomainDecoder(val b: GlobalConfig) extends Module { val ls_default_decode = List(N, N, DADDR, DADDR, DSPECIAL, N) val ls_decode_list = ListLookup(func7, ls_default_decode, Array( MSET_BITPAT -> List(N, N, 0.U(memAddrLen.W), rs1(bankIdLen - 1, 0), rs2, Y), - MVIN_BITPAT -> List(Y, N, rs2(memAddrLen - 1, 0), rs1(bankIdLen - 1, 0), rs2, Y), - MVIN_2D_BITPAT -> List(Y, N, rs2(31, 0), rs1(bankIdLen - 1, 0), rs2, Y), + MVIN_BITPAT -> List(Y, N, rs2(memAddrLen - 1, 0), rs1(bankIdLen + 19, 20), rs2, Y), + MVIN_2D_BITPAT -> List(Y, N, rs2(31, 0), rs1(bankIdLen + 19, 20), rs2, Y), MVOUT_BITPAT -> List(N, Y, rs2(memAddrLen - 1, 0), rs1(bankIdLen - 1, 0), rs2, Y), MVIN_MMIO_BITPAT -> List(Y, N, rs2(memAddrLen - 1, 0), 0.U(bankIdLen.W), rs2, Y) ) @@ -104,7 +105,7 @@ class MemDomainDecoder(val b: GlobalConfig) extends Module { // ----------------------------------------------------------------------------- io.mem_decode_cmd_o.valid := io.cmd_i.valid && (io.cmd_i.bits.domain_id === DomainId.MEM) - val raw_bank_id = rs1(9, 0) + val raw_bank_id = Mux(func7 === MVIN_BITPAT || func7 === MVIN_2D_BITPAT, rs1(29, 20), rs1(9, 0)) val shared_bank_id = b.memDomain.sharedEnable.B && raw_bank_id >= sharedBankIdBase.U // format: off // BB_BANK0 is encoded in rs1[9:0]. Keep the configured architectural ID; @@ -136,6 +137,9 @@ class MemDomainDecoder(val b: GlobalConfig) extends Module { assert(rs2(54, 49) + height * width <= b.memDomain.bankEntries.U, "MVIN_2D destination exceeds bank") assert(rs2(63, 62) === 0.U, "MVIN_2D reserves rs2[63:62]") } + when(io.cmd_i.fire && (func7 === MVIN_BITPAT || func7 === MVIN_2D_BITPAT)) { + assert(rs1(19, 0) === 0.U, "MVIN write-bank encoding reserves rs1[19:0]") + } val ls_bank_id = ls_decode_list(LSDecodeFields.BANK_ID.id).asUInt io.mem_decode_cmd_o.bits.bank_id := Mux(io.mem_decode_cmd_o.valid, ls_bank_id, 0.U(b.memDomain.vbankIdWidth.W)) diff --git a/arch/src/main/scala/framework/memdomain/frontend/mem/MemConfiger.scala b/arch/src/main/scala/framework/memdomain/frontend/mem/MemConfiger.scala index 9836ef492..e38cf490a 100644 --- a/arch/src/main/scala/framework/memdomain/frontend/mem/MemConfiger.scala +++ b/arch/src/main/scala/framework/memdomain/frontend/mem/MemConfiger.scala @@ -4,6 +4,7 @@ import chisel3._ import chisel3.util._ import framework.top.GlobalConfig import framework.balldomain.blink.BankWrite +import framework.memdomain.backend.shared.SharedMemLayout import framework.memdomain.frontend.cmd.rs.{MemRsComplete, MemRsIssue} import chisel3.experimental.hierarchy.{instantiable, public, Instance, Instantiate} @@ -12,8 +13,8 @@ class MemConfigerIO(val b: GlobalConfig) extends Bundle { val is_shared = Output(Bool()) val is_multi = Output(Bool()) val alloc = Output(Bool()) - val group_id = Output(UInt(log2Up(b.memDomain.bankNum).W)) - val hart_id = Output(UInt(b.core.xLen.W)) + val group_id = Output(UInt(b.memDomain.groupIdWidth.W)) + val hart_id = Output(UInt(b.tile.xLen.W)) } @instantiable @@ -25,7 +26,7 @@ class MemConfiger(val b: GlobalConfig) extends Module { val cmdReq = Flipped(Decoupled(new MemRsIssue(b))) val cmdResp = Decoupled(new MemRsComplete(b)) val config = Decoupled(new MemConfigerIO(b)) - val hartid = Input(UInt(b.core.xLen.W)) + val hartid = Input(UInt(b.tile.xLen.W)) val bankWrite = Flipped(new BankWrite(b)) }) @@ -34,13 +35,13 @@ class MemConfiger(val b: GlobalConfig) extends Module { val state = RegInit(idle) val alloc_reg = RegInit(false.B) val is_shared_reg = RegInit(false.B) - val col_reg = RegInit(0.U(log2Up(b.memDomain.bankNum + 1).W)) + val col_reg = RegInit(0.U(b.memDomain.groupCountWidth.W)) val clear_reg = RegInit(false.B) val vbank_id_reg = RegInit(0.U(b.memDomain.vbankIdWidth.W)) val rob_id_reg = RegInit(0.U(rob_id_width.W)) val is_sub_reg = RegInit(false.B) val sub_rob_id_reg = RegInit(0.U(log2Up(b.frontend.sub_rob_depth * 4).W)) - val counter = RegInit(0.U(log2Up(b.memDomain.bankNum + 1).W)) + val counter = RegInit(0.U(b.memDomain.groupCountWidth.W)) val zeroLastRow = RegInit(false.B) val zeroLines: Instance[ZeroLineGenerator] = Instantiate(new ZeroLineGenerator(b.memDomain.bankWidth)) @@ -65,7 +66,7 @@ class MemConfiger(val b: GlobalConfig) extends Module { io.bankWrite.bank_id := vbank_id_reg io.bankWrite.rob_id := rob_id_reg io.bankWrite.ball_id := 0.U - io.bankWrite.group_id := counter(log2Up(b.memDomain.bankNum) - 1, 0) + io.bankWrite.group_id := counter(b.memDomain.groupIdWidth - 1, 0) zeroLines.io.req.valid := state === zeroReq zeroLines.io.req.bits.rows := b.memDomain.bankEntries.U @@ -78,7 +79,16 @@ class MemConfiger(val b: GlobalConfig) extends Module { when(io.cmdReq.fire) { val rawCol = io.cmdReq.bits.cmd.special(9, 5) val alloc = io.cmdReq.bits.cmd.special(10) - val fullCol = b.memDomain.bankNum.U(col_reg.getWidth.W) + val fullCol = + if (b.memDomain.sharedEnable) { + Mux( + io.cmdReq.bits.cmd.is_shared, + SharedMemLayout.totalBank(b).U(col_reg.getWidth.W), + b.memDomain.bankNum.U(col_reg.getWidth.W) + ) + } else { + b.memDomain.bankNum.U(col_reg.getWidth.W) + } state := config col_reg := Mux(alloc && rawCol === 0.U, fullCol, Mux(rawCol > 1.U, rawCol, 1.U)) @@ -101,7 +111,7 @@ class MemConfiger(val b: GlobalConfig) extends Module { io.config.bits.is_shared := is_shared_reg io.config.bits.alloc := alloc_reg io.config.bits.vbank_id := vbank_id_reg - io.config.bits.group_id := counter(log2Up(b.memDomain.bankNum) - 1, 0) + io.config.bits.group_id := counter(b.memDomain.groupIdWidth - 1, 0) io.config.valid := true.B when(io.config.fire) { diff --git a/arch/src/main/scala/framework/memdomain/frontend/mem/MemLoader.scala b/arch/src/main/scala/framework/memdomain/frontend/mem/MemLoader.scala index e92efb6b5..38af49164 100644 --- a/arch/src/main/scala/framework/memdomain/frontend/mem/MemLoader.scala +++ b/arch/src/main/scala/framework/memdomain/frontend/mem/MemLoader.scala @@ -33,7 +33,7 @@ class MemLoader(val b: GlobalConfig) extends Module { val query_valid = Output(Bool()) val query_vbank_id = Output(UInt(b.memDomain.vbankIdWidth.W)) val query_is_shared = Output(Bool()) - val query_group_count = Input(UInt(log2Up(b.memDomain.bankNum + 1).W)) + val query_group_count = Input(UInt(b.memDomain.groupCountWidth.W)) // Propagate decoded shared/private access intent. val is_shared = Output(Bool()) @@ -55,8 +55,8 @@ class MemLoader(val b: GlobalConfig) extends Module { val is_shared_reg = RegInit(false.B) // Group counter for multi-bank writes - val group_counter = RegInit(0.U(log2Up(b.memDomain.bankNum + 1).W)) - val group_count_reg = RegInit(0.U(log2Up(b.memDomain.bankNum + 1).W)) + val group_counter = RegInit(0.U(b.memDomain.groupCountWidth.W)) + val group_count_reg = RegInit(0.U(b.memDomain.groupCountWidth.W)) val rowAddr = RegInit(0.U(log2Ceil(b.memDomain.bankEntries).W)) // MMIO routing info (latched at cmdReq.fire, exposed to upper level) @@ -116,7 +116,7 @@ class MemLoader(val b: GlobalConfig) extends Module { io.bankWrite.rob_id := rob_id_reg io.bankWrite.bank_id := wr_bank_reg io.bankWrite.ball_id := 0.U - io.bankWrite.group_id := group_counter(log2Up(b.memDomain.bankNum) - 1, 0) + io.bankWrite.group_id := group_counter(b.memDomain.groupIdWidth - 1, 0) io.is_shared := is_shared_reg // cmdResp (Decoupled): hold valid until accepted diff --git a/arch/src/main/scala/framework/memdomain/frontend/mem/MemStorer.scala b/arch/src/main/scala/framework/memdomain/frontend/mem/MemStorer.scala index dab5eb880..f426377f9 100644 --- a/arch/src/main/scala/framework/memdomain/frontend/mem/MemStorer.scala +++ b/arch/src/main/scala/framework/memdomain/frontend/mem/MemStorer.scala @@ -33,7 +33,7 @@ class MemStorer(val b: GlobalConfig) extends Module { val query_valid = Output(Bool()) val query_vbank_id = Output(UInt(b.memDomain.vbankIdWidth.W)) val query_is_shared = Output(Bool()) - val query_group_count = Input(UInt(log2Up(b.memDomain.bankNum + 1).W)) + val query_group_count = Input(UInt(b.memDomain.groupCountWidth.W)) // Propagate decoded shared/private access intent. val is_shared = Output(Bool()) @@ -52,11 +52,11 @@ class MemStorer(val b: GlobalConfig) extends Module { val iter_reg = RegInit(0.U(b.frontend.iter_len.W)) val rd_bank_reg = RegInit(0.U(b.memDomain.vbankIdWidth.W)) val stride_reg = RegInit(1.U(19.W)) - val group_count_reg = RegInit(1.U(log2Up(b.memDomain.bankNum + 1).W)) + val group_count_reg = RegInit(1.U(b.memDomain.groupCountWidth.W)) val is_shared_reg = RegInit(false.B) val addr_counter = RegInit(0.U(b.frontend.iter_len.W)) - val group_counter = RegInit(0.U(log2Up(b.memDomain.bankNum + 1).W)) + val group_counter = RegInit(0.U(b.memDomain.groupCountWidth.W)) val cursor = RegInit(0.U(b.memDomain.memAddrLen.W)) val rowDelta = RegInit(0.U(b.memDomain.memAddrLen.W)) @@ -133,7 +133,7 @@ class MemStorer(val b: GlobalConfig) extends Module { io.bankRead.rob_id := rob_id_reg io.bankRead.bank_id := target_bank io.bankRead.ball_id := 0.U - io.bankRead.group_id := group_counter(log2Up(b.memDomain.bankNum) - 1, 0) + io.bankRead.group_id := group_counter(b.memDomain.groupIdWidth - 1, 0) io.is_shared := is_shared_reg io.bankRead.io.req.valid := (state === s_issue_sram_req) diff --git a/arch/src/main/scala/framework/memdomain/frontend/mem/dma/StreamReader.scala b/arch/src/main/scala/framework/memdomain/frontend/mem/dma/StreamReader.scala index b657e8d1e..ddd4f6f4d 100644 --- a/arch/src/main/scala/framework/memdomain/frontend/mem/dma/StreamReader.scala +++ b/arch/src/main/scala/framework/memdomain/frontend/mem/dma/StreamReader.scala @@ -89,7 +89,7 @@ class StreamReader(val b: GlobalConfig)(edge: TLEdgeOut) extends Module { val bytesLeft = reqReg.len - bytesRequested val groupsLeftInRow = reqReg.groups - groupIdx val rowBytesLeft = groupsLeftInRow << lgBeat - val pageBytesLeft = (1.U << b.core.pgIdxBits) - readVaddr(b.core.pgIdxBits - 1, 0) + val pageBytesLeft = (1.U << b.tile.pgIdxBits) - readVaddr(b.tile.pgIdxBits - 1, 0) val maxBurstBytes = Seq(bytesLeft, rowBytesLeft, pageBytesLeft, burstMaxBytes.U).reduce((a, c) => Mux(a < c, a, c)) val burstCandidates = Iterator.iterate(beatBytes)(_ * 2).takeWhile(_ <= burstMaxBytes).toSeq diff --git a/arch/src/main/scala/framework/memdomain/frontend/mem/dma/StreamWriter.scala b/arch/src/main/scala/framework/memdomain/frontend/mem/dma/StreamWriter.scala index b4af052a6..fe42f5b96 100644 --- a/arch/src/main/scala/framework/memdomain/frontend/mem/dma/StreamWriter.scala +++ b/arch/src/main/scala/framework/memdomain/frontend/mem/dma/StreamWriter.scala @@ -23,7 +23,7 @@ class BBWriteResponse extends Bundle { @instantiable class StreamWriter(val b: GlobalConfig)(edge: TLEdgeOut) extends Module { - val vaddrBits = b.core.vaddrBits + val vaddrBits = b.tile.vaddrBits val beatBits = b.memDomain.dma_buswidth val dataWidth = b.memDomain.dma_buswidth val beatBytes = beatBits / 8 diff --git a/arch/src/main/scala/framework/memdomain/frontend/mem/tlb/BBTLBIO.scala b/arch/src/main/scala/framework/memdomain/frontend/mem/tlb/BBTLBIO.scala index ec84cc19d..719de6882 100644 --- a/arch/src/main/scala/framework/memdomain/frontend/mem/tlb/BBTLBIO.scala +++ b/arch/src/main/scala/framework/memdomain/frontend/mem/tlb/BBTLBIO.scala @@ -146,12 +146,12 @@ class BBPMP(val paddrBits: Int) extends Bundle { // PTW IO class BBTLBPTWIO(val b: GlobalConfig) extends Bundle { - val vaddrBits = b.core.vaddrBits - val paddrBits = b.core.paddrBits - val pgIdxBits = b.core.pgIdxBits - val xLen = b.core.xLen - val pgLevels = b.rocketCore.pgLevels - val nPMPs = b.core.nPMPs + val vaddrBits = b.tile.vaddrBits + val paddrBits = b.tile.paddrBits + val pgIdxBits = b.tile.pgIdxBits + val xLen = b.tile.xLen + val pgLevels = b.tile.pgLevels + val nPMPs = b.tile.nPMPs val req = Decoupled(Valid(new BBTLBPTWReq(vaddrBits, pgIdxBits))) val resp = Flipped(Valid(new BBTLBPTWResp(vaddrBits, paddrBits, pgIdxBits, pgLevels))) @@ -167,7 +167,7 @@ class BBTLBPTWIO(val b: GlobalConfig) extends Bundle { // TLB Client IO (used in TLBCluster) class BBTLBIO(val b: GlobalConfig) extends Bundle { - val lgMaxSize = log2Ceil(b.core.coreDataBytes) - val req = Flipped(Decoupled(new BBTLBReq(lgMaxSize, b.core.vaddrBits, b.core.xLen))) - val resp = Decoupled(new BBTLBResp(lgMaxSize, b.core.paddrBits, b.core.vaddrBits)) + val lgMaxSize = log2Ceil(b.tile.coreDataBytes) + val req = Flipped(Decoupled(new BBTLBReq(lgMaxSize, b.tile.vaddrBits, b.tile.xLen))) + val resp = Decoupled(new BBTLBResp(lgMaxSize, b.tile.paddrBits, b.tile.vaddrBits)) } diff --git a/arch/src/main/scala/framework/memdomain/frontend/mem/tlb/TLB.scala b/arch/src/main/scala/framework/memdomain/frontend/mem/tlb/TLB.scala index d20708ae0..0375587a9 100644 --- a/arch/src/main/scala/framework/memdomain/frontend/mem/tlb/TLB.scala +++ b/arch/src/main/scala/framework/memdomain/frontend/mem/tlb/TLB.scala @@ -10,16 +10,16 @@ import framework.top.GlobalConfig @instantiable class TLB(val b: GlobalConfig, val lgMaxSize: Int) extends Module { val entries = b.memDomain.tlb_size - val vaddrBits = b.core.vaddrBits - val paddrBits = b.core.paddrBits - val pgIdxBits = b.core.pgIdxBits + val vaddrBits = b.tile.vaddrBits + val paddrBits = b.tile.paddrBits + val pgIdxBits = b.tile.pgIdxBits val vpnBits = vaddrBits - pgIdxBits val ppnBits = paddrBits - pgIdxBits - val pgLevels = b.rocketCore.pgLevels + val pgLevels = b.tile.pgLevels @public val io = IO(new Bundle { - val req = Flipped(Decoupled(new BBTLBReq(lgMaxSize, vaddrBits, b.core.xLen))) + val req = Flipped(Decoupled(new BBTLBReq(lgMaxSize, vaddrBits, b.tile.xLen))) val resp = Decoupled(new BBTLBResp(lgMaxSize, paddrBits, vaddrBits)) val ptw = new BBTLBPTWIO(b) val sfence = Flipped(Valid(Bool())) // Simplified flush signal diff --git a/arch/src/main/scala/framework/memdomain/frontend/mem/tlb/TLBCluster.scala b/arch/src/main/scala/framework/memdomain/frontend/mem/tlb/TLBCluster.scala index 9ed9e71d7..5982162a4 100644 --- a/arch/src/main/scala/framework/memdomain/frontend/mem/tlb/TLBCluster.scala +++ b/arch/src/main/scala/framework/memdomain/frontend/mem/tlb/TLBCluster.scala @@ -11,11 +11,11 @@ class BBTLBCluster(val b: GlobalConfig)(implicit val edge: TLEdgeOut) extends Mo val nClients = 2 val entries = b.memDomain.tlb_size - val maxSize = b.core.coreDataBytes - val lgMaxSize = log2Ceil(b.core.coreDataBytes) - val vaddrBits = b.core.vaddrBits - val paddrBits = b.core.paddrBits - val pgIdxBits = b.core.pgIdxBits + val maxSize = b.tile.coreDataBytes + val lgMaxSize = log2Ceil(b.tile.coreDataBytes) + val vaddrBits = b.tile.vaddrBits + val paddrBits = b.tile.paddrBits + val pgIdxBits = b.tile.pgIdxBits @public val io = IO(new Bundle { @@ -33,7 +33,7 @@ class BBTLBCluster(val b: GlobalConfig)(implicit val edge: TLEdgeOut) extends Mo // Connect PTW io.ptw(0) <> tlb.io.ptw - val tlbArb = Module(new RRArbiter(new BBTLBReq(lgMaxSize, vaddrBits, b.core.xLen), nClients)) + val tlbArb = Module(new RRArbiter(new BBTLBReq(lgMaxSize, vaddrBits, b.tile.xLen), nClients)) val tlbArbOut = tlbArb.io.out val tlb_io = tlb.io diff --git a/arch/src/main/scala/framework/memdomain/midend/MemMidend.scala b/arch/src/main/scala/framework/memdomain/midend/MemMidend.scala index 2fc76a7dd..2b0b10c63 100644 --- a/arch/src/main/scala/framework/memdomain/midend/MemMidend.scala +++ b/arch/src/main/scala/framework/memdomain/midend/MemMidend.scala @@ -5,7 +5,7 @@ import chisel3.util._ import framework.top.GlobalConfig import framework.balldomain.blink.{BankRead, BankWrite} import chisel3.experimental.hierarchy.{instantiable, public} -import framework.memdomain.backend.{MTraceIssueDPI, MemRequestIO} +import framework.memdomain.backend.MemRequestIO // BankRead/BankWrite with is_shared flag, used for unified midend interface class BankReadWithShared(val b: GlobalConfig) extends Bundle { @@ -44,7 +44,8 @@ class MemMidend(val b: GlobalConfig) extends Module { val ballChannelActive = Input(Vec(b.ballDomain.ballNum, Bool())) val ballChannelReady = Output(Vec(b.ballDomain.ballNum, Bool())) - val hartid = Input(UInt(b.core.xLen.W)) + val hartid = Input(UInt(b.tile.xLen.W)) + val inst_ids = Input(Vec(b.frontend.rob_entries, UInt(64.W))) // Output to backend (MemManager) val mem_req = Vec(b.memDomain.bankChannel, new MemRequestIO(b)) @@ -169,6 +170,7 @@ class MemMidend(val b: GlobalConfig) extends Module { io.mem_req(i).is_shared := false.B io.mem_req(i).hart_id := io.hartid io.mem_req(i).rob_id := 0.U + io.mem_req(i).inst_id := 0.U val isRead = mappingTable(i).isRead val rid = mappingTable(i).id @@ -197,6 +199,7 @@ class MemMidend(val b: GlobalConfig) extends Module { io.mem_req(i).group_id := rgroup_id io.mem_req(i).is_shared := r_shared io.mem_req(i).rob_id := rrob_id + io.mem_req(i).inst_id := io.inst_ids(rrob_id) } }.otherwise { when(ballRouteOpen) { @@ -205,27 +208,12 @@ class MemMidend(val b: GlobalConfig) extends Module { io.mem_req(i).group_id := wgroup_id io.mem_req(i).is_shared := w_shared io.mem_req(i).rob_id := wrob_id + io.mem_req(i).inst_id := io.inst_ids(wrob_id) } } } } - // Count the actual write beats accepted by each backend channel. This is the - // generation-side event at the same granularity as the target SRAM `fire` - // arrival event, while remaining upstream of the backend/physical-bank path. - // A DPI instance per channel preserves simultaneous accepted beats. - val writeIssueTraces = Seq.fill(b.memDomain.bankChannel)(Module(new MTraceIssueDPI)) - for (i <- 0 until b.memDomain.bankChannel) { - writeIssueTraces(i).io.clock := clock - writeIssueTraces(i).io.reset := reset.asBool - writeIssueTraces(i).io.hart_id := io.mem_req(i).hart_id - writeIssueTraces(i).io.is_shared := io.mem_req(i).is_shared.asUInt - writeIssueTraces(i).io.rob_id := io.mem_req(i).rob_id - writeIssueTraces(i).io.vbank_id := io.mem_req(i).bank_id - writeIssueTraces(i).io.group_id := io.mem_req(i).group_id - writeIssueTraces(i).io.enable := io.mem_req(i).write.req.fire - } - // Mapping table release for (i <- 0 until b.memDomain.bankChannel) { val releaseCounter = RegInit(0.U(5.W)) diff --git a/arch/src/main/scala/framework/root/root-chip/build.sc b/arch/src/main/scala/framework/root/root-chip/build.sc index 3ae7a6e21..9f7ab1550 100644 --- a/arch/src/main/scala/framework/root/root-chip/build.sc +++ b/arch/src/main/scala/framework/root/root-chip/build.sc @@ -27,17 +27,12 @@ object bank extends ChiselModule { override def moduleDeps = Seq(axis) } -object cache extends ChiselModule { - override def moduleRoot = memCoreRoot / "cache" - override def moduleDeps = Seq(chi) -} - object coherence extends ChiselModule { override def moduleRoot = memCoreRoot / "coherence" - override def moduleDeps = Seq(chi, cache) + override def moduleDeps = Seq(chi) } object root_chip extends ChiselModule { override def moduleRoot = os.pwd - override def moduleDeps = Seq(axis, chi, bank, coherence, cache) + override def moduleDeps = Seq(axis, chi, bank, coherence) } diff --git a/arch/src/main/scala/framework/root/root-chip/src/main/scala/chip/mesh/CoherentMeshSystem.scala b/arch/src/main/scala/framework/root/root-chip/src/main/scala/chip/mesh/CoherentMeshSystem.scala index ad5eaa503..28fdf57c4 100644 --- a/arch/src/main/scala/framework/root/root-chip/src/main/scala/chip/mesh/CoherentMeshSystem.scala +++ b/arch/src/main/scala/framework/root/root-chip/src/main/scala/chip/mesh/CoherentMeshSystem.scala @@ -4,7 +4,10 @@ import chisel3._ import chisel3.util._ import chisel3.experimental.hierarchy.{Instance, Instantiate} import memcore.bus.chi._ -import memcore.memory.cache._ +import memcore.bus.chi.hnf.ChiHome +import memcore.bus.chi.rnf.{BankedChiCache, CacheAccess, CacheResult} +import memcore.bus.chi.rni.{NpuBeat, NpuCommand, NpuRegionAgent, RegionDirectory, RegionEntry} +import memcore.bus.chi.snf.{LineRequest, LineResponse, LineSram} import memcore.memory.coherence._ /** diff --git a/arch/src/main/scala/framework/system/configloader/ChipLoader.scala b/arch/src/main/scala/framework/system/configloader/ChipLoader.scala index cca96cefa..5edb8a9a9 100644 --- a/arch/src/main/scala/framework/system/configloader/ChipLoader.scala +++ b/arch/src/main/scala/framework/system/configloader/ChipLoader.scala @@ -1,15 +1,16 @@ package framework.system.configloader import buckyball.config.{ - BoomCoreConfig, + BoomCpuConfig, Chip, CoreInstance, - CoreParamConfig, + CpuConfig, FrontendConfig, GpDomainConfig, MemDomainConfig, - RocketCoreConfig, + RocketCpuConfig, SharedMemConfig, + TileParamConfig, TilePlacement } import java.nio.file.{Files, Path, Paths} @@ -17,12 +18,11 @@ import framework.balldomain.configs.{BallDomainParam, BallISAEntry, BallIdMappin import framework.frontend.configs.FrontendParam import framework.gpdomain.configs.GpDomainParam import framework.memdomain.configs.MemDomainParam -import framework.system.core.configs.CoreParam -import framework.system.core.boom.configs.{BoomCoreParam, BoomDCacheParam, BoomICacheParam} +import framework.system.core.boom.configs.{BoomCpuParam, BoomDCacheParam, BoomICacheParam} import framework.system.core.rocket.configs._ import framework.system.tile.PrivateDCacheParams +import framework.system.tile.configs.TileParam import framework.top.GlobalConfig -import framework.top.configs.TopConfig import scala.jdk.CollectionConverters._ /** Load ExampleTopology from chip.pb. */ @@ -74,12 +74,10 @@ object ChipLoader { } private def parseTile(tile: TilePlacement, cores: Seq[CoreInstance], repo: Path): TileTopology = { - val indices = tile.getCoreIndicesList.asScala.map(_.toInt).toSeq - val nCores = indices.size - val hasBuckyball = indices.exists(i => cores(i).getBalldomain.getBallNum > 0) - val memBallChannelNum = - if (hasBuckyball) tile.getMemBallChannelNum - else 0 + val indices = tile.getCoreIndicesList.asScala.map(_.toInt).toSeq + val nCores = indices.size + val hasBuckyball = indices.exists(i => cores(i).getBalldomain.getBallNum > 0) + val tileParam = parseTileParam(tile.getParam) val shared = tile.getSharedMem val virtualBankCount = tile.getVirtualBankCount @@ -87,21 +85,22 @@ object ChipLoader { if (hasBuckyball) { require(virtualBankCount > 0, s"tile ${tile.getPath}: virtual_bank_count must be > 0") } - if (shared.getEnable) { - val first = cores(indices.head) - val firstBank = first.getMem.getBank - indices.iterator.map(idx => cores(idx)).filter(_.getBalldomain.getBallNum > 0).foreach { core => + val sharedBankNum = + if (shared.getEnable) { + val firstBank = cores(indices.head).getMem.getBank + indices.iterator.map(idx => cores(idx)).filter(_.getBalldomain.getBallNum > 0).foreach { core => + require( + core.getMem.getBank.getWidth == firstBank.getWidth, + s"tile ${tile.getPath}: all Buckyball cores must use shared bank width ${firstBank.getWidth}" + ) + } + require(shared.getEntries > 0, s"tile ${tile.getPath}: shared entries must be > 0") require( - core.getMem.getBank.getWidth == firstBank.getWidth, - s"tile ${tile.getPath}: all Buckyball cores must use shared bank width ${firstBank.getWidth}" + shared.getEntries % firstBank.getEntries == 0, + s"tile ${tile.getPath}: shared entries ${shared.getEntries} must be divisible by slot-0 bank entries ${firstBank.getEntries}" ) - } - require(shared.getEntries > 0, s"tile ${tile.getPath}: shared entries must be > 0") - require( - shared.getEntries % firstBank.getEntries == 0, - s"tile ${tile.getPath}: shared entries ${shared.getEntries} must be divisible by slot-0 bank entries ${firstBank.getEntries}" - ) - } + shared.getEntries / firstBank.getEntries + } else 0 val privateDCache = if (!tile.hasPrivateDcache || !tile.getPrivateDcache.getEnable) None else { @@ -118,54 +117,59 @@ object ChipLoader { } val tileCores = indices.map { idx => - parseCore(cores(idx), shared, virtualBankCount, memBallChannelNum, nCores, repo) + parseCore(cores(idx), tileParam, shared, sharedBankNum, virtualBankCount, nCores, repo) } - TileTopology(tileCores, privateDCache) + TileTopology(tileParam, tileCores, privateDCache) } private def parseCore( - core: CoreInstance, - shared: SharedMemConfig, - virtualBankCount: Int, - memBallChannelNum: Int, - nCores: Int, - repo: Path + core: CoreInstance, + tile: TileParam, + shared: SharedMemConfig, + sharedBankNum: Int, + virtualBankCount: Int, + nCores: Int, + repo: Path ): TileCore = { - val kind = core.getKind + require(core.hasCpu, s"core ${core.getPkg}: missing cpu config") + val cpu = core.getCpu + val kind = cpu.getKind kind match { - case "rocket" => parseRocketCoreSlot(core, shared, virtualBankCount, memBallChannelNum, nCores, repo) + case "rocket" => parseRocketCoreSlot(core, tile, shared, sharedBankNum, virtualBankCount, nCores, repo) case "boom" => if (core.getBalldomain.getBallNum > 0) { throw new RuntimeException(s"core ${core.getPkg}: kind=boom forbids balldomain") } - if (!core.hasBoomCore) { - throw new RuntimeException(s"core ${core.getPkg}: kind=boom missing boom_core") + if (!cpu.hasBoom) { + throw new RuntimeException(s"core ${core.getPkg}: kind=boom missing cpu.boom") } - BoomTileCore(parseBoomCore(core.getBoomCore)) + BoomTileCore(parseBoomCpu(cpu.getBoom)) case other => throw new RuntimeException(s"core ${core.getPkg}: unsupported kind '$other'") } } private def parseRocketCoreSlot( - core: CoreInstance, - shared: SharedMemConfig, - virtualBankCount: Int, - memBallChannelNum: Int, - nCores: Int, - repo: Path + core: CoreInstance, + tile: TileParam, + shared: SharedMemConfig, + sharedBankNum: Int, + virtualBankCount: Int, + nCores: Int, + repo: Path ): RocketTileCore = { - if (!core.hasRocketCore) { - throw new RuntimeException(s"core ${core.getPkg}: kind=rocket missing rocket_core") + val cpu = core.getCpu + if (!cpu.hasRocket) { + throw new RuntimeException(s"core ${core.getPkg}: kind=rocket missing cpu.rocket") } - val rocket = parseRocketCore(core.getRocketCore) + val rocket = parseRocketCpu(cpu.getRocket) val domain = core.getBalldomain if (domain.getBallNum == 0) { return RocketTileCore(rocket, None) } require(core.hasFrontend, s"core ${core.getPkg} missing frontend config") require(core.hasGpDomain, s"core ${core.getPkg} missing gpdomain config") - require(core.hasCore, s"core ${core.getPkg} missing core config") + require(tile.coreDataBytes > 0, s"core ${core.getPkg} missing tile config") val frontend = core.getFrontend require( virtualBankCount <= (1 << frontend.getBankIdLen), @@ -190,10 +194,8 @@ object ChipLoader { ballDomain = parseBallDomain(core, repo), frontend = parseFrontend(core.getFrontend), gpDomain = parseGpDomain(core.getGpDomain), - core = parseCoreParam(core.getCore), - memDomain = parseMemDomain(core.getMem, shared, virtualBankCount), - rocketCore = rocket, - top = TopConfig(memBallChannelNum = memBallChannelNum, nCores = nCores) + tile = tile, + memDomain = parseMemDomain(core.getMem, shared, sharedBankNum, virtualBankCount, nCores) ) RocketTileCore(rocket, Some(buckyball)) } @@ -221,7 +223,9 @@ object ChipLoader { private def parseMemDomain( mem: MemDomainConfig, shared: SharedMemConfig, - virtualBankCount: Int + sharedBankNum: Int, + virtualBankCount: Int, + nCores: Int ): MemDomainParam = { val bank = mem.getBank val dma = mem.getDma @@ -236,8 +240,10 @@ object ChipLoader { virtualBankCount = virtualBankCount, sharedEnable = shared.getEnable, sharedEntries = shared.getEntries, + sharedBankNum = sharedBankNum, sharedInputChannels = shared.getInputChannels, sharedDefaultGroupCount = shared.getDefaultGroupCount, + nCores = nCores, tlb_size = tlb.getSize, dma_n_xacts = dma.getNXacts, dma_burst_maxbytes = dma.getBurstMaxBytes, @@ -277,25 +283,24 @@ object ChipLoader { laneScale = gp.getLaneScale ) - private def parseCoreParam(core: CoreParamConfig): CoreParam = - CoreParam( - coreDataBytes = core.getCoreDataBytes, - xLen = core.getXLen, - vaddrBits = core.getVaddrBits, - paddrBits = core.getPaddrBits, - pgIdxBits = core.getPgIdxBits, - nPMPs = core.getNPmps + private def parseTileParam(param: TileParamConfig): TileParam = + TileParam( + coreDataBytes = param.getCoreDataBytes, + xLen = param.getXLen, + vaddrBits = param.getVaddrBits, + paddrBits = param.getPaddrBits, + pgIdxBits = param.getPgIdxBits, + pgLevels = param.getPgLevels, + nPMPs = param.getNPmps ) - private def parseRocketCore(rocket: RocketCoreConfig): RocketCoreParam = { + private def parseRocketCpu(rocket: RocketCpuConfig): RocketCpuParam = { val mulDiv = rocket.getMulDiv val fpu = rocket.getFpu val dcache = rocket.getDcache val icache = rocket.getIcache val btb = rocket.getBtb - RocketCoreParam( - xLen = rocket.getXLen, - pgLevels = rocket.getPgLevels, + RocketCpuParam( useVM = rocket.getUseVm, useZba = rocket.getUseZba, useZbb = rocket.getUseZbb, @@ -329,10 +334,10 @@ object ChipLoader { ) } - private def parseBoomCore(boom: BoomCoreConfig): BoomCoreParam = { + private def parseBoomCpu(boom: BoomCpuConfig): BoomCpuParam = { val dcache = boom.getDcache val icache = boom.getIcache - BoomCoreParam( + BoomCpuParam( fetchWidth = boom.getFetchWidth, decodeWidth = boom.getDecodeWidth, numRobEntries = boom.getNumRobEntries, diff --git a/arch/src/main/scala/framework/system/configloader/Topology.scala b/arch/src/main/scala/framework/system/configloader/Topology.scala index 1d77eb132..d1cfbc296 100644 --- a/arch/src/main/scala/framework/system/configloader/Topology.scala +++ b/arch/src/main/scala/framework/system/configloader/Topology.scala @@ -1,28 +1,22 @@ package framework.system.configloader import framework.system.tile.PrivateDCacheParams -import framework.system.core.rocket.configs.RocketCoreParam -import framework.system.core.boom.configs.BoomCoreParam +import framework.system.core.rocket.configs.RocketCpuParam +import framework.system.core.boom.configs.BoomCpuParam +import framework.system.tile.configs.TileParam import framework.top.GlobalConfig -/** Loader-private bundle of tile-shared memory fields. */ -private[configloader] case class SharedMemFields( - sharedEnable: Boolean, - sharedEntries: Int, - sharedInputChannels: Int, - sharedDefaultGroupCount: Int) - /** Top-level example topology loaded from chip.pb. */ case class ExampleTopology(tiles: Seq[TileTopology]) sealed trait TileCore case class RocketTileCore( - rocket: RocketCoreParam, + cpu: RocketCpuParam, buckyball: Option[GlobalConfig]) extends TileCore -case class BoomTileCore(boom: BoomCoreParam) extends TileCore +case class BoomTileCore(cpu: BoomCpuParam) extends TileCore /** * Per-tile topology: ordered cores + optional privateDCache. @@ -30,5 +24,6 @@ case class BoomTileCore(boom: BoomCoreParam) extends TileCore * CPU kind is per-core. Shared mem / private DCache are tile-level. */ case class TileTopology( + param: TileParam, cores: Seq[TileCore], privateDCache: Option[PrivateDCacheParams]) diff --git a/arch/src/main/scala/framework/system/core/accelerator/BuckyballAccelerator.scala b/arch/src/main/scala/framework/system/core/accelerator/BuckyballAccelerator.scala index 83d51f1f2..0bb51c918 100644 --- a/arch/src/main/scala/framework/system/core/accelerator/BuckyballAccelerator.scala +++ b/arch/src/main/scala/framework/system/core/accelerator/BuckyballAccelerator.scala @@ -15,6 +15,7 @@ import framework.memdomain.backend.shared.SharedMemLayout import framework.memdomain.frontend.mem.{MemConfigerIO} import framework.memdomain.frontend.mem.tlb.{BBTLBExceptionIO, BBTLBPTWIO} import framework.balldomain.BallDomain +import framework.memdomain.backend.banks.btrace.PhysicalBankHash /** * Standalone Buckyball accelerator module. @@ -28,18 +29,19 @@ import framework.balldomain.BallDomain */ @instantiable class BuckyballAccelerator(val b: GlobalConfig)(edge: TLEdgeOut) extends Module { - val totalBallRead = b.ballDomain.ballIdMappings.map(_.inBW).sum - val totalBallWrite = b.ballDomain.ballIdMappings.map(_.outBW).sum + val totalBallRead = b.ballDomain.ballIdMappings.map(_.inBW).sum + val totalBallWrite = b.ballDomain.ballIdMappings.map(_.outBW).sum + val sharedHashCount = if (b.memDomain.sharedEnable) SharedMemLayout.totalBank(b) else 0 @public val io = IO(new Bundle { // RoCC command/response (connected to Rocket core inside tile) - val cmd = Flipped(Decoupled(new RoCCCommandBB(b.core.xLen))) - val resp = Decoupled(new RoCCResponseBB(b.core.xLen)) + val cmd = Flipped(Decoupled(new RoCCCommandBB(b.tile.xLen))) + val resp = Decoupled(new RoCCResponseBB(b.tile.xLen)) val busy = Output(Bool()) val retired = Output(Bool()) val interrupt = Output(Bool()) - val hartid = Input(UInt(b.core.xLen.W)) + val hartid = Input(UInt(b.tile.xLen.W)) // PTW interface (shared with Rocket core's PTW) val ptw = Vec(1, new BBTLBPTWIO(b)) @@ -57,7 +59,14 @@ class BuckyballAccelerator(val b: GlobalConfig)(edge: TLEdgeOut) extends Module val shared_config = Decoupled(new MemConfigerIO(b)) val shared_query_valid = Output(Bool()) val shared_query_vbank_id = Output(UInt(b.memDomain.vbankIdWidth.W)) - val shared_query_group_count = Input(UInt(log2Up(b.memDomain.bankNum + 1).W)) + val shared_query_group_count = Input(UInt(b.memDomain.groupCountWidth.W)) + + val shared_bank_hashes = + if (b.sim.diffTest && b.memDomain.sharedEnable) { + Some(Input(Vec(sharedHashCount, new PhysicalBankHash(b)))) + } else { + None + } // Barrier interface — connected to tile-level BarrierUnit val barrier_arrive = Output(Bool()) @@ -69,6 +78,9 @@ class BuckyballAccelerator(val b: GlobalConfig)(edge: TLEdgeOut) extends Module val ballDomain: Instance[BallDomain] = Instantiate(new BallDomain(b)) val memDomain: Instance[MemDomain] = Instantiate(new MemDomain(b)(edge)) val gpDomain: Instance[GpDomain] = Instantiate(new GpDomain(b)) + frontend.io.hartid := io.hartid + frontend.io.bank_hashes.foreach(_ := memDomain.io.bank_hashes.get) + memDomain.io.shared_bank_hashes.foreach(_ := io.shared_bank_hashes.get) // --- Frontend <- cmd --- frontend.io.cmd.valid := io.cmd.valid @@ -90,7 +102,8 @@ class BuckyballAccelerator(val b: GlobalConfig)(edge: TLEdgeOut) extends Module // --- Frontend -> MemDomain --- memDomain.io.global_issue_i <> frontend.io.mem_issue_o frontend.io.mem_complete_i <> memDomain.io.global_complete_o - memDomain.io.hartid := io.hartid + memDomain.io.hartid := io.hartid + memDomain.io.inst_ids := frontend.io.inst_ids // --- Frontend -> GpDomain --- gpDomain.io.global_issue_i <> frontend.io.gp_issue_o diff --git a/arch/src/main/scala/framework/system/core/boom/configs/BoomCoreParam.scala b/arch/src/main/scala/framework/system/core/boom/configs/BoomCpuParam.scala similarity index 76% rename from arch/src/main/scala/framework/system/core/boom/configs/BoomCoreParam.scala rename to arch/src/main/scala/framework/system/core/boom/configs/BoomCpuParam.scala index 1cd7d2b2c..3514534af 100644 --- a/arch/src/main/scala/framework/system/core/boom/configs/BoomCoreParam.scala +++ b/arch/src/main/scala/framework/system/core/boom/configs/BoomCpuParam.scala @@ -22,24 +22,24 @@ object BoomICacheParam { implicit val rw: ReadWriter[BoomICacheParam] = macroRW } -case class BoomCoreParam( +case class BoomCpuParam( fetchWidth: Int = 4, decodeWidth: Int = 1, numRobEntries: Int = 32, dcache: BoomDCacheParam = BoomDCacheParam(), icache: BoomICacheParam = BoomICacheParam()) -object BoomCoreParam { - implicit val rw: ReadWriter[BoomCoreParam] = macroRW +object BoomCpuParam { + implicit val rw: ReadWriter[BoomCpuParam] = macroRW - def toBoomCoreParams(p: BoomCoreParam): BoomCoreParams = BoomCoreParams( + def toBoomCoreParams(p: BoomCpuParam): BoomCoreParams = BoomCoreParams( fetchWidth = p.fetchWidth, decodeWidth = p.decodeWidth, numRobEntries = p.numRobEntries, fpu = Some(FPUParams(sfmaLatency = 4, dfmaLatency = 4, divSqrt = true)) ) - def toDCacheParams(p: BoomCoreParam, rowBits: Int): DCacheParams = DCacheParams( + def toDCacheParams(p: BoomCpuParam, rowBits: Int): DCacheParams = DCacheParams( rowBits = rowBits, nSets = p.dcache.nSets, nWays = p.dcache.nWays, @@ -47,7 +47,7 @@ object BoomCoreParam { nTLBWays = 8 ) - def toICacheParams(p: BoomCoreParam, rowBits: Int): ICacheParams = ICacheParams( + def toICacheParams(p: BoomCpuParam, rowBits: Int): ICacheParams = ICacheParams( rowBits = rowBits, nSets = p.icache.nSets, nWays = p.icache.nWays, diff --git a/arch/src/main/scala/framework/system/core/rocket/configs/RocketCoreParam.scala b/arch/src/main/scala/framework/system/core/rocket/configs/RocketCpuParam.scala similarity index 82% rename from arch/src/main/scala/framework/system/core/rocket/configs/RocketCoreParam.scala rename to arch/src/main/scala/framework/system/core/rocket/configs/RocketCpuParam.scala index 187ef0015..c41eb0c43 100644 --- a/arch/src/main/scala/framework/system/core/rocket/configs/RocketCoreParam.scala +++ b/arch/src/main/scala/framework/system/core/rocket/configs/RocketCpuParam.scala @@ -5,9 +5,9 @@ import freechips.rocketchip.rocket.{BTBParams, DCacheParams, ICacheParams, MulDi import freechips.rocketchip.tile.FPUParams /** - * JSON-serializable Rocket Core configuration parameters. + * JSON-serializable Rocket CPU configuration parameters. * - * Phase 1: Common parameters (xLen, pgLevels, useVM, Zb*, mulDiv, fpu, cache, btb) + * Phase 1: CPU parameters (useVM, Zb*, mulDiv, fpu, cache, btb) * Phase 2: Advanced parameters (TLB, ECC, clockGate, etc.) - to be added later * * Optional features (mulDiv, fpu, btb) use an `enable` flag instead of Option[T], @@ -101,9 +101,7 @@ object BTBParam { } -case class RocketCoreParam( - xLen: Int = 64, - pgLevels: Int = 3, +case class RocketCpuParam( useVM: Boolean = true, useZba: Boolean = true, useZbb: Boolean = true, @@ -115,16 +113,16 @@ case class RocketCoreParam( icache: ICacheParam = ICacheParam(), btb: BTBParam = BTBParam()) -object RocketCoreParam { - implicit val rw: ReadWriter[RocketCoreParam] = macroRW +object RocketCpuParam { + implicit val rw: ReadWriter[RocketCpuParam] = macroRW /** * Convert to rocket-chip RocketCoreParams. * rowBits and blockBytes are injected from site(SystemBusKey) and site(CacheBlockBytes). */ - def toRocketCoreParams(p: RocketCoreParam): RocketCoreParams = RocketCoreParams( - xLen = p.xLen, - pgLevels = p.pgLevels, + def toRocketCoreParams(p: RocketCpuParam, xLen: Int, pgLevels: Int): RocketCoreParams = RocketCoreParams( + xLen = xLen, + pgLevels = pgLevels, useVM = p.useVM, useZba = p.useZba, useZbb = p.useZbb, @@ -134,12 +132,12 @@ object RocketCoreParam { fpu = FPUParam.toFPUParams(p.fpu) ) - def toDCacheParams(p: RocketCoreParam, rowBits: Int, blockBytes: Int): DCacheParams = + def toDCacheParams(p: RocketCpuParam, rowBits: Int, blockBytes: Int): DCacheParams = DCacheParam.toDCacheParams(p.dcache, rowBits, blockBytes) - def toICacheParams(p: RocketCoreParam, rowBits: Int, blockBytes: Int): ICacheParams = + def toICacheParams(p: RocketCpuParam, rowBits: Int, blockBytes: Int): ICacheParams = ICacheParam.toICacheParams(p.icache, rowBits, blockBytes) - def toBTBParams(p: RocketCoreParam): Option[BTBParams] = + def toBTBParams(p: RocketCpuParam): Option[BTBParams] = BTBParam.toBTBParams(p.btb) } diff --git a/arch/src/main/scala/framework/system/tile/BBTile.scala b/arch/src/main/scala/framework/system/tile/BBTile.scala index d42591bbc..4af88eabf 100644 --- a/arch/src/main/scala/framework/system/tile/BBTile.scala +++ b/arch/src/main/scala/framework/system/tile/BBTile.scala @@ -44,6 +44,7 @@ import framework.system.core.rocket.RocketBB import framework.system.core.rocket.id.RVVRoCCDecode import framework.system.core.accelerator.{BuckyballAccelerator, BuckyballRushBKey, RushBCommandBridge, RushBCoreId} import framework.memdomain.backend.MemRequestIO +import framework.top.configs.SimParamKey import framework.memdomain.backend.shared.SharedMemBackend import framework.memdomain.backend.shared.SharedMemLayout import framework.memdomain.frontend.mem.MemConfigerIO @@ -99,12 +100,15 @@ class BBTile private ( "core-0 must enable buckyball because RoCC cmd/resp is currently wired to core-0 only" ) val cfg0 = bbSharedConfig.get - require(cfg0.top.nCores == nCores, s"buckyball top.nCores (${cfg0.top.nCores}) must equal tile nCores ($nCores)") + require( + cfg0.memDomain.nCores == nCores, + s"buckyball memDomain.nCores (${cfg0.memDomain.nCores}) must equal tile nCores ($nCores)" + ) bbEnabledCoreIds.foreach { i => val cfg = bbPerCore(i).get require( - cfg.top.nCores == nCores, - s"core-$i buckyball top.nCores (${cfg.top.nCores}) must equal tile nCores ($nCores)" + cfg.memDomain.nCores == nCores, + s"core-$i buckyball memDomain.nCores (${cfg.memDomain.nCores}) must equal tile nCores ($nCores)" ) require(cfg.memDomain.bankChannel == cfg0.memDomain.bankChannel, s"core-$i bankChannel mismatch") require(cfg.memDomain.dma_buswidth == cfg0.memDomain.dma_buswidth, s"core-$i dma_buswidth mismatch") @@ -367,6 +371,7 @@ class BBTileModuleImp(outer: BBTile) extends BaseTileModuleImp(outer) with HasIC val nCores = outer.nCores val rushBEnabled = outer.p(BuckyballRushBKey) + val simParam = outer.p(SimParamKey) def coreParamsForCore(coreIdx: Int): BBTileParams = outer.bbParams.copy(core = outer.bbParams.rocketCoreForCore(coreIdx)) @@ -607,7 +612,7 @@ class BBTileModuleImp(outer: BBTile) extends BaseTileModuleImp(outer) with HasIC } if (outer.hasBuckyball) { - val cfg0 = outer.bbSharedConfig.get + val cfg0 = outer.bbSharedConfig.get.copy(sim = simParam) val sharedPerCore = SharedMemLayout.channelPerHart(cfg0) // Instantiate accelerators for enabled cores only @@ -615,7 +620,7 @@ class BBTileModuleImp(outer: BBTile) extends BaseTileModuleImp(outer) with HasIC outer.bbPerCore(i).map { cfg => val (tl_reader, edge) = outer.bb_reader_nodes(i).get.out(0) val (tl_writer, _) = outer.bb_writer_nodes(i).get.out(0) - val acc = Module(new BuckyballAccelerator(cfg)(edge)) + val acc = Module(new BuckyballAccelerator(cfg.copy(sim = simParam))(edge)) acc.io.hartid := hartIdForCore(i) tl_reader <> acc.io.tl_reader @@ -633,7 +638,7 @@ class BBTileModuleImp(outer: BBTile) extends BaseTileModuleImp(outer) with HasIC if (rushBEnabled) { val source = Module(new RushBCommandBridge( RushBCoreId(outer.bbParams.tileId, i), - accelerator.b.core.xLen + accelerator.b.tile.xLen )) source.io.retired := accelerator.io.retired Some(source) @@ -668,6 +673,12 @@ class BBTileModuleImp(outer: BBTile) extends BaseTileModuleImp(outer) with HasIC // SharedMemBackend (tile-level singleton) val sharedBackend = Module(new SharedMemBackend(cfg0)) + if (cfg0.sim.diffTest) { + for (acc <- enabledAccelerators) { + acc.io.shared_bank_hashes.get := sharedBackend.io.bank_hashes.get + } + } + // Connect each accelerator's shared ports to the SharedMemBackend for (i <- 0 until nCores) { for (ch <- 0 until sharedPerCore) { diff --git a/arch/src/main/scala/framework/system/tile/Configs.scala b/arch/src/main/scala/framework/system/tile/Configs.scala index e87c7b270..55626cfbc 100644 --- a/arch/src/main/scala/framework/system/tile/Configs.scala +++ b/arch/src/main/scala/framework/system/tile/Configs.scala @@ -5,7 +5,8 @@ import freechips.rocketchip.rocket.{BTBParams, DCacheParams, ICacheParams, MulDi import freechips.rocketchip.subsystem._ import freechips.rocketchip.tile.{FPUParams, RocketTileBoundaryBufferParams} import framework.top.GlobalConfig -import framework.system.core.rocket.configs.RocketCoreParam +import framework.system.core.rocket.configs.RocketCpuParam +import framework.system.tile.configs.TileParam /** * Config fragment to add N BBTiles. @@ -24,61 +25,35 @@ object WithNBBTiles { } ) - /** - * Resolve the per-tile rocketCore param from buckyballPerCore. - * - * Multi-core within a tile currently shares one RocketCoreParam (BBTileParams - * has tile-level core/dcache/icache fields). All Some(_) entries must agree. - * Falls back to RocketCoreParam() when nothing is defined. - */ - def resolveRocketCore( - buckyballPerCore: Seq[Option[GlobalConfig]], - buckyballConfig: GlobalConfig - ): RocketCoreParam = { - val defined = buckyballPerCore.flatten.map(_.rocketCore) - if (defined.isEmpty) { - buckyballConfig.rocketCore - } else { - val head = defined.head - require( - defined.forall(_ == head), - "All cores within a BBTile must currently share the same rocketCore config; " + - "heterogeneous per-core Rocket params is not yet supported." - ) - head - } - } - - def resolveRocketCores( - nCoresPerTile: Int, - buckyballPerCore: Seq[Option[GlobalConfig]], - buckyballConfig: GlobalConfig, - rocketCorePerCore: Option[Seq[RocketCoreParam]] - ): Seq[RocketCoreParam] = { - rocketCorePerCore match { + def resolveRocketCpus( + nCoresPerTile: Int, + rocketCpuPerCore: Option[Seq[RocketCpuParam]] + ): Seq[RocketCpuParam] = { + rocketCpuPerCore match { case Some(cores) => require( cores.size == nCoresPerTile, - s"rocketCorePerCore size (${cores.size}) must equal nCoresPerTile ($nCoresPerTile)" + s"rocketCpuPerCore size (${cores.size}) must equal nCoresPerTile ($nCoresPerTile)" ) cores case None => - Seq.fill(nCoresPerTile)(resolveRocketCore(buckyballPerCore, buckyballConfig)) + throw new RuntimeException("rocketCpuPerCore must be specified") } } } class WithBBTile( - location: HierarchicalLocation = InSubsystem, - withBuckyball: Boolean = true, - buckyballConfig: GlobalConfig = GlobalConfig(), - crossing: Option[RocketCrossingParams] = None, - nCoresPerTile: Int = 1, - buckyballPerCore: Option[Seq[Option[GlobalConfig]]] = None, - rocketCorePerCore: Option[Seq[RocketCoreParam]] = None, - privateDCache: Option[PrivateDCacheParams] = None, - hiddenHartBase: Option[Int] = None) + tileParam: TileParam, + location: HierarchicalLocation = InSubsystem, + withBuckyball: Boolean = true, + buckyballConfig: GlobalConfig = GlobalConfig(), + crossing: Option[RocketCrossingParams] = None, + nCoresPerTile: Int = 1, + buckyballPerCore: Option[Seq[Option[GlobalConfig]]] = None, + rocketCpuPerCore: Option[Seq[RocketCpuParam]] = None, + privateDCache: Option[PrivateDCacheParams] = None, + hiddenHartBase: Option[Int] = None) extends Config((site, here, up) => { case TilesLocated(`location`) => val prev = up(TilesLocated(`location`), site) @@ -91,13 +66,11 @@ class WithBBTile( resolvedBuckyballPerCore.size == nCoresPerTile, s"buckyballPerCore size (${resolvedBuckyballPerCore.size}) must equal nCoresPerTile ($nCoresPerTile)" ) - val rocketCores = WithNBBTiles.resolveRocketCores( + val rocketCpus = WithNBBTiles.resolveRocketCpus( nCoresPerTile, - resolvedBuckyballPerCore, - buckyballConfig, - rocketCorePerCore + rocketCpuPerCore ) - val rocketCore = rocketCores.head + val rocketCpu = rocketCpus.head val rowBits = site(SystemBusKey).beatBits val blockBytes = site(CacheBlockBytes) val tileParams = BBTileParams( @@ -105,13 +78,13 @@ class WithBBTile( withBuckyball = withBuckyball, buckyballConfig = buckyballConfig, buckyballPerCore = resolvedBuckyballPerCore, - rocketCorePerCore = rocketCores.map(RocketCoreParam.toRocketCoreParams), + rocketCorePerCore = rocketCpus.map(RocketCpuParam.toRocketCoreParams(_, tileParam.xLen, tileParam.pgLevels)), privateDCache = privateDCache, hiddenHartBase = hiddenHartBase, - core = RocketCoreParam.toRocketCoreParams(rocketCore), - dcache = Some(RocketCoreParam.toDCacheParams(rocketCore, rowBits, blockBytes)), - icache = Some(RocketCoreParam.toICacheParams(rocketCore, rowBits, blockBytes)), - btb = RocketCoreParam.toBTBParams(rocketCore) + core = RocketCpuParam.toRocketCoreParams(rocketCpu, tileParam.xLen, tileParam.pgLevels), + dcache = Some(RocketCpuParam.toDCacheParams(rocketCpu, rowBits, blockBytes)), + icache = Some(RocketCpuParam.toICacheParams(rocketCpu, rowBits, blockBytes)), + btb = RocketCpuParam.toBTBParams(rocketCpu) ) BBTileAttachParams( tileParams.copy(tileId = idOffset), @@ -121,16 +94,17 @@ class WithBBTile( }) class WithNBBTiles( - n: Int, - location: HierarchicalLocation = InSubsystem, - withBuckyball: Boolean = true, - buckyballConfig: GlobalConfig = GlobalConfig(), - crossing: Option[RocketCrossingParams] = None, - nCoresPerTile: Int = 1, - buckyballPerCore: Option[Seq[Option[GlobalConfig]]] = None, - rocketCorePerCore: Option[Seq[RocketCoreParam]] = None, - privateDCache: Option[PrivateDCacheParams] = None, - hiddenHartBase: Option[Int] = None) + n: Int, + tileParam: TileParam, + location: HierarchicalLocation = InSubsystem, + withBuckyball: Boolean = true, + buckyballConfig: GlobalConfig = GlobalConfig(), + crossing: Option[RocketCrossingParams] = None, + nCoresPerTile: Int = 1, + buckyballPerCore: Option[Seq[Option[GlobalConfig]]] = None, + rocketCpuPerCore: Option[Seq[RocketCpuParam]] = None, + privateDCache: Option[PrivateDCacheParams] = None, + hiddenHartBase: Option[Int] = None) extends Config((site, here, up) => { case TilesLocated(`location`) => val prev = up(TilesLocated(`location`), site) @@ -143,13 +117,11 @@ class WithNBBTiles( resolvedBuckyballPerCore.size == nCoresPerTile, s"buckyballPerCore size (${resolvedBuckyballPerCore.size}) must equal nCoresPerTile ($nCoresPerTile)" ) - val rocketCores = WithNBBTiles.resolveRocketCores( + val rocketCpus = WithNBBTiles.resolveRocketCpus( nCoresPerTile, - resolvedBuckyballPerCore, - buckyballConfig, - rocketCorePerCore + rocketCpuPerCore ) - val rocketCore = rocketCores.head + val rocketCpu = rocketCpus.head val rowBits = site(SystemBusKey).beatBits val blockBytes = site(CacheBlockBytes) val tileParams = BBTileParams( @@ -157,13 +129,13 @@ class WithNBBTiles( withBuckyball = withBuckyball, buckyballConfig = buckyballConfig, buckyballPerCore = resolvedBuckyballPerCore, - rocketCorePerCore = rocketCores.map(RocketCoreParam.toRocketCoreParams), + rocketCorePerCore = rocketCpus.map(RocketCpuParam.toRocketCoreParams(_, tileParam.xLen, tileParam.pgLevels)), privateDCache = privateDCache, hiddenHartBase = hiddenHartBase, - core = RocketCoreParam.toRocketCoreParams(rocketCore), - dcache = Some(RocketCoreParam.toDCacheParams(rocketCore, rowBits, blockBytes)), - icache = Some(RocketCoreParam.toICacheParams(rocketCore, rowBits, blockBytes)), - btb = RocketCoreParam.toBTBParams(rocketCore) + core = RocketCpuParam.toRocketCoreParams(rocketCpu, tileParam.xLen, tileParam.pgLevels), + dcache = Some(RocketCpuParam.toDCacheParams(rocketCpu, rowBits, blockBytes)), + icache = Some(RocketCpuParam.toICacheParams(rocketCpu, rowBits, blockBytes)), + btb = RocketCpuParam.toBTBParams(rocketCpu) ) List.tabulate(n)(i => BBTileAttachParams( diff --git a/arch/src/main/scala/framework/system/tile/WithBoomTile.scala b/arch/src/main/scala/framework/system/tile/WithBoomTile.scala index 585d5b36e..c8376902c 100644 --- a/arch/src/main/scala/framework/system/tile/WithBoomTile.scala +++ b/arch/src/main/scala/framework/system/tile/WithBoomTile.scala @@ -3,10 +3,10 @@ package framework.system.tile import org.chipsalliance.cde.config._ import freechips.rocketchip.subsystem._ import boom.v3.common.{BoomTileAttachParams, BoomTileParams, WithTAGELBPD} -import framework.system.core.boom.configs.BoomCoreParam +import framework.system.core.boom.configs.BoomCpuParam -/** Attach one BoomTile from BoomCoreParam. */ -class WithBoomTile(param: BoomCoreParam, location: HierarchicalLocation = InSubsystem) +/** Attach one BoomTile from BoomCpuParam. */ +class WithBoomTile(param: BoomCpuParam, location: HierarchicalLocation = InSubsystem) extends Config( new WithTAGELBPD ++ new Config((site, here, up) => { @@ -15,9 +15,9 @@ class WithBoomTile(param: BoomCoreParam, location: HierarchicalLocation = InSubs val idOffset = up(NumTiles) val rowBits = site(SystemBusKey).beatBits val tileParams = BoomTileParams( - core = BoomCoreParam.toBoomCoreParams(param), - dcache = Some(BoomCoreParam.toDCacheParams(param, rowBits)), - icache = Some(BoomCoreParam.toICacheParams(param, rowBits)), + core = BoomCpuParam.toBoomCoreParams(param), + dcache = Some(BoomCpuParam.toDCacheParams(param, rowBits)), + icache = Some(BoomCpuParam.toICacheParams(param, rowBits)), tileId = idOffset ) BoomTileAttachParams( diff --git a/arch/src/main/scala/framework/system/tile/WithBuckyballTiles.scala b/arch/src/main/scala/framework/system/tile/WithBuckyballTiles.scala index 8c0e4ad9d..98249c056 100644 --- a/arch/src/main/scala/framework/system/tile/WithBuckyballTiles.scala +++ b/arch/src/main/scala/framework/system/tile/WithBuckyballTiles.scala @@ -50,28 +50,29 @@ object WithBuckyballTiles { throw new RuntimeException("boom-only tile cannot enable privateDCache") } tile.cores.map { - case BoomTileCore(boom) => new WithBoomTile(boom) - case other => throw new RuntimeException(s"expected BoomTileCore, got $other") + case BoomTileCore(cpu) => new WithBoomTile(cpu) + case other => throw new RuntimeException(s"expected BoomTileCore, got $other") } } else { if (tile.privateDCache.isDefined) { throw new RuntimeException("heterogeneous tile cannot enable privateDCache") } tile.cores.map { - case RocketTileCore(rocket, buckyball) => + case RocketTileCore(cpu, buckyball) => if (buckyball.isDefined) { throw new RuntimeException("heterogeneous tile cannot enable buckyball") } new WithBBTile( + tileParam = tile.param, withBuckyball = false, nCoresPerTile = 1, buckyballPerCore = Some(Seq(None)), - rocketCorePerCore = Some(Seq(rocket)), + rocketCpuPerCore = Some(Seq(cpu)), privateDCache = None, hiddenHartBase = hiddenHartBase ) - case BoomTileCore(boom) => - new WithBoomTile(boom) + case BoomTileCore(cpu) => + new WithBoomTile(cpu) } } } @@ -82,17 +83,18 @@ object WithBuckyballTiles { hiddenHartBase: Option[Int] ): Config = { val rockets = tile.cores.map { - case RocketTileCore(rocket, bb) => (rocket, bb) - case other => throw new RuntimeException(s"expected RocketTileCore, got $other") + case RocketTileCore(cpu, bb) => (cpu, bb) + case other => throw new RuntimeException(s"expected RocketTileCore, got $other") } val resolved = if (withBuckyball) rockets.map(_._2) else rockets.map(_ => None) new WithBBTile( + tileParam = tile.param, withBuckyball = resolved.exists(_.isDefined), nCoresPerTile = rockets.size, buckyballPerCore = Some(resolved), - rocketCorePerCore = Some(rockets.map(_._1)), + rocketCpuPerCore = Some(rockets.map(_._1)), privateDCache = tile.privateDCache, hiddenHartBase = hiddenHartBase ) diff --git a/arch/src/main/scala/framework/system/core/configs/CoreParam.scala b/arch/src/main/scala/framework/system/tile/configs/TileParam.scala similarity index 61% rename from arch/src/main/scala/framework/system/core/configs/CoreParam.scala rename to arch/src/main/scala/framework/system/tile/configs/TileParam.scala index 5f0e0a901..bb59efd4d 100644 --- a/arch/src/main/scala/framework/system/core/configs/CoreParam.scala +++ b/arch/src/main/scala/framework/system/tile/configs/TileParam.scala @@ -1,27 +1,26 @@ -package framework.system.core.configs +package framework.system.tile.configs import upickle.default._ -/** - * Core Parameter - */ -case class CoreParam( +case class TileParam( coreDataBytes: Int, xLen: Int, vaddrBits: Int, paddrBits: Int, pgIdxBits: Int, + pgLevels: Int, nPMPs: Int) // Physical Memory Protection entries, typically 8 or 16 -object CoreParam { - implicit val rw: ReadWriter[CoreParam] = macroRW +object TileParam { + implicit val rw: ReadWriter[TileParam] = macroRW - def apply(): CoreParam = CoreParam( + def apply(): TileParam = TileParam( coreDataBytes = 0, xLen = 0, vaddrBits = 0, paddrBits = 0, pgIdxBits = 0, + pgLevels = 0, nPMPs = 0 ) diff --git a/arch/src/main/scala/framework/top/GlobalConfig.scala b/arch/src/main/scala/framework/top/GlobalConfig.scala index 0bec473b5..28b41dc58 100644 --- a/arch/src/main/scala/framework/top/GlobalConfig.scala +++ b/arch/src/main/scala/framework/top/GlobalConfig.scala @@ -6,18 +6,16 @@ import framework.memdomain.configs.MemDomainParam import framework.frontend.configs.FrontendParam import framework.gpdomain.configs.GpDomainParam import framework.balldomain.configs.BallDomainParam -import framework.system.core.configs.CoreParam -import framework.system.core.rocket.configs.RocketCoreParam -import framework.top.configs.TopConfig +import framework.system.tile.configs.TileParam +import framework.top.configs.SimParam case class GlobalConfig( memDomain: MemDomainParam, frontend: FrontendParam, gpDomain: GpDomainParam, ballDomain: BallDomainParam, - core: CoreParam, - top: TopConfig, - rocketCore: RocketCoreParam) + tile: TileParam, + sim: SimParam) extends SerializableModuleParameter object GlobalConfig { @@ -29,9 +27,8 @@ object GlobalConfig { frontend = FrontendParam(), gpDomain = GpDomainParam(), ballDomain = BallDomainParam(), - core = CoreParam(), - top = TopConfig(), - rocketCore = RocketCoreParam() + tile = TileParam(), + sim = SimParam() ) } diff --git a/arch/src/main/scala/framework/top/configs/SimParam.scala b/arch/src/main/scala/framework/top/configs/SimParam.scala new file mode 100644 index 000000000..27712cb73 --- /dev/null +++ b/arch/src/main/scala/framework/top/configs/SimParam.scala @@ -0,0 +1,17 @@ +package framework.top.configs + +import org.chipsalliance.cde.config.{Config, Field} +import upickle.default._ + +case class SimParam(diffTest: Boolean = false) + +object SimParam { + implicit val rw: ReadWriter[SimParam] = macroRW +} + +case object SimParamKey extends Field[SimParam](SimParam()) + +class WithSimParam(param: SimParam) + extends Config((site, here, up) => { + case SimParamKey => param + }) diff --git a/arch/src/main/scala/framework/top/configs/TopConfig.scala b/arch/src/main/scala/framework/top/configs/TopConfig.scala deleted file mode 100644 index 909509d09..000000000 --- a/arch/src/main/scala/framework/top/configs/TopConfig.scala +++ /dev/null @@ -1,14 +0,0 @@ -package framework.top.configs - -import upickle.default._ - -case class TopConfig( - memBallChannelNum: Int, - nCores: Int) - -object TopConfig { - implicit val rw: ReadWriter[TopConfig] = macroRW - - /** Stub; real values come from ChipLoader (tile + derived nCores). */ - def apply(): TopConfig = TopConfig(memBallChannelNum = 0, nCores = 0) -} diff --git a/arch/src/main/scala/sims/hash/BankHash.scala b/arch/src/main/scala/sims/hash/BankHash.scala new file mode 100644 index 000000000..901beb0b7 --- /dev/null +++ b/arch/src/main/scala/sims/hash/BankHash.scala @@ -0,0 +1,75 @@ +package sims.hash + +import chisel3._ +import chisel3.experimental.hierarchy.{instantiable, public} +import chisel3.util._ +import framework.top.GlobalConfig + +class BankHashWrite(val b: GlobalConfig) extends Bundle { + val addr = UInt(log2Ceil(b.memDomain.bankEntries).W) + val mask = Vec(b.memDomain.bankMaskLen, Bool()) + val data = UInt(b.memDomain.bankWidth.W) +} + +@instantiable +class BankHashMonitor(val b: GlobalConfig) extends Module { + require(b.memDomain.bankWidth == 128, "bank hash requires 128-bit bank rows") + require(b.memDomain.bankMaskLen == 16, "bank hash requires byte write masks") + + @public + val io = IO(new Bundle { + val bind = Input(Bool()) + val write = Flipped(Valid(new BankHashWrite(b))) + val statusHash = Output(UInt(32.W)) + }) + + val shadow = SyncReadMem(b.memDomain.bankEntries, UInt(128.W)) + val validRows = RegInit(VecInit(Seq.fill(b.memDomain.bankEntries)(false.B))) + val generation = RegInit(0.U(8.W)) + val statusHash = RegInit(0.U(32.W)) + + def rotateLeft(value: UInt, amount: Int): UInt = + Cat(value(31 - amount, 0), value(31, 32 - amount)) + + def rowHash(addr: UInt, row: UInt): UInt = { + val address = addr.pad(32) + val mixed = row(31, 0) ^ rotateLeft(row(63, 32), 7) ^ rotateLeft(row(95, 64), 13) ^ + rotateLeft(row(127, 96), 21) ^ rotateLeft(address, 11) + Mux(row.orR, mixed, 0.U) + } + + val readData = shadow.read(io.write.bits.addr, io.write.valid) + val writeValid = RegNext(io.write.valid, false.B) + val writeBits = RegEnable(io.write.bits, io.write.valid) + val writeGeneration = RegEnable(generation, io.write.valid) + val lastValid = RegInit(false.B) + val lastAddr = Reg(UInt(io.write.bits.addr.getWidth.W)) + val lastData = Reg(UInt(128.W)) + val lastGeneration = Reg(UInt(generation.getWidth.W)) + val memoryOld = Mux(validRows(writeBits.addr), readData, 0.U) + val bypass = lastValid && lastGeneration === writeGeneration && lastAddr === writeBits.addr + val oldRow = Mux(bypass, lastData, memoryOld) + val oldBytes = oldRow.asTypeOf(Vec(16, UInt(8.W))) + val writeBytes = writeBits.data.asTypeOf(Vec(16, UInt(8.W))) + val newBytes = VecInit((0 until 16).map(i => Mux(writeBits.mask(i), writeBytes(i), oldBytes(i)))) + val newRow = newBytes.asUInt + val nextHash = statusHash - rowHash(writeBits.addr, oldRow) + rowHash(writeBits.addr, newRow) + val commit = writeValid && writeGeneration === generation && !io.bind + + io.statusHash := statusHash + + when(io.bind) { + generation := generation + 1.U + statusHash := 0.U + lastValid := false.B + validRows.foreach(_ := false.B) + }.elsewhen(commit) { + shadow.write(writeBits.addr, newRow) + validRows(writeBits.addr) := true.B + statusHash := nextHash + lastValid := true.B + lastAddr := writeBits.addr + lastData := newRow + lastGeneration := writeGeneration + } +} diff --git a/arch/src/main/scala/sims/p2e/TargetConfigs.scala b/arch/src/main/scala/sims/p2e/TargetConfigs.scala index 21fb5a580..89aca3085 100644 --- a/arch/src/main/scala/sims/p2e/TargetConfigs.scala +++ b/arch/src/main/scala/sims/p2e/TargetConfigs.scala @@ -3,6 +3,7 @@ package sims.p2e import chisel3._ import _root_.circt.stage.ChiselStage import org.chipsalliance.cde.config.Config +import framework.top.configs.{SimParam, WithSimParam} import freechips.rocketchip.devices.tilelink.{BootROMLocated, BootROMParams} import freechips.rocketchip.subsystem.{InSubsystem, WithCustomMemPort} import sims.scu.WithSCU @@ -49,7 +50,8 @@ class WithP2EDDR4MemPort // ============================================================================= class P2EBaseConfig(maxHarts: Int = 64) extends Config( - new WithP2EHarness ++ + new WithSimParam(SimParam()) ++ + new WithP2EHarness ++ new WithSCU(maxHarts = maxHarts) ++ new WithP2EDDR4MemPort ++ new WithP2EBootROM @@ -95,7 +97,7 @@ object Elaborate extends App { val configClassName = args(0) println(s"Elaborating P2EHarness with config: $configClassName") - val config: Config = + val baseConfig: Config = try { val configClass = Class.forName(configClassName) configClass.getDeclaredConstructor().newInstance().asInstanceOf[Config] @@ -109,22 +111,31 @@ object Elaborate extends App { sys.exit(1) } - val firtoolOpts = args.drop(1) + val rawFirtoolOpts = args.drop(1) + + val config: Config = + if (rawFirtoolOpts.contains("--difftest")) + new Config(new WithSimParam(SimParam(diffTest = true)).orElse(baseConfig)) + else baseConfig - val outDir = firtoolOpts.collectFirst { + val outDir = rawFirtoolOpts.collectFirst { case opt if opt.startsWith("-o=") => opt.stripPrefix("-o=") }.getOrElse { throw new Exception("missing -o= in firtool opts") } + val firtoolOpts = rawFirtoolOpts.filterNot { opt => + opt == "--split-verilog" || opt == "--difftest" || opt.startsWith("-o=") + } + ChiselStage.emitSystemVerilogFile( new P2EHarness()(config.toInstance), firtoolOpts = firtoolOpts, - args = Array("--target-dir", outDir) + args = Array("--target-dir", outDir, "--split-verilog") ) ChiselStage.emitSystemVerilogFile( new P2ETop, firtoolOpts = firtoolOpts, - args = Array("--target-dir", outDir) + args = Array("--target-dir", outDir, "--split-verilog") ) } diff --git a/arch/src/main/scala/sims/verilator/BBSimHarness.scala b/arch/src/main/scala/sims/verilator/BBSimHarness.scala index 2d64e8669..de65b44dc 100644 --- a/arch/src/main/scala/sims/verilator/BBSimHarness.scala +++ b/arch/src/main/scala/sims/verilator/BBSimHarness.scala @@ -6,6 +6,7 @@ import org.chipsalliance.cde.config.{Config, Parameters} import chipyard.harness.{HarnessBinder, HasHarnessInstantiators} import chipyard.iobinders.AXI4MemPort +import framework.top.configs.{SimParam, WithSimParam} import sims.scu.WithSCU class WithBBSimMem @@ -36,7 +37,8 @@ class WithBBSimMem // ============================================================================= class BBSimConfig(maxHarts: Int = 64) extends Config( - new WithSCU(maxHarts = maxHarts) ++ + new WithSimParam(SimParam()) ++ + new WithSCU(maxHarts = maxHarts) ++ new WithBBSimMem ++ new chipyard.config.WithUniformBusFrequencies(1000.0) ++ new chipyard.harness.WithTieOffInterrupts ++ diff --git a/arch/src/main/scala/sims/verilator/TargetConfig.scala b/arch/src/main/scala/sims/verilator/TargetConfig.scala index 7a75d6a74..dc84f98a6 100644 --- a/arch/src/main/scala/sims/verilator/TargetConfig.scala +++ b/arch/src/main/scala/sims/verilator/TargetConfig.scala @@ -5,6 +5,7 @@ import _root_.circt.stage.ChiselStage import org.chipsalliance.cde.config.Config import freechips.rocketchip.devices.tilelink.{BootROMLocated, BootROMParams} import freechips.rocketchip.subsystem.InSubsystem +import framework.top.configs.{SimParam, WithSimParam} class WithCustomBootROM extends Config((site, here, up) => { @@ -132,7 +133,7 @@ object Elaborate extends App { val configClassName = args(0) println(s"Elaborating BBSimHarness with config: $configClassName") - val config: Config = + val baseConfig: Config = try { val configClass = Class.forName(configClassName) configClass.getDeclaredConstructor().newInstance().asInstanceOf[Config] @@ -146,17 +147,26 @@ object Elaborate extends App { sys.exit(1) } - val firtoolOpts = args.drop(1) + val rawFirtoolOpts = args.drop(1) + + val config: Config = + if (rawFirtoolOpts.contains("--difftest")) + new Config(new WithSimParam(SimParam(diffTest = true)).orElse(baseConfig)) + else baseConfig - val outDir = firtoolOpts.collectFirst { + val outDir = rawFirtoolOpts.collectFirst { case opt if opt.startsWith("-o=") => opt.stripPrefix("-o=") }.getOrElse { throw new Exception("missing -o= in firtool opts") } + val firtoolOpts = rawFirtoolOpts.filterNot { opt => + opt == "--split-verilog" || opt == "--difftest" || opt.startsWith("-o=") + } + ChiselStage.emitSystemVerilogFile( new BBSimHarness()(config.toInstance), firtoolOpts = firtoolOpts, - args = Array("--target-dir", outDir) + args = Array("--target-dir", outDir, "--split-verilog") ) } diff --git a/bb-tests/workloads/CMakeLists.txt b/bb-tests/workloads/CMakeLists.txt index 57cf8971c..a1fd342f3 100644 --- a/bb-tests/workloads/CMakeLists.txt +++ b/bb-tests/workloads/CMakeLists.txt @@ -244,6 +244,7 @@ function(add_buckyball_rushb_native TARGET_NAME) if(RUSHB_BACKEND STREQUAL "bemu") set(RUSHB_LIBRARY ${BUCKYBALL_RUSHB_BEMU_LIBRARY}) set(RUSHB_LIBRARY_NAME bebop_bemu) + set(RUSHB_BACKEND_DEFINE -DBUCKYBALL_RUSHB_BEMU) set(RUSHB_BUILD_RUNTIME COMMAND ${CMAKE_COMMAND} -E env --unset=CC --unset=CXX @@ -253,6 +254,7 @@ function(add_buckyball_rushb_native TARGET_NAME) else() set(RUSHB_LIBRARY ${BUCKYBALL_RUSHB_VERILATOR_LIBRARY}) set(RUSHB_LIBRARY_NAME bebop_verilator) + set(RUSHB_BACKEND_DEFINE -DBUCKYBALL_RUSHB_VERILATOR) set(RUSHB_BUILD_RUNTIME) set(RUSHB_RUNTIME_DEPENDENCY ${BUCKYBALL_RUSHB_VERILATOR_LIBRARY}) endif() @@ -297,6 +299,7 @@ function(add_buckyball_rushb_native TARGET_NAME) OUTPUT ${RUSHB_BINARY} ${RUSHB_INSTALLED} ${RUSHB_SYNCED} COMMAND ${CMAKE_COMMAND} -E make_directory ${RUSHB_BUILD_DIR} COMMAND ${RUSHB_COMPILER} -no-pie ${RUSHB_STANDARD} -O2 -DBUCKYBALL_RUSHB + ${RUSHB_BACKEND_DEFINE} -DBUCKYBALL_RUSHB_CORE_ID=${ARG_CORE_ID} ${RUSHB_INCLUDE_ARGS} ${ARG_SOURCES} ${BUCKYBALL_REPO_ROOT}/compiler/lib/RushBRuntime.c diff --git a/bb-tests/workloads/lib/bbhw/isa/33_mvin.c b/bb-tests/workloads/lib/bbhw/isa/33_mvin.c index 1d366b5e6..feb39b917 100644 --- a/bb-tests/workloads/lib/bbhw/isa/33_mvin.c +++ b/bb-tests/workloads/lib/bbhw/isa/33_mvin.c @@ -10,7 +10,7 @@ do { \ bb_dma_cache_flush(); \ rushb_mvin(BUCKYBALL_RUSHB_CORE, \ - (uint64_t)(BB_BANK0(bank_id) | BB_ITER(depth)), \ + (uint64_t)(BB_BANK2(bank_id) | BB_ITER(depth)), \ (uint64_t)(FIELD(mem_addr, 0, 38) | FIELD(stride, 39, 57)), \ (const void *)(uintptr_t)(mem_addr)); \ } while (0) @@ -19,7 +19,7 @@ do { \ bb_dma_cache_flush(); \ BUCKYBALL_INSTRUCTION_R_R( \ - (BB_BANK0(bank_id) | BB_ITER(depth)), \ + (BB_BANK2(bank_id) | BB_ITER(depth)), \ (FIELD(mem_addr, 0, 38) | FIELD(stride, 39, 57)), BB_MVIN_FUNC7); \ } while (0) #endif diff --git a/bb-tests/workloads/lib/bbhw/isa/34_mvin_2d.c b/bb-tests/workloads/lib/bbhw/isa/34_mvin_2d.c index 7728e34ff..ae62a65df 100644 --- a/bb-tests/workloads/lib/bbhw/isa/34_mvin_2d.c +++ b/bb-tests/workloads/lib/bbhw/isa/34_mvin_2d.c @@ -5,7 +5,7 @@ #define BB_MVIN_2D_FUNC7 34 -// rs1: bank id and tile height. +// rs1: write bank in BANK2 and tile height. // rs2: [31:0] address, [38:32] physical pixel bytes / 8, // [48:39] source width, [54:49] destination row base, // [57:55] tile width - 1, [61:58] valid bytes (0 encodes 16). @@ -14,7 +14,7 @@ do { \ bb_dma_cache_flush(); \ BUCKYBALL_INSTRUCTION_R_R( \ - (BB_BANK0(bank_id) | BB_ITER(height)), \ + (BB_BANK2(bank_id) | BB_ITER(height)), \ (FIELD(mem_addr, 0, 31) | FIELD((pixel_bytes) / 8, 32, 38) | \ FIELD(source_width, 39, 48) | FIELD(dst_base, 49, 54) | \ FIELD((tile_width) - 1, 55, 57) | \ diff --git a/bbdev b/bbdev index bd0298c50..f8a97b13f 160000 --- a/bbdev +++ b/bbdev @@ -1 +1 @@ -Subproject commit bd0298c50aa7daa2be03746859c54546c4caae73 +Subproject commit f8a97b13f6458a37a54382d3e4e05ea4af40f47e diff --git a/bebop b/bebop index 490c9aa94..a9f30755f 160000 --- a/bebop +++ b/bebop @@ -1 +1 @@ -Subproject commit 490c9aa942a9425727ab7db37eb67075ba234149 +Subproject commit a9f30755fc5fd81f8e35458d7fd6000674386870 diff --git a/compiler/lib/RushBRuntime.c b/compiler/lib/RushBRuntime.c index d1f83bf21..287109899 100644 --- a/compiler/lib/RushBRuntime.c +++ b/compiler/lib/RushBRuntime.c @@ -1,5 +1,54 @@ #include +#if defined(BUCKYBALL_RUSHB_BEMU) +#define RUSHB_BACKEND(name) bemu_##name +#elif defined(BUCKYBALL_RUSHB_VERILATOR) +#define RUSHB_BACKEND(name) verilator_##name +#else +#error "RushB backend is not selected" +#endif + +extern void RUSHB_BACKEND(rushb_init)(void); +extern void RUSHB_BACKEND(rushb_destroy)(void); +extern void RUSHB_BACKEND(rushb_mset)(uint32_t core_id, uint64_t xs1, + uint64_t xs2); +extern void RUSHB_BACKEND(rushb_mvin)(uint32_t core_id, uint64_t xs1, + uint64_t packed_xs2, + const void *host_ptr); +extern void RUSHB_BACKEND(rushb_mvin_mmio)(uint32_t core_id, uint64_t xs1, + uint64_t packed_xs2, + const void *host_ptr); +extern void RUSHB_BACKEND(rushb_mvout)(uint32_t core_id, uint64_t xs1, + uint64_t packed_xs2, void *host_ptr); +extern void RUSHB_BACKEND(rushb_custom)(uint32_t core_id, uint64_t xs1, + uint64_t xs2, uint32_t funct7); +extern uint64_t RUSHB_BACKEND(rushb_cycles)(uint32_t core_id); + +void rushb_init(void) { RUSHB_BACKEND(rushb_init)(); } +void rushb_destroy(void) { RUSHB_BACKEND(rushb_destroy)(); } +void rushb_mset(uint32_t core_id, uint64_t xs1, uint64_t xs2) { + RUSHB_BACKEND(rushb_mset)(core_id, xs1, xs2); +} +void rushb_mvin(uint32_t core_id, uint64_t xs1, uint64_t packed_xs2, + const void *host_ptr) { + RUSHB_BACKEND(rushb_mvin)(core_id, xs1, packed_xs2, host_ptr); +} +void rushb_mvin_mmio(uint32_t core_id, uint64_t xs1, uint64_t packed_xs2, + const void *host_ptr) { + RUSHB_BACKEND(rushb_mvin_mmio)(core_id, xs1, packed_xs2, host_ptr); +} +void rushb_mvout(uint32_t core_id, uint64_t xs1, uint64_t packed_xs2, + void *host_ptr) { + RUSHB_BACKEND(rushb_mvout)(core_id, xs1, packed_xs2, host_ptr); +} +void rushb_custom(uint32_t core_id, uint64_t xs1, uint64_t xs2, + uint32_t funct7) { + RUSHB_BACKEND(rushb_custom)(core_id, xs1, xs2, funct7); +} +uint64_t rushb_cycles(uint32_t core_id) { + return RUSHB_BACKEND(rushb_cycles)(core_id); +} + static void __attribute__((constructor)) rushb_runtime_init(void) { rushb_init(); } diff --git a/compiler/src/Dialect/Buckyball/Transforms/LegalizeForLLVMExportBase.cpp b/compiler/src/Dialect/Buckyball/Transforms/LegalizeForLLVMExportBase.cpp index a9f23ecb6..8a56ca2f5 100644 --- a/compiler/src/Dialect/Buckyball/Transforms/LegalizeForLLVMExportBase.cpp +++ b/compiler/src/Dialect/Buckyball/Transforms/LegalizeForLLVMExportBase.cpp @@ -121,6 +121,12 @@ Value packRs1BankIter(OpBuilder &b, Location loc, Value bankId, Value depth) { return packRs1BanksIter(b, loc, bankId, z, z, depth); } +Value packRs1WriteBankIter(OpBuilder &b, Location loc, Value bankId, + Value depth) { + Value z = cstI64(b, loc, 0); + return packRs1BanksIter(b, loc, z, z, bankId, depth); +} + Value packRs2MemStride(OpBuilder &b, Location loc, Value memAddr, Value stride) { Value mem = @@ -278,8 +284,8 @@ struct BuckyballMvinLowering : public ConvertOpToLLVMPattern { MemrefAddress memref = extractMemrefAddress(rewriter, loc, op.getInput()); if (!rushB) emitDmaCacheFlush(rewriter, loc); - Value rs1 = - packRs1BankIter(rewriter, loc, adaptor.getAddr(), adaptor.getDepth()); + Value rs1 = packRs1WriteBankIter(rewriter, loc, adaptor.getAddr(), + adaptor.getDepth()); Value rs2 = packRs2MemStride(rewriter, loc, memref.address, adaptor.getStride()); if (rushB) { @@ -306,8 +312,8 @@ struct BuckyballMvin2dLowering : public ConvertOpToLLVMPattern { Location loc = op.getLoc(); MemrefAddress memref = extractMemrefAddress(rewriter, loc, op.getInput()); emitDmaCacheFlush(rewriter, loc); - Value rs1 = - packRs1BankIter(rewriter, loc, adaptor.getAddr(), adaptor.getHeight()); + Value rs1 = packRs1WriteBankIter(rewriter, loc, adaptor.getAddr(), + adaptor.getHeight()); Value address = rewriter.create( loc, memref.address, cstI64(rewriter, loc, 0xffff'ffffULL)); Value pixel = rewriter.create(loc, adaptor.getPixelBytes(), diff --git a/compiler/src/Dialect/Buckyball/Transforms/LegalizeForLLVMExportBase.h b/compiler/src/Dialect/Buckyball/Transforms/LegalizeForLLVMExportBase.h index 06302d173..4b05c8251 100644 --- a/compiler/src/Dialect/Buckyball/Transforms/LegalizeForLLVMExportBase.h +++ b/compiler/src/Dialect/Buckyball/Transforms/LegalizeForLLVMExportBase.h @@ -40,6 +40,8 @@ mlir::Value packRs1BanksIter(mlir::OpBuilder &b, mlir::Location loc, mlir::Value wBank, mlir::Value iter); mlir::Value packRs1BankIter(mlir::OpBuilder &b, mlir::Location loc, mlir::Value bankId, mlir::Value depth); +mlir::Value packRs1WriteBankIter(mlir::OpBuilder &b, mlir::Location loc, + mlir::Value bankId, mlir::Value depth); mlir::Value packRs2MemStride(mlir::OpBuilder &b, mlir::Location loc, mlir::Value memAddr, mlir::Value stride); void emitMset(mlir::OpBuilder &b, mlir::Location loc, uint64_t bankId, diff --git a/examples/balls/gemmini/arch/src/main/scala/LoopCmdEncoder.scala b/examples/balls/gemmini/arch/src/main/scala/LoopCmdEncoder.scala index 526c52d79..9433a1b31 100644 --- a/examples/balls/gemmini/arch/src/main/scala/LoopCmdEncoder.scala +++ b/examples/balls/gemmini/arch/src/main/scala/LoopCmdEncoder.scala @@ -90,7 +90,7 @@ class LoopCmdEncoder(val b: GlobalConfig) extends Module { is(LoopSubCmdType.MVIN) { slot.cmd.domain_id := DomainId.MEM slot.cmd.cmd.funct := 0x21.U // MVIN (enable=010, opcode=1) - slot.cmd.cmd.rs1Data := lsub.bits.bank_id | (lsub.bits.iter << 30) + slot.cmd.cmd.rs1Data := (lsub.bits.bank_id << 20) | (lsub.bits.iter << 30) slot.cmd.cmd.rs2Data := lsub.bits.dram_addr | (lsub.bits.stride << 39) slot.cmd.bankAccess.wr_bank_valid := true.B slot.cmd.bankAccess.wr_bank_id := lsub.bits.bank_id diff --git a/examples/balls/gemmini/emu/src/80_gemmini_loop_ws.rs b/examples/balls/gemmini/emu/src/80_gemmini_loop_ws.rs index b2fcb8731..6b82fa3ae 100644 --- a/examples/balls/gemmini/emu/src/80_gemmini_loop_ws.rs +++ b/examples/balls/gemmini/emu/src/80_gemmini_loop_ws.rs @@ -4,7 +4,7 @@ use super::super::bank::{bank_row_bytes, MATRIX_SIZE}; use super::gemmini_state::gemini; use super::instruction::ExecContext; use super::loop_micro_ops::{ - alloc, checked_stride, compute, free_after_digest, mvin, mvout, preload, + alloc, checked_stride, compute, free_after_hash, mvin, mvout, preload, }; // Shared implementation @@ -125,9 +125,9 @@ fn exec_loop_impl(xs2: u64, ctx: &mut ExecContext) -> u64 { } } - free_after_digest(ctx, bank_a); - free_after_digest(ctx, bank_b); - free_after_digest(ctx, bank_c); + free_after_hash(ctx, bank_a); + free_after_hash(ctx, bank_b); + free_after_hash(ctx, bank_c); 0 } diff --git a/examples/balls/gemmini/emu/src/96_gemmini_loop_conv_ws.rs b/examples/balls/gemmini/emu/src/96_gemmini_loop_conv_ws.rs index fb3cb4108..36d72f72b 100644 --- a/examples/balls/gemmini/emu/src/96_gemmini_loop_conv_ws.rs +++ b/examples/balls/gemmini/emu/src/96_gemmini_loop_conv_ws.rs @@ -4,7 +4,7 @@ use super::super::bank::{bank_row_bytes, MATRIX_SIZE}; use super::gemmini_state::gemini; use super::instruction::ExecContext; use super::loop_micro_ops::{ - alloc, checked_stride, compute, free_after_digest, mvin, mvout, preload, + alloc, checked_stride, compute, free_after_hash, mvin, mvout, preload, }; // Shared implementation @@ -266,9 +266,9 @@ fn exec_loop_impl(xs2: u64, ctx: &mut ExecContext) -> u64 { } } - free_after_digest(ctx, bank_input); - free_after_digest(ctx, bank_weight); - free_after_digest(ctx, bank_output); + free_after_hash(ctx, bank_input); + free_after_hash(ctx, bank_weight); + free_after_hash(ctx, bank_output); 0 } diff --git a/examples/balls/gemmini/emu/src/gemmini_state.rs b/examples/balls/gemmini/emu/src/gemmini_state.rs index 3da2a7956..04c4b9d4f 100644 --- a/examples/balls/gemmini/emu/src/gemmini_state.rs +++ b/examples/balls/gemmini/emu/src/gemmini_state.rs @@ -1,5 +1,4 @@ //! Global config for Gemmini / loop instructions. Mutex is fine because Spike calls in on a single worker. -use super::super::bank::{mem_read, mem_write}; use std::sync::{Mutex, OnceLock}; #[derive(Clone, Default)] @@ -98,26 +97,3 @@ pub fn in_shift(v: i32, shift: u32) -> i32 { base } } - -pub fn mem_u8(mem: &[u8], addr: u64) -> u8 { - mem_read(mem, addr) -} - -pub fn mem_i8(mem: &[u8], addr: u64) -> i8 { - mem_u8(mem, addr) as i8 -} - -pub fn mem_i32_le(mem: &[u8], addr: u64) -> i32 { - let mut b = [0u8; 4]; - for (i, byte) in b.iter_mut().enumerate() { - *byte = mem_read(mem, addr + i as u64); - } - i32::from_le_bytes(b) -} - -pub fn mem_write_i32(mem: &mut [u8], addr: u64, v: i32) { - let b = v.to_le_bytes(); - for (i, byte) in b.iter().enumerate() { - mem_write(mem, addr + i as u64, *byte); - } -} diff --git a/examples/balls/gemmini/emu/src/loop_micro_ops.rs b/examples/balls/gemmini/emu/src/loop_micro_ops.rs index e2f09a2ff..2363ff88f 100644 --- a/examples/balls/gemmini/emu/src/loop_micro_ops.rs +++ b/examples/balls/gemmini/emu/src/loop_micro_ops.rs @@ -1,16 +1,14 @@ use super::decode; -use super::instruction::ExecContext; +use super::f53_gemmini_preload::GemminiPreload; +use super::f66_gemmini_compute_preloaded::GemminiComputePreloaded; +use super::f67_gemmini_compute_accumulated::GemminiComputeAccumulated; +use super::instruction::{BallInstruction, ExecContext}; const FUNCT_MVOUT: u32 = 16; const FUNCT_MSET: u32 = 32; const FUNCT_MVIN: u32 = 33; const MAX_DMA_STRIDE: u64 = (1 << 19) - 1; -fn ball_funct(mnemonic: &str) -> u32 { - crate::config::ball_domain::funct_for_mnemonic(mnemonic) - .unwrap_or_else(|| panic!("Gemmini mnemonic {mnemonic} is not declared in Core ballISA")) -} - fn execute(funct: u32, xs1: u64, xs2: u64, ctx: &mut ExecContext) { decode::execute_known(funct, xs1, xs2, ctx) .unwrap_or_else(|| panic!("Gemmini loop emitted unsupported micro-op funct7={funct}")); @@ -59,7 +57,7 @@ pub fn alloc(ctx: &mut ExecContext, bank: u64, groups: u64) { } pub fn mvin(ctx: &mut ExecContext, bank: u64, addr: u64, iter: u64, stride: u64) { - execute(FUNCT_MVIN, banks(bank, 0, 0, iter), dma(addr, stride), ctx); + execute(FUNCT_MVIN, banks(0, 0, bank, iter), dma(addr, stride), ctx); } pub fn mvout(ctx: &mut ExecContext, bank: u64, addr: u64, iter: u64, stride: u64) { @@ -67,7 +65,7 @@ pub fn mvout(ctx: &mut ExecContext, bank: u64, addr: u64, iter: u64, stride: u64 } pub fn preload(ctx: &mut ExecContext, source: u64, output: u64, iter: u64) { - execute(ball_funct("GEMMINI_PRELOAD"), banks(source, 0, output, iter), 1, ctx); + GemminiPreload::exec(banks(source, 0, output, iter), 1, ctx); } pub fn compute( @@ -80,16 +78,16 @@ pub fn compute( zero_op2: bool, zero_op1_tail: bool, ) { - let funct = if accumulated { - ball_funct("GEMMINI_COMPUTE_ACCUMULATED") - } else { - ball_funct("GEMMINI_COMPUTE_PRELOADED") - }; let mode = if accumulated { 3 } else { 2 }; let xs2 = mode | ((zero_op2 as u64) << 4) | ((zero_op1_tail as u64) << 5); - execute(funct, banks(op1, op2, output, iter), xs2, ctx); + let xs1 = banks(op1, op2, output, iter); + if accumulated { + GemminiComputeAccumulated::exec(xs1, xs2, ctx); + } else { + GemminiComputePreloaded::exec(xs1, xs2, ctx); + } } -pub fn free_after_digest(ctx: &mut ExecContext, bank: u64) { +pub fn free_after_hash(ctx: &mut ExecContext, bank: u64) { ctx.defer_bank_free(bank); } diff --git a/examples/balls/gemmini/verify/casegen/Cargo.lock b/examples/balls/gemmini/verify/casegen/Cargo.lock new file mode 100644 index 000000000..7e0748b4a --- /dev/null +++ b/examples/balls/gemmini/verify/casegen/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "gemmini-casegen" +version = "0.1.0" diff --git a/examples/balls/gemmini/verify/casegen/Cargo.toml b/examples/balls/gemmini/verify/casegen/Cargo.toml new file mode 100644 index 000000000..6e83ff22e --- /dev/null +++ b/examples/balls/gemmini/verify/casegen/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "gemmini-casegen" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["cdylib"] diff --git a/examples/balls/gemmini/verify/casegen/src/lib.rs b/examples/balls/gemmini/verify/casegen/src/lib.rs new file mode 100644 index 000000000..d027d29e4 --- /dev/null +++ b/examples/balls/gemmini/verify/casegen/src/lib.rs @@ -0,0 +1,4 @@ +#[no_mangle] +pub extern "C" fn gemmini_casegen_present() -> u32 { + 1 +} diff --git a/examples/balls/gemmini/verify/filelists/gemmini_ball.f b/examples/balls/gemmini/verify/filelists/gemmini_ball.f new file mode 100644 index 000000000..c4b12100e --- /dev/null +++ b/examples/balls/gemmini/verify/filelists/gemmini_ball.f @@ -0,0 +1,29 @@ ++incdir+@UVM@/src/ball ++incdir+src ++incdir+src/pkg ++incdir+src/tests ++incdir+@RTL@ + +@UVM@/src/ball/bb_blink_if.sv +@RTL@/PE.sv +@RTL@/AlwaysOutTransposer.sv +@RTL@/MacUnit.sv +@RTL@/PE_256.sv +@RTL@/Tile.sv +@RTL@/Mesh.sv +@RTL@/TagQueue.sv +@RTL@/ram_6x16.sv +@RTL@/Queue6_TagWithIdAndTotalRows.sv +@RTL@/MeshWithDelays.sv +@RTL@/ram_data_16x128.sv +@RTL@/Queue16_SramReadResp.sv +@RTL@/GemminiExCtrl.sv +@RTL@/LoopMatmulUnroller.sv +@RTL@/LoopConvAddrGen.sv +@RTL@/LoopConvUnroller.sv +@RTL@/LoopCmdEncoder.sv +@RTL@/Arbiter2_LoopCmd.sv +@RTL@/GemminiBall.sv + +src/pkg/gemmini_pkg.sv +src/tb_top.sv diff --git a/examples/balls/gemmini/verify/src/common/gemmini_defs.svh b/examples/balls/gemmini/verify/src/common/gemmini_defs.svh new file mode 100644 index 000000000..c2e9a59da --- /dev/null +++ b/examples/balls/gemmini/verify/src/common/gemmini_defs.svh @@ -0,0 +1,3 @@ +`ifndef GEMMINI_LOOP_WS_CONFIG_BOUNDS_FUNCT7 +`error "GEMMINI_LOOP_WS_CONFIG_BOUNDS_FUNCT7 must be provided by the selected Core ballISA" +`endif diff --git a/examples/balls/gemmini/verify/src/pkg/gemmini_pkg.sv b/examples/balls/gemmini/verify/src/pkg/gemmini_pkg.sv new file mode 100644 index 000000000..a74a62eff --- /dev/null +++ b/examples/balls/gemmini/verify/src/pkg/gemmini_pkg.sv @@ -0,0 +1,7 @@ +package gemmini_pkg; + import uvm_pkg::*; + `include "uvm_macros.svh" + + `include "common/gemmini_defs.svh" + `include "tests/gemmini_test.svh" +endpackage diff --git a/examples/balls/gemmini/verify/src/tb_top.sv b/examples/balls/gemmini/verify/src/tb_top.sv new file mode 100644 index 000000000..be6204609 --- /dev/null +++ b/examples/balls/gemmini/verify/src/tb_top.sv @@ -0,0 +1,81 @@ +module tb_top; + import uvm_pkg::*; + import gemmini_pkg::*; + + bb_blink_if #(`BB_IN_BW, `BB_OUT_BW) intf (); + + GemminiBall dut ( + .clock(intf.clock), + .reset(intf.reset), + .io_channelReady(1'b1), + .io_cmdReq_ready(intf.cmd_req_ready), + .io_cmdReq_valid(intf.cmd_req_valid), + .io_cmdReq_bits_cmd_bid(intf.cmd_req_bits_cmd_bid), + .io_cmdReq_bits_cmd_funct7(intf.cmd_req_bits_cmd_funct7), + .io_cmdReq_bits_cmd_iter(intf.cmd_req_bits_cmd_iter), + .io_cmdReq_bits_cmd_op1_en(intf.cmd_req_bits_cmd_op1_en), + .io_cmdReq_bits_cmd_op2_en(intf.cmd_req_bits_cmd_op2_en), + .io_cmdReq_bits_cmd_wr_spad_en(intf.cmd_req_bits_cmd_wr_spad_en), + .io_cmdReq_bits_cmd_op1_from_spad(intf.cmd_req_bits_cmd_op1_from_spad), + .io_cmdReq_bits_cmd_op2_from_spad(intf.cmd_req_bits_cmd_op2_from_spad), + .io_cmdReq_bits_cmd_special(intf.cmd_req_bits_cmd_special), + .io_cmdReq_bits_cmd_op1_bank(intf.cmd_req_bits_cmd_op1_bank), + .io_cmdReq_bits_cmd_op2_bank(intf.cmd_req_bits_cmd_op2_bank), + .io_cmdReq_bits_cmd_wr_bank(intf.cmd_req_bits_cmd_wr_bank), + .io_cmdReq_bits_cmd_op1_col(intf.cmd_req_bits_cmd_op1_col), + .io_cmdReq_bits_cmd_op2_col(intf.cmd_req_bits_cmd_op2_col), + .io_cmdReq_bits_cmd_wr_col(intf.cmd_req_bits_cmd_wr_col), + .io_cmdReq_bits_cmd_meta_bank(intf.cmd_req_bits_cmd_meta_bank), + .io_cmdReq_bits_cmd_rs1(intf.cmd_req_bits_cmd_rs1), + .io_cmdReq_bits_cmd_rs2(intf.cmd_req_bits_cmd_rs2), + .io_cmdReq_bits_rob_id(intf.cmd_req_bits_rob_id), + .io_cmdReq_bits_is_sub(intf.cmd_req_bits_is_sub), + .io_cmdReq_bits_sub_rob_id(intf.cmd_req_bits_sub_rob_id), + .io_cmdResp_ready(intf.cmd_resp_ready), + .io_cmdResp_valid(intf.cmd_resp_valid), + .io_cmdResp_bits_rob_id(intf.cmd_resp_bits_rob_id), + .io_cmdResp_bits_is_sub(intf.cmd_resp_bits_is_sub), + .io_cmdResp_bits_sub_rob_id(intf.cmd_resp_bits_sub_rob_id), + .io_bankRead_0_io_req_ready(intf.bank_read_req_ready[0]), + .io_bankRead_0_io_req_valid(intf.bank_read_req_valid[0]), + .io_bankRead_0_io_resp_ready(intf.bank_read_resp_ready[0]), + .io_bankRead_0_io_resp_valid(intf.bank_read_resp_valid[0]), + .io_bankRead_0_io_resp_bits_data(intf.bank_read_resp_data[0]), + .io_bankRead_1_io_req_ready(intf.bank_read_req_ready[1]), + .io_bankRead_1_io_req_valid(intf.bank_read_req_valid[1]), + .io_bankRead_1_io_resp_ready(intf.bank_read_resp_ready[1]), + .io_bankRead_1_io_resp_valid(intf.bank_read_resp_valid[1]), + .io_bankRead_1_io_resp_bits_data(intf.bank_read_resp_data[1]), + .io_bankWrite_0_io_req_ready(intf.bank_write_req_ready[0]), + .io_bankWrite_0_io_req_valid(intf.bank_write_req_valid[0]), + .io_bankWrite_0_io_resp_ready(intf.bank_write_resp_ready[0]), + .io_bankWrite_0_io_resp_valid(intf.bank_write_resp_valid[0]), + .io_bankWrite_0_io_resp_bits_ok(intf.bank_write_resp_ok[0]), + .io_bankWrite_1_io_req_ready(intf.bank_write_req_ready[1]), + .io_bankWrite_1_io_req_valid(intf.bank_write_req_valid[1]), + .io_bankWrite_1_io_resp_ready(intf.bank_write_resp_ready[1]), + .io_bankWrite_1_io_resp_valid(intf.bank_write_resp_valid[1]), + .io_bankWrite_1_io_resp_bits_ok(intf.bank_write_resp_ok[1]), + .io_bankWrite_2_io_req_ready(intf.bank_write_req_ready[2]), + .io_bankWrite_2_io_req_valid(intf.bank_write_req_valid[2]), + .io_bankWrite_2_io_resp_ready(intf.bank_write_resp_ready[2]), + .io_bankWrite_2_io_resp_valid(intf.bank_write_resp_valid[2]), + .io_bankWrite_2_io_resp_bits_ok(intf.bank_write_resp_ok[2]), + .io_bankWrite_3_io_req_ready(intf.bank_write_req_ready[3]), + .io_bankWrite_3_io_req_valid(intf.bank_write_req_valid[3]), + .io_bankWrite_3_io_resp_ready(intf.bank_write_resp_ready[3]), + .io_bankWrite_3_io_resp_valid(intf.bank_write_resp_valid[3]), + .io_bankWrite_3_io_resp_bits_ok(intf.bank_write_resp_ok[3]), + .io_subRobReq_ready(intf.sub_rob_req_ready) + ); + + initial begin + intf.clock = 1'b0; + forever #5 intf.clock = ~intf.clock; + end + + initial begin + uvm_config_db#(virtual bb_blink_if #(`BB_IN_BW, `BB_OUT_BW))::set(null, "*", "vif", intf); + run_test("gemmini_ball_test"); + end +endmodule diff --git a/examples/balls/gemmini/verify/src/tests/gemmini_test.svh b/examples/balls/gemmini/verify/src/tests/gemmini_test.svh new file mode 100644 index 000000000..f986e8e0d --- /dev/null +++ b/examples/balls/gemmini/verify/src/tests/gemmini_test.svh @@ -0,0 +1,98 @@ +class gemmini_ball_test extends uvm_test; + `uvm_component_utils(gemmini_ball_test) + + typedef virtual bb_blink_if #(`BB_IN_BW, `BB_OUT_BW) vif_t; + vif_t vif; + + function new(string name, uvm_component parent); + super.new(name, parent); + endfunction + + function void build_phase(uvm_phase phase); + super.build_phase(phase); + if (!uvm_config_db#(vif_t)::get(this, "", "vif", vif)) + `uvm_fatal("NOVIF", "bb_blink_if not found") + endfunction + + task run_phase(uvm_phase phase); + int cycles; + int unsigned bid; + phase.raise_objection(this); + apply_reset(); + + @(negedge vif.clock); + if (!$value$plusargs("BID=%d", bid)) `uvm_fatal("BID", "+BID is required") + vif.cmd_req_bits_cmd_bid = bid[4:0]; + vif.cmd_req_bits_cmd_funct7 = `GEMMINI_LOOP_WS_CONFIG_BOUNDS_FUNCT7; + vif.cmd_req_bits_cmd_iter = '0; + vif.cmd_req_bits_cmd_op1_en = 1'b0; + vif.cmd_req_bits_cmd_op2_en = 1'b0; + vif.cmd_req_bits_cmd_wr_spad_en = 1'b0; + vif.cmd_req_bits_cmd_op1_from_spad = 1'b0; + vif.cmd_req_bits_cmd_op2_from_spad = 1'b0; + vif.cmd_req_bits_cmd_special = 64'h0003_0002_0001; + vif.cmd_req_bits_cmd_op1_bank = '0; + vif.cmd_req_bits_cmd_op2_bank = '0; + vif.cmd_req_bits_cmd_wr_bank = '0; + vif.cmd_req_bits_cmd_op1_col = '0; + vif.cmd_req_bits_cmd_op2_col = '0; + vif.cmd_req_bits_cmd_wr_col = '0; + vif.cmd_req_bits_cmd_meta_bank = '0; + vif.cmd_req_bits_cmd_rs1 = '0; + vif.cmd_req_bits_cmd_rs2 = '0; + vif.cmd_req_bits_rob_id = 4'h9; + vif.cmd_req_bits_is_sub = 1'b1; + vif.cmd_req_bits_sub_rob_id = 8'h5a; + vif.cmd_req_valid = 1'b1; + + cycles = 0; + do begin + @(posedge vif.clock); + cycles++; + if (cycles > 20) `uvm_fatal("TIMEOUT", "Gemmini config command was not accepted") + end while (!vif.cmd_req_ready); + @(negedge vif.clock); + vif.cmd_req_valid = 1'b0; + + if (!vif.cmd_resp_valid) `uvm_fatal("RESP", "Gemmini config response was not observed") + if (vif.cmd_resp_bits_rob_id !== 4'h9 || vif.cmd_resp_bits_is_sub !== 1'b1 || + vif.cmd_resp_bits_sub_rob_id !== 8'h5a) + `uvm_fatal("RESP", $sformatf( + "metadata mismatch: rob=%0h is_sub=%0b sub_rob=%0h", + vif.cmd_resp_bits_rob_id, + vif.cmd_resp_bits_is_sub, + vif.cmd_resp_bits_sub_rob_id + )) + for (int i = 0; i < `BB_IN_BW; i++) begin + if (vif.bank_read_req_valid[i]) + `uvm_fatal("BANK", "Gemmini config command unexpectedly read a bank") + end + for (int i = 0; i < `BB_OUT_BW; i++) begin + if (vif.bank_write_req_valid[i]) + `uvm_fatal("BANK", "Gemmini config command unexpectedly wrote a bank") + end + + `uvm_info("GEMMINI", "loop-ws config command passed", UVM_LOW) + phase.drop_objection(this); + endtask + + task apply_reset(); + vif.cmd_req_valid = 1'b0; + vif.cmd_resp_ready = 1'b1; + vif.sub_rob_req_ready = 1'b1; + for (int i = 0; i < `BB_IN_BW; i++) begin + vif.bank_read_req_ready[i] = 1'b1; + vif.bank_read_resp_valid[i] = 1'b0; + vif.bank_read_resp_data[i] = '0; + end + for (int i = 0; i < `BB_OUT_BW; i++) begin + vif.bank_write_req_ready[i] = 1'b1; + vif.bank_write_resp_valid[i] = 1'b0; + vif.bank_write_resp_ok[i] = 1'b1; + end + vif.reset = 1'b1; + repeat (5) @(posedge vif.clock); + vif.reset = 1'b0; + repeat (2) @(posedge vif.clock); + endtask +endclass diff --git a/examples/balls/im2col/arch/src/main/scala/Im2col.scala b/examples/balls/im2col/arch/src/main/scala/Im2col.scala index 40a55c45f..567da6f3a 100644 --- a/examples/balls/im2col/arch/src/main/scala/Im2col.scala +++ b/examples/balls/im2col/arch/src/main/scala/Im2col.scala @@ -218,4 +218,5 @@ class Im2col(val b: GlobalConfig) extends Module { win.io.next := true.B localWindow := localWindow + 1.U } + } diff --git a/examples/balls/smatmul/emu/src/smatmul.rs b/examples/balls/smatmul/emu/src/smatmul.rs index 8be7f56f4..e4152858b 100644 --- a/examples/balls/smatmul/emu/src/smatmul.rs +++ b/examples/balls/smatmul/emu/src/smatmul.rs @@ -2,6 +2,7 @@ use super::super::bank::{bank_lines, bank_row_bytes}; use super::decode::{pbank, rs1_b0, rs1_b1, rs1_b2, rs1_iter}; use super::instruction::ExecContext; use std::cell::RefCell; +use std::collections::HashMap; const BALL_CLASS: &str = "examples.balls.smatmul.SMatMulBall"; @@ -23,7 +24,7 @@ struct Chain { } thread_local! { - static STATE: RefCell = RefCell::new(State::default()); + static STATES: RefCell> = RefCell::new(HashMap::new()); } fn read_i32(bank: &[u8], row: usize, lane: usize) -> i32 { @@ -31,11 +32,6 @@ fn read_i32(bank: &[u8], row: usize, lane: usize) -> i32 { i32::from_le_bytes(bank[offset..offset + 4].try_into().unwrap()) } -fn write_i32(bank: &mut [u8], row: usize, lane: usize, value: i32) { - let offset = row * bank_row_bytes() + lane * 4; - bank[offset..offset + 4].copy_from_slice(&value.to_le_bytes()); -} - pub(crate) fn exec_bias(xs1: u64, xs2: u64, ctx: &mut ExecContext) -> u64 { let bank = rs1_b0(xs1); let input_base = (xs2 & 0x3f) as usize; @@ -55,8 +51,9 @@ pub(crate) fn exec_bias(xs1: u64, xs2: u64, ctx: &mut ExecContext) -> u64 { bias[group * 4 + lane] = read_i32(&ctx.banks[physical], input_base + group, lane); } } - STATE.with(|state| { - let mut state = state.borrow_mut(); + STATES.with(|states| { + let mut states = states.borrow_mut(); + let state = states.entry(ctx.hart_id).or_default(); if state.chain.is_some() { panic!("smatmul_bias: cannot replace bias during an accumulation chain"); } @@ -105,8 +102,9 @@ pub(crate) fn exec_smatmul(xs1: u64, xs2: u64, ctx: &mut ExecContext) -> u64 { panic!("smatmul: bank footprint exceeds bank depth"); } - let mut chain = STATE.with(|state| { - let mut state = state.borrow_mut(); + let mut chain = STATES.with(|states| { + let mut states = states.borrow_mut(); + let state = states.entry(ctx.hart_id).or_default(); if first { if state.chain.is_some() { panic!("smatmul: first block issued while another chain is live"); @@ -178,16 +176,15 @@ pub(crate) fn exec_smatmul(xs1: u64, xs2: u64, ctx: &mut ExecContext) -> u64 { let pc = pbank(ctx, c_bank); for row in 0..rows { for col in 0..cols { - write_i32( - &mut ctx.banks[pc], - output_base + row * 4 + col / 4, - col % 4, - chain.accumulators[row * cols + col], - ); + let offset = (output_base + row * 4 + col / 4) * bank_row_bytes() + col % 4 * 4; + ctx.banks[pc][offset..offset + 4] + .copy_from_slice(&chain.accumulators[row * cols + col].to_le_bytes()); } } } else { - STATE.with(|state| state.borrow_mut().chain = Some(chain)); + STATES.with(|states| { + states.borrow_mut().entry(ctx.hart_id).or_default().chain = Some(chain); + }); } 0 } diff --git a/examples/balls/smatmul/verify/filelists/smatmul_ball.f b/examples/balls/smatmul/verify/filelists/smatmul_ball.f index bc43b7b92..0e290bb6c 100644 --- a/examples/balls/smatmul/verify/filelists/smatmul_ball.f +++ b/examples/balls/smatmul/verify/filelists/smatmul_ball.f @@ -17,7 +17,11 @@ @UVM@/src/ball/bb_blink_if.sv @UVM@/src/ball/bb_uvm_pkg.sv --f @RTL@/filelist.f +@RTL@/PE.sv +@RTL@/Array.sv +@RTL@/SMatMulUnit.sv +@RTL@/SMatMulBall.sv +@RTL@/@SMATMUL_ACCUMULATOR@ src/pkg/smatmul_pkg.sv src/tb_top.sv diff --git a/examples/chips/goban/configs/chip.toml b/examples/chips/goban/configs/chip.toml index c019a8fd6..4ec7a7a58 100644 --- a/examples/chips/goban/configs/chip.toml +++ b/examples/chips/goban/configs/chip.toml @@ -4,3 +4,7 @@ include = "designs/goban.toml" [sims] verilator = "sims.verilator.BuckyballGoban4CoreVerilatorConfig" p2e = "sims.p2e.BuckyballGoban4CoreLinuxP2EConfig" + +[uvm] +balls = ["smatmul", "toint8", "int2fp", "transpose"] +ips = [] diff --git a/examples/chips/goban/configs/designs/tiles/16core-incoherent.toml b/examples/chips/goban/configs/designs/tiles/16core-incoherent.toml index aceef646d..64b651ec5 100644 --- a/examples/chips/goban/configs/designs/tiles/16core-incoherent.toml +++ b/examples/chips/goban/configs/designs/tiles/16core-incoherent.toml @@ -1,5 +1,13 @@ # Goban Tile (16 identical cores) +coreDataBytes = 64 +xLen = 64 +vaddrBits = 39 +paddrBits = 56 +pgIdxBits = 12 +pgLevels = 3 +nPMPs = 8 + memBallChannelNum = 6 [privateDCache] diff --git a/examples/chips/goban/configs/designs/tiles/16core.toml b/examples/chips/goban/configs/designs/tiles/16core.toml index 57648b82b..ab6d33253 100644 --- a/examples/chips/goban/configs/designs/tiles/16core.toml +++ b/examples/chips/goban/configs/designs/tiles/16core.toml @@ -1,5 +1,13 @@ # Goban Tile (16 identical cores) +coreDataBytes = 64 +xLen = 64 +vaddrBits = 39 +paddrBits = 56 +pgIdxBits = 12 +pgLevels = 3 +nPMPs = 8 + memBallChannelNum = 6 [privateDCache] diff --git a/examples/chips/goban/configs/designs/tiles/2core.toml b/examples/chips/goban/configs/designs/tiles/2core.toml index 7660cbf3d..438dfaa11 100644 --- a/examples/chips/goban/configs/designs/tiles/2core.toml +++ b/examples/chips/goban/configs/designs/tiles/2core.toml @@ -1,5 +1,13 @@ # Goban Tile (2 identical cores) +coreDataBytes = 64 +xLen = 64 +vaddrBits = 39 +paddrBits = 56 +pgIdxBits = 12 +pgLevels = 3 +nPMPs = 8 + memBallChannelNum = 6 [privateDCache] diff --git a/examples/chips/goban/configs/designs/tiles/32core.toml b/examples/chips/goban/configs/designs/tiles/32core.toml index 62a4faa3f..54ea67e3f 100644 --- a/examples/chips/goban/configs/designs/tiles/32core.toml +++ b/examples/chips/goban/configs/designs/tiles/32core.toml @@ -1,5 +1,13 @@ # Goban Tile (32 identical cores) +coreDataBytes = 64 +xLen = 64 +vaddrBits = 39 +paddrBits = 56 +pgIdxBits = 12 +pgLevels = 3 +nPMPs = 8 + memBallChannelNum = 6 [privateDCache] diff --git a/examples/chips/goban/configs/designs/tiles/4core-private-1bb.toml b/examples/chips/goban/configs/designs/tiles/4core-private-1bb.toml index f324a3766..0d60159e8 100644 --- a/examples/chips/goban/configs/designs/tiles/4core-private-1bb.toml +++ b/examples/chips/goban/configs/designs/tiles/4core-private-1bb.toml @@ -1,5 +1,13 @@ # Goban Tile (4 cores: core 0 has Buckyball, cores 1-3 are Rocket-only) +coreDataBytes = 64 +xLen = 64 +vaddrBits = 39 +paddrBits = 56 +pgIdxBits = 12 +pgLevels = 3 +nPMPs = 8 + memBallChannelNum = 6 [privateDCache] diff --git a/examples/chips/goban/configs/designs/tiles/64core.toml b/examples/chips/goban/configs/designs/tiles/64core.toml index f46dd4bf1..11652d008 100644 --- a/examples/chips/goban/configs/designs/tiles/64core.toml +++ b/examples/chips/goban/configs/designs/tiles/64core.toml @@ -1,5 +1,13 @@ # Goban Tile (16 identical cores) +coreDataBytes = 64 +xLen = 64 +vaddrBits = 39 +paddrBits = 56 +pgIdxBits = 12 +pgLevels = 3 +nPMPs = 8 + memBallChannelNum = 6 [privateDCache] diff --git a/examples/chips/goban/configs/designs/tiles/8core-incoherent.toml b/examples/chips/goban/configs/designs/tiles/8core-incoherent.toml index 90d1f5c8a..77b7d0a23 100644 --- a/examples/chips/goban/configs/designs/tiles/8core-incoherent.toml +++ b/examples/chips/goban/configs/designs/tiles/8core-incoherent.toml @@ -1,5 +1,13 @@ # Goban Tile (8 identical cores) +coreDataBytes = 64 +xLen = 64 +vaddrBits = 39 +paddrBits = 56 +pgIdxBits = 12 +pgLevels = 3 +nPMPs = 8 + memBallChannelNum = 6 [privateDCache] diff --git a/examples/chips/goban/configs/designs/tiles/8core.toml b/examples/chips/goban/configs/designs/tiles/8core.toml index dfb6f9411..d4c6ef4e4 100644 --- a/examples/chips/goban/configs/designs/tiles/8core.toml +++ b/examples/chips/goban/configs/designs/tiles/8core.toml @@ -1,5 +1,13 @@ # Goban Tile (8 identical cores) +coreDataBytes = 64 +xLen = 64 +vaddrBits = 39 +paddrBits = 56 +pgIdxBits = 12 +pgLevels = 3 +nPMPs = 8 + memBallChannelNum = 6 [privateDCache] diff --git a/examples/chips/goban/configs/designs/tiles/default.toml b/examples/chips/goban/configs/designs/tiles/default.toml index fc5bd61bc..86ff6b542 100644 --- a/examples/chips/goban/configs/designs/tiles/default.toml +++ b/examples/chips/goban/configs/designs/tiles/default.toml @@ -1,5 +1,13 @@ # Goban Tile (default: 4 identical cores) +coreDataBytes = 64 +xLen = 64 +vaddrBits = 39 +paddrBits = 56 +pgIdxBits = 12 +pgLevels = 3 +nPMPs = 8 + memBallChannelNum = 6 [privateDCache] diff --git a/examples/chips/goban/emu/Cargo.lock b/examples/chips/goban/emu/Cargo.lock index 462490dc2..e197405d0 100644 --- a/examples/chips/goban/emu/Cargo.lock +++ b/examples/chips/goban/emu/Cargo.lock @@ -104,7 +104,6 @@ dependencies = [ "serde", "serde_json", "snafu", - "xxhash-rust", ] [[package]] @@ -113,8 +112,10 @@ version = "0.1.0" dependencies = [ "bebop-bank-hash", "bebop-bemu-profile", + "bebop-clint", "bebop-dtb", "bebop-elf", + "bebop-plic", "bebop-rushb", "bebop-syscall", "bebop-uart", @@ -145,14 +146,26 @@ dependencies = [ "walkdir", ] +[[package]] +name = "bebop-clint" +version = "0.1.0" + [[package]] name = "bebop-dtb" version = "0.1.0" +dependencies = [ + "bebop-clint", + "bebop-plic", +] [[package]] name = "bebop-elf" version = "0.1.0" +[[package]] +name = "bebop-plic" +version = "0.1.0" + [[package]] name = "bebop-rushb" version = "0.1.0" @@ -1037,12 +1050,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "xxhash-rust" -version = "0.8.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aee1b19627c7c60102ab80d3a9cbe18de90bfe03bfa6c3715447681f0e8c8af6" - [[package]] name = "zmij" version = "1.0.23" diff --git a/examples/chips/goban/emu/src/main.rs b/examples/chips/goban/emu/src/main.rs index 39ef1cbeb..ff846a96f 100644 --- a/examples/chips/goban/emu/src/main.rs +++ b/examples/chips/goban/emu/src/main.rs @@ -1,15 +1,12 @@ use bebop_bemu::{tile_topology, BemuInstance, SharedMemory, TraceConfig}; use clap::Parser; use std::path::{Path, PathBuf}; -use std::sync::atomic::{AtomicBool, AtomicI32, Ordering}; -use std::sync::{mpsc, Arc, Condvar, Mutex}; -use std::thread; +use std::sync::Arc; const DRAM_SIZE: usize = 1 << 30; #[derive(Parser, Debug)] struct Args { - /// Tile index in the chip bundle. #[arg(long, default_value_t = 0)] tile_index: usize, #[arg(long)] @@ -28,39 +25,6 @@ struct Args { mtrace: bool, } -struct StartGate { - result: Mutex>>, - ready: Condvar, -} - -impl StartGate { - fn new() -> Self { - Self { - result: Mutex::new(None), - ready: Condvar::new(), - } - } - - fn wait(&self) -> Result<(), String> { - let mut result = self - .result - .lock() - .map_err(|_| "BEMU start gate poisoned".to_string())?; - while result.is_none() { - result = self - .ready - .wait(result) - .map_err(|_| "BEMU start gate poisoned".to_string())?; - } - result.as_ref().expect("BEMU start gate was set").clone() - } - - fn release(&self, result: Result<(), String>) { - *self.result.lock().expect("BEMU start gate poisoned") = Some(result); - self.ready.notify_all(); - } -} - fn main() { if let Err(error) = run(Args::parse()) { eprintln!("error: {error}"); @@ -72,9 +36,6 @@ fn run(args: Args) -> Result<(), String> { let elf = absolute(&args.elf)?; let log_dir = absolute(&args.log_dir)?; let topology = tile_topology(args.tile_index); - if topology.cores.is_empty() { - return Err(format!("tile {} has no Core instances", args.tile_index)); - } eprintln!( "[INFO] Goban Chip BEMU: tile_index={} cores={} shared_dram={}MiB", args.tile_index, @@ -91,172 +52,53 @@ fn run(args: Args) -> Result<(), String> { topology.shared_bank_size, virtual_bank_count, ); - let schedule = Arc::new(Mutex::new(())); - let start = Arc::new(StartGate::new()); - let done = Arc::new(AtomicBool::new(false)); - let exit_code = Arc::new(AtomicI32::new(0)); - let (prepared_tx, prepared_rx) = mpsc::channel(); - let mut workers = Vec::with_capacity(topology.cores.len()); + let mut harts = Vec::with_capacity(core_count); for (local_id, (core_name, core_index)) in topology.cores.into_iter().enumerate() { let hart_id = args.tile_index * core_count + local_id; - let elf = elf.clone(); - let worker_log = log_dir.join(format!("hart-{hart_id}")); - let memory = Arc::clone(&memory); - let schedule = Arc::clone(&schedule); - let start = Arc::clone(&start); - let done = Arc::clone(&done); - let exit_code = Arc::clone(&exit_code); - let prepared_tx = prepared_tx.clone(); - let pk = args.pk; - let disasm = args.disasm; - let tool_profile = args.tool_profile; - let trace = TraceConfig::new(args.itrace, args.mtrace); - workers.push( - thread::Builder::new() - .name(format!("core-{hart_id}-{core_name}")) - .spawn(move || { - run_core( - hart_id, - local_id, - &core_name, - core_index, - &elf, - &worker_log, - pk, - disasm, - tool_profile, - trace, - memory, - schedule, - start, - done, - exit_code, - prepared_tx, - virtual_bank_count, - ) - }) - .map_err(|error| format!("failed to spawn Core worker {hart_id}: {error}"))?, - ); - } - drop(prepared_tx); - - let mut preparation_error = None; - for _ in 0..workers.len() { - if let Err(error) = prepared_rx - .recv() - .map_err(|_| "Core worker exited before initialization".to_string())? - { - preparation_error.get_or_insert(error); - } - } - start.release(preparation_error.map_or(Ok(()), Err)); - - let mut first_error = None; - for (hart_id, worker) in workers.into_iter().enumerate() { - match worker.join() { - Ok(Ok(())) => {} - Ok(Err(error)) => { - first_error.get_or_insert(format!("Core worker {hart_id}: {error}")); - } - Err(_) => { - first_error.get_or_insert(format!("Core worker {hart_id} panicked")); - } - }; - } - first_error.map_or(Ok(()), Err) -} - -#[allow(clippy::too_many_arguments)] -fn run_core( - hart_id: usize, - local_id: usize, - core_name: &str, - core_index: usize, - elf: &Path, - log_dir: &Path, - pk: bool, - disasm: bool, - tool_profile: bool, - trace: TraceConfig, - memory: Arc, - schedule: Arc>, - start: Arc, - done: Arc, - exit_code: Arc, - prepared: mpsc::Sender>, - virtual_bank_count: usize, -) -> Result<(), String> { - eprintln!( - "[INFO] starting Core worker hart={hart_id} core={core_name} core_index={core_index}" - ); - let prepared_bemu = (|| { - let _turn = schedule - .lock() - .map_err(|_| "BEMU scheduler poisoned".to_string())?; let mut bemu = BemuInstance::new_with_core_hart( - log_dir, - trace, - disasm, - tool_profile, + &log_dir.join(format!("hart-{hart_id}")), + TraceConfig::new(args.itrace, args.mtrace), + args.disasm, + args.tool_profile, core_index, hart_id, Some(Arc::clone(&memory)), Some(virtual_bank_count), ) .map_err(|error| error.to_string())?; - bemu.load_elf(elf).map_err(|error| error.to_string())?; - bemu.init_hart(pk).map_err(|error| error.to_string())?; - Ok::(bemu) - })(); - - let mut bemu = match prepared_bemu { - Ok(bemu) => { - let _ = prepared.send(Ok(())); - bemu - } - Err(error) => { - let _ = prepared.send(Err(error.clone())); - return Err(error); - } - }; - start.wait()?; + bemu.load_elf(&elf).map_err(|error| error.to_string())?; + bemu.init_hart(args.pk).map_err(|error| error.to_string())?; + harts.push((hart_id, core_name, bemu, false)); + } loop { - let barrier_hit = { - let _turn = schedule - .lock() - .map_err(|_| "BEMU scheduler poisoned".to_string())?; - if done.load(Ordering::Acquire) { - bemu.stop(exit_code.load(Ordering::Acquire)); - break; + if let Some((hart_id, core_name, code)) = harts.iter().find_map(|(hart_id, core_name, bemu, _)| { + bemu.finished().then(|| (*hart_id, core_name.clone(), bemu.exit_code().unwrap_or(1))) + }) { + for (_, _, bemu, _) in &mut harts { + bemu.stop(code); } - if let Err(error) = bemu.step() { - exit_code.store(1, Ordering::Release); - done.store(true, Ordering::Release); - memory.abort_barrier(); - return Err(error.to_string()); - } - bemu.barrier_hit() - }; - if barrier_hit { - memory.wait_barrier(local_id); + eprintln!("[INFO] stopped Core worker hart={hart_id} core={core_name} exit={code}"); + return if code == 0 { + Ok(()) + } else { + Err(format!("Core worker {hart_id}: guest exited with code {code}")) + }; } - if bemu.finished() { - let code = bemu.exit_code().unwrap_or(1); - exit_code.store(code, Ordering::Release); - done.store(true, Ordering::Release); - memory.abort_barrier(); - break; + + if harts.iter().all(|(_, _, _, waiting)| *waiting) { + for (_, _, _, waiting) in &mut harts { + *waiting = false; + } } - } - let code = exit_code.load(Ordering::Acquire); - eprintln!("[INFO] stopped Core worker hart={hart_id} core={core_name} exit={code}"); - if code == 0 { - Ok(()) - } else { - Err(format!("guest exited with code {code}")) + for (_, _, bemu, waiting) in &mut harts { + if !*waiting { + bemu.step(1).map_err(|error| error.to_string())?; + *waiting = bemu.take_barrier(); + } + } } } diff --git a/examples/chips/goban/regression/batch/p2e/workloads-elf.toml b/examples/chips/goban/regression/batch/p2e/workloads-elf.toml new file mode 100644 index 000000000..fd68ff340 --- /dev/null +++ b/examples/chips/goban/regression/batch/p2e/workloads-elf.toml @@ -0,0 +1,11 @@ +[workloads] +tests = [ + "goban-goban-ctest-chip-topology_smoke_test-multicore-baremetal.hex", + "goban-goban-ctest-chip-barrier_test-multicore-baremetal.hex", + "goban-goban-ctest-chip-barrier_mvin_test-multicore-baremetal.hex", + "goban-goban-ctest-chip-shared_barrier_mvin_test-multicore-baremetal.hex", + "goban-goban-ctest-chip-shared_same_vbank_test-multicore-baremetal.hex", + "goban-goban-ctest-chip-shared_multigroup_mvin_test-multicore-baremetal.hex", + "goban-goban-ctest-chip-shared_transpose_test-multicore-baremetal.hex", + "goban-goban-ctest-chip-shared_smatmul_quant_int2fp_pipeline_test-multicore-baremetal.hex", +] diff --git a/examples/chips/multi-rocket/configs/chip.toml b/examples/chips/multi-rocket/configs/chip.toml index 505b0694d..39d68a9a4 100644 --- a/examples/chips/multi-rocket/configs/chip.toml +++ b/examples/chips/multi-rocket/configs/chip.toml @@ -4,3 +4,7 @@ include = "designs/multi-rocket.toml" [sims] verilator = "sims.verilator.MultiRocket32CoreVerilatorConfig" p2e = "sims.p2e.MultiRocket32CoreLinuxP2EConfig" + +[uvm] +balls = [] +ips = ["axis"] diff --git a/examples/chips/multi-rocket/configs/designs/tiles/32core.toml b/examples/chips/multi-rocket/configs/designs/tiles/32core.toml index 53f185086..77e54dede 100644 --- a/examples/chips/multi-rocket/configs/designs/tiles/32core.toml +++ b/examples/chips/multi-rocket/configs/designs/tiles/32core.toml @@ -1,5 +1,13 @@ # multi-rocket Tile (32 Rocket-only cores) +coreDataBytes = 64 +xLen = 64 +vaddrBits = 39 +paddrBits = 56 +pgIdxBits = 12 +pgLevels = 3 +nPMPs = 8 + [privateDCache] enable = true ways = 4 diff --git a/examples/chips/multi-rocket/configs/designs/tiles/48core.toml b/examples/chips/multi-rocket/configs/designs/tiles/48core.toml index 0dcd6c8b7..c4468831c 100644 --- a/examples/chips/multi-rocket/configs/designs/tiles/48core.toml +++ b/examples/chips/multi-rocket/configs/designs/tiles/48core.toml @@ -1,5 +1,13 @@ # multi-rocket Tile (48 Rocket-only cores) +coreDataBytes = 64 +xLen = 64 +vaddrBits = 39 +paddrBits = 56 +pgIdxBits = 12 +pgLevels = 3 +nPMPs = 8 + [privateDCache] enable = true ways = 4 diff --git a/examples/chips/multi-rocket/emu/src/main.rs b/examples/chips/multi-rocket/emu/src/main.rs index 175e089dd..aea42b9fd 100644 --- a/examples/chips/multi-rocket/emu/src/main.rs +++ b/examples/chips/multi-rocket/emu/src/main.rs @@ -1,5 +1,5 @@ -use clap::Parser; use bebop_bemu::{tile_topology, BemuInstance, SharedMemory, TraceConfig}; +use clap::Parser; use std::path::{Path, PathBuf}; use std::sync::atomic::{AtomicBool, AtomicI32, Ordering}; use std::sync::{mpsc, Arc, Condvar, Mutex}; @@ -38,9 +38,15 @@ impl StartGate { } fn wait(&self) -> Result<(), String> { - let mut result = self.result.lock().map_err(|_| "BEMU start gate poisoned".to_string())?; + let mut result = self + .result + .lock() + .map_err(|_| "BEMU start gate poisoned".to_string())?; while result.is_none() { - result = self.ready.wait(result).map_err(|_| "BEMU start gate poisoned".to_string())?; + result = self + .ready + .wait(result) + .map_err(|_| "BEMU start gate poisoned".to_string())?; } result.as_ref().expect("BEMU start gate was set").clone() } @@ -129,7 +135,10 @@ fn run(args: Args) -> Result<(), String> { let mut preparation_error = None; for _ in 0..workers.len() { - if let Err(error) = prepared_rx.recv().map_err(|_| "Core worker exited before initialization".to_string())? { + if let Err(error) = prepared_rx + .recv() + .map_err(|_| "Core worker exited before initialization".to_string())? + { preparation_error.get_or_insert(error); } } @@ -172,7 +181,9 @@ fn run_core( "[INFO] starting Core worker hart={hart_id} core={core_name} core_index={core_index}" ); let prepared_bemu = (|| { - let _turn = schedule.lock().map_err(|_| "BEMU scheduler poisoned".to_string())?; + let _turn = schedule + .lock() + .map_err(|_| "BEMU scheduler poisoned".to_string())?; let mut bemu = BemuInstance::new_with_core_hart( log_dir, TraceConfig::new(false, false), @@ -203,12 +214,14 @@ fn run_core( loop { let barrier_hit = { - let _turn = schedule.lock().map_err(|_| "BEMU scheduler poisoned".to_string())?; + let _turn = schedule + .lock() + .map_err(|_| "BEMU scheduler poisoned".to_string())?; if done.load(Ordering::Acquire) { bemu.stop(exit_code.load(Ordering::Acquire)); break; } - if let Err(error) = bemu.step() { + if let Err(error) = bemu.step(1) { exit_code.store(1, Ordering::Release); done.store(true, Ordering::Release); memory.abort_barrier(); diff --git a/examples/chips/multi-rocket/regression/batch/p2e/workloads-elf.toml b/examples/chips/multi-rocket/regression/batch/p2e/workloads-elf.toml new file mode 100644 index 000000000..eb3873881 --- /dev/null +++ b/examples/chips/multi-rocket/regression/batch/p2e/workloads-elf.toml @@ -0,0 +1,21 @@ +[workloads] +tests = [ + "multi-rocket-rocket-ctest-benchmark-embench_aha-mont64-baremetal.hex", + "multi-rocket-rocket-ctest-benchmark-embench_crc32-baremetal.hex", + "multi-rocket-rocket-ctest-benchmark-embench_edn-baremetal.hex", + "multi-rocket-rocket-ctest-benchmark-embench_huffbench-baremetal.hex", + "multi-rocket-rocket-ctest-benchmark-embench_matmult-int-baremetal.hex", + "multi-rocket-rocket-ctest-benchmark-embench_minver-baremetal.hex", + "multi-rocket-rocket-ctest-benchmark-embench_nbody-baremetal.hex", + "multi-rocket-rocket-ctest-benchmark-embench_nettle-aes-baremetal.hex", + "multi-rocket-rocket-ctest-benchmark-embench_nettle-sha256-baremetal.hex", + "multi-rocket-rocket-ctest-benchmark-embench_nsichneu-baremetal.hex", + "multi-rocket-rocket-ctest-benchmark-embench_picojpeg-baremetal.hex", + "multi-rocket-rocket-ctest-benchmark-embench_qrduino-baremetal.hex", + "multi-rocket-rocket-ctest-benchmark-embench_sglib-combined-baremetal.hex", + "multi-rocket-rocket-ctest-benchmark-embench_slre-baremetal.hex", + "multi-rocket-rocket-ctest-benchmark-embench_st-baremetal.hex", + "multi-rocket-rocket-ctest-benchmark-embench_statemate-baremetal.hex", + "multi-rocket-rocket-ctest-benchmark-embench_ud-baremetal.hex", + "multi-rocket-rocket-ctest-benchmark-embench_wikisort-baremetal.hex", +] diff --git a/examples/chips/pebble/configs/chip.toml b/examples/chips/pebble/configs/chip.toml index 8a2a4ead1..e1281687b 100644 --- a/examples/chips/pebble/configs/chip.toml +++ b/examples/chips/pebble/configs/chip.toml @@ -6,3 +6,7 @@ verilator = "sims.verilator.BuckyballPebbleVerilatorConfig" p2e = "sims.p2e.P2EPebbleLinuxConfig" tapeout = "sims.tapeout.BuckyballPebbleTapeoutConfig" firesim = "sims.firesim.FireSimBuckyballPebbleConfig" + +[uvm] +balls = ["transpose", "smatmul", "im2col", "toint8", "int2fp", "lut", "maxpool", "int8add", "int8mul", "matadd"] +ips = [] diff --git a/examples/chips/pebble/configs/designs/tiles/default.toml b/examples/chips/pebble/configs/designs/tiles/default.toml index e91d7b9b6..6ea1654c0 100644 --- a/examples/chips/pebble/configs/designs/tiles/default.toml +++ b/examples/chips/pebble/configs/designs/tiles/default.toml @@ -1,5 +1,13 @@ # Pebble tile configuration +coreDataBytes = 64 +xLen = 64 +vaddrBits = 39 +paddrBits = 56 +pgIdxBits = 12 +pgLevels = 3 +nPMPs = 8 + memBallChannelNum = 6 [privateDCache] diff --git a/examples/chips/pebble/regression/batch/p2e/workloads-pk.toml b/examples/chips/pebble/regression/batch/p2e/workloads-pk.toml index e873b2161..7e7565072 100644 --- a/examples/chips/pebble/regression/batch/p2e/workloads-pk.toml +++ b/examples/chips/pebble/regression/batch/p2e/workloads-pk.toml @@ -1,4 +1,4 @@ [workloads] tests = [ - "fw_payload-pebble-pk.hex", + "fw_payload-v1-t1-pebble-pk.hex", ] diff --git a/examples/chips/poly/arch/src/main/scala/sims/verilator/TargetConfigs.scala b/examples/chips/poly/arch/src/main/scala/sims/verilator/TargetConfigs.scala index 6cdcd8a13..3c1bab498 100644 --- a/examples/chips/poly/arch/src/main/scala/sims/verilator/TargetConfigs.scala +++ b/examples/chips/poly/arch/src/main/scala/sims/verilator/TargetConfigs.scala @@ -4,7 +4,8 @@ import org.chipsalliance.cde.config.Config class BuckyballPolyVerilatorConfig extends Config( - new BBSimConfig(maxHarts = 20) ++ + new freechips.rocketchip.subsystem.WithoutTLMonitors ++ + new BBSimConfig(maxHarts = 20) ++ new WithCustomBootROM ++ new examples.poly.BuckyballPolyConfig ) diff --git a/examples/chips/poly/configs/chip.toml b/examples/chips/poly/configs/chip.toml index 1e38dff3c..9f4a42822 100644 --- a/examples/chips/poly/configs/chip.toml +++ b/examples/chips/poly/configs/chip.toml @@ -4,3 +4,7 @@ include = "designs/poly.toml" [sims] verilator = "sims.verilator.BuckyballPolyVerilatorConfig" p2e = "sims.p2e.BuckyballPolyLinuxP2EConfig" + +[uvm] +balls = ["smatmul", "toint8", "int2fp", "transpose"] +ips = [] diff --git a/examples/chips/poly/configs/designs/tiles/default.toml b/examples/chips/poly/configs/designs/tiles/default.toml index fdf1973e7..14ae03d1f 100644 --- a/examples/chips/poly/configs/designs/tiles/default.toml +++ b/examples/chips/poly/configs/designs/tiles/default.toml @@ -1,5 +1,13 @@ # Poly Tile: three prefill Cores and two decode Cores. +coreDataBytes = 64 +xLen = 64 +vaddrBits = 39 +paddrBits = 56 +pgIdxBits = 12 +pgLevels = 3 +nPMPs = 8 + memBallChannelNum = 6 [privateDCache] diff --git a/examples/chips/poly/emu/Cargo.lock b/examples/chips/poly/emu/Cargo.lock index 0f1ef1213..9d6543b94 100644 --- a/examples/chips/poly/emu/Cargo.lock +++ b/examples/chips/poly/emu/Cargo.lock @@ -104,7 +104,6 @@ dependencies = [ "serde", "serde_json", "snafu", - "xxhash-rust", ] [[package]] @@ -113,8 +112,10 @@ version = "0.1.0" dependencies = [ "bebop-bank-hash", "bebop-bemu-profile", + "bebop-clint", "bebop-dtb", "bebop-elf", + "bebop-plic", "bebop-rushb", "bebop-syscall", "bebop-uart", @@ -145,14 +146,26 @@ dependencies = [ "walkdir", ] +[[package]] +name = "bebop-clint" +version = "0.1.0" + [[package]] name = "bebop-dtb" version = "0.1.0" +dependencies = [ + "bebop-clint", + "bebop-plic", +] [[package]] name = "bebop-elf" version = "0.1.0" +[[package]] +name = "bebop-plic" +version = "0.1.0" + [[package]] name = "bebop-rushb" version = "0.1.0" @@ -1037,12 +1050,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "xxhash-rust" -version = "0.8.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aee1b19627c7c60102ab80d3a9cbe18de90bfe03bfa6c3715447681f0e8c8af6" - [[package]] name = "zmij" version = "1.0.23" diff --git a/examples/chips/poly/emu/src/main.rs b/examples/chips/poly/emu/src/main.rs index 2b1ee4fb3..e9fd323d9 100644 --- a/examples/chips/poly/emu/src/main.rs +++ b/examples/chips/poly/emu/src/main.rs @@ -1,9 +1,7 @@ -use clap::Parser; use bebop_bemu::{tile_topology, BemuInstance, SharedMemory, TraceConfig}; +use clap::Parser; use std::path::{Path, PathBuf}; -use std::sync::atomic::{AtomicBool, AtomicI32, Ordering}; -use std::sync::{mpsc, Arc, Condvar, Mutex}; -use std::thread; +use std::sync::Arc; const DRAM_SIZE: usize = 1 << 30; @@ -28,33 +26,6 @@ struct Args { mtrace: bool, } -struct StartGate { - result: Mutex>>, - ready: Condvar, -} - -impl StartGate { - fn new() -> Self { - Self { - result: Mutex::new(None), - ready: Condvar::new(), - } - } - - fn wait(&self) -> Result<(), String> { - let mut result = self.result.lock().map_err(|_| "BEMU start gate poisoned".to_string())?; - while result.is_none() { - result = self.ready.wait(result).map_err(|_| "BEMU start gate poisoned".to_string())?; - } - result.as_ref().expect("BEMU start gate was set").clone() - } - - fn release(&self, result: Result<(), String>) { - *self.result.lock().expect("BEMU start gate poisoned") = Some(result); - self.ready.notify_all(); - } -} - fn main() { if let Err(error) = run(Args::parse()) { eprintln!("error: {error}"); @@ -66,9 +37,6 @@ fn run(args: Args) -> Result<(), String> { let elf = absolute(&args.elf)?; let log_dir = absolute(&args.log_dir)?; let topology = tile_topology(args.tile_index); - if topology.cores.is_empty() { - return Err(format!("tile {} has no Core instances", args.tile_index)); - } eprintln!( "[INFO] Poly Chip BEMU: tile_index={} cores={} shared_dram={}MiB", args.tile_index, @@ -85,165 +53,54 @@ fn run(args: Args) -> Result<(), String> { topology.shared_bank_size, virtual_bank_count, ); - let schedule = Arc::new(Mutex::new(())); - let start = Arc::new(StartGate::new()); - let done = Arc::new(AtomicBool::new(false)); - let exit_code = Arc::new(AtomicI32::new(0)); - let (prepared_tx, prepared_rx) = mpsc::channel(); - let mut workers = Vec::with_capacity(topology.cores.len()); + let mut harts = Vec::with_capacity(topology.cores.len()); for (local_id, (core_name, core_index)) in topology.cores.into_iter().enumerate() { let hart_id = args.tile_index * core_count + local_id; - let elf = elf.clone(); let worker_log = log_dir.join(format!("hart-{hart_id}")); - let memory = Arc::clone(&memory); - let schedule = Arc::clone(&schedule); - let start = Arc::clone(&start); - let done = Arc::clone(&done); - let exit_code = Arc::clone(&exit_code); - let prepared_tx = prepared_tx.clone(); - let pk = args.pk; - let disasm = args.disasm; - let tool_profile = args.tool_profile; - let trace = TraceConfig::new(args.itrace, args.mtrace); - workers.push( - thread::Builder::new() - .name(format!("core-{hart_id}-{core_name}")) - .spawn(move || { - run_core( - hart_id, - local_id, - &core_name, - core_index, - &elf, - &worker_log, - pk, - disasm, - tool_profile, - trace, - memory, - schedule, - start, - done, - exit_code, - prepared_tx, - virtual_bank_count, - ) - }) - .map_err(|error| format!("failed to spawn Core worker {hart_id}: {error}"))?, - ); - } - drop(prepared_tx); - - let mut preparation_error = None; - for _ in 0..workers.len() { - if let Err(error) = prepared_rx.recv().map_err(|_| "Core worker exited before initialization".to_string())? { - preparation_error.get_or_insert(error); - } - } - start.release(preparation_error.map_or(Ok(()), Err)); - - let mut first_error = None; - for (hart_id, worker) in workers.into_iter().enumerate() { - match worker.join() { - Ok(Ok(())) => {} - Ok(Err(error)) => { - first_error.get_or_insert(format!("Core worker {hart_id}: {error}")); - } - Err(_) => { - first_error.get_or_insert(format!("Core worker {hart_id} panicked")); - } - }; - } - first_error.map_or(Ok(()), Err) -} - -#[allow(clippy::too_many_arguments)] -fn run_core( - hart_id: usize, - local_id: usize, - core_name: &str, - core_index: usize, - elf: &Path, - log_dir: &Path, - pk: bool, - disasm: bool, - tool_profile: bool, - trace: TraceConfig, - memory: Arc, - schedule: Arc>, - start: Arc, - done: Arc, - exit_code: Arc, - prepared: mpsc::Sender>, - virtual_bank_count: usize, -) -> Result<(), String> { - eprintln!( - "[INFO] starting Core worker hart={hart_id} core={core_name} core_index={core_index}" - ); - let prepared_bemu = (|| { - let _turn = schedule.lock().map_err(|_| "BEMU scheduler poisoned".to_string())?; let mut bemu = BemuInstance::new_with_core_hart( - log_dir, - trace, - disasm, - tool_profile, + &worker_log, + TraceConfig::new(args.itrace, args.mtrace), + args.disasm, + args.tool_profile, core_index, hart_id, Some(Arc::clone(&memory)), Some(virtual_bank_count), ) .map_err(|error| error.to_string())?; - bemu.load_elf(elf).map_err(|error| error.to_string())?; - bemu.init_hart(pk).map_err(|error| error.to_string())?; - Ok::(bemu) - })(); - - let mut bemu = match prepared_bemu { - Ok(bemu) => { - let _ = prepared.send(Ok(())); - bemu - } - Err(error) => { - let _ = prepared.send(Err(error.clone())); - return Err(error); - } - }; - start.wait()?; + bemu.load_elf(&elf).map_err(|error| error.to_string())?; + bemu.init_hart(args.pk).map_err(|error| error.to_string())?; + harts.push((hart_id, core_name, bemu, false)); + } loop { - let barrier_hit = { - let _turn = schedule.lock().map_err(|_| "BEMU scheduler poisoned".to_string())?; - if done.load(Ordering::Acquire) { - bemu.stop(exit_code.load(Ordering::Acquire)); - break; + if let Some((hart_id, core_name, code)) = harts.iter().find_map(|(hart_id, core_name, bemu, _)| { + bemu.finished().then(|| (*hart_id, core_name.clone(), bemu.exit_code().unwrap_or(1))) + }) { + for (_, _, bemu, _) in &mut harts { + bemu.stop(code); } - if let Err(error) = bemu.step() { - exit_code.store(1, Ordering::Release); - done.store(true, Ordering::Release); - memory.abort_barrier(); - return Err(error.to_string()); - } - bemu.barrier_hit() - }; - if barrier_hit { - memory.wait_barrier(local_id); + eprintln!("[INFO] stopped Core worker hart={hart_id} core={core_name} exit={code}"); + return if code == 0 { + Ok(()) + } else { + Err(format!("Core worker {hart_id}: guest exited with code {code}")) + }; } - if bemu.finished() { - let code = bemu.exit_code().unwrap_or(1); - exit_code.store(code, Ordering::Release); - done.store(true, Ordering::Release); - memory.abort_barrier(); - break; + + if harts.iter().all(|(_, _, _, waiting)| *waiting) { + for (_, _, _, waiting) in &mut harts { + *waiting = false; + } } - } - let code = exit_code.load(Ordering::Acquire); - eprintln!("[INFO] stopped Core worker hart={hart_id} core={core_name} exit={code}"); - if code == 0 { - Ok(()) - } else { - Err(format!("guest exited with code {code}")) + for (_, _, bemu, waiting) in &mut harts { + if !*waiting { + bemu.step(1).map_err(|error| error.to_string())?; + *waiting = bemu.take_barrier(); + } + } } } diff --git a/examples/chips/poly/regression/batch/p2e/workloads-elf.toml b/examples/chips/poly/regression/batch/p2e/workloads-elf.toml new file mode 100644 index 000000000..e447bec52 --- /dev/null +++ b/examples/chips/poly/regression/batch/p2e/workloads-elf.toml @@ -0,0 +1,4 @@ +[workloads] +tests = [ + "poly-decode-ctest-chip-vecmat16_atranspose_16x16-multicore-baremetal.hex", +] diff --git a/examples/chips/poly/regression/batch/verilator/workloads-elf.toml b/examples/chips/poly/regression/batch/verilator/workloads-elf.toml new file mode 100644 index 000000000..8ab0aa98c --- /dev/null +++ b/examples/chips/poly/regression/batch/verilator/workloads-elf.toml @@ -0,0 +1,4 @@ +[workloads] +tests = [ + "poly-decode-ctest-chip-vecmat16_atranspose_16x16-multicore-baremetal", +] diff --git a/examples/chips/poly/workloads/ctests/vecmat16_atranspose_16x16/vecmat16_atranspose_16x16-main.cpp b/examples/chips/poly/workloads/ctests/vecmat16_atranspose_16x16/vecmat16_atranspose_16x16-main.cpp index 68db94635..efe27760f 100644 --- a/examples/chips/poly/workloads/ctests/vecmat16_atranspose_16x16/vecmat16_atranspose_16x16-main.cpp +++ b/examples/chips/poly/workloads/ctests/vecmat16_atranspose_16x16/vecmat16_atranspose_16x16-main.cpp @@ -9,6 +9,9 @@ volatile int test_result = 1; int main() { core_id_t id = bb_get_core_id(); + if (id.tile != 0) + for (;;) + asm volatile("wfi"); if (id.core < 3) return prefill_main(id); if (id.core < 5) diff --git a/examples/chips/toy/configs/chip.toml b/examples/chips/toy/configs/chip.toml index c25088232..7fd790325 100644 --- a/examples/chips/toy/configs/chip.toml +++ b/examples/chips/toy/configs/chip.toml @@ -5,3 +5,7 @@ include = "designs/toy.toml" verilator = "sims.verilator.BuckyballToyVerilatorConfig" p2e = "sims.p2e.P2EToyLinuxConfig" firesim = "sims.firesim.FireSimBuckyballToyConfig" + +[uvm] +balls = ["gemmini"] +ips = ["axis"] diff --git a/examples/chips/toy/configs/designs/tiles/16core.toml b/examples/chips/toy/configs/designs/tiles/16core.toml index 33db43e84..01d7a0ee5 100644 --- a/examples/chips/toy/configs/designs/tiles/16core.toml +++ b/examples/chips/toy/configs/designs/tiles/16core.toml @@ -1,5 +1,13 @@ # Toy Tile Configuration (16 cores, shared tile-private L2) +coreDataBytes = 64 +xLen = 64 +vaddrBits = 39 +paddrBits = 56 +pgIdxBits = 12 +pgLevels = 3 +nPMPs = 8 + memBallChannelNum = 6 [privateDCache] diff --git a/examples/chips/toy/configs/designs/tiles/4core.toml b/examples/chips/toy/configs/designs/tiles/4core.toml index 71e4fd902..43b34ad7b 100644 --- a/examples/chips/toy/configs/designs/tiles/4core.toml +++ b/examples/chips/toy/configs/designs/tiles/4core.toml @@ -1,5 +1,13 @@ # Toy Tile Configuration (8 cores, shared tile-private L2) +coreDataBytes = 64 +xLen = 64 +vaddrBits = 39 +paddrBits = 56 +pgIdxBits = 12 +pgLevels = 3 +nPMPs = 8 + memBallChannelNum = 6 [privateDCache] diff --git a/examples/chips/toy/configs/designs/tiles/8core.toml b/examples/chips/toy/configs/designs/tiles/8core.toml index 2db67672c..3b323e41b 100644 --- a/examples/chips/toy/configs/designs/tiles/8core.toml +++ b/examples/chips/toy/configs/designs/tiles/8core.toml @@ -1,5 +1,13 @@ # Toy Tile Configuration (8 cores, shared tile-private L2) +coreDataBytes = 64 +xLen = 64 +vaddrBits = 39 +paddrBits = 56 +pgIdxBits = 12 +pgLevels = 3 +nPMPs = 8 + memBallChannelNum = 6 [privateDCache] diff --git a/examples/chips/toy/configs/designs/tiles/default.toml b/examples/chips/toy/configs/designs/tiles/default.toml index d83ed3031..f830aaba2 100644 --- a/examples/chips/toy/configs/designs/tiles/default.toml +++ b/examples/chips/toy/configs/designs/tiles/default.toml @@ -1,5 +1,13 @@ # Toy Tile Configuration (1 core) +coreDataBytes = 64 +xLen = 64 +vaddrBits = 39 +paddrBits = 56 +pgIdxBits = 12 +pgLevels = 3 +nPMPs = 8 + memBallChannelNum = 6 [privateDCache] diff --git a/examples/cores/boom/configs/boomCore.toml b/examples/cores/boom/configs/cpu/boom/default.toml similarity index 100% rename from examples/cores/boom/configs/boomCore.toml rename to examples/cores/boom/configs/cpu/boom/default.toml diff --git a/examples/cores/boom/configs/cpu/default.toml b/examples/cores/boom/configs/cpu/default.toml new file mode 100644 index 000000000..40b4f000e --- /dev/null +++ b/examples/cores/boom/configs/cpu/default.toml @@ -0,0 +1,2 @@ +kind = "boom" +config = "./boom/default.toml" diff --git a/examples/cores/boom/configs/default.toml b/examples/cores/boom/configs/default.toml index 90a11178c..c691e6a4a 100644 --- a/examples/cores/boom/configs/default.toml +++ b/examples/cores/boom/configs/default.toml @@ -1,6 +1,5 @@ # Boom-only core configuration -kind = "boom" memdomain = "memdomains/default.toml" balldomain = "balldomains/default.toml" -boomCore = "boomCore.toml" +cpu = "cpu/default.toml" diff --git a/examples/cores/decode/configs/core/default.toml b/examples/cores/decode/configs/core/default.toml deleted file mode 100644 index ac2a168ba..000000000 --- a/examples/cores/decode/configs/core/default.toml +++ /dev/null @@ -1,6 +0,0 @@ -coreDataBytes = 64 -xLen = 64 -vaddrBits = 39 -paddrBits = 56 -pgIdxBits = 12 -nPMPs = 8 diff --git a/examples/cores/decode/configs/cpu/default.toml b/examples/cores/decode/configs/cpu/default.toml new file mode 100644 index 000000000..1bf2f46e8 --- /dev/null +++ b/examples/cores/decode/configs/cpu/default.toml @@ -0,0 +1,2 @@ +kind = "rocket" +config = "../../../rocket/configs/cpu/rocket/default.toml" diff --git a/examples/cores/decode/configs/default.toml b/examples/cores/decode/configs/default.toml index fc7c21711..53eaa2fd0 100644 --- a/examples/cores/decode/configs/default.toml +++ b/examples/cores/decode/configs/default.toml @@ -1,9 +1,7 @@ # Decode Core Configuration (default) -kind = "rocket" balldomain = "balldomains/default.toml" memdomain = "memdomains/default.toml" frontend = "frontends/default.toml" gpdomain = "gpdomains/default.toml" -core = "core/default.toml" -rocketCore = "../../rocket/configs/rocketCore.toml" +cpu = "cpu/default.toml" diff --git a/examples/cores/goban/configs/core/default.toml b/examples/cores/goban/configs/core/default.toml deleted file mode 100644 index ac2a168ba..000000000 --- a/examples/cores/goban/configs/core/default.toml +++ /dev/null @@ -1,6 +0,0 @@ -coreDataBytes = 64 -xLen = 64 -vaddrBits = 39 -paddrBits = 56 -pgIdxBits = 12 -nPMPs = 8 diff --git a/examples/cores/goban/configs/cpu/default.toml b/examples/cores/goban/configs/cpu/default.toml new file mode 100644 index 000000000..1bf2f46e8 --- /dev/null +++ b/examples/cores/goban/configs/cpu/default.toml @@ -0,0 +1,2 @@ +kind = "rocket" +config = "../../../rocket/configs/cpu/rocket/default.toml" diff --git a/examples/cores/goban/configs/default.toml b/examples/cores/goban/configs/default.toml index 29a2941fa..9b86a2cef 100644 --- a/examples/cores/goban/configs/default.toml +++ b/examples/cores/goban/configs/default.toml @@ -1,9 +1,7 @@ # Goban Core Configuration (default) -kind = "rocket" balldomain = "balldomains/default.toml" memdomain = "memdomains/default.toml" frontend = "frontends/default.toml" gpdomain = "gpdomains/default.toml" -core = "core/default.toml" -rocketCore = "../../rocket/configs/rocketCore.toml" +cpu = "cpu/default.toml" diff --git a/examples/cores/pebble/configs/core/default.toml b/examples/cores/pebble/configs/core/default.toml deleted file mode 100644 index ac2a168ba..000000000 --- a/examples/cores/pebble/configs/core/default.toml +++ /dev/null @@ -1,6 +0,0 @@ -coreDataBytes = 64 -xLen = 64 -vaddrBits = 39 -paddrBits = 56 -pgIdxBits = 12 -nPMPs = 8 diff --git a/examples/cores/pebble/configs/cpu/default.toml b/examples/cores/pebble/configs/cpu/default.toml new file mode 100644 index 000000000..e651581c6 --- /dev/null +++ b/examples/cores/pebble/configs/cpu/default.toml @@ -0,0 +1,2 @@ +kind = "rocket" +config = "./rocket/default.toml" diff --git a/examples/cores/pebble/configs/cpu/rocket/default.toml b/examples/cores/pebble/configs/cpu/rocket/default.toml new file mode 100644 index 000000000..b44c13ce6 --- /dev/null +++ b/examples/cores/pebble/configs/cpu/rocket/default.toml @@ -0,0 +1,30 @@ +useVM = true +useZba = true +useZbb = true +useZbs = true +haveCFlush = false + +[mulDiv] +enable = true +mulUnroll = 8 +mulEarlyOut = true +divEarlyOut = true + +[fpu] +enable = true +minFLen = 16 +fLen = 64 + +[dcache] +nSets = 32 +nWays = 4 +nMSHRs = 0 + +[icache] +nSets = 64 +nWays = 8 + +[btb] +enable = true +nEntries = 28 +nRAS = 6 diff --git a/examples/cores/pebble/configs/default.toml b/examples/cores/pebble/configs/default.toml index 8f6d405ce..07f7d433c 100644 --- a/examples/cores/pebble/configs/default.toml +++ b/examples/cores/pebble/configs/default.toml @@ -1,9 +1,7 @@ # Pebble Core Configuration (default) -kind = "rocket" balldomain = "balldomains/default.toml" memdomain = "memdomains/default.toml" frontend = "frontends/default.toml" gpdomain = "gpdomains/default.toml" -core = "core/default.toml" -rocketCore = "../../rocket/configs/rocketCore.toml" +cpu = "cpu/default.toml" diff --git a/examples/cores/prefill/configs/core/default.toml b/examples/cores/prefill/configs/core/default.toml deleted file mode 100644 index ac2a168ba..000000000 --- a/examples/cores/prefill/configs/core/default.toml +++ /dev/null @@ -1,6 +0,0 @@ -coreDataBytes = 64 -xLen = 64 -vaddrBits = 39 -paddrBits = 56 -pgIdxBits = 12 -nPMPs = 8 diff --git a/examples/cores/prefill/configs/cpu/default.toml b/examples/cores/prefill/configs/cpu/default.toml new file mode 100644 index 000000000..1bf2f46e8 --- /dev/null +++ b/examples/cores/prefill/configs/cpu/default.toml @@ -0,0 +1,2 @@ +kind = "rocket" +config = "../../../rocket/configs/cpu/rocket/default.toml" diff --git a/examples/cores/prefill/configs/default.toml b/examples/cores/prefill/configs/default.toml index ece1c2e73..2f58e7421 100644 --- a/examples/cores/prefill/configs/default.toml +++ b/examples/cores/prefill/configs/default.toml @@ -1,9 +1,7 @@ # Prefill Core Configuration (default) -kind = "rocket" balldomain = "balldomains/default.toml" memdomain = "memdomains/default.toml" frontend = "frontends/default.toml" gpdomain = "gpdomains/default.toml" -core = "core/default.toml" -rocketCore = "../../rocket/configs/rocketCore.toml" +cpu = "cpu/default.toml" diff --git a/examples/cores/rocket/configs/cpu/default.toml b/examples/cores/rocket/configs/cpu/default.toml new file mode 100644 index 000000000..e651581c6 --- /dev/null +++ b/examples/cores/rocket/configs/cpu/default.toml @@ -0,0 +1,2 @@ +kind = "rocket" +config = "./rocket/default.toml" diff --git a/examples/cores/rocket/configs/rocketCore.toml b/examples/cores/rocket/configs/cpu/rocket/default.toml similarity index 93% rename from examples/cores/rocket/configs/rocketCore.toml rename to examples/cores/rocket/configs/cpu/rocket/default.toml index daffea1a1..854871f19 100644 --- a/examples/cores/rocket/configs/rocketCore.toml +++ b/examples/cores/rocket/configs/cpu/rocket/default.toml @@ -1,5 +1,3 @@ -xLen = 64 -pgLevels = 3 useVM = true useZba = true useZbb = true diff --git a/examples/cores/rocket/configs/default.toml b/examples/cores/rocket/configs/default.toml index e4939c5f7..b59e347c5 100644 --- a/examples/cores/rocket/configs/default.toml +++ b/examples/cores/rocket/configs/default.toml @@ -1,6 +1,5 @@ # Rocket-only core configuration -kind = "rocket" memdomain = "memdomains/default.toml" balldomain = "balldomains/default.toml" -rocketCore = "rocketCore.toml" +cpu = "cpu/default.toml" diff --git a/examples/cores/toy/configs/core/default.toml b/examples/cores/toy/configs/core/default.toml deleted file mode 100644 index ac2a168ba..000000000 --- a/examples/cores/toy/configs/core/default.toml +++ /dev/null @@ -1,6 +0,0 @@ -coreDataBytes = 64 -xLen = 64 -vaddrBits = 39 -paddrBits = 56 -pgIdxBits = 12 -nPMPs = 8 diff --git a/examples/cores/toy/configs/cpu/default.toml b/examples/cores/toy/configs/cpu/default.toml new file mode 100644 index 000000000..1bf2f46e8 --- /dev/null +++ b/examples/cores/toy/configs/cpu/default.toml @@ -0,0 +1,2 @@ +kind = "rocket" +config = "../../../rocket/configs/cpu/rocket/default.toml" diff --git a/examples/cores/toy/configs/default.toml b/examples/cores/toy/configs/default.toml index 8d024f15c..071e6987f 100644 --- a/examples/cores/toy/configs/default.toml +++ b/examples/cores/toy/configs/default.toml @@ -1,9 +1,7 @@ # Toy Core Configuration (default) -kind = "rocket" balldomain = "balldomains/default.toml" memdomain = "memdomains/default.toml" frontend = "frontends/default.toml" gpdomain = "gpdomains/default.toml" -core = "core/default.toml" -rocketCore = "../../rocket/configs/rocketCore.toml" +cpu = "cpu/default.toml" diff --git a/examples/cores/toy/configs/demo.toml b/examples/cores/toy/configs/demo.toml index c3b9a707c..8c17b28f9 100644 --- a/examples/cores/toy/configs/demo.toml +++ b/examples/cores/toy/configs/demo.toml @@ -1,9 +1,7 @@ # Toy Core Configuration (demo frontend) -kind = "rocket" balldomain = "balldomains/default.toml" memdomain = "memdomains/default.toml" frontend = "frontends/demo.toml" gpdomain = "gpdomains/default.toml" -core = "core/default.toml" -rocketCore = "../../rocket/configs/rocketCore.toml" +cpu = "cpu/default.toml" diff --git a/sourceme.sh b/sourceme.sh index 83fd3d303..6c6e1f4c5 100644 --- a/sourceme.sh +++ b/sourceme.sh @@ -50,6 +50,7 @@ export PATH="${RESULT_PATH}/bin:${PATH}" # bbdev CLI and Python utils export PATH="${BBDIR}/bbdev:${PATH}" export PYTHONPATH="${BBDIR}/bbdev/api:${PYTHONPATH}" +export PYTHONPATH="${BBDIR}/thirdparty/soc-framework/ip:${PYTHONPATH}" # firesim manager