3.9 KiB
CoreMark — EEMBC's standard embedded benchmark
CoreMark 1.0 ported to the W65816 / Apple IIgs target. Source is
vendored under coremark-src/ from
github.com/eembc/coremark.
CoreMark exercises three distinct algorithm families:
- Linked list traversal + insert/sort (
core_list_join.c) - Matrix init + multiply (
core_matrix.c) - State machine processing a string (
core_state.c)
…plus utility code (CRC, RNG) in core_util.c. Total ~2000 LOC.
This is the embedded benchmark vendors publish CoreMark/MHz scores against (Cortex-M0, AVR, RISC-V, ...). It's a useful cross-platform sanity check on our backend's code-quality.
Files
coremark-src/— vendored EEMBC source (read-only)core_portme.h/.c— W65816 porting layer (timing, malloc, printf bridge)build.sh— compile the 5 core .c files + portmerunCoreMark.sh— build + link + run under MAME
Building
bash tests/coremark/build.sh --layer2
--layer2 enables -mllvm -w65816-dbr-safe-ptrs. This is required
to fit the binary in a single bank; without it, text crosses the IO
window at 0xC000. CoreMark only touches malloc/static-array memory,
so the dbr-safe-ptrs assumption is correct.
Default iteration count is 1 (smallest valid run). Override for publishable scores:
ITERATIONS=5 bash tests/coremark/build.sh --layer2
CoreMark spec recommends >= 10 seconds of runtime. At ~1 MHz, expect roughly one iteration per second of in-IIgs time — so iteration counts of 10–60 give a representative score.
Running
bash tests/coremark/runCoreMark.sh --layer2
The run terminates with 0xC0DE written to $025000 on success.
Elapsed VBL ticks (60 Hz) are stored at $025002 (low/hi halves).
Note: running CoreMark under MAME inside this project's restricted
shell crashes MAME (same SIGSEGV as Lua's full interpreter run —
see feedback_lua_compile_test.md). The build produces a valid
binary; the run only works in an unrestricted shell. Workaround: copy
coreMark.bin out of the sandbox and run with the same
runInMame.sh invocation directly.
Size vs Calypsi (5 core files, ITERATIONS=1, PERFORMANCE_RUN)
| File | Ours (L2+threshold=75) | Calypsi 5.16 | Ratio |
|---|---|---|---|
| core_list_join.o | 10,188 | 9,073 | 1.12× |
| core_main.o | 11,656 | 19,772 | 0.59× |
| core_matrix.o | 15,180 | 11,078 | 1.37× |
| core_state.o | 7,348 | 9,944 | 0.74× |
| core_util.o | 3,156 | 4,631 | 0.68× |
| TOTAL | 47,528 | 54,498 | 0.87× |
We beat Calypsi by 13% on CoreMark overall.
Notes on the porting layer
ee_u32isunsigned long(notunsigned int— on W65816intis 16-bit;longis 32-bit). CoreMark depends on 32-bitee_u32for CRC and timing math.MEM_METHOD = MEM_STATIC— a single 2 KB static array in BSS. Avoids dynamic alloc and the resulting heap-management overhead.start_time/stop_timeuseclock()which returns the 60 Hz VBL counter.EE_TICKS_PER_SEC = 60.HAS_FLOAT = 1— CoreMark uses double precision for the score calculation; our soft-double handles it.MULTITHREAD = 1— single-context. The IIgs doesn't have threads.
Comparing builds
Lua and CoreMark together cover roughly disjoint code patterns:
| Pattern | Lua | CoreMark |
|---|---|---|
| VM dispatch | yes (luaV_execute 30+ case switch) |
no |
| Recursive descent parsing | yes (lparser.c) |
no |
| String + hash table | yes | no |
| Linked-list traversal + sort | (small) | yes |
| Matrix init + multiply | no | yes |
| State machine | (JSON tokenizer in smoke) | yes (formal CoreMark state) |
| CRC | yes (in smoke) | yes |
| Recursion-heavy | yes | no |
So they complement each other for backend coverage. Both now compile to under-or-near Calypsi size with the standard Layer 2 + threshold=75 config.