Skip to content

MAGIA_V3_REBASED_PR - #55

Open
Dequino wants to merge 87 commits into
mainfrom
ad/magia_v3_rebase_pr
Open

MAGIA_V3_REBASED_PR#55
Dequino wants to merge 87 commits into
mainfrom
ad/magia_v3_rebase_pr

Conversation

@Dequino

@Dequino Dequino commented Aug 5, 2026

Copy link
Copy Markdown
Member

Realignment with MAGIA_V3, also rebasing the changes in main with chips-it fork.

Dequino and others added 30 commits July 13, 2026 12:35
…instead of float16

HP Float support seems to have problems
callme-sam and others added 30 commits August 5, 2026 19:13
  - Fix RedMulE register offsets in tile_ctrl.h (X=0x2C, MCFG0=0x20, etc.)
    to match gvsoc LightRedmule req_v2 interface; removes computation errors
    in test_mm_os
  - Restore mcfg_reg1 format bits and MCFG2 write in redmule_isa_utils.h
  - Re-add mhartid guard on BSS clear in crt0.S to prevent hart races
  - Include base magia tests for magia_v3 in all TEST_MAPPINGS branches
…cate task symbols

  Redesign the PULP cluster software interface to align with the new GVSoC
  cluster_regs model:

  API changes (magia_pulp_utils.h):
  - pulp_init(binary) drops the nb_cores argument; broadcasts CLK_EN and
    busy-waits until all PULP cores signal READY
  - pulp_run_task(task, core_mask) accepts a one-hot core bitmask, sets
    nb_cores_to_wait = popcount(mask) internally, writes the mask to PULP_START,
    then polls until PULP_START is cleared by the cores' ACK

  pulp_crt0.S rewritten with a two-phase completion protocol:
  1. ACK phase (before task): each woken hart writes 0 to PULP_START;
     cluster_regs counts ACKs and clears the register, unblocking the CV32 poll
  2. DONE phase (after task): each hart writes 1 to PULP_DONE after the task
     returns; cluster_regs counts DONEs and fires the DONE IRQ to the CV32 event
     unit, waking eu_pulp_wait()

  Task symbol deduplication:
  - Rename hello_task → hello_pulp_task / hello_spatz_task in all test sources
    to avoid HELLO_TASK name collision in combined Spatz+PULP tests
  - Remove stale FIRST_TASK_NAME overrides from CMakeLists (default now matches
    the renamed function names)
  - Update extract_pulp_symbols.sh grep pattern to match renamed symbols
Adds tests/spatz_pulp_on_magia/multi_task — a test that exercises two sequential Spatz tasks and four sequential PULP task dispatches on different core pairs within the same run.

  Spatz tasks (fp16 RVV):
    1. vec_add: vfadd.vv on A+B → C
    2. vec_relu: vfmax.vf(0) on X → Y

  PULP tasks (int32, one pair of cores each):
    1. vec_sum   — cores 0+1  (mask=0x03): parallel partial sums
    2. vec_dot   — cores 2+3  (mask=0x0C): parallel partial dot product
    3. vec_scale — cores 4+5  (mask=0x30): element-wise multiply by scalar
    4. vec_absmax — cores 6+7 (mask=0xC0): parallel absolute maximum

Each PULP task uses pair_local_id = GET_PULP_LOCAL_ID(hartid) % 2 to split work between the two dispatched cores. CV32 verifies all results before proceeding to the next dispatch.
  multi_task used flat L1_BASE for PULP/Spatz buffers, but each tile's L1 is
  at L1_BASE + tile_id*L1_TILE_OFFSET -> on a mesh all tiles aliased onto
  tile 0's L1 and clobbered each other (wrong results / hang; ok in 1x1).
  Use get_l1_base(get_hartid()) instead.

  Also: build io.c with -fno-tree-loop-distribute-patterns (memset was
  rewritten into infinite self-recursion at -O3); CV32 sp starts at top of
  its stack band; add PULP-only multi_task; hello_spatz_pulp HELLO_TASK ->
  HELLO_SPATZ_TASK.
Heavy-duty application/benchmark for the magia_v3 4x4 mesh: one inference of
a fused NN block, driving RedMulE, Spatz and the 8-core PULP cluster on every
tile.

  Z = X*W + bias            RedMulE, input-stationary (mm_is dataflow),
                            iDMA + FractalSync neighbour handover
  P = hardswish(Z*s + b)    Spatz, fp16 vector
  P = layernorm_rowwise(P)  Spatz, fp16 vector
  Q = softmax_rowwise_q15   PULP cluster, 8 cores, int16 packed SIMD

At M=N=K=512 that is 262 656 parameters and 268.4 MFLOP per inference, the
size of one attention projection in a d_model=512 transformer. Weights are
pseudo-random and the norm/softmax groups follow the mesh partitioning, so it
is a benchmark and not an inference engine; see the header of main.c.

The phases are pipelined rather than run in sequence: block r of Z is picked up
NN_PIPE_LAG rounds after the round that produced it, which the neighbour syncs
alone already order, so no extra barrier is needed. Measured 394 697 cycles per
inference against 461 658 phase-by-phase. RedMulE runs at 97.7% of peak.

Two feed paths: standalone under gvrun with the matrices inside the ELF, or a
payload staged in L2 by a VFIO host (contract in include/nn_is_params.h).

The dataset headers are generated at build time by scripts/gen_nn_is_data.py
and are not committed: nn_is_data.h alone is 6.3 MB of hex literals and is
fully reproducible from -DNN_SIZE / -DNN_TIMESLOTS / -DNN_SEED.

Also: align .pulp_binary to 256 bytes in link.ld with the boundary labels
inside the section. CV32E40P hardwires mtvec[7:2]=0, so the PULP trap handler
must sit on a 256-byte boundary or a dispatch IRQ vectors into the middle of
the startup code.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants