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=