Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -357,15 +357,15 @@ controller calibrates, so software never observes an uninitialized main memory.

| Resource | Used | Available | Util% |
|----------|-----:|----------:|------:|
| CLB LUTs | 158,254 | 1,029,600 | 15.4% |
| LUT as Logic | 137,072 | 1,029,600 | 13.3% |
| CLB LUTs | 157,437 | 1,029,600 | 15.3% |
| LUT as Logic | 136,254 | 1,029,600 | 13.2% |
| LUT as Distributed RAM | 19,914 | — | — |
| LUT as Shift Register | 1,268 | — | — |
| CLB Registers | 121,955 | 2,059,200 | 5.9% |
| LUT as Shift Register | 1,269 | — | — |
| CLB Registers | 119,092 | 2,059,200 | 5.8% |
| Block RAM Tile | 246 | 2,112 | 11.7% |
| URAM | 64 | 352 | 18.2% |
| DSPs | 31 | 1,320 | 2.4% |
| CARRY8 | 4,924 | 128,700 | 3.8% |
| CARRY8 | 4,685 | 128,700 | 3.6% |
| F7 Muxes | 1,206 | 514,800 | 0.2% |
| F8 Muxes | 548 | 257,400 | 0.2% |
| Bonded IOB | 132 | 364 | 36.3% |
Expand All @@ -376,11 +376,11 @@ controller calibrates, so software never observes an uninitialized main memory.

| Resource | Used | Available | Util% |
|----------|-----:|----------:|------:|
| Slice LUTs | 139,934 | 203,800 | 68.7% |
| LUT as Logic | 118,255 | 203,800 | 58.0% |
| LUT as Distributed RAM | 20,752 | — | — |
| LUT as Shift Register | 927 | — | — |
| Slice Registers | 95,899 | 407,600 | 23.5% |
| Slice LUTs | 141,383 | 203,800 | 69.4% |
| LUT as Logic | 119,598 | 203,800 | 58.7% |
| LUT as Distributed RAM | 20,860 | — | — |
| LUT as Shift Register | 925 | — | — |
| Slice Registers | 96,160 | 407,600 | 23.6% |
| Block RAM Tile | 225 | 445 | 50.6% |
| DSPs | 32 | 840 | 3.8% |
| F7 Muxes | 1,096 | 101,900 | 1.1% |
Expand Down
4 changes: 2 additions & 2 deletions fpga/hw_regression.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,8 @@
# (977 CoreMark at 300 MHz, 3.26 CoreMark/MHz), the same figure the README
# headline cites. Re-arm from the next hardware run.
BASELINE_SCORES: dict[str, dict[str, float | None]] = {
"x3": {"coremark": 977.13, "coremark_pro": 111.14},
"genesys2": {"coremark": 433.65, "coremark_pro": 39.0},
"x3": {"coremark": 977.13, "coremark_pro": 131.22},
"genesys2": {"coremark": 436.17, "coremark_pro": 45.32},
}

# Default allowed drop below baseline (percent). FROST is cycle-deterministic
Expand Down
32 changes: 31 additions & 1 deletion hw/rtl/cpu_and_mem/cpu/if_stage/pc_controller.sv
Original file line number Diff line number Diff line change
Expand Up @@ -618,10 +618,38 @@ module pc_controller #(
end
end

// The target-handoff consume must ride the same !fetch_stall enable as the
// pc_reg flop it hands off to. An ungated consume during a stall discards
// the pending target while pc_reg is frozen: pc_reg then advances
// SEQUENTIALLY past the predicted-taken branch while fetch follows the
// target, and the aligner serves target-path bytes under sequential
// pc_reg PCs. Downstream decode faithfully manufactures phantom
// instructions from that pairing (a non-branch can dispatch as a
// taken branch, "mispredict", and redirect the machine to a garbage
// address). The crossing arm needs no gate: it consumes implicitly via
// stale_pending_prediction only after pc_reg really advances.
assign clear_pending_prediction_state =
redirect_kill_pending_q || pending_prediction_target_handoff ||
redirect_kill_pending_q || (pending_prediction_target_handoff && !fetch_stall) ||
stale_pending_prediction;

`ifndef SYNTHESIS
// The un-stalled handoff consume assumes the target arm actually wins the
// next_pc_reg mux. The redirect arms are fine (they kill the pending state
// themselves), but the three non-redirect arms above the target arm would
// consume without applying — the same desync this consume gate fixes, via
// a different door. Keep that assumption observable.
always_comb begin
if (pending_prediction_target_handoff && !fetch_stall && !i_reset && !$isunknown(
{i_window_cannot_serve, i_slot2_prediction_used_for_pc,
o_pending_prediction_target_holdoff}
)) begin
p_handoff_consume_implies_apply :
assert (!i_window_cannot_serve && !i_slot2_prediction_used_for_pc &&
!o_pending_prediction_target_holdoff);
end
end
`endif

// Express the valid bit as clear/enable/set control rather than a full
// next-state mux on D. The priority is unchanged, but Vivado can map the
// clear and hold portions onto flop control pins and keep the prediction arm
Expand Down Expand Up @@ -823,4 +851,6 @@ module pc_controller #(
end
`endif



endmodule : pc_controller
22 changes: 17 additions & 5 deletions sw/apps/coremark_pro/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,19 @@ ABI := $(FROST_FP_ABI)
# FROST port does the same).
FPGA_CPU_CLK_FREQ ?= 30000000

# Base flags shared by every translation unit (matches the FROST project flags
# and the upstream util/make/gccrv32.mak "FROST sizing" toolchain file).
BASE_FLAGS := -march=$(ARCH) -mabi=$(ABI) -O2 \
# Optimization level for every CoreMark-PRO translation unit and the link.
# -O3 matches the rest of the FROST software tree (sw/common/common.mk
# OPT_LEVEL default, the plain-CoreMark port). EEMBC's shipped GCC toolchain
# files (util/make/gcc*.mak) all use -O2, but that is reference-toolchain
# convention, not a rule: the coremark-pro README "Run Rules" allow any
# toolchain/build options provided every workload is compiled and linked with
# the SAME flags, disclosed with published scores. Uniformity holds by
# construction here (this feeds BASE_FLAGS, shared by every TU and the link).
# Overridable for A/B runs: `make OPT_LEVEL=-O2` or OPT_LEVEL=-O2 in the env.
OPT_LEVEL ?= -O3

# Base flags shared by every translation unit and the final link.
BASE_FLAGS := -march=$(ARCH) -mabi=$(ABI) $(OPT_LEVEL) \
-nostdlib -nostartfiles -ffreestanding \
-ffunction-sections -fdata-sections -fno-strict-aliasing \
-DCOREMARK_PRO_TRACE=$(COREMARK_PRO_TRACE)
Expand Down Expand Up @@ -431,8 +441,10 @@ MITH_DEFINES := -DHOST_EXAMPLE_CODE=1 \
# GCC 15 defaults to C23, where implicit declarations / int<->ptr conversions
# are hard errors. The MITH AL and several benchmark kernels use POSIX
# prototypes / K&R idioms they expect the system to supply; build them as gnu11
# and downgrade those to warnings (then silence with -w), as the upstream
# gccrv32.mak does. GCC 14+ additionally promotes -Wincompatible-pointer-types
# and downgrade those to warnings (then silence with -w; EEMBC's own gcc*.mak
# files build this era of code as gnu99, and the user guide's errata appendix
# lists the surviving warnings as expected and safely ignorable).
# GCC 14+ additionally promotes -Wincompatible-pointer-types
# / -Wint-conversion to *errors* that -w does NOT downgrade, so demote them
# explicitly.
MITH_COMPAT := -std=gnu11 -w -fsigned-char \
Expand Down
55 changes: 30 additions & 25 deletions sw/apps/software_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,76 +67,81 @@ def hardware_validation_run_args(self) -> str:
app_name="coremark_pro_core",
workload="core",
description="CoreMark-PRO core workload",
# One iteration measured 24.231s on X3 / 54.520s on genesys2.
# -O3: one iteration measured 24.927s on X3 / 56.087s on genesys2.
hardware_iterations={"x3": 1, "genesys2": 1},
),
CoremarkProProgram(
app_name="coremark_pro_cjpeg",
workload="cjpeg-rose7-preset",
description="CoreMark-PRO JPEG compression workload",
# X3: 49 iters measured 10.242s (41 fell short at 8.571s).
# genesys2: 22 iters measured 10.347s (18 fell short at 8.467s).
hardware_iterations={"x3": 49, "genesys2": 22},
# -O3: X3 5.176 iter/s (71 iters measured 13.717s) -> 54 ~= 10.4s.
# genesys2 2.300 iter/s (32 iters measured 13.911s) -> 24 ~= 10.4s.
hardware_iterations={"x3": 54, "genesys2": 24},
),
CoremarkProProgram(
app_name="coremark_pro_linear_alg",
workload="linear_alg-mid-100x100-sp",
description="CoreMark-PRO LINPACK single-precision workload",
# X3: 24 iters measured 10.248s (12 fell short at 5.124s).
# genesys2: 11 iters measured 10.568s (4 fell short at 3.843s).
hardware_iterations={"x3": 24, "genesys2": 11},
# -O3: X3 3.091 iter/s (37 iters measured 11.970s) -> 32 ~= 10.4s.
# genesys2 1.374 iter/s (17 iters measured 12.375s) -> 14 ~= 10.2s.
hardware_iterations={"x3": 32, "genesys2": 14},
),
CoremarkProProgram(
app_name="coremark_pro_loops",
workload="loops-all-mid-10k-sp",
description="CoreMark-PRO Livermore loops single-precision workload",
# ~6 MiB heap, satisfied by the DDR-backed cached region (heap ~1 GiB).
# X3: 2 iterations measured 17.284s (1 fell short at 8.635s).
# genesys2: one iteration measured 24.732s.
# -O3: X3 2 iterations measured 16.440s (1 falls short at ~8.2s).
# genesys2: one iteration measured 23.742s.
hardware_iterations={"x3": 2, "genesys2": 1},
),
CoremarkProProgram(
app_name="coremark_pro_nnet",
workload="nnet_test",
description="CoreMark-PRO neural net workload",
# One iteration measured 16.251s on X3 / 36.564s on genesys2.
hardware_iterations={"x3": 1, "genesys2": 1},
# -O3: X3 2 iterations measured 19.591s -- one iteration would run
# ~9.8s, under the floor (FP64-heavy; the 64-bit data tier sped this
# workload ~1.66x). genesys2: one iteration measured 22.051s.
hardware_iterations={"x3": 2, "genesys2": 1},
),
CoremarkProProgram(
app_name="coremark_pro_parser",
workload="parser-125k",
description="CoreMark-PRO XML parser workload",
# Parser runtime is heap-size sensitive (per-iteration isn't constant).
# X3: 18 iters measured 10.358s (17 fell short at 9.821s).
# genesys2: 4 iters measured 11.066s (3 fell short at 9.039s).
hardware_iterations={"x3": 18, "genesys2": 4},
# Parser runtime is heap-size sensitive (per-iteration isn't constant),
# so both counts keep extra margin above the usual ~10.4s target.
# -O3: X3 1.786 iter/s (26 iters measured 14.555s) -> 19 ~= 10.6s.
# genesys2 0.398 iter/s (6 iters measured 15.064s) -> 5 ~= 12.6s.
hardware_iterations={"x3": 19, "genesys2": 5},
),
CoremarkProProgram(
app_name="coremark_pro_radix2",
workload="radix2-big-64k",
description="CoreMark-PRO radix-2 FFT workload",
# The ~800 KiB of constant FFT data is placed in the cached region
# (.ddr_rodata via the unified linker) and delivered through the
# sw_ddr.mem image. X3: 63 iters measured 10.165s (61 fell short at
# 9.842s). genesys2: 11 iters measured 10.201s.
hardware_iterations={"x3": 63, "genesys2": 11},
# sw_ddr.mem image. -O3: X3 10.475 iter/s (98 iters measured 9.356s,
# under the floor -- the 64-bit data tier + -O3 sped this 1.69x) ->
# 110 ~= 10.5s. genesys2 1.423 iter/s (17 iters measured 11.945s)
# -> 15 ~= 10.5s.
hardware_iterations={"x3": 110, "genesys2": 15},
),
CoremarkProProgram(
app_name="coremark_pro_sha",
workload="sha-test",
description="CoreMark-PRO SHA-256 workload",
# X3: 103 iters measured 10.104s (75 fell short at 7.357s).
# genesys2: 44 iters measured 10.176s (33 fell short at 7.632s).
hardware_iterations={"x3": 103, "genesys2": 44},
# -O3: X3 10.516 iter/s (150 iters measured 14.264s) -> 110 ~= 10.5s.
# genesys2 4.461 iter/s (64 iters measured 14.347s) -> 46 ~= 10.3s.
hardware_iterations={"x3": 110, "genesys2": 46},
),
CoremarkProProgram(
app_name="coremark_pro_zip",
workload="zip-test",
description="CoreMark-PRO zlib workload",
# ~3.3 MiB heap, satisfied by the DDR-backed cached region. Measured at
# -v0: X3 21 iters took 10.470s (18 fell short at 8.975s). genesys2
# 9 iters took 11.077s (7 fell short at 8.618s).
hardware_iterations={"x3": 21, "genesys2": 9},
# ~3.3 MiB heap, satisfied by the DDR-backed cached region.
# -O3: X3 2.083 iter/s (30 iters measured 14.401s) -> 22 ~= 10.6s.
# genesys2 0.840 iter/s (12 iters measured 14.288s) -> 9 ~= 10.7s.
hardware_iterations={"x3": 22, "genesys2": 9},
),
)

Expand Down
Loading