contrib/plugins: add MicroBlaze cycle-counting plugin (mb_cycles)#108
Open
thesamprice wants to merge 6 commits into
Open
contrib/plugins: add MicroBlaze cycle-counting plugin (mb_cycles)#108thesamprice wants to merge 6 commits into
thesamprice wants to merge 6 commits into
Conversation
Throughput model (stalls=off, default): counts 1 cycle per issued
instruction with opcode-class overrides from UG984 §5 (idiv=34,
fpu=6, mts/mfs=2). Uses QEMU_PLUGIN_INLINE_ADD_U64 — minimal
overhead.
RAW-stall model (stalls=on): additionally inserts pipeline bubble
cycles when an instruction reads a register whose forwarded value is
not yet ready. Pipeline model: C_AREA_OPTIMIZED=0 with forwarding:
ALU→ALU is 0 stalls; load-use (lw/lh/lb → use) is 1 stall; blocking
instructions (idiv, fpu) incur no extra stall because their base
throughput cost already covers the latency.
Uses full per-instruction callbacks in stall mode; throughput mode
keeps the INLINE_ADD_U64 path for benchmarking.
Options: verbose=on prints per-opcode-class breakdown on exit.
stalls=on enables the RAW-stall pipeline model.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
petalogix_s3adsp1800_mmu: add memory-mapped exit/counter device at 0xFF000000.
- Write 0 → clean QEMU shutdown; nonzero → panic exit with code.
- Reads at +4/+8 return lo/hi of QEMU virtual clock (ns), which with
-icount 0 equals the instruction count. Used by bare-metal benchmarks.
mb_cycles: per-instruction FPU latency dispatch and configurable area_opt.
- opcode 0x16 (FPU) now dispatches on instruction bits[9:7] to give
per-instruction latencies: fadd/frsub=4, fmul=4, fdiv=30, fcmp=4,
flt=5, fint=4, fsqrt=27 (C_AREA_OPTIMIZED=0).
- Full 3×8 latency table covers all three C_AREA_OPTIMIZED levels;
select at runtime via area_opt=0|1|2 plugin argument.
- WIC (opcode 0x24, func bit[3]=1) correctly counted as 2 cycles.
- stall model: base_cyc packed into meta[31:24] at translation time,
eliminating the table lookup from the hot callback path.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ection
Branch taken/not-taken penalties (per UG984 §5):
- Non-D conditional (bgti, bnei, …): 1 cycle not-taken, 3 cycles taken.
Implemented via retroactive accounting: save fallthrough_pc at the end
of each TB; if the next TB starts elsewhere, add 2 extra wcycles.
- Non-D unconditional (bri, bra, …): always 3 cycles.
- D-form (bgtid, bneid, rtsd, …): 1 cycle; delay slot counted separately
at its own cost. No branch-taken penalty (delay slot absorbs it).
Fix is_delayed_branch() D-bit detection:
- 0x26 (br/brd): D was at bit 8 (wrong), now bit 20 (Ra field MSB).
- 0x27 (beq/beqd): D was at bit 20 (wrong), now bit 25 (rD field MSB).
- 0x2E (bri/brid): D was at bit 8 (wrong), now bit 20.
- 0x2F (beqi/beqid): D was at bit 20 (wrong), now bit 25.
Also add:
- Cross-TB load-use stall detection for loads at TB boundaries.
- delay_slot_filled_count / delay_slot_nop_count metrics per benchmark.
- stalls=on mode tracks pipeline_cycle and reg_ready per-register.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
BSEFI (opcode 0x19, bit[14]=1) extracts bits [IMMW:IMMS] from rA, where IMMW is the end-bit index (inclusive) and IMMS is the start bit. The correct width is (IMMW - IMMS + 1). gen_bsefi was incorrectly passing imm_w directly as the length argument to tcg_gen_extract_i32, treating it as a field width rather than an end-bit index. For bsefi r22, r19, 27, 24 (extract nibble 6), QEMU was extracting 27 bits from bit 24 instead of 4 bits — reading well past the h[] table and returning garbage. gen_bsifi already uses the correct (imm_w - imm_s + 1) convention; align gen_bsefi to match. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The previous commit changed gen_bsefi to interpret bits[10:6] as an end-bit index (imm_w - imm_s + 1) to match the (wrong) LLVM backend encoding. That made QEMU agree with our wrong toolchain but diverge from real hardware and GAS. Upstream GAS (AMD/Xilinx 2023 tc-microblaze.c) and upstream QEMU master both store WIDTH directly in bits[10:6] for BSEFI. BSIFI is the asymmetric one: it stores end-bit = start+width-1 in bits[10:6]. The correct LLVM fix is in tryBSEFI (see companion llvm-project commit). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…-use detection Detect the 1-cycle load-use stall at TB translation time by inspecting adjacent instruction pairs, baking the penalty into a constant inline add. Cross-TB pairs are resolved with one lightweight callback per TB. Removes the stalls=on/off mode split; the weighted model now includes load-use stalls by default. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
thesamprice
added a commit
to thesamprice/mb-tester
that referenced
this pull request
Jul 7, 2026
Each modified submodule now tracks its own feature branch with our commits, ready for upstream review. The master/main branches of each fork are left at upstream state. qemu-xilinx → branch: microblaze-mb-cycles-plugin PR: Xilinx/qemu#108 xilinx-gcc → branch: microblaze-fix-macro-concat PR: Xilinx/gcc#2 xilinx-gcc-13 → branch: microblaze-multilib-le PR: thesamprice/gcc#1 picolibc → branch: microblaze-cross-clang PR: picolibc/picolibc#1299 llvm-project remains on microblaze/lld (still in development). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
contrib/plugins/mb_cycles.c, a QEMU plugin for counting cycles on MicroBlaze targets using the UG984 §5 latency tables (C_AREA_OPTIMIZED selectable, default=0).hw/microblaze/petalogix_s3adsp1800_mmu.cat0xFF000000for use by bare-metal benchmark runtimes.Plugin details
Two modes selectable at runtime:
stalls=off(default) — throughput model usingQEMU_PLUGIN_INLINE_ADD_U64; minimal overheadstalls=on— full RAW-stall model using per-instruction callbacksFPU instructions (opcode
0x16) dispatch on instruction bits[9:7] for per-instruction latencies (fdiv=30 cycles, fsqrt=27, fadd/frsub/fint=4, fmul=4, flt=5). All threeC_AREA_OPTIMIZEDlevels are supported viaarea_opt=0|1|2plugin argument.WIC (
0x24, func bit[3]=1) correctly counted as 2 cycles.Exit device (
0xFF000000)0→ cleanqemu_system_shutdown_request+4/+8→ low/high 32 bits ofQEMU_CLOCK_VIRTUAL(ns); equals instruction count with-icount 0Test plan
meson/makeformicroblazeandmicroblazeeltargetsqemu-system-microblazeel -M petalogix-s3adsp1800 -plugin libmb_cycles.so🤖 Generated with Claude Code