Softcores and FPGA SoCs

Last lesson ended with a warning: an FPGA does not execute anything. But here is the loophole, and it is glorious: a CPU is just a circuit — registers, an ALU, a fetch-decode-execute datapath — and circuits are exactly what the flow builds. So describe a processor in RTL, push it through the flow, and your fabric now contains a computer: a softcore. Software runs on it in the ordinary way — while the fabric around it remains free for whatever custom hardware you like. This lesson is about processors made of LUTs, the chips that bake a hard processor next to the fabric, and the strange economics of when either one is the right call.

A CPU made of LUTs

The classic softcores are the vendors' own — Xilinx's MicroBlaze, Altera/Intel's NIOS — joined lately by a swarm of open-source RISC-V cores (PicoRV32, VexRiscv, NEORV32…) that you can read, modify and ship without a license fee. A small one costs a few thousand LUTs; a mid-range FPGA could hold dozens.

The price is speed. A softcore's datapath is built from LUTs and programmable routing, and every programmable switch adds delay that a custom-silicon CPU simply does not have. The rule of thumb is roughly a 10× clock penalty: a softcore that closes timing at 100–200 MHz on fabric would run past 1–2 GHz as hard silicon. What you buy with that penalty is total malleability:

Hard plus soft: the FPGA SoC

Around 2011 the vendors asked the obvious next question: if most FPGA designs end up needing a processor anyway, why build it from expensive fabric? The answer is the FPGA SoC — Xilinx's Zynq line is the archetype — which bakes a hard ARM cluster (GHz-class, with caches, DDR controller and the usual peripherals) onto the same die as a full FPGA fabric. Between the two worlds runs a bridge of AXI ports — the industry-standard on-chip bus, which Module 7 dissects — over which the ARM sees your fabric hardware as memory-mapped devices, and your fabric can master transfers into the ARM's memory:

The division of labour writes itself: the hard cores run Linux, the network stack, the boring 95% of the product — and the fabric runs the 5% that must be hardware: the motor control loop with microsecond deadlines, the video pipeline, the protocol that no off-the-shelf chip speaks.

Where softcores and SoCs earn their keep

Run a softcore right now

To make "a CPU is just a circuit" concrete, here is a four-instruction softcore in the two-phase settle-then-snap style from Module 1 — registers as state, one next() as the combinational logic, the loop as the clock. It is a toy, but its shape is honestly that of MicroBlaze, and Module 6 grows exactly this pattern into a real pipelined CPU:

// A 4-instruction softcore: LI (load immediate), ADD, JNZ, HALT. type Instr = | { op: "LI"; rd: number; imm: number } | { op: "ADD"; rd: number; ra: number; rb: number } | { op: "JNZ"; ra: number; target: number } | { op: "HALT" }; // Program: sum 5 + 4 + 3 + 2 + 1 into r2. const program: Instr[] = [ { op: "LI", rd: 1, imm: 5 }, // 0: r1 = 5 (counter) { op: "LI", rd: 2, imm: 0 }, // 1: r2 = 0 (sum) { op: "LI", rd: 3, imm: -1 }, // 2: r3 = -1 { op: "ADD", rd: 2, ra: 2, rb: 1 }, // 3: r2 += r1 { op: "ADD", rd: 1, ra: 1, rb: 3 }, // 4: r1 -= 1 { op: "JNZ", ra: 1, target: 3 }, // 5: loop while r1 != 0 { op: "HALT" }, // 6: ]; interface State { pc: number; regs: number[]; halted: boolean } // Settle: compute the whole next state from the old one. Snap: commit it at the "edge". function next(s: State): State { const instr = program[s.pc]; const regs = s.regs.slice(); let pc = s.pc + 1, halted = false; switch (instr.op) { case "LI": regs[instr.rd] = instr.imm; break; case "ADD": regs[instr.rd] = s.regs[instr.ra] + s.regs[instr.rb]; break; case "JNZ": if (s.regs[instr.ra] !== 0) pc = instr.target; break; case "HALT": halted = true; pc = s.pc; break; } return { pc, regs, halted }; } let state: State = { pc: 0, regs: [0, 0, 0, 0], halted: false }; console.log("cycle | pc | r1 r2 r3"); console.log("------+----+-----------"); for (let cycle = 0; cycle < 24 && !state.halted; cycle++) { const r = state.regs; console.log(` ${String(cycle).padStart(2)} | ${state.pc} | ${String(r[1]).padStart(2)} ${String(r[2]).padStart(2)} ${String(r[3]).padStart(2)}`); state = next(state); // one clock edge } console.log(`\nHalted. r2 = ${state.regs[2]} (5+4+3+2+1) - software, running on described hardware.`);

Now imagine noticing that the whole loop (instructions 3–5) is your program's hot spot, and adding a SUMN instruction that does it in one cycle of fabric logic. That edit — impossible on any chip you can buy — is a Tuesday afternoon on a softcore.

Walk into the emulation lab of any big chip company and you will find corridors of refrigerator- sized racks, each stuffed with the largest FPGAs manufactured — devices so big they are barely sold to anyone else, partitioning one giant ASIC design across dozens of chips. On them runs the real, complete RTL of an unreleased processor at perhaps 10–50 MHz: a hundred times slower than the final silicon, but fast enough to boot the operating system, run the actual graphics driver, and play (slowly, heroically) an actual game — months before tape-out. Teams book time on the farm around the clock; finding a bug there costs a re-synthesis, while finding it after tape-out costs a mask respin and a season of schedule. The punchline for this course: the GPU is both the destination of our syllabus and a heavy user of the FPGA techniques in this module — every serious ASIC spends its adolescence as a bitstream.

Here is an embarrassing benchmark: your carefully-tuned softcore closes timing at 100 MHz on a $150 FPGA — and a $1 off-the-shelf microcontroller runs the same C code at 480 MHz while sipping less power. If raw CPU speed (or cost, or watts) is the requirement, the hard chip wins, always, and by a margin that is not close; choosing a softcore for speed alone is engineering malpractice. Softcores win on integration: the CPU sits millimetres of routing — not centimetres of circuit board — away from your custom logic, shares its memory, can be cloned eight times, and can grow instructions your algorithm wishes existed. The honest decision question is never "is the softcore fast?" but "does my design need a modest CPU inside the fabric?" If yes, nothing else comes close; if no, buy the dollar chip and spend the fabric on hardware.