Digital Design
: no matching posts.
Clear filtersRISC-V Branches and Jumps: Resolve Stage, JAL/JALR, Return-Address Stack Hints
Part 18 of the RISC-V series. I added the branch resolve stage, JAL redirect in ID, BTFN static prediction, and a RAS that follows the hints in spec section 2.5 to a pipeline model and compared them. CPI dropped from 1.368 to 1.227, and an 8-entry RAS predicted 98.3% of fib's returns.
RISC-V 5-Stage Pipeline: Forwarding and Stall Conditions, Handling x0
Part 17 of the RISC-V series. I ran the same programs on a 5-stage pipeline model, matched them against QEMU, and measured CPI: 1.37 with forwarding, 1.83 without. Dropping the rd≠0 condition made a program using the HINT ntl.all write 0x80000000 instead of 0.
The Immediate Generator and a RISC-V Single-Cycle Datapath
Part 16 of the RISC-V series. I turned the selector table from Part 2 into an immediate generator circuit and assembled a single-cycle datapath. Running 5 programs and 1,076,364 instructions matched QEMU on every pc trace and register, and 20.0% of instructions were branches (58.5% of them taken).
RISC-V Decoder Design: Decode Tables, Formats, and Illegal Instructions
Part 15 of the RISC-V series. Fills in the RV32I decode table down to the control signals and defines five illegal instruction conditions, then checks it against GNU objdump on 174,608 words. 165,923 matched, and all 8,685 mismatches were explained by four causes.
The Memory Model: RVWMO, What FENCE Means, and Ztso
Part 9 of the RISC-V series. Covers preserved program order in the RVWMO memory model, fence pred/succ, aq/rl, and Ztso. I enumerated 7 litmus tests under SC, TSO, and RVWMO to count whether MP, SB, and LB are allowed, and compared GCC's C11 atomic mappings under RVWMO and Ztso.
The A Extension: LR/SC, AMOs, and aq/rl
Part 8 of the RISC-V series. I checked the A extension's LR/SC reservations and failure conditions, the nine AMOs, and the aq/rl bits on QEMU. With 8 harts racing on a counter, plain increments kept only 22% while every atomic method was exact, and I found that QEMU lets sc succeed after another hart re-stores the same value.
The M Extension: Multiply, Divide, and the Rules for Divide-by-Zero and Overflow
Part 7 of the RISC-V series. Covers the 13 multiply and divide instructions of the M extension and the defined results for divide-by-zero and overflow (no exceptions), then runs 1,948 boundary cases on QEMU and confirms they all match a reference model. Without M, each multiply costs 86 extra instructions.
FENCE.I and Self-Modifying Code: What the Instruction Side Must Honor
Part 22 of the RISC-V series. Covers FENCE.I and self-modifying code. Without fence.i, QEMU ran the new code when it was written elsewhere but the old code inside the block being executed. Running 16 combinations on an instruction-set model, I identified the minimal FENCE.I implementation for each core organization.
C Extension: Decompressor, 16-Bit Fetch, and Misaligned 32-Bit Instructions
Part 21 of the RISC-V series. I built the C extension's decompressor and fetch buffer in Python and checked all 49,152 16-bit values and a real rv32imc program against objdump. 36.7% of executed instructions spanned two words, and the fetch buffer cut word reads from 33,771 to 23,903.
Implementing the A Extension: Reservations, Where AMOs Run, aq/rl, FENCE
Part 20 of the RISC-V series. I compared LR/SC reservation sets, AMO atomicity, and aq/rl and FENCE implementations with a two-hart model. If reservations aren't cleared on another hart's store, the counter drops to 69.6%, and QEMU let SC succeed in all 20 runs of an ABA test.
Implementing the M Extension: Multiply/Divide Units and Divide-by-Zero
Part 19 of the RISC-V series. I implemented the M extension's multiplier and divider as bit-exact Python models. A single 33-bit multiplier handles all three mulh variants, with zero mismatches across 300,000 pairs and 648 QEMU results, and I found a trap when dividing a negative number by zero (5,039 mismatches).
Small Extensions: Zicsr, Zifencei, Zicntr·Zihpm, B (Zba·Zbb·Zbs), Zicond, Zicbom
Part 12 of the RISC-V series. I check in QEMU the rule by which CSR instructions decide whether to read or write based on whether rd and rs1 are x0, and run the B and Zicond instructions over 2,772 combinations on RV32 and 3,720 on RV64, all matching a reference model. Enabling B shrank the code by 6.6–9.0%.
The C Extension: Compressed Formats and Their 32-bit Equivalents
Part 11 of the RISC-V series. Covers the nine 16-bit formats of the C extension and their 32-bit equivalents, then checks a hand-written decompressor against objdump for all 49,152 16-bit values. In real code, 51–69% of instructions became 16-bit, shrinking code by 26–34%.
F and D Extensions: FP Registers, Rounding, fcsr Flags, NaN Boxing
Part 10 of the RISC-V series. I ran 229 instructions on QEMU covering the F and D extensions' rounding modes and exception flags, the canonical NaN, NaN boxing, and saturation rules for out-of-range integer conversion, and confirmed that all of them matched an exact-fraction reference model.
V Extension 2: Masks, Load/Store Types, Reductions, Permutes, Tail/Mask Agnostic
Part 14 of the RISC-V series. I ran v0 masks, the four kinds of loads and stores, a first-fault strlen, reductions and permutations, and ta/ma in QEMU. Four kernels matched Python on all 78 items, and at VLEN 1024 they executed 4–7% as many instructions as scalar code.
V Extension 1: VLEN, SEW, LMUL, vsetvli, and Vector-Length-Agnostic Code
Part 13 of the RISC-V series. Covers vector registers, VLEN, SEW, and LMUL, and the rules by which vsetvli sets vl. Running the same machine code on QEMU at VLEN 128 to 1024, a 100-element add looped 25, 13, 7, and 4 times and executed 313 to 61 instructions (813 for scalar).
Assembly and the ABI: Registers, Calling Convention, Stack Frames, ELF
Part 6 of the RISC-V series. I follow the psABI calling convention and stack frame through real C functions. The work() frame was 80 bytes, and arguments from the 9th onward went on the stack. I checked argument locations per ABI and relocations, and linker relaxation shrank .text from 800 bytes to 712 bytes.
RV64I: W Instructions, Sign-Extension Rules, and What Differs from 32-Bit
Part 5 of the RISC-V series. I checked RV64I's W instructions and sign-extension rules on QEMU. 0x7fffffff+1 became 0xffffffff80000000 with addw, and 64-bit constants took an average of 7.887 instructions with li. I also look at why utoa10 from part 1 grew.
RV32I 3: Branches, Jumps, Loads/Stores and Alignment, FENCE, ECALL/EBREAK
Part 4 of the RISC-V series. I ran the six branches, jal/jalr, load sign extension, misaligned accesses, and fence/ecall/ebreak on QEMU. jalr turned 0x80000021 into 0x80000020, and all 56 results matched a reference model.
RV32I 2: Integer Ops, Compares, Shifts, and Building Constants with lui/auipc
Part 3 of the RISC-V series. Checks RV32I integer arithmetic, compares, shifts, and flagless overflow handling on QEMU with 15 edge cases, then examines the +1 correction for building 32-bit constants and addresses with lui and auipc through 1 million random trials.
RV32I 1: Registers, Six Instruction Formats, and Why Immediates Are Scrambled
Part 2 of the RISC-V series. Looks at RV32I's registers and six instruction formats, and explains why the immediate bits are scrambled by counting multiplexer inputs in the immediate generator (70 vs. 98). A hand-written encoder and decoder were checked against GNU as on 5,000 instructions.
RISC-V Overview: The Spec, ISA Names, and What Extensions Do to Code
Part 1 of the RISC-V series. Covers the design principles of a modular ISA, how the specification is split into two volumes (Unprivileged and Privileged), and how to read names like rv64gc, then compiles the same C functions under different extension combinations and measures the code size dropping from 972 bytes to 402 bytes.

RISC-V