Two memory-mapped accelerators that make SIMD work on a narrow bus.
Two small IPs attached to a RISC-V core over APB. One splits a 32-bit word into four 8-bit
lanes to parallelise addition; the other performs z = z + (x × y) lane-wise across 128
bits. The inputs are chosen so the accumulated result decodes back into an ASCII sentence,
which proves lane parallelism and accumulation in a single check. FPGA execution matches RTL
simulation 100%.
Attaching an accelerator IP tends to get stuck on the bus side rather than the arithmetic. How to lay out the register map, what has to hold between a write and a read, and above all how to confirm the IP is really mapped and responding all need to be settled first.
So two small IPs went first to establish that path. The K-means FPU project sits on the same RISC-V SoC and APB platform and shares the register-map layout and verification approach.
| Host | RISC-V SoC platform |
| Bus | APB slave, mapped into the user region |
| mini1 | 32-bit word split into four 8-bit lanes, no carry between lanes |
| mini2 | 128-bit SIMD MAC, four 32-bit lanes |
A 32-bit register is treated as four independent bytes. Write the two operands, pulse the request, read once, and four additions have happened together. The point is that SIMD comes for free on a narrow bus: the data was already there, only the interpretation changed.
Two inputs settle it.
| Input | Result | What it shows |
|---|---|---|
0x12345678 + 0x98765432 |
0xAAAAAAAA |
baseline, no carries |
0x6745ABEF + 0xABAB8967 |
0x12F03456 |
carries do not cross into the next lane |
The second is the discriminator. EF + 67 = 0x156, so only the low eight bits survive as
56, and 12F03456 appears only if that carry stays put. A plain 32-bit addition would give
something entirely different, so this single input decides whether the IP is really SIMD.
Four 32-bit lanes multiply and accumulate in one operation. Going from scalar to array turned
the registers into reg [31:0] var_x [3:0], grew the address decode from three offsets to
twelve, and replaced the individual assignments with a for(j=0; j<4; j=j+1) loop.
The verification module calls the accumulating MAC three times back to back with no reset in between, and the inputs are arranged so the resulting bytes decode into an ASCII sentence. A plain assignment instead of an accumulation, one lane multiplying incorrectly, or the four reads and writes going out of order all break the sentence. The third call uses negative operands deliberately, subtracting from what the first two accumulated to land exactly on the target codes.
"You can create a" + "nything, you can" + " become anything"
→ "You can create anything, you can become anything"
test1_apb.v contains code that copies internal array elements onto plain wires. Array
contents do not appear in the waveform viewer, so without it there is no way to see internal
state while debugging. It has no functional effect.
★ = written by me · (provided) = distributed by the course
mini1/test1_apb.v ★ byte-parallel adder — var_simd register, offset 0x14 added
mini1/main.c ★ perform_simd1() API and two verification scenarios
mini1/lec_apb_user_region.vh ★ glue — instantiates the IP into the SoC wiring
mini1/lec_apb.xml (provided) platform description
mini2/test1_apb.v ★ four-lane array extension, twelve address decodes,
accumulating MAC, debug wires for waveform viewing
docs/ submitted reports, two parts (mini1, mini2)
The scalar APB IP these build on (add, subtract, MAC) is the lecture example; both IPs here extend it into SIMD.
| mini1 | 32-bit word split into four 8-bit lanes, no carry between lanes |
| mini2 | 128-bit SIMD MAC — z = z + (x × y) across four 32-bit lanes in parallel |
| Verification | the accumulated result decodes to an ASCII sentence, proving lane parallelism and accumulation together |
| Agreement | FPGA execution matches RTL simulation 100% |
[EMU@FPGA]
simd_add : 0001E76D, 0001E77F, 00224408, 00110019,
simd_sub : 0001E749, 0001E737, 00224402, 00110009,
simd_mac : 01234567, 02468ACE, 0369CF12, 048C048C,
You can create anything, you can become anything
Prerequisites — the course RISC-V SoC platform (RVX toolchain), Questa or ModelSim, Vivado.
Add test1_apb.v to the platform's user region, rebuild the SoC, then build the matching
main.c together with the platform headers.
My part — two individual assignments. The scalar base IP and the platform description
(lec_apb.xml) were distributed by the course; the RTL extensions, the C API, simulation and
board verification are mine.
Not included — the application code for mini2. Its verification harness (simd_func.c)
is distributed material and cannot be redistributed, so only the RTL is here. The lecture
slides are excluded for the same reason.