diff --git a/.github/workflows/check.yaml b/.github/workflows/check.yaml index 33c8b3442..783f60758 100644 --- a/.github/workflows/check.yaml +++ b/.github/workflows/check.yaml @@ -63,12 +63,12 @@ jobs: matrix: include: - chip: toy - enable_rushb: false + enable_rushb: true run_bemu_elf_tests: true run_bemu_pk_tests: true run_verilator_batch_tests: true - chip: pebble - enable_rushb: false + enable_rushb: true run_bemu_elf_tests: true run_bemu_pk_tests: true run_verilator_batch_tests: true @@ -164,6 +164,9 @@ jobs: nix develop -c bbdev workload --build '--chip ${{ matrix.chip }} --rushB bemu' nix develop -c bbdev bebop-bemu --batch '--chip ${{ matrix.chip }} --test elf-tests --rushB --clean-before' nix develop -c bbdev bebop-bemu --batch '--chip ${{ matrix.chip }} --test pk-tests --rushB --clean-before' + nix develop -c bbdev bebop-verilator --clean '--chip ${{ matrix.chip }} --rushB' + nix develop -c bbdev bebop-verilator --verilog '--chip ${{ matrix.chip }} --rushB' + nix develop -c bbdev bebop-verilator --build '--jobs 16 --chip ${{ matrix.chip }} --rushB' nix develop -c bbdev workload --build '--chip ${{ matrix.chip }} --rushB verilator' nix develop -c bbdev bebop-verilator --batch '--chip ${{ matrix.chip }} --test elf-tests --rushB --clean-before' nix develop -c bbdev bebop-verilator --batch '--chip ${{ matrix.chip }} --test pk-tests --rushB --clean-before' diff --git a/arch/src/main/scala/framework/frontend/globalrs/GlobalROB.scala b/arch/src/main/scala/framework/frontend/globalrs/GlobalROB.scala index 92ce5f890..a8d697e34 100644 --- a/arch/src/main/scala/framework/frontend/globalrs/GlobalROB.scala +++ b/arch/src/main/scala/framework/frontend/globalrs/GlobalROB.scala @@ -163,7 +163,8 @@ class GlobalROB(val b: GlobalConfig) extends Module { } val hasCommit = commitScan.asUInt.orR val tailAlias = Wire(UInt(b.frontend.bank_id_len.W)) - tailAlias := (b.frontend.vbank_id_upper_bound + 1).U + tailPtr + tailAlias := + (b.frontend.vbank_id_upper_bound + 1).U(b.frontend.bank_id_len.W) + tailPtr val tailAliasLive = WireDefault(false.B) for (i <- 0 until robDepth) { diff --git a/arch/src/main/scala/framework/frontend/globalrs/GlobalScheduler.scala b/arch/src/main/scala/framework/frontend/globalrs/GlobalScheduler.scala index 76c11d0f5..b30a377f3 100644 --- a/arch/src/main/scala/framework/frontend/globalrs/GlobalScheduler.scala +++ b/arch/src/main/scala/framework/frontend/globalrs/GlobalScheduler.scala @@ -228,5 +228,5 @@ class GlobalScheduler(val b: GlobalConfig) extends Module { io.scheduler_rocc_o.resp.bits.rd := 0.U 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 + io.retired := rob.io.complete.fire && rob.io.entry_valid(rob.io.complete.bits) } 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 d93b95c82..71c218343 100644 --- a/arch/src/main/scala/framework/system/core/accelerator/BuckyballAccelerator.scala +++ b/arch/src/main/scala/framework/system/core/accelerator/BuckyballAccelerator.scala @@ -172,7 +172,15 @@ class BuckyballAccelerator(val b: GlobalConfig)(edge: TLEdgeOut) extends Module io.interrupt := memDomain.io.tlbExp(0).interrupt // --- Busy watchdog --- - val busy_counter = RegInit(0.U(32.W)) - busy_counter := Mux(frontend.io.busy, busy_counter + 1.U, 0.U) - assert(busy_counter < 100000.U, "BuckyballAccelerator: busy for too long!") + // BootRom clears and initializes the local memories before the external + // command interface becomes ready. That initialization can legitimately + // exceed the runtime watchdog limit, so only start monitoring after the + // first external command has handshaken. + val runtime_started = RegInit(false.B) + when(io.cmd.fire) { + runtime_started := true.B + } + val busy_counter = RegInit(0.U(32.W)) + busy_counter := Mux(runtime_started && frontend.io.busy, busy_counter + 1.U, 0.U) + assert(busy_counter < 10000000.U, "BuckyballAccelerator: busy for too long!") } diff --git a/arch/src/main/scala/framework/system/core/accelerator/RushB.scala b/arch/src/main/scala/framework/system/core/accelerator/RushB.scala index 8a762027d..3ce773c5d 100644 --- a/arch/src/main/scala/framework/system/core/accelerator/RushB.scala +++ b/arch/src/main/scala/framework/system/core/accelerator/RushB.scala @@ -8,14 +8,14 @@ import framework.system.core.rocket.RoCCCommandBB /** Enables the Verilator-only rushB command source at elaboration time. */ case object BuckyballRushBKey extends Field[Boolean](false) -/** rushB ABI ID: tile ID in the high half, local accelerator index below it. */ -object RushBAcceleratorId { +/** rushB ABI ID: tile ID in the high half, local Core index below it. */ +object RushBCoreId { private val LocalIdBits = 16 private val LocalIdMask = (1 << LocalIdBits) - 1 def apply(tileId: Int, localIndex: Int): Int = { require(tileId >= 0 && tileId < (1 << LocalIdBits), s"tile ID does not fit rushB ABI: $tileId") - require(localIndex >= 0 && localIndex <= LocalIdMask, s"accelerator index does not fit rushB ABI: $localIndex") + require(localIndex >= 0 && localIndex <= LocalIdMask, s"Core index does not fit rushB ABI: $localIndex") (tileId << LocalIdBits) | localIndex } @@ -24,14 +24,14 @@ object RushBAcceleratorId { /** * Stable DPI boundary for host-driven RTL simulation. * - * One instance is created for every Buckyball accelerator. The accelerator ID - * is an ABI identifier, not a hart ID: heterogeneous systems may assign - * arbitrary hart IDs and may give individual accelerators different configs. + * One instance is created for every RushB-capable Core. The Core ID is an ABI + * identifier, not a hart ID: heterogeneous systems may assign arbitrary hart + * IDs and may give individual Cores different configs. */ -class RushBCommandDPI(acceleratorId: Int, xLen: Int) +class RushBCommandDPI(coreId: Int, xLen: Int) extends BlackBox(Map( - "ACCELERATOR_ID" -> acceleratorId, - "XLEN" -> xLen + "CORE_ID" -> coreId, + "XLEN" -> xLen )) with HasBlackBoxInline { @@ -49,7 +49,7 @@ class RushBCommandDPI(acceleratorId: Int, xLen: Int) "RushBCommandDPI.v", """ |module RushBCommandDPI #( - | parameter integer ACCELERATOR_ID = 0, + | parameter integer CORE_ID = 0, | parameter integer XLEN = 64 |)( | input clock, input ready, input retired, @@ -58,36 +58,36 @@ class RushBCommandDPI(acceleratorId: Int, xLen: Int) | output logic [XLEN-1:0] rs1Data, output logic [XLEN-1:0] rs2Data |); | import "DPI-C" function void verilator_rushb_peek( - | input int accelerator_id, + | input int core_id, | output bit valid, | output longint unsigned xs1_data, | output longint unsigned xs2_data, | output int unsigned funct); - | import "DPI-C" function void verilator_rushb_accept(input int accelerator_id); + | import "DPI-C" function void verilator_rushb_accept(input int core_id); | import "DPI-C" function void verilator_rushb_observe( - | input int accelerator_id, input bit valid, input bit ready); + | input int core_id, input bit valid, input bit ready); | import "DPI-C" function void verilator_rushb_report( - | input int accelerator_id, input bit retired); + | input int core_id, input bit retired); | | bit accept_pending = 1'b0; | int unsigned dpi_funct; | | always @(posedge clock) begin - | verilator_rushb_observe(ACCELERATOR_ID, valid, ready); + | verilator_rushb_observe(CORE_ID, valid, ready); | accept_pending <= valid && ready; - | verilator_rushb_report(ACCELERATOR_ID, retired); + | verilator_rushb_report(CORE_ID, retired); | end | | always @(negedge clock) begin | if (accept_pending) begin - | verilator_rushb_accept(ACCELERATOR_ID); + | verilator_rushb_accept(CORE_ID); | accept_pending <= 1'b0; | valid = 1'b0; | end else if (!valid) begin | // DPI calls mutate C++ state without creating an RTL event. Load a | // one-entry register on the falling edge, so command bits are | // stable for the full following sampling edge. - | verilator_rushb_peek(ACCELERATOR_ID, valid, rs1Data, rs2Data, dpi_funct); + | verilator_rushb_peek(CORE_ID, valid, rs1Data, rs2Data, dpi_funct); | funct = dpi_funct[6:0]; | end | end @@ -103,14 +103,14 @@ class RushBCommandDPI(acceleratorId: Int, xLen: Int) ) } -class RushBCommandBridge(acceleratorId: Int, xLen: Int) extends Module { +class RushBCommandBridge(coreId: Int, xLen: Int) extends Module { val io = IO(new Bundle { val cmd = Decoupled(new RoCCCommandBB(xLen)) val retired = Input(Bool()) }) - val dpi = Module(new RushBCommandDPI(acceleratorId, xLen)) + val dpi = Module(new RushBCommandDPI(coreId, xLen)) dpi.io.clock := clock dpi.io.ready := io.cmd.ready dpi.io.retired := io.retired diff --git a/arch/src/main/scala/framework/system/tile/BBTile.scala b/arch/src/main/scala/framework/system/tile/BBTile.scala index ea793b9a6..d42591bbc 100644 --- a/arch/src/main/scala/framework/system/tile/BBTile.scala +++ b/arch/src/main/scala/framework/system/tile/BBTile.scala @@ -42,12 +42,7 @@ import freechips.rocketchip.util.BooleanToAugmentedBoolean import framework.top.GlobalConfig import framework.system.core.rocket.RocketBB import framework.system.core.rocket.id.RVVRoCCDecode -import framework.system.core.accelerator.{ - BuckyballAccelerator, - BuckyballRushBKey, - RushBAcceleratorId, - RushBCommandBridge -} +import framework.system.core.accelerator.{BuckyballAccelerator, BuckyballRushBKey, RushBCommandBridge, RushBCoreId} import framework.memdomain.backend.MemRequestIO import framework.memdomain.backend.shared.SharedMemBackend import framework.memdomain.backend.shared.SharedMemLayout @@ -637,7 +632,7 @@ class BBTileModuleImp(outer: BBTile) extends BaseTileModuleImp(outer) with HasIC acc.map { accelerator => if (rushBEnabled) { val source = Module(new RushBCommandBridge( - RushBAcceleratorId(outer.bbParams.tileId, i), + RushBCoreId(outer.bbParams.tileId, i), accelerator.b.core.xLen )) source.io.retired := accelerator.io.retired diff --git a/arch/src/main/scala/sims/verilator/BBsimDRAM.scala b/arch/src/main/scala/sims/verilator/BBsimDRAM.scala index ba4813a6d..7f8e19748 100644 --- a/arch/src/main/scala/sims/verilator/BBsimDRAM.scala +++ b/arch/src/main/scala/sims/verilator/BBsimDRAM.scala @@ -185,6 +185,11 @@ class BBSimDRAM( | reg [1:0] __b_resp_reg; | | always @(posedge clock) begin + | if (!initialized) begin + | channel = bbsim_memory_init(CHIP_ID, MEM_SIZE, WORD_SIZE, LINE_SIZE, ID_BITS, CLOCK_HZ, MEM_BASE); + | initialized = 1'b1; + | end + | | if (reset) begin | __ar_ready = 1'b0; | __aw_ready = 1'b0; @@ -198,11 +203,6 @@ class BBSimDRAM( | __r_valid_reg <= 1'b0; | __b_valid_reg <= 1'b0; | end else begin - | if (!initialized) begin - | channel = bbsim_memory_init(CHIP_ID, MEM_SIZE, WORD_SIZE, LINE_SIZE, ID_BITS, CLOCK_HZ, MEM_BASE); - | initialized = 1'b1; - | end - | | bbsim_memory_tick( | channel, | diff --git a/bb-tests/workloads/CMakeLists.txt b/bb-tests/workloads/CMakeLists.txt index 7f1209f51..e15ba6f3c 100644 --- a/bb-tests/workloads/CMakeLists.txt +++ b/bb-tests/workloads/CMakeLists.txt @@ -57,7 +57,7 @@ execute_process( --isa-dir "${BUCKYBALL_ISA_DIR}" --print-targets --print-target-balls - --print-core-targets + --print-rushb-targets RESULT_VARIABLE BUCKYBALL_TARGET_REGISTRY_RESULT OUTPUT_VARIABLE BUCKYBALL_TARGETS_RAW ERROR_VARIABLE BUCKYBALL_TARGET_REGISTRY_ERROR) @@ -83,23 +83,49 @@ string(REPLACE "\n" ";" BUCKYBALL_BANK_TARGETS "${BUCKYBALL_BANK_TARGETS_RAW}") list(REMOVE_ITEM BUCKYBALL_BANK_TARGETS "") set(BUCKYBALL_TARGET_BALL_LINES) -set(BUCKYBALL_CORE_TARGET_LINES) +set(BUCKYBALL_RUSHB_TARGET_LINES) foreach(BUCKYBALL_TARGET_LINE ${BUCKYBALL_TARGETS}) if(BUCKYBALL_TARGET_LINE MATCHES "^([0-9]+):([^,]+)$") - set(BUCKYBALL_CORE_TARGET_${CMAKE_MATCH_1} "${CMAKE_MATCH_2}") - list(APPEND BUCKYBALL_CORE_TARGET_LINES ${BUCKYBALL_TARGET_LINE}) + list(APPEND BUCKYBALL_RUSHB_TARGET_LINES ${BUCKYBALL_TARGET_LINE}) elseif(BUCKYBALL_TARGET_LINE MATCHES "^([^:]+):(.*)$") set(BUCKYBALL_TARGET_BALLS_${CMAKE_MATCH_1} "${CMAKE_MATCH_2}") list(APPEND BUCKYBALL_TARGET_BALL_LINES ${BUCKYBALL_TARGET_LINE}) endif() endforeach() list(REMOVE_ITEM BUCKYBALL_TARGETS ${BUCKYBALL_TARGET_BALL_LINES} - ${BUCKYBALL_CORE_TARGET_LINES} "") + ${BUCKYBALL_RUSHB_TARGET_LINES} "") if(NOT BUCKYBALL_TARGETS) message(FATAL_ERROR "Chip.pb has no compiler targets") endif() message(STATUS "Buckyball compiler targets: ${BUCKYBALL_TARGETS}") message(STATUS "Buckyball bank targets: ${BUCKYBALL_BANK_TARGETS}") +message(STATUS "Buckyball rushB targets: ${BUCKYBALL_RUSHB_TARGET_LINES}") + +function(buckyball_rushb_cores OUT_VAR TARGET) + set(_cores) + foreach(_entry IN LISTS BUCKYBALL_RUSHB_TARGET_LINES) + if(_entry MATCHES "^([0-9]+):(.+)$") + set(_core "${CMAKE_MATCH_1}") + set(_target "${CMAKE_MATCH_2}") + if(_target STREQUAL "${TARGET}") + list(APPEND _cores "${_core}") + endif() + endif() + endforeach() + set(${OUT_VAR} "${_cores}" PARENT_SCOPE) +endfunction() + +function(buckyball_rushb_default_core OUT_VAR TARGET) + buckyball_rushb_cores(_cores "${TARGET}") + # Core ID 0 is valid, but CMake treats the string "0" as false. + # Test for an empty list explicitly so the first Core is accepted. + if("${_cores}" STREQUAL "") + message(FATAL_ERROR + "target '${TARGET}' has no RushB-capable Core in Chip.pb") + endif() + list(GET _cores 0 _core) + set(${OUT_VAR} "${_core}" PARENT_SCOPE) +endfunction() function(buckyball_assign_physical_banks TARGET OUT) list(FIND BUCKYBALL_BANK_TARGETS "${TARGET}" _bank_target_index) @@ -127,7 +153,7 @@ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=rv64gc") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static -Wl,--no-dynamic-linker") function(add_buckyball_rushb_native TARGET_NAME) - cmake_parse_arguments(ARG "CXX" "OUTPUT_SUBDIR" "SOURCES;INCLUDE_DIRS;DEPENDS" ${ARGN}) + cmake_parse_arguments(ARG "CXX" "OUTPUT_SUBDIR;CORE_ID" "SOURCES;INCLUDE_DIRS;DEPENDS" ${ARGN}) if(NOT ARG_SOURCES) message(FATAL_ERROR "${TARGET_NAME}: rushB runner has no sources") @@ -140,6 +166,13 @@ function(add_buckyball_rushb_native TARGET_NAME) message(FATAL_ERROR "add_buckyball_rushb_native requires BUILD_BIN_DIR and OUTPUT_BIN_DIR") endif() + if(NOT DEFINED ARG_CORE_ID OR ARG_CORE_ID STREQUAL "") + set(ARG_CORE_ID 0) + endif() + if(NOT ARG_CORE_ID MATCHES "^[0-9]+$") + message(FATAL_ERROR + "${TARGET_NAME}: RushB CORE_ID must be a non-negative integer") + endif() set(RUSHB_OUTPUT_ROOT ${OUTPUT_BIN_DIR}/${ARG_OUTPUT_SUBDIR}) set(RUSHB_SYNC_ROOT ${BUILD_BIN_DIR}/${ARG_OUTPUT_SUBDIR}) @@ -171,7 +204,9 @@ function(add_buckyball_rushb_native TARGET_NAME) set(RUSHB_LIBRARY ${BUCKYBALL_RUSHB_BEMU_LIBRARY}) set(RUSHB_LIBRARY_NAME bebop_bemu) set(RUSHB_BUILD_RUNTIME - COMMAND ${CMAKE_COMMAND} -E env CARGO_TARGET_DIR=${BUCKYBALL_CARGO_TARGET_DIR} + COMMAND ${CMAKE_COMMAND} -E env + --unset=CC --unset=CXX + CARGO_TARGET_DIR=${BUCKYBALL_CARGO_TARGET_DIR} cargo build --release --manifest-path ${BUCKYBALL_RUSHB_BEMU_MANIFEST} --lib) set(RUSHB_RUNTIME_DEPENDENCY ${BUCKYBALL_RUSHB_BEMU_MANIFEST}) else() @@ -221,6 +256,7 @@ function(add_buckyball_rushb_native TARGET_NAME) OUTPUT ${RUSHB_BINARY} ${RUSHB_INSTALLED} ${RUSHB_SYNCED} COMMAND ${CMAKE_COMMAND} -E make_directory ${RUSHB_BUILD_DIR} COMMAND ${RUSHB_COMPILER} -no-pie ${RUSHB_STANDARD} -O2 -DBUCKYBALL_RUSHB + -DBUCKYBALL_RUSHB_CORE_ID=${ARG_CORE_ID} ${RUSHB_INCLUDE_ARGS} ${ARG_SOURCES} ${BUCKYBALL_REPO_ROOT}/compiler/lib/RushBRuntime.c -L${RUSHB_LIBRARY_DIR} -l${RUSHB_LIBRARY_NAME} @@ -311,6 +347,7 @@ function(add_toy_mlir_rushb) NOT DEFINED BUCKYBALL_RUSHB_VERILATOR_LIBRARY) return() endif() + buckyball_rushb_default_core(RUSHB_CORE_ID "${ARG_TARGET}") set(MLIR_SRC ${CMAKE_CURRENT_SOURCE_DIR}/${ARG_NAME}.mlir) set(RUSHB_OBJ ${CMAKE_CURRENT_BINARY_DIR}/${ARG_NAME}-rushB.o) @@ -332,7 +369,7 @@ function(add_toy_mlir_rushb) -convert-math-to-llvm -finalize-memref-to-llvm -convert-func-to-llvm - -lower-buckyball-intrinsics-to-rushb + "-lower-buckyball-intrinsics-to-rushb=core_id=${RUSHB_CORE_ID}" -reconcile-unrealized-casts | ${BUDDY_TRANSLATE} --buddy-to-llvmir | ${BUDDY_LLC} -filetype=obj -mtriple=x86_64 -O2 -o ${RUSHB_OBJ} @@ -349,6 +386,7 @@ function(add_toy_mlir_rushb) add_buckyball_rushb_native(${ARG_TARGET_STEM} ${RUSHB_CXX_FLAG} OUTPUT_SUBDIR src/CTest/rushB + CORE_ID ${RUSHB_CORE_ID} SOURCES ${ARG_SOURCES} ${RUSHB_OBJ} INCLUDE_DIRS ${ARG_INCLUDE_DIRS} DEPENDS ${RUSHB_OBJ} ${ARG_DEPENDS}) diff --git a/bb-tests/workloads/lib/bbhw/isa/00_fence.c b/bb-tests/workloads/lib/bbhw/isa/00_fence.c index b7bf839c8..78c87a99a 100644 --- a/bb-tests/workloads/lib/bbhw/isa/00_fence.c +++ b/bb-tests/workloads/lib/bbhw/isa/00_fence.c @@ -5,13 +5,19 @@ #define BB_FENCE_FUNC7 0 +#if defined(BUCKYBALL_RUSHB) +#define bb_dma_cache_flush() \ + do { \ + } while (0) +#define bb_fence() BUCKYBALL_INSTRUCTION_R_R(0, 0, BB_FENCE_FUNC7) +#else #define bb_dma_cache_flush() asm volatile("fence.i" ::: "memory") - #define bb_fence() \ do { \ BUCKYBALL_INSTRUCTION_R_R(0, 0, BB_FENCE_FUNC7); \ asm volatile("fence rw, rw" ::: "memory"); \ bb_dma_cache_flush(); \ } while (0) +#endif #endif // _BB_FENCE_H_ diff --git a/bb-tests/workloads/lib/bbhw/isa/16_mvout.c b/bb-tests/workloads/lib/bbhw/isa/16_mvout.c index 7339a18b0..04dedb10a 100644 --- a/bb-tests/workloads/lib/bbhw/isa/16_mvout.c +++ b/bb-tests/workloads/lib/bbhw/isa/16_mvout.c @@ -26,6 +26,7 @@ BB_MVOUT_TOUCH(_bb_mo_addr, _bb_mo_depth, _bb_mo_stride, _bb_mo_bank); \ bb_dma_cache_flush(); \ rushb_mvout( \ + BUCKYBALL_RUSHB_CORE, \ (uint64_t)(BB_BANK0(_bb_mo_bank) | BB_ITER(_bb_mo_depth)), \ (uint64_t)(FIELD(_bb_mo_addr, 0, 38) | FIELD(_bb_mo_stride, 39, 57)), \ (void *)_bb_mo_addr); \ diff --git a/bb-tests/workloads/lib/bbhw/isa/32_mset.c b/bb-tests/workloads/lib/bbhw/isa/32_mset.c index f44fa6d1b..f3b1bf964 100644 --- a/bb-tests/workloads/lib/bbhw/isa/32_mset.c +++ b/bb-tests/workloads/lib/bbhw/isa/32_mset.c @@ -14,10 +14,11 @@ #if defined(BUCKYBALL_RUSHB) #define bb_mset(bank_id, alloc, row, col) \ - rushb_mset((uint64_t)BB_BANK0(bank_id), \ + rushb_mset(BUCKYBALL_RUSHB_CORE, (uint64_t)BB_BANK0(bank_id), \ (uint64_t)BB_MSET_RS2(row, col, alloc, 0)) #define bb_mset_clear(bank_id, row, col) \ - rushb_mset((uint64_t)BB_BANK0(bank_id), (uint64_t)BB_MSET_RS2(row, col, 1, 1)) + rushb_mset(BUCKYBALL_RUSHB_CORE, (uint64_t)BB_BANK0(bank_id), \ + (uint64_t)BB_MSET_RS2(row, col, 1, 1)) #else #define bb_mset(bank_id, alloc, row, col) \ BUCKYBALL_INSTRUCTION_R_R(BB_BANK0(bank_id), \ diff --git a/bb-tests/workloads/lib/bbhw/isa/33_mvin.c b/bb-tests/workloads/lib/bbhw/isa/33_mvin.c index 4c2b321b6..1d366b5e6 100644 --- a/bb-tests/workloads/lib/bbhw/isa/33_mvin.c +++ b/bb-tests/workloads/lib/bbhw/isa/33_mvin.c @@ -9,7 +9,8 @@ #define bb_mvin(mem_addr, bank_id, depth, stride) \ do { \ bb_dma_cache_flush(); \ - rushb_mvin((uint64_t)(BB_BANK0(bank_id) | BB_ITER(depth)), \ + rushb_mvin(BUCKYBALL_RUSHB_CORE, \ + (uint64_t)(BB_BANK0(bank_id) | BB_ITER(depth)), \ (uint64_t)(FIELD(mem_addr, 0, 38) | FIELD(stride, 39, 57)), \ (const void *)(uintptr_t)(mem_addr)); \ } while (0) diff --git a/bb-tests/workloads/lib/bbhw/isa/35_mvin_mmio.c b/bb-tests/workloads/lib/bbhw/isa/35_mvin_mmio.c index 633669e14..91cbb0c39 100644 --- a/bb-tests/workloads/lib/bbhw/isa/35_mvin_mmio.c +++ b/bb-tests/workloads/lib/bbhw/isa/35_mvin_mmio.c @@ -24,6 +24,15 @@ // [63:56] = col (write mask: valid bytes per row, 1..16) // // funct7 = 0x23 (35 decimal) +#if defined(BUCKYBALL_RUSHB) +#define bb_mvin_mmio(dram_addr, mmio_addr, row, col) \ + do { \ + rushb_mvin_mmio(BUCKYBALL_RUSHB_CORE, (uint64_t)BB_ITER(row), \ + (uint64_t)(FIELD(dram_addr, 0, 38) | \ + FIELD(mmio_addr, 39, 55) | FIELD(col, 56, 63)), \ + (const void *)(uintptr_t)(dram_addr)); \ + } while (0) +#else #define bb_mvin_mmio(dram_addr, mmio_addr, row, col) \ do { \ bb_dma_cache_flush(); \ @@ -32,5 +41,6 @@ FIELD(mmio_addr, 39, 55) | FIELD(col, 56, 63)), \ BB_MVIN_MMIO_FUNC7); \ } while (0) +#endif #endif // _BB_MVIN_MMIO_H_ diff --git a/bb-tests/workloads/lib/bbhw/isa/isa.h b/bb-tests/workloads/lib/bbhw/isa/isa.h index d9e4946d5..cafd6a61e 100644 --- a/bb-tests/workloads/lib/bbhw/isa/isa.h +++ b/bb-tests/workloads/lib/bbhw/isa/isa.h @@ -6,6 +6,10 @@ #if defined(BUCKYBALL_RUSHB) #include +#if !defined(BUCKYBALL_RUSHB_CORE_ID) +#error "RushB workloads require a Core ID" +#endif +#define BUCKYBALL_RUSHB_CORE (uint32_t)BUCKYBALL_RUSHB_CORE_ID #endif // Data type for matrix elements @@ -41,7 +45,8 @@ typedef int32_t result_t; #if defined(BUCKYBALL_RUSHB) #define BUCKYBALL_INSTRUCTION_R_R(rs1_val, rs2_val, func7) \ do { \ - rushb_custom((uint64_t)(rs1_val), (uint64_t)(rs2_val), (uint32_t)(func7)); \ + rushb_custom(BUCKYBALL_RUSHB_CORE, (uint64_t)(rs1_val), \ + (uint64_t)(rs2_val), (uint32_t)(func7)); \ } while (0) #else #define BUCKYBALL_INSTRUCTION_R_R(rs1_val, rs2_val, func7) \ diff --git a/bb-tests/workloads/lib/buckyball.c b/bb-tests/workloads/lib/buckyball.c index 58a1cc128..cbc509144 100644 --- a/bb-tests/workloads/lib/buckyball.c +++ b/bb-tests/workloads/lib/buckyball.c @@ -11,7 +11,7 @@ On RV32 we read low/high and detect rollover to produce a 64-bit value. */ unsigned long long read_rdcycle(void) { #if defined(BUCKYBALL_RUSHB) - return rushb_cycles(); + return rushb_cycles(BUCKYBALL_RUSHB_CORE); #elif defined(__riscv_xlen) && __riscv_xlen == 64 unsigned long long cycles; asm volatile("rdcycle %0" : "=r"(cycles)); @@ -287,7 +287,7 @@ void cpu_transfer(elem_t *src, elem_t *dst, int rows, int cols) { } unsigned long long read_cycle(void) { #if defined(BUCKYBALL_RUSHB) - return rushb_cycles(); + return rushb_cycles(BUCKYBALL_RUSHB_CORE); #else unsigned long long c; asm volatile("csrr %0, cycle" : "=r"(c)); diff --git a/bb-tests/workloads/scripts/build.py b/bb-tests/workloads/scripts/build.py index dd64fdc62..b26fe3cf8 100644 --- a/bb-tests/workloads/scripts/build.py +++ b/bb-tests/workloads/scripts/build.py @@ -231,7 +231,11 @@ def build_workload( f"missing {missing} in cmake.defs for rushB; run bbdev config --install" ) compiler_build = root / "compiler" / "thirdparty" / "buddy-mlir" / "build" / chip - python = shutil.which("python3") + riscv = _require_riscv() + project_python = riscv / "bin" / "python3" + python = ( + str(project_python) if project_python.is_file() else shutil.which("python3") + ) if not python: raise RuntimeError("python3 not in PATH; enter nix develop") @@ -254,7 +258,6 @@ def build_workload( task_scope=task_scope, ) - riscv = _require_riscv() linux_cc = riscv / "bin" / "riscv64-unknown-linux-gnu-gcc" linux_cxx = riscv / "bin" / "riscv64-unknown-linux-gnu-g++" if not linux_cc.is_file() or not linux_cxx.is_file(): diff --git a/bb-tests/workloads/src/CTest/CMakeLists.txt b/bb-tests/workloads/src/CTest/CMakeLists.txt index b2008f983..b9b76f0e8 100644 --- a/bb-tests/workloads/src/CTest/CMakeLists.txt +++ b/bb-tests/workloads/src/CTest/CMakeLists.txt @@ -152,8 +152,11 @@ function(add_buckyball_ctest SOURCE_FILE) if(_rushb_ok AND DEFINED BUCKYBALL_RUSHB_BEMU_MANIFEST AND DEFINED BUCKYBALL_RUSHB_VERILATOR_LIBRARY) + buckyball_rushb_default_core( + _rushb_core "${BUCKYBALL_CTEST_TARGET}") add_buckyball_rushb_native(${TEST_NAME} OUTPUT_SUBDIR src/CTest/rushB + CORE_ID ${_rushb_core} SOURCES ${SOURCE_DIR}/${SOURCE_FILE} ${WORKLOAD_LIB_DIR}/buckyball.c diff --git a/bb-tests/workloads/src/MLIRTest/CMakeLists.txt b/bb-tests/workloads/src/MLIRTest/CMakeLists.txt index aa185fc64..06da9da4b 100644 --- a/bb-tests/workloads/src/MLIRTest/CMakeLists.txt +++ b/bb-tests/workloads/src/MLIRTest/CMakeLists.txt @@ -200,6 +200,7 @@ function(add_buckyball_mlir_test NAME) "rushB MLIR lowers require BUCKYBALL_LOWER_*_RUSHB " "(define them in bb-tests/workloads/CMakeLists.txt)") endif() + buckyball_rushb_default_core(_rushb_core "${ARG_TARGET}") set(RUSHB_MLIR_PASSES) set(RUSHB_HAS_RECONCILE FALSE) foreach(MLIR_PASS ${MLIR_PASSES}) @@ -210,7 +211,7 @@ function(add_buckyball_mlir_test NAME) elseif(MLIR_PASS STREQUAL "-reconcile-unrealized-casts") set(RUSHB_HAS_RECONCILE TRUE) list(APPEND RUSHB_MLIR_PASSES - -lower-buckyball-intrinsics-to-rushb + "-lower-buckyball-intrinsics-to-rushb=core_id=${_rushb_core}" -reconcile-unrealized-casts) else() list(APPEND RUSHB_MLIR_PASSES ${MLIR_PASS}) @@ -232,6 +233,7 @@ function(add_buckyball_mlir_test NAME) add_buckyball_rushb_native(${BUCKYBALL_WORKLOAD_CHIP}-${ARG_TARGET}-mlirtest-${TEST_ID} CXX OUTPUT_SUBDIR src/MLIRTest/rushB + CORE_ID ${_rushb_core} SOURCES ${CRUNNER_UTILS_SRC} ${BBHW_MEM_C} ${MAIN_SRC} ${RUSHB_OBJ} INCLUDE_DIRS ${LLVM_MLIR_EXECUTION_ENGINE_DIR} diff --git a/bb-tests/workloads/src/ModelTest/e2e b/bb-tests/workloads/src/ModelTest/e2e index 4672c666e..0933c92cc 160000 --- a/bb-tests/workloads/src/ModelTest/e2e +++ b/bb-tests/workloads/src/ModelTest/e2e @@ -1 +1 @@ -Subproject commit 4672c666ebf133b82d3361f0af88c29ac54e1356 +Subproject commit 0933c92ccda595534890d56e77add6c5caebf8d7 diff --git a/bbdev b/bbdev index 371b9aa2c..b0bd921d6 160000 --- a/bbdev +++ b/bbdev @@ -1 +1 @@ -Subproject commit 371b9aa2cd780dd0f5a1c5021a9f5662a61b36bb +Subproject commit b0bd921d6d113d1ec184a7a404debcc4f91a96f0 diff --git a/bebop b/bebop index 86c9180e7..8cce7f5be 160000 --- a/bebop +++ b/bebop @@ -1 +1 @@ -Subproject commit 86c9180e7e65f800d1cfc6c1d2ad7de463f720e7 +Subproject commit 8cce7f5be773c2d0e7e65699371dcdada22a63ce diff --git a/compiler/include/buckyball/rushb.h b/compiler/include/buckyball/rushb.h index a15ecd6c8..519c9dbfa 100644 --- a/compiler/include/buckyball/rushb.h +++ b/compiler/include/buckyball/rushb.h @@ -9,12 +9,16 @@ extern "C" { void rushb_init(void); void rushb_destroy(void); -void rushb_select_accelerator(uint32_t accelerator_id, int32_t chip_id); -void rushb_mset(uint64_t xs1, uint64_t xs2); -void rushb_mvin(uint64_t xs1, uint64_t packed_xs2, const void *host_ptr); -void rushb_mvout(uint64_t xs1, uint64_t packed_xs2, void *host_ptr); -void rushb_custom(uint64_t xs1, uint64_t xs2, uint32_t funct7); -uint64_t rushb_cycles(void); +void rushb_mset(uint32_t core_id, uint64_t xs1, uint64_t xs2); +void rushb_mvin(uint32_t core_id, uint64_t xs1, uint64_t packed_xs2, + const void *host_ptr); +void rushb_mvin_mmio(uint32_t core_id, uint64_t xs1, uint64_t packed_xs2, + const void *host_ptr); +void rushb_mvout(uint32_t core_id, uint64_t xs1, uint64_t packed_xs2, + void *host_ptr); +void rushb_custom(uint32_t core_id, uint64_t xs1, uint64_t xs2, + uint32_t funct7); +uint64_t rushb_cycles(uint32_t core_id); #ifdef __cplusplus } diff --git a/compiler/scripts/pb_to_target_registry.py b/compiler/scripts/pb_to_target_registry.py index d2c21eed2..24c2fc7e2 100644 --- a/compiler/scripts/pb_to_target_registry.py +++ b/compiler/scripts/pb_to_target_registry.py @@ -33,6 +33,29 @@ def _target_name(core) -> str: return core.role or core.pkg +def _rushb_targets(chip) -> list[tuple[int, str]]: + result: list[tuple[int, str]] = [] + for tile_id, tile in enumerate(chip.tiles): + if tile_id > 0xFFFF: + _die(f"tile index does not fit rushB ABI: {tile_id}") + for local_id, core_index in enumerate(tile.core_indices): + if local_id > 0xFFFF: + _die( + f"tile {tile_id}: local Core index does not fit rushB ABI: {local_id}" + ) + if core_index >= len(chip.cores): + _die( + f"tile {tile_id}: Core index {core_index} out of range " + f"(n={len(chip.cores)})" + ) + core = chip.cores[core_index] + if not core.balldomain.mappings: + continue + core_id = (tile_id << 16) | local_id + result.append((core_id, _target_name(core))) + return result + + def _cxx_string(value: str) -> str: if not value: _die("empty string is not a valid compiler target field") @@ -350,6 +373,7 @@ def main() -> None: parser.add_argument("--print-bank-targets", action="store_true") parser.add_argument("--print-target-balls", action="store_true") parser.add_argument("--print-core-targets", action="store_true") + parser.add_argument("--print-rushb-targets", action="store_true") parser.add_argument("--print-ball-dialect-dirs", action="store_true") parser.add_argument( "--print-ball-compiler-paths", @@ -367,6 +391,7 @@ def main() -> None: and not args.print_bank_targets and not args.print_target_balls and not args.print_core_targets + and not args.print_rushb_targets and not args.print_ball_dialect_dirs and args.print_ball_compiler_paths is None ): @@ -418,6 +443,12 @@ def main() -> None: if target not in targets: _die(f"CoreInstance {core.index}: no compiler profile {target}") print(f"{core.index}:{target}") + if args.print_rushb_targets: + targets = {profile.name for profile in chip.profiles} + for core_id, target in _rushb_targets(chip): + if target not in targets: + _die(f"rushB Core {core_id}: no compiler profile {target}") + print(f"{core_id}:{target}") if args.print_ball_dialect_dirs: for dialect_dir in _ball_dialect_dirs(chip, repo): print(dialect_dir) diff --git a/compiler/src/Dialect/Buckyball/Transforms/LegalizeForLLVMExportBase.cpp b/compiler/src/Dialect/Buckyball/Transforms/LegalizeForLLVMExportBase.cpp index 1e8626e50..509273abc 100644 --- a/compiler/src/Dialect/Buckyball/Transforms/LegalizeForLLVMExportBase.cpp +++ b/compiler/src/Dialect/Buckyball/Transforms/LegalizeForLLVMExportBase.cpp @@ -240,17 +240,23 @@ class ForwardOperands : public OpConversionPattern { }; struct BuckyballFenceLowering : public ConvertOpToLLVMPattern { - using ConvertOpToLLVMPattern::ConvertOpToLLVMPattern; + BuckyballFenceLowering(LLVMTypeConverter &converter, bool rushB) + : ConvertOpToLLVMPattern(converter), rushB(rushB) {} + LogicalResult matchAndRewrite(FenceOp op, OpAdaptor, ConversionPatternRewriter &rewriter) const override { Location loc = op.getLoc(); Value zero = cstI64(rewriter, loc, 0); rewriter.create(loc, zero, zero); - emitDmaCacheFence(rewriter, loc); + if (!rushB) + emitDmaCacheFence(rewriter, loc); rewriter.eraseOp(op); return success(); } + +private: + bool rushB; }; struct BuckyballMsetLowering : public ConvertOpToLLVMPattern { @@ -284,7 +290,8 @@ struct BuckyballMvinLowering : public ConvertOpToLLVMPattern { ConversionPatternRewriter &rewriter) const override { Location loc = op.getLoc(); MemrefAddress memref = extractMemrefAddress(rewriter, loc, op.getInput()); - emitDmaCacheFlush(rewriter, loc); + if (!rushB) + emitDmaCacheFlush(rewriter, loc); Value rs1 = packRs1BankIter(rewriter, loc, adaptor.getAddr(), adaptor.getDepth()); Value rs2 = @@ -312,7 +319,8 @@ struct BuckyballMvoutLowering : public ConvertOpToLLVMPattern { MemrefAddress memref = extractMemrefAddress(rewriter, loc, op.getOutput()); emitBbDmaTouchMvout(rewriter, loc, memref.hostPtr, adaptor.getDepth(), adaptor.getStride(), adaptor.getAddr()); - emitDmaCacheFlush(rewriter, loc); + if (!rushB) + emitDmaCacheFlush(rewriter, loc); Value rs1 = packRs1BankIter(rewriter, loc, adaptor.getAddr(), adaptor.getDepth()); Value rs2 = @@ -352,7 +360,7 @@ void populateBaseLegalizeForLLVMExportPatterns( ForwardOperands>(converter, &converter.getContext()); } - patterns.add(converter); + patterns.add(converter, rushB); patterns.add(converter); patterns.add(converter, rushB); patterns.add(converter, rushB); diff --git a/examples/balls/int2fp/compiler/src/Dialect/Buckyball/Transforms/LegalizeForLLVMExport.cpp b/examples/balls/int2fp/compiler/src/Dialect/Buckyball/Transforms/LegalizeForLLVMExport.cpp index 92132f2cd..e78e53927 100644 --- a/examples/balls/int2fp/compiler/src/Dialect/Buckyball/Transforms/LegalizeForLLVMExport.cpp +++ b/examples/balls/int2fp/compiler/src/Dialect/Buckyball/Transforms/LegalizeForLLVMExport.cpp @@ -1,6 +1,7 @@ #include "mlir/Conversion/LLVMCommon/ConversionTarget.h" #include "mlir/Conversion/LLVMCommon/Pattern.h" #include "mlir/Dialect/Arith/IR/Arith.h" +#include "mlir/Dialect/SCF/IR/SCF.h" #include "mlir/IR/Matchers.h" #include "mlir/IR/PatternMatch.h" @@ -16,6 +17,75 @@ using namespace buddy::buckyball::legalize; namespace { +static std::optional getConstantInt(Value value) { + llvm::APInt constant(64, 0); + if (!matchPattern(value, m_ConstantInt(&constant))) + return std::nullopt; + return constant.getSExtValue(); +} + +// Channel lowering advances Dw by four bytes for each output channel. Keep +// accepting literal addresses, but also recognize the bounded affine form +// emitted by the im2col/matmul-to-bank-SSA lowering: +// +// dwBase + index_cast(scf.for induction variable) * byteStride +// +// This is deliberately narrower than accepting an arbitrary runtime value: it +// proves the minimum address, alignment, and the 13-bit instruction field. +static bool isValidDynamicChannelDwAddr(Value value) { + auto add = value.getDefiningOp(); + if (!add) + return false; + + Value offset; + std::optional base = getConstantInt(add.getLhs()); + if (base) + offset = add.getRhs(); + else { + base = getConstantInt(add.getRhs()); + offset = add.getLhs(); + } + constexpr int64_t maxDwAddr = (1 << 13) - 1; + if (!base || *base < 16 || *base > maxDwAddr || *base % 4 != 0) + return false; + + auto mul = offset.getDefiningOp(); + if (!mul) + return false; + Value induction; + std::optional byteStride = getConstantInt(mul.getLhs()); + if (byteStride) + induction = mul.getRhs(); + else { + byteStride = getConstantInt(mul.getRhs()); + induction = mul.getLhs(); + } + if (!byteStride || *byteStride <= 0 || *byteStride % 4 != 0) + return false; + + auto cast = induction.getDefiningOp(); + if (!cast) + return false; + auto blockArg = dyn_cast(cast.getIn()); + if (!blockArg) + return false; + auto loop = dyn_cast_or_null(blockArg.getOwner()->getParentOp()); + if (!loop || blockArg != loop.getInductionVar()) + return false; + + std::optional lower = getConstantInt(loop.getLowerBound()); + std::optional upper = getConstantInt(loop.getUpperBound()); + std::optional step = getConstantInt(loop.getStep()); + if (!lower || !upper || !step || *lower < 0 || *upper <= *lower || *step <= 0) + return false; + + // Dw occupies special[25:13], hence its byte address must fit in 13 bits. + // Use upper - 1 as a conservative bound for the induction variable. + if (*upper - 1 > (maxDwAddr - *base) / *byteStride) + return false; + return true; +} + template struct Int2FpLowering : public ConvertOpToLLVMPattern { using ConvertOpToLLVMPattern::ConvertOpToLLVMPattern; @@ -28,12 +98,13 @@ struct Int2FpLowering : public ConvertOpToLLVMPattern { if (!matchPattern(op.getDaAddr(), m_ConstantInt(&daAddr)) || daAddr.getSExtValue() != 0) return op.emitError("INT2FP Da address must be 0"); - llvm::APInt dwConst(64, 0); - if (matchPattern(op.getDwAddr(), m_ConstantInt(&dwConst))) { - if (dwConst.getSExtValue() < 16 || dwConst.getSExtValue() % 4 != 0) - return op.emitError( - "INT2FP Dw address must be >= 16 and 4-byte aligned"); - } + std::optional dwAddr = getConstantInt(op.getDwAddr()); + bool validConstant = dwAddr && *dwAddr >= 16 && + *dwAddr <= ((1 << 13) - 1) && *dwAddr % 4 == 0; + bool validDynamic = std::is_same_v && + isValidDynamicChannelDwAddr(op.getDwAddr()); + if (!validConstant && !validDynamic) + return op.emitError("INT2FP Dw address must be >= 16 and 4-byte aligned"); if (adaptor.getInputBankId() == adaptor.getOutputBankId()) return op.emitError("INT2FP forbids in-place dequantization"); Location loc = op.getLoc(); diff --git a/examples/balls/smatmul/compiler/src/Dialect/Buckyball/Transforms/LegalizeForLLVMExport.cpp b/examples/balls/smatmul/compiler/src/Dialect/Buckyball/Transforms/LegalizeForLLVMExport.cpp index a849dabc3..adbbd49cf 100644 --- a/examples/balls/smatmul/compiler/src/Dialect/Buckyball/Transforms/LegalizeForLLVMExport.cpp +++ b/examples/balls/smatmul/compiler/src/Dialect/Buckyball/Transforms/LegalizeForLLVMExport.cpp @@ -95,7 +95,8 @@ struct SMatMulMatmulLowering : public ConvertOpToLLVMPattern { cstI64(rewriter, loc, depthA)); Value rs2A = packRs2MemStride(rewriter, loc, aPtr, cstI64(rewriter, loc, 1)); - emitDmaCacheFlush(rewriter, loc); + if (!rushB) + emitDmaCacheFlush(rewriter, loc); if (rushB) { Type ptrType = LLVM::LLVMPointerType::get(rewriter.getContext()); rewriter.create( @@ -109,7 +110,8 @@ struct SMatMulMatmulLowering : public ConvertOpToLLVMPattern { cstI64(rewriter, loc, depthB)); Value rs2B = packRs2MemStride(rewriter, loc, bPtr, cstI64(rewriter, loc, 1)); - emitDmaCacheFlush(rewriter, loc); + if (!rushB) + emitDmaCacheFlush(rewriter, loc); if (rushB) { Type ptrType = LLVM::LLVMPointerType::get(rewriter.getContext()); rewriter.create( @@ -129,7 +131,8 @@ struct SMatMulMatmulLowering : public ConvertOpToLLVMPattern { cstI64(rewriter, loc, depthC)); Value rs2C = packRs2MemStride(rewriter, loc, packedPtr, cstI64(rewriter, loc, 1)); - emitDmaCacheFlush(rewriter, loc); + if (!rushB) + emitDmaCacheFlush(rewriter, loc); if (rushB) { Type ptrType = LLVM::LLVMPointerType::get(rewriter.getContext()); rewriter.create( @@ -141,7 +144,8 @@ struct SMatMulMatmulLowering : public ConvertOpToLLVMPattern { Value zero = cstI64(rewriter, loc, 0); rewriter.create(loc, zero, zero); - emitDmaCacheFence(rewriter, loc); + if (!rushB) + emitDmaCacheFence(rewriter, loc); Value indexZero = rewriter.create(loc, 0); Value indexOne = rewriter.create(loc, 1); diff --git a/examples/chips/pebble/regression/batch/bemu/workloads-elf-rushB.toml b/examples/chips/pebble/regression/batch/bemu/workloads-elf-rushB.toml new file mode 100644 index 000000000..e99a59c81 --- /dev/null +++ b/examples/chips/pebble/regression/batch/bemu/workloads-elf-rushB.toml @@ -0,0 +1,8 @@ +[workloads] +search_path = "workloads/src" +tests = [ + "pebble-pebble-ctest-mvin_mvout_test-rushB-bemu-run", + "pebble-pebble-ctest-mvin_mvout_stride_test-rushB-bemu-run", + "pebble-pebble-ctest-mvout_fence_loop_test-rushB-bemu-run", + "pebble-pebble-mlirtest-tile_conv2d_12x12_k5-rushB-bemu-run", +] diff --git a/examples/chips/pebble/regression/batch/bemu/workloads-pk-rushB.toml b/examples/chips/pebble/regression/batch/bemu/workloads-pk-rushB.toml new file mode 100644 index 000000000..e99a59c81 --- /dev/null +++ b/examples/chips/pebble/regression/batch/bemu/workloads-pk-rushB.toml @@ -0,0 +1,8 @@ +[workloads] +search_path = "workloads/src" +tests = [ + "pebble-pebble-ctest-mvin_mvout_test-rushB-bemu-run", + "pebble-pebble-ctest-mvin_mvout_stride_test-rushB-bemu-run", + "pebble-pebble-ctest-mvout_fence_loop_test-rushB-bemu-run", + "pebble-pebble-mlirtest-tile_conv2d_12x12_k5-rushB-bemu-run", +] diff --git a/examples/chips/pebble/regression/batch/verilator/workloads-elf-rushB.toml b/examples/chips/pebble/regression/batch/verilator/workloads-elf-rushB.toml new file mode 100644 index 000000000..e7e3a7114 --- /dev/null +++ b/examples/chips/pebble/regression/batch/verilator/workloads-elf-rushB.toml @@ -0,0 +1,8 @@ +[workloads] +search_path = "workloads/src" +tests = [ + "pebble-pebble-ctest-mvin_mvout_test-rushB-verilator-run", + "pebble-pebble-ctest-mvin_mvout_stride_test-rushB-verilator-run", + "pebble-pebble-ctest-mvout_fence_loop_test-rushB-verilator-run", + "pebble-pebble-mlirtest-tile_conv2d_12x12_k5-rushB-verilator-run", +] diff --git a/examples/chips/pebble/regression/batch/verilator/workloads-pk-rushB.toml b/examples/chips/pebble/regression/batch/verilator/workloads-pk-rushB.toml new file mode 100644 index 000000000..e7e3a7114 --- /dev/null +++ b/examples/chips/pebble/regression/batch/verilator/workloads-pk-rushB.toml @@ -0,0 +1,8 @@ +[workloads] +search_path = "workloads/src" +tests = [ + "pebble-pebble-ctest-mvin_mvout_test-rushB-verilator-run", + "pebble-pebble-ctest-mvin_mvout_stride_test-rushB-verilator-run", + "pebble-pebble-ctest-mvout_fence_loop_test-rushB-verilator-run", + "pebble-pebble-mlirtest-tile_conv2d_12x12_k5-rushB-verilator-run", +] diff --git a/examples/chips/pebble/workloads/ctests/mvout_fence_loop_test.c b/examples/chips/pebble/workloads/ctests/mvout_fence_loop_test.c index a955d4d65..866691140 100644 --- a/examples/chips/pebble/workloads/ctests/mvout_fence_loop_test.c +++ b/examples/chips/pebble/workloads/ctests/mvout_fence_loop_test.c @@ -8,9 +8,10 @@ /* Closer to MobileNet tile epilogue: compute, mvout, fence, bank * release/realloc, second mvout, fence. Hang was after ~24 tiles. */ #define M 16 -#define N 1 +#define N 16 #define K 16 #define LOOPS 24 +#define OUTPUT_GROUPS 2 static elem_t a[M * K] __attribute__((aligned(64))); static elem_t b[K * 16] __attribute__((aligned(64))); @@ -36,7 +37,7 @@ int main(void) { for (int i = 0; i < LOOPS; ++i) { bb_mem_alloc(0, 1, 1); bb_mem_alloc(1, 1, 1); - bb_mem_alloc(2, 1, 4); + bb_mem_alloc(2, 1, OUTPUT_GROUPS); bb_mvin((uintptr_t)a, 0, M, 1); bb_mvin((uintptr_t)b, 1, K, 1); bb_mvin((uintptr_t)zero, 2, M, 1); @@ -45,7 +46,7 @@ int main(void) { bb_fence(); bb_mem_release(2); - bb_mem_alloc(2, 1, 4); + bb_mem_alloc(2, 1, OUTPUT_GROUPS); bb_mvin((uintptr_t)zero, 2, M, 1); bb_mvout((uintptr_t)out, 2, M, 1); bb_fence(); diff --git a/examples/cores/decode/compiler/src/Conversion/LowerBuckyball/LowerBuckyballPass.cpp b/examples/cores/decode/compiler/src/Conversion/LowerBuckyball/LowerBuckyballPass.cpp index c09bde647..00f575f5e 100644 --- a/examples/cores/decode/compiler/src/Conversion/LowerBuckyball/LowerBuckyballPass.cpp +++ b/examples/cores/decode/compiler/src/Conversion/LowerBuckyball/LowerBuckyballPass.cpp @@ -166,8 +166,8 @@ class LowerBuckyballIntrinsicsToRushBPass Option coreId{ *this, "core_id", - llvm::cl::desc("Bind generated rushB calls to a tile Core."), - llvm::cl::init(-1)}; + llvm::cl::desc("RushB Core ID passed to every host ABI call."), + llvm::cl::init(0)}; void getDependentDialects(DialectRegistry ®istry) const override { registry.insert(); @@ -185,32 +185,12 @@ class LowerBuckyballIntrinsicsToRushBPass OpBuilder builder(&getContext()); Type i32Type = IntegerType::get(&getContext(), 32); Type voidType = LLVM::LLVMVoidType::get(&getContext()); - FlatSymbolRefAttr selectCallee; - if (coreId >= 0) { - auto selectType = - LLVM::LLVMFunctionType::get(voidType, {i32Type, i32Type}); - selectCallee = getOrInsertRushBFunction( - builder, module, "rushb_select_accelerator", selectType); - } - llvm::SmallPtrSet boundFunctions; for (Operation *op : intrinsicOps) { - if (coreId >= 0) { - if (auto function = op->getParentOfType(); - function && boundFunctions.insert(function).second) { - OpBuilder::InsertionGuard guard(builder); - builder.setInsertionPointToStart(&function.front()); - auto selected = LLVM::ConstantOp::create( - builder, function.getLoc(), i32Type, - builder.getI32IntegerAttr(static_cast(coreId))); - auto chip = - LLVM::ConstantOp::create(builder, function.getLoc(), i32Type, - builder.getI32IntegerAttr(0)); - LLVM::CallOp::create(builder, function.getLoc(), TypeRange{}, - selectCallee, ValueRange{selected, chip}); - } - } builder.setInsertionPoint(op); - SmallVector operands; + Value core = LLVM::ConstantOp::create( + builder, op->getLoc(), i32Type, + builder.getI32IntegerAttr(static_cast(coreId))); + SmallVector operands{core}; StringRef name; if (isa(op)) { name = "rushb_mset"; diff --git a/examples/cores/goban/compiler/src/Conversion/LowerBuckyball/LowerBuckyballPass.cpp b/examples/cores/goban/compiler/src/Conversion/LowerBuckyball/LowerBuckyballPass.cpp index e2a287071..6c74d818e 100644 --- a/examples/cores/goban/compiler/src/Conversion/LowerBuckyball/LowerBuckyballPass.cpp +++ b/examples/cores/goban/compiler/src/Conversion/LowerBuckyball/LowerBuckyballPass.cpp @@ -166,8 +166,8 @@ class LowerBuckyballIntrinsicsToRushBPass Option coreId{ *this, "core_id", - llvm::cl::desc("Bind generated rushB calls to a tile Core."), - llvm::cl::init(-1)}; + llvm::cl::desc("RushB Core ID passed to every host ABI call."), + llvm::cl::init(0)}; void getDependentDialects(DialectRegistry ®istry) const override { registry.insert(); @@ -185,32 +185,12 @@ class LowerBuckyballIntrinsicsToRushBPass OpBuilder builder(&getContext()); Type i32Type = IntegerType::get(&getContext(), 32); Type voidType = LLVM::LLVMVoidType::get(&getContext()); - FlatSymbolRefAttr selectCallee; - if (coreId >= 0) { - auto selectType = - LLVM::LLVMFunctionType::get(voidType, {i32Type, i32Type}); - selectCallee = getOrInsertRushBFunction( - builder, module, "rushb_select_accelerator", selectType); - } - llvm::SmallPtrSet boundFunctions; for (Operation *op : intrinsicOps) { - if (coreId >= 0) { - if (auto function = op->getParentOfType(); - function && boundFunctions.insert(function).second) { - OpBuilder::InsertionGuard guard(builder); - builder.setInsertionPointToStart(&function.front()); - auto selected = LLVM::ConstantOp::create( - builder, function.getLoc(), i32Type, - builder.getI32IntegerAttr(static_cast(coreId))); - auto chip = - LLVM::ConstantOp::create(builder, function.getLoc(), i32Type, - builder.getI32IntegerAttr(0)); - LLVM::CallOp::create(builder, function.getLoc(), TypeRange{}, - selectCallee, ValueRange{selected, chip}); - } - } builder.setInsertionPoint(op); - SmallVector operands; + Value core = LLVM::ConstantOp::create( + builder, op->getLoc(), i32Type, + builder.getI32IntegerAttr(static_cast(coreId))); + SmallVector operands{core}; StringRef name; if (isa(op)) { name = "rushb_mset"; diff --git a/examples/cores/pebble/compiler/src/Conversion/LowerBuckyball/LowerBuckyballPass.cpp b/examples/cores/pebble/compiler/src/Conversion/LowerBuckyball/LowerBuckyballPass.cpp index 870ffdeba..9dac29d6c 100644 --- a/examples/cores/pebble/compiler/src/Conversion/LowerBuckyball/LowerBuckyballPass.cpp +++ b/examples/cores/pebble/compiler/src/Conversion/LowerBuckyball/LowerBuckyballPass.cpp @@ -168,8 +168,8 @@ class LowerBuckyballIntrinsicsToRushBPass Option coreId{ *this, "core_id", - llvm::cl::desc("Bind generated rushB calls to a tile Core."), - llvm::cl::init(-1)}; + llvm::cl::desc("RushB Core ID passed to every host ABI call."), + llvm::cl::init(0)}; void getDependentDialects(DialectRegistry ®istry) const override { registry.insert(); @@ -187,32 +187,12 @@ class LowerBuckyballIntrinsicsToRushBPass OpBuilder builder(&getContext()); Type i32Type = IntegerType::get(&getContext(), 32); Type voidType = LLVM::LLVMVoidType::get(&getContext()); - FlatSymbolRefAttr selectCallee; - if (coreId >= 0) { - auto selectType = - LLVM::LLVMFunctionType::get(voidType, {i32Type, i32Type}); - selectCallee = getOrInsertRushBFunction( - builder, module, "rushb_select_accelerator", selectType); - } - llvm::SmallPtrSet boundFunctions; for (Operation *op : intrinsicOps) { - if (coreId >= 0) { - if (auto function = op->getParentOfType(); - function && boundFunctions.insert(function).second) { - OpBuilder::InsertionGuard guard(builder); - builder.setInsertionPointToStart(&function.front()); - auto selected = LLVM::ConstantOp::create( - builder, function.getLoc(), i32Type, - builder.getI32IntegerAttr(static_cast(coreId))); - auto chip = - LLVM::ConstantOp::create(builder, function.getLoc(), i32Type, - builder.getI32IntegerAttr(0)); - LLVM::CallOp::create(builder, function.getLoc(), TypeRange{}, - selectCallee, ValueRange{selected, chip}); - } - } builder.setInsertionPoint(op); - SmallVector operands; + Value core = LLVM::ConstantOp::create( + builder, op->getLoc(), i32Type, + builder.getI32IntegerAttr(static_cast(coreId))); + SmallVector operands{core}; StringRef name; if (isa(op)) { name = "rushb_mset"; diff --git a/examples/cores/prefill/compiler/src/Conversion/LowerBuckyball/LowerBuckyballPass.cpp b/examples/cores/prefill/compiler/src/Conversion/LowerBuckyball/LowerBuckyballPass.cpp index 6ad04d6fa..71def13e5 100644 --- a/examples/cores/prefill/compiler/src/Conversion/LowerBuckyball/LowerBuckyballPass.cpp +++ b/examples/cores/prefill/compiler/src/Conversion/LowerBuckyball/LowerBuckyballPass.cpp @@ -166,8 +166,8 @@ class LowerBuckyballIntrinsicsToRushBPass Option coreId{ *this, "core_id", - llvm::cl::desc("Bind generated rushB calls to a tile Core."), - llvm::cl::init(-1)}; + llvm::cl::desc("RushB Core ID passed to every host ABI call."), + llvm::cl::init(0)}; void getDependentDialects(DialectRegistry ®istry) const override { registry.insert(); @@ -185,32 +185,12 @@ class LowerBuckyballIntrinsicsToRushBPass OpBuilder builder(&getContext()); Type i32Type = IntegerType::get(&getContext(), 32); Type voidType = LLVM::LLVMVoidType::get(&getContext()); - FlatSymbolRefAttr selectCallee; - if (coreId >= 0) { - auto selectType = - LLVM::LLVMFunctionType::get(voidType, {i32Type, i32Type}); - selectCallee = getOrInsertRushBFunction( - builder, module, "rushb_select_accelerator", selectType); - } - llvm::SmallPtrSet boundFunctions; for (Operation *op : intrinsicOps) { - if (coreId >= 0) { - if (auto function = op->getParentOfType(); - function && boundFunctions.insert(function).second) { - OpBuilder::InsertionGuard guard(builder); - builder.setInsertionPointToStart(&function.front()); - auto selected = LLVM::ConstantOp::create( - builder, function.getLoc(), i32Type, - builder.getI32IntegerAttr(static_cast(coreId))); - auto chip = - LLVM::ConstantOp::create(builder, function.getLoc(), i32Type, - builder.getI32IntegerAttr(0)); - LLVM::CallOp::create(builder, function.getLoc(), TypeRange{}, - selectCallee, ValueRange{selected, chip}); - } - } builder.setInsertionPoint(op); - SmallVector operands; + Value core = LLVM::ConstantOp::create( + builder, op->getLoc(), i32Type, + builder.getI32IntegerAttr(static_cast(coreId))); + SmallVector operands{core}; StringRef name; if (isa(op)) { name = "rushb_mset"; diff --git a/examples/cores/toy/compiler/src/Conversion/LowerBuckyball/LowerBuckyballPass.cpp b/examples/cores/toy/compiler/src/Conversion/LowerBuckyball/LowerBuckyballPass.cpp index 9ac545b69..d1e29b6b9 100644 --- a/examples/cores/toy/compiler/src/Conversion/LowerBuckyball/LowerBuckyballPass.cpp +++ b/examples/cores/toy/compiler/src/Conversion/LowerBuckyball/LowerBuckyballPass.cpp @@ -154,6 +154,9 @@ class LowerBuckyballIntrinsicsToRushBPass public: MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID( LowerBuckyballIntrinsicsToRushBPass) + LowerBuckyballIntrinsicsToRushBPass() = default; + LowerBuckyballIntrinsicsToRushBPass( + const LowerBuckyballIntrinsicsToRushBPass &) {} StringRef getArgument() const final { return "lower-buckyball-intrinsics-to-rushb"; @@ -162,6 +165,11 @@ class LowerBuckyballIntrinsicsToRushBPass return "Lower Buckyball intrinsic ops to the rushB host ABI."; } + Option coreId{ + *this, "core_id", + llvm::cl::desc("RushB Core ID passed to every host ABI call."), + llvm::cl::init(0)}; + void getDependentDialects(DialectRegistry ®istry) const override { registry.insert(); } @@ -180,14 +188,19 @@ class LowerBuckyballIntrinsicsToRushBPass Type voidType = LLVM::LLVMVoidType::get(&getContext()); auto call = [&](Operation *op, StringRef name, ValueRange operands) { + SmallVector arguments; + arguments.push_back(LLVM::ConstantOp::create( + builder, op->getLoc(), i32Type, + builder.getI32IntegerAttr(static_cast(coreId)))); + arguments.append(operands.begin(), operands.end()); SmallVector argumentTypes; - argumentTypes.reserve(operands.size()); - for (Value operand : operands) + argumentTypes.reserve(arguments.size()); + for (Value operand : arguments) argumentTypes.push_back(operand.getType()); auto type = LLVM::LLVMFunctionType::get(voidType, argumentTypes); auto callee = getOrInsertRushBFunction(builder, module, name, type); LLVM::CallOp::create(builder, op->getLoc(), TypeRange{}, callee, - operands); + arguments); op->erase(); };