100 projects that show what you can do

Each project has its own spec, steps, deliverables and a way to measure success. Pick one in your track, finish it properly, and write it up. That is worth more than ten half-done copies.

Most of these are industry-level and take weeks. New to digital design? Do the Digital Electronics and Verilog paths first, then start with a Beginner or Intermediate project in your track.

001Configurable 5-Stage RISC-V CPU with InterruptsA parameterized RV32I five-stage pipelined core with machine-mode traps, interrupts and one custom instruction, verified against the official RISC-V test suites.RTL designAdvanced10-12 wks

Goal. Build an RV32I core that passes the rv32ui riscv-tests and handles timer and external interrupts through machine-mode CSRs. Parameters let you switch forwarding, branch prediction and the custom instruction on or off.

Specification

  • ISA: RV32I (37 base instructions plus FENCE, ECALL, EBREAK) with Zicsr for machine-mode CSRs
  • Pipeline: IF, ID, EX, MEM, WB with full forwarding and one-cycle load-use stall
  • Traps: mstatus, mie, mip, mtvec, mepc, mcause, MRET; machine timer and external interrupt inputs
  • Custom instruction on the custom-0 opcode (0001011), e.g. a single-cycle population count
  • Parameters: RESET_PC, ENABLE_FORWARDING, BRANCH_PREDICT (static not-taken or 2-bit BHT)
  • Separate instruction and data memory ports with a simple valid/ready handshake

Steps

  1. Write a one-page spec: pipeline diagram, hazard table, CSR list and the exact interrupt entry and exit sequence.
  2. Start from a verified 5-stage RV32I core (project 51) and tag it in Git as the baseline.
  3. Turn forwarding and branch prediction into parameters, then rerun rv32ui in every configuration.
  4. Add Zicsr, the trap unit and MRET; write directed tests for ECALL, illegal instruction and timer interrupt.
  5. Add the custom-0 instruction, a GCC inline-asm .insn wrapper and a C test that uses it.
  6. Compare a retired-instruction trace against the Spike ISS on random programs and fix every mismatch.
  7. Synthesize with Yosys and report LUT or cell count and the critical path for each parameter setting.

Deliverables

  • Parameterized SystemVerilog RTL with a block diagram and hazard table
  • Verilator regression script that runs riscv-tests and prints pass/fail per test
  • Spike trace-compare log and a list of bugs found and fixed
  • Synthesis report comparing area and Fmax across configurations

How you know it works

  • All rv32ui-p riscv-tests pass, e.g. 100% of the suite with no waivers
  • CPI on a CoreMark-style loop, e.g. below 1.3 with forwarding enabled
  • Interrupt latency from mip bit set to first handler fetch, e.g. 5 cycles or fewer
  • Zero trace mismatches against Spike on e.g. 1,000 random programs

Tools

Open-source Verilator, Icarus Verilog, GTKWave, Yosys, Spike ISS, riscv-gnu-toolchain

Industry Synopsys VCS, Cadence Xcelium, Synopsys Design Compiler, Cadence Genus

Before you start

  • A working 5-stage RV32I core (project 51)
  • Synthesizable SystemVerilog
  • RISC-V assembly basics
  • Makefiles and Linux shell

Go further

  • Add the M extension with a multi-cycle divider
  • Add a 4 KB instruction cache
  • Run it on an FPGA with a UART bootloader

Watch out for

  • Writing mepc with the wrong PC when an interrupt arrives during a stalled or flushed instruction.
  • Forgetting that writes to x0 must be ignored by the forwarding logic too.

Resume line Designed a parameterized 5-stage RV32I core with machine-mode interrupts that passed all rv32ui riscv-tests and reached a CPI of X at Y MHz.

Proves: RTL designArchitecture / AI hardware

002INT8 Systolic-Array Matrix MultiplierAn 8x8 output-stationary systolic array that multiplies INT8 matrices into INT32 results, the core block inside most neural-network accelerators.RTL designIntermediate6-8 wks

Goal. Build a tiled engine that computes C = A x B for matrices up to 64x64. It must match a NumPy golden model bit for bit and report MACs per cycle.

Specification

  • 8x8 grid of processing elements, each one INT8 x INT8 multiply with an INT32 accumulator
  • Output-stationary dataflow: A streams left to right, B streams top to bottom, skewed by one cycle per row
  • Peak 64 MACs per cycle, e.g. 6.4 GMAC/s at 100 MHz
  • On-chip SRAM buffers for A and B tiles, double-buffered so loading overlaps compute
  • AXI4-Lite control registers (start, done, matrix size) and an AXI4-Stream data port
  • Optional ReLU and right-shift requantization on the output path

Steps

  1. Write the PE in RTL and unit-test it: one multiply-accumulate per cycle plus a clear signal.
  2. Instantiate the 8x8 array with generate loops and the input skew registers for A and B.
  3. Build a tile controller that walks K in steps of 8 and drains results after the last partial sum.
  4. Add double-buffered tile SRAMs and the AXI4-Lite register block.
  5. Write a cocotb test that drives random matrices and compares against numpy.matmul with int32 results.
  6. Measure cycles per 64x64 multiply and compute utilization as actual MACs divided by 64 times cycles.
  7. Synthesize with Yosys or Vivado and report area, DSP usage and Fmax.

Deliverables

  • RTL for PE, array, tile controller and AXI wrappers
  • cocotb testbench with NumPy golden model and random seeds
  • Utilization and throughput table for 8x8, 32x32 and 64x64 matrices
  • Short report explaining the dataflow with a timing diagram of the skew

How you know it works

  • Bit-exact match with NumPy on e.g. 10,000 random matrix pairs
  • Array utilization on 64x64, e.g. above 85%
  • Fmax after synthesis, e.g. 150 MHz on a mid-range FPGA
  • No accumulator overflow for K up to e.g. 256 with INT8 inputs

Tools

Open-source Verilator, cocotb, Python with NumPy, Yosys, GTKWave

Industry AMD Vivado, Synopsys VCS, Cadence Genus

Before you start

  • Signed fixed-point arithmetic
  • Generate loops in Verilog
  • Matrix multiplication by hand
  • Basic Python

Go further

  • Compare a weight-stationary version and explain the bandwidth trade-off
  • Add 2:4 structured sparsity skipping
  • Run one layer of a small CNN end to end

Watch out for

  • Getting the input skew off by one so partial sums mix values from different k indices.
  • Sign-extending INT8 operands incorrectly before multiplication.

Resume line Built an 8x8 INT8 systolic-array matrix engine with double-buffered tiles, verified bit-exact against NumPy and reaching X% utilization at Y MHz.

Proves: RTL designArchitecture / AI hardware

003MESI Cache Coherence Controller for a Dual-Core SystemTwo private L1 data caches kept coherent with the MESI snooping protocol over a shared bus, the textbook basis of multi-core coherence.RTL designAdvanced8-10 wks

Goal. Build two write-back L1 caches and a snooping bus that keep shared memory coherent under concurrent reads and writes. Prove with tests and assertions that no two caches ever hold a line in Modified or Exclusive state together.

Specification

  • Two L1 data caches, each 4 KB, 2-way set-associative, 16-byte lines, LRU replacement
  • Write-back, write-allocate policy with a one-entry writeback buffer
  • MESI states per line; bus transactions BusRd, BusRdX, BusUpgr and Flush
  • Shared atomic bus with a round-robin arbiter and a single-ported main memory model
  • Core-side interface: 32-bit load and store with byte enables and a stall signal
  • Invariant: at most one cache holds a line in M or E state at any time

Steps

  1. Draw the full MESI state table: every processor event and snooped bus event, with next state and bus action.
  2. Build and verify a single non-coherent cache with tag, data and LRU arrays.
  3. Add the snoop port, the MESI state bits and the bus arbiter.
  4. Handle races: a snoop hitting a line that is waiting in the writeback buffer, and simultaneous upgrades.
  5. Write SVA invariants for single-writer and data-value consistency and bind them to the system.
  6. Run directed litmus tests (message passing, store buffering) and long random load/store traffic from both cores.
  7. Collect state-transition coverage and report how many of the table entries were exercised.

Deliverables

  • MESI state-transition table and bus timing diagrams
  • RTL for cache, snoop logic, arbiter and memory model
  • Testbench with litmus tests, random traffic and a golden memory checker
  • Coverage report of state transitions and a bug log

How you know it works

  • Zero coherence violations over e.g. 1 million random memory operations
  • Transition coverage of the MESI table, e.g. 100% of legal transitions hit
  • Hit rate on a shared-counter benchmark reported per core, e.g. above 90%
  • Read-miss latency served by cache-to-cache transfer, e.g. under 10 cycles

Tools

Open-source Verilator, Icarus Verilog, SymbiYosys, GTKWave, Python

Industry Synopsys VCS, Cadence Xcelium, Cadence JasperGold, Siemens Questa

Before you start

  • Set-associative cache design
  • FSM design
  • SystemVerilog assertions basics
  • Computer architecture course

Go further

  • Extend to four cores and measure bus contention
  • Add MOESI and compare memory traffic
  • Replace the bus with a simple directory

Watch out for

  • Ignoring the transient states between a bus request and its grant, which causes most coherence bugs.
  • Testing only one core at a time, so races never happen.

Resume line Designed a dual-core MESI snooping cache system and verified it with SVA invariants over X million random operations with zero coherence violations.

Proves: RTL designArchitecture / AI hardwareVerification

004DDR4 SDRAM Memory ControllerA DDR4-1600 controller that runs the JEDEC power-up sequence, schedules reads and writes across bank groups, and handles refresh without timing violations.RTL designAdvanced12-14 wks

Goal. Build a controller core that talks to a DDR4 memory model through a DFI-style PHY interface and obeys every JEDEC timing parameter. Show bandwidth and latency numbers for sequential and random traffic.

Specification

  • Target: one x16 DDR4-1600 device (tCK 1.25 ns, CL 11), 2 bank groups x 4 banks, BL8
  • Controller clock at 1:4 ratio to the DRAM clock (200 MHz), DFI-style command and data interface
  • Power-up: RESET_n low 200 us, CKE low 500 us, MRS to MR3, MR6, MR5, MR4, MR2, MR1, MR0, then ZQCL
  • Timing parameters as registers: tRCD, tRP, tRAS, tRC, tRRD_S/L, tCCD_S/L, tFAW, tWTR, tRTP, tWR, tRFC
  • Refresh every tREFI = 7.8 us with postponement of up to 8 refreshes when busy
  • Open-page policy with a reorder queue that prefers row hits and alternates bank groups

Steps

  1. Read the DDR4 JESD79-4 command truth table and timing chapter; build a spreadsheet of every parameter in clocks.
  2. Write the initialization FSM and check it against the memory model's power-up checks.
  3. Build per-bank state trackers with timers that block ACT, RD, WR and PRE until each constraint is met.
  4. Add the command scheduler: row-hit first, oldest first otherwise, bank-group interleave for tCCD_S.
  5. Add the refresh engine with tREFI counter, postponement and closing of all banks before REF.
  6. Run sequential, random and row-conflict traffic against a vendor DDR4 model and fix every timing violation.
  7. Measure bandwidth efficiency and average read latency for each traffic pattern.

Deliverables

  • Timing-parameter spreadsheet and controller architecture document
  • RTL for init FSM, bank machines, scheduler, refresh engine and host interface
  • Testbench with traffic generators and a self-checking data scoreboard
  • Bandwidth and latency plots for three traffic patterns

How you know it works

  • Zero timing violations reported by the memory model over e.g. 100,000 transactions
  • Sequential-read bandwidth efficiency, e.g. above 80% of peak
  • Random-access efficiency reported honestly, e.g. 30-40%
  • No missed refresh: every 8 x tREFI window contains at least the required REF commands

Tools

Open-source Verilator, cocotb, Python, GTKWave, LiteDRAM (as a reference design)

Industry Synopsys VCS, Cadence Xcelium, Siemens Questa, AMD Vivado (MIG for comparison)

Before you start

  • SDRAM basics: rows, banks, precharge, refresh
  • Complex FSM design
  • Reading a JEDEC datasheet
  • Self-checking testbenches

Go further

  • Add a write-to-read turnaround optimizer and measure the gain
  • Support two ranks
  • Add ECC with a SECDED code on a 72-bit bus

Watch out for

  • Mixing up tCCD_L and tCCD_S, so back-to-back commands to the same bank group violate timing.
  • Converting nanosecond parameters to clocks by rounding down instead of up.

Resume line Designed a DDR4-1600 controller with JEDEC initialization, bank-group-aware scheduling and refresh, reaching X% sequential bandwidth efficiency with zero timing violations.

Proves: RTL designFPGA

005Network-on-Chip Mesh RouterA five-port wormhole router with XY routing and credit-based flow control, tiled into a 4x4 mesh and measured under synthetic traffic.RTL designIntermediate6-8 wks

Goal. Build a router that moves packets between 16 nodes without deadlock or flit loss. Produce a latency-versus-injection-rate curve and find the saturation point.

Specification

  • Five ports: North, South, East, West and Local
  • 32-bit flits with a 2-bit type field (head, body, tail, single); packets of 1-8 flits
  • Dimension-order XY routing, which is deadlock-free on a mesh
  • Wormhole switching with a 4-flit input FIFO per port and credit-based flow control
  • Separable round-robin switch allocator; 2-cycle per-hop pipeline (route plus allocate, then traverse)
  • 4x4 mesh testbench with uniform-random, transpose and hotspot traffic

Steps

  1. Specify flit format, router pipeline and credit protocol on one page with a timing diagram.
  2. Build the input unit: FIFO, route computation from the head flit and output-port lock until the tail flit.
  3. Build the round-robin switch allocator and the 5x5 crossbar.
  4. Add credit counters per output and verify a single router with directed tests.
  5. Tile 16 routers into a 4x4 mesh with generate loops and add traffic injectors at each Local port.
  6. Run uniform-random traffic from low to high injection rate and log per-packet latency.
  7. Plot average latency versus injection rate and identify saturation throughput.

Deliverables

  • Router and mesh RTL with flit-format documentation
  • Traffic generators and a scoreboard that checks every packet arrives once and in order
  • Latency-versus-load plots for three traffic patterns
  • Synthesis area and Fmax for one router

How you know it works

  • Zero lost, duplicated or reordered flits over e.g. 1 million packets
  • Zero-load latency per hop, e.g. 2 cycles
  • Saturation throughput under uniform-random traffic, e.g. 0.3-0.4 flits/node/cycle
  • Router area, e.g. under 15k NAND2-equivalent gates

Tools

Open-source Verilator, cocotb, Python with Matplotlib, Yosys

Industry Synopsys VCS, Cadence Xcelium, Synopsys Design Compiler

Before you start

  • FIFOs and valid/ready handshakes
  • Arbiters
  • Generate loops
  • Basic Python plotting

Go further

  • Add two virtual channels per port
  • Implement west-first adaptive routing
  • Add a NoC interface that packs AXI4-Lite requests into packets

Watch out for

  • Releasing the output port on the head flit instead of the tail flit, which interleaves packets.
  • Counting credits off by one so a FIFO silently overflows under heavy load.

Resume line Built a 5-port wormhole NoC router and a 4x4 mesh with credit flow control, reaching X flits/node/cycle saturation throughput with zero packet loss.

Proves: RTL designArchitecture / AI hardware

006AES-256 Encryption and Decryption EngineAn iterative AES-256 core with on-the-fly key expansion that encrypts and decrypts 128-bit blocks and passes the FIPS-197 test vectors.RTL designIntermediate4-6 wks

Goal. Build an AES-256 core that processes one round per clock and matches FIPS-197 and NIST known-answer tests. Add ECB and CTR modes behind a register interface.

Specification

  • 128-bit block, 256-bit key, 14 rounds, 15 round keys (60 32-bit words)
  • One round per cycle: 14 cycles of compute plus load and output, about 16 cycles per block
  • Both directions: encryption and the inverse cipher with InvSubBytes, InvShiftRows, InvMixColumns
  • S-box as a 256-entry ROM or composite-field logic, selectable by parameter
  • ECB and CTR modes; AXI4-Lite or APB registers for key, IV, data and status
  • Throughput target e.g. 800 Mb/s at 100 MHz (128 bits / 16 cycles x 100 MHz)

Steps

  1. Write a Python reference of AES-256 and check it against the FIPS-197 Appendix C.3 vector.
  2. Build SubBytes, ShiftRows, MixColumns and AddRoundKey as separate tested modules.
  3. Build the key expansion, including the extra SubWord step when the word index mod 8 equals 4.
  4. Wrap the round in an iterative datapath with a round counter and a final round without MixColumns.
  5. Add the decryption path and verify encrypt-then-decrypt returns the plaintext.
  6. Add CTR mode and the register interface; test against NIST SP 800-38A CTR vectors.
  7. Synthesize both S-box styles and compare area and Fmax.

Deliverables

  • RTL for round functions, key schedule, controller and bus interface
  • Python golden model and a cocotb test with FIPS-197 and SP 800-38A vectors
  • Area and Fmax table for ROM versus composite-field S-boxes
  • README with a block diagram and cycle-by-cycle timing

How you know it works

  • All FIPS-197 and SP 800-38A AES-256 vectors pass
  • Latency, e.g. 16 cycles per block
  • Throughput, e.g. at least 800 Mb/s at 100 MHz
  • Random round-trip test: e.g. 100,000 random keys and blocks decrypt correctly

Tools

Open-source Icarus Verilog, Verilator, cocotb, Python (pycryptodome for reference), Yosys

Industry Synopsys VCS, Cadence Xcelium, AMD Vivado, Cadence Genus

Before you start

  • Verilog modules and FSMs
  • Basic finite-field (GF(2^8)) arithmetic
  • Python scripting

Go further

  • Fully unrolled pipeline at one block per cycle
  • Add GCM mode with a GHASH multiplier
  • Add first-order masking against power analysis

Watch out for

  • Copying the AES-128 key schedule and missing the extra SubWord step that AES-256 needs.
  • Applying MixColumns in the final round.

Resume line Designed an iterative AES-256 core with ECB and CTR modes that passed all FIPS-197 and NIST SP 800-38A vectors at X Mb/s and Y MHz.

Proves: RTL designFPGA

007SHA3-256 (Keccak) Hash AcceleratorA Keccak-f[1600] permutation core with sponge padding that computes SHA3-256 digests for messages of any length.RTL designIntermediate4-6 wks

Goal. Build a SHA3-256 engine that absorbs a byte stream, applies FIPS 202 padding and outputs a 256-bit digest. Match NIST test vectors including the empty message.

Specification

  • Keccak-f[1600]: 5x5 lanes of 64 bits, 24 rounds of theta, rho, pi, chi and iota
  • SHA3-256 sponge: rate 1088 bits (136 bytes), capacity 512 bits, 256-bit output
  • FIPS 202 padding: domain bits 0x06, then zeros, then 0x80 in the last byte of the block
  • One round per cycle, so 24 cycles per 136-byte block
  • 64-bit input stream with valid, ready and last-byte-count signals
  • Throughput target e.g. 4.5 Gb/s at 100 MHz (1088 bits / 24 cycles)

Steps

  1. Write a Python Keccak model and match hashlib.sha3_256 for several messages.
  2. Build theta, rho, pi, chi and iota as combinational blocks and test each against the Python model.
  3. Wrap them in an iterative round with a round counter and a 24-entry round-constant table.
  4. Build the absorb logic that XORs 17 input lanes into the state.
  5. Add padding for messages that end mid-block and for messages that fill a block exactly.
  6. Test with NIST vectors and random lengths from 0 to e.g. 1,000 bytes.
  7. Synthesize and report area, Fmax and throughput per unit area.

Deliverables

  • Keccak and sponge RTL with a datapath diagram
  • Python golden model and cocotb tests with NIST vectors
  • Edge-case table: empty message, 135, 136 and 137 bytes
  • Synthesis report and throughput calculation

How you know it works

  • Matches hashlib.sha3_256 on e.g. 10,000 random-length messages
  • Correct digest for the empty message (a7ffc6f8...)
  • Throughput, e.g. above 4 Gb/s at 100 MHz
  • Cycles per block, e.g. 24 plus at most 2 overhead

Tools

Open-source Verilator, cocotb, Python hashlib, Yosys, GTKWave

Industry Synopsys VCS, Cadence Xcelium, AMD Vivado, Synopsys Design Compiler

Before you start

  • Bitwise operations and rotations
  • Verilog arrays
  • Python scripting

Go further

  • Support SHA3-224/384/512 and SHAKE128/256 by parameter
  • Unroll two rounds per cycle and compare area-time product
  • Add an AXI4-Stream wrapper and DMA

Watch out for

  • Getting the lane bit order wrong, since Keccak is little-endian within each 64-bit lane.
  • Using the old Keccak padding (0x01) instead of the SHA-3 domain byte 0x06.

Resume line Implemented a SHA3-256 Keccak-f[1600] accelerator with FIPS 202 padding that matched NIST vectors and reached X Gb/s at Y MHz.

Proves: RTL designFPGA

008Baseline JPEG Encoder PipelineA streaming grayscale JPEG encoder with 2-D DCT, quantization, zigzag, run-length and Huffman coding, producing files any image viewer opens.RTL designAdvanced10-12 wks

Goal. Build a baseline JPEG (ITU-T T.81) encoder that compresses a 640x480 grayscale image in real time. The output file must open in a standard viewer and match a software encoder's quality.

Specification

  • Input: 8-bit grayscale pixels in 8x8 block order, one pixel per clock
  • Separable 2-D DCT: row 1-D DCT, transpose buffer, column 1-D DCT, fixed-point coefficients
  • Quantization with the standard luminance table scaled by a quality factor, using reciprocal multipliers
  • Zigzag reorder, DC difference coding, AC run-length with ZRL (16 zeros) and EOB
  • Huffman coding with the standard Annex K tables, bit packer with 0xFF00 byte stuffing
  • Throughput target: 640x480 at 30 frames/s, which needs about 9.2 Mpixel/s

Steps

  1. Write a Python encoder that mirrors your fixed-point choices and produces a valid .jpg file.
  2. Build the 1-D DCT, the transpose buffer and the 2-D DCT; compare coefficients against the Python model.
  3. Add quantization and the zigzag reorder buffer.
  4. Build the run-length coder and the Huffman encoder with DC and AC tables in ROM.
  5. Build the bit packer with byte stuffing; add JFIF headers in the testbench or in RTL.
  6. Encode several test images, open them in a viewer and compute PSNR against the original.
  7. Synthesize and check the throughput target is met with margin.

Deliverables

  • RTL for DCT, quantizer, zigzag, entropy coder and bit packer
  • Python reference encoder and bit-exact stage-by-stage comparison scripts
  • Encoded test images with PSNR and compression ratio table
  • Pipeline diagram with per-stage latency

How you know it works

  • Output files decode in a standard viewer with no errors
  • PSNR at quality 75, e.g. above 35 dB on standard test images
  • Bit-exact entropy-coded stream versus the Python model
  • Sustained throughput, e.g. 1 pixel/clock at 50 MHz

Tools

Open-source Verilator, cocotb, Python with NumPy and Pillow, Yosys, GTKWave

Industry Synopsys VCS, AMD Vivado, Cadence Genus

Before you start

  • Fixed-point arithmetic
  • Pipelined datapaths
  • Basic signal processing (DCT)
  • Python with NumPy

Go further

  • Add YCbCr 4:2:0 color with chroma tables
  • Run on an FPGA with a camera input
  • Add restart markers

Watch out for

  • Forgetting to insert 0x00 after every 0xFF byte in the entropy-coded data.
  • Mishandling runs of more than 15 zeros, which need ZRL symbols.

Resume line Designed a streaming baseline JPEG encoder with 2-D DCT and Huffman coding, producing viewer-compatible files at X dB PSNR and Y frames/s for 640x480.

Proves: RTL designFPGA

009IEEE 754 Single-Precision Floating-Point UnitA single-precision FPU for add, subtract, multiply and divide with all four rounding modes, subnormals and the five IEEE exception flags.RTL designAdvanced8-10 wks

Goal. Build an FPU that gives bit-exact results against Berkeley SoftFloat for every operation and rounding mode. Report latency and Fmax for each operation.

Specification

  • Format: binary32, 1 sign, 8 exponent (bias 127), 23 fraction bits
  • Operations: FADD, FSUB, FMUL (pipelined, 3-4 stages), FDIV (iterative radix-2 or radix-4)
  • Rounding: round-to-nearest-even, toward zero, toward +infinity, toward -infinity
  • Flags: invalid, divide-by-zero, overflow, underflow, inexact
  • Full subnormal input and output support; canonical quiet NaN output
  • Guard, round and sticky bits for every rounding step

Steps

  1. Write a table of special cases: zeros, infinities, NaNs, subnormals and their expected results and flags.
  2. Build the unpack and classify stage shared by all operations.
  3. Build the adder: exponent compare, alignment shift with sticky, add, leading-zero count, normalize, round.
  4. Build the multiplier with a 24x24 mantissa product and the same normalize-round stage.
  5. Build the divider as an iterative restoring or SRT unit and handle divide-by-zero.
  6. Generate test vectors with Berkeley TestFloat for each operation and rounding mode, and compare bit-exactly.
  7. Synthesize and report latency, Fmax and area per operation.

Deliverables

  • RTL for unpack, adder, multiplier, divider and shared rounding
  • Special-case table and test plan
  • TestFloat regression logs for all operations and rounding modes
  • Latency, area and Fmax table

How you know it works

  • Zero mismatches against TestFloat on e.g. 1 million vectors per operation and rounding mode
  • All five exception flags match the reference
  • FMUL throughput, e.g. one result per cycle
  • FDIV latency, e.g. under 30 cycles

Tools

Open-source Verilator, Berkeley TestFloat and SoftFloat, Yosys, GTKWave, Python

Industry Synopsys VCS, Cadence Xcelium, Synopsys Design Compiler, Cadence JasperGold

Before you start

  • Binary arithmetic and shifters
  • Pipelining
  • IEEE 754 format basics
  • C or Python for test harnesses

Go further

  • Add fused multiply-add with a single rounding
  • Add square root
  • Plug the FPU into the RISC-V core as the F extension

Watch out for

  • Dropping the sticky bit during alignment, which breaks round-to-nearest-even on ties.
  • Treating subnormal inputs as zero without saying so.

Resume line Designed an IEEE 754 single-precision FPU with all rounding modes and subnormals that matched Berkeley TestFloat on X million vectors at Y MHz.

Proves: RTL designArchitecture / AI hardware

010Hardware RTOS Task SchedulerA memory-mapped peripheral that picks the highest-priority ready task in constant time and interrupts the CPU to preempt, offloading an RTOS kernel.RTL designIntermediate5-7 wks

Goal. Build a scheduler that tracks 32 tasks, picks the next task in a fixed number of cycles, and raises a preemption interrupt. Show how many CPU cycles it saves compared with a software scheduler.

Specification

  • 32 tasks, 8 priority levels, round-robin among tasks of equal priority
  • Per-task state: ready, blocked or delayed, with a 16-bit delay counter decremented on each tick
  • O(1) selection with a priority bitmap and leading-zero count, e.g. result in 2 cycles
  • APB slave register map: task control, current task, next task, tick period, IRQ status
  • Preemption IRQ when a higher-priority task becomes ready than the running one
  • Configurable tick from a prescaled system clock, e.g. 1 ms at 50 MHz

Steps

  1. Write the register map and a timeline showing tick, wake-up, IRQ and context switch.
  2. Build the task table and the per-task delay counters.
  3. Build the priority bitmap, leading-zero count and per-level round-robin pointer.
  4. Add the APB slave and the IRQ logic with clear-on-write status.
  5. Write directed tests for preemption, equal-priority rotation and many tasks waking on one tick.
  6. Write a C driver and run a small multi-task demo on a RISC-V core in simulation.
  7. Count CPU cycles per context switch with and without the hardware scheduler.

Deliverables

  • Register map document and timing diagrams
  • Scheduler RTL with APB interface
  • Testbench with a software reference scheduler model
  • C driver, demo program and cycle-count comparison

How you know it works

  • Next-task selection latency, e.g. 2 cycles regardless of task count
  • Matches the software reference model on e.g. 100,000 random wake/block events
  • Context-switch decision cycles saved, e.g. X% versus a software list scan
  • Area, e.g. under 5k NAND2-equivalent gates

Tools

Open-source Verilator, Icarus Verilog, cocotb, riscv-gnu-toolchain, Yosys

Industry Synopsys VCS, Cadence Xcelium, Synopsys Design Compiler

Before you start

  • Priority encoders and arbiters
  • APB protocol
  • Basic RTOS concepts
  • C programming

Go further

  • Add earliest-deadline-first mode
  • Add priority inheritance for one mutex
  • Add hardware semaphores

Watch out for

  • Not defining what happens when software writes a task's state on the same cycle as a tick.
  • Letting the round-robin pointer skip tasks when one becomes blocked.

Resume line Built a 32-task hardware RTOS scheduler with O(1) priority selection and preemption IRQ, cutting scheduling overhead by X% in a RISC-V demo.

Proves: RTL designEmbedded

011UVM Verification of a RISC-V CPUA UVM environment that runs random and directed programs on an RV32I core and compares every retired instruction against the Spike reference model.VerificationAdvanced10-12 wks

Goal. Build a layered testbench that finds real bugs in a RISC-V core through instruction-level comparison and functional coverage. Close coverage on opcodes, hazards and traps.

Specification

  • DUT: your own RV32I core or an open-source one exposing a retirement trace (e.g. RVFI signals)
  • Agents: instruction memory, data memory and interrupt agents; a retirement monitor
  • Scoreboard: compares PC, instruction, rd and value per retired instruction against a Spike trace
  • Stimulus: riscv-tests, riscv-dv generated programs and directed hazard sequences
  • Coverage: every opcode, every rs1/rs2/rd forwarding pair, branch taken/not-taken, every mcause
  • Regression with seeds, pass/fail summary and failure triage log

Steps

  1. Write a verification plan mapping each feature to tests, checkers and coverpoints.
  2. Build the memory agents that load an ELF image and serve fetch and load/store requests.
  3. Build the retirement monitor and the Spike-trace scoreboard.
  4. Run riscv-tests first, then riscv-dv random programs, and triage each mismatch to RTL or testbench.
  5. Add an interrupt agent and sequences that fire interrupts during stalls, branches and loads.
  6. Write covergroups for opcodes, hazards and traps; add directed tests for holes.
  7. Automate a nightly-style regression with seeds and a coverage merge.

Deliverables

  • Verification plan with feature-to-coverpoint mapping
  • UVM environment source: agents, sequences, scoreboard, coverage
  • Regression scripts and a summary report
  • Bug log with root cause for each bug found

How you know it works

  • Functional coverage, e.g. above 95% with holes explained
  • Zero mismatches against Spike on e.g. 500 random programs
  • Bugs found and fixed, reported with root cause, e.g. X bugs
  • Regression wall time, e.g. under 30 minutes for 200 seeds

Tools

Open-source cocotb with pyuvm, Verilator, Spike ISS, riscv-dv (pygen mode; its SystemVerilog generator needs a commercial simulator), riscv-gnu-toolchain

Industry Synopsys VCS, Cadence Xcelium, Siemens Questa

Before you start

  • SystemVerilog OOP and UVM basics
  • RISC-V ISA
  • Functional coverage
  • Python or Perl scripting

Go further

  • Add formal checks with riscv-formal on the same core
  • Add a trap-heavy random generator mode
  • Verify the M extension

Watch out for

  • Comparing only register files at the end of a test, which hides when and where the bug happened.
  • Treating a testbench bug as a DUT bug and patching the RTL.

Resume line Built a UVM environment for an RV32I core with a Spike trace scoreboard, reaching X% functional coverage and finding Y RTL bugs.

Proves: Verification

012AXI4 Verification IP (Master, Slave and Monitor)A reusable AXI4 VIP with master and slave agents, a protocol checker and coverage, usable in any UVM testbench.VerificationIntermediate8-10 wks

Goal. Build an AXI4 VIP that generates legal bursts, models a slave memory with out-of-order responses, and flags protocol violations. Demonstrate it on an AXI interconnect or memory DUT.

Specification

  • Five channels: AW, W, B, AR, R with VALID/READY handshakes
  • Burst types FIXED, INCR (1-256 beats) and WRAP (2, 4, 8 or 16 beats); sizes 1-128 bytes
  • Rule: an INCR burst must not cross a 4 KB address boundary
  • Multiple outstanding transactions with AXI IDs; out-of-order responses across different IDs
  • Configurable data width (32, 64, 128 bits), random READY back-pressure
  • Protocol assertions: VALID held until READY, payload stable while VALID and not READY, WLAST on the right beat

Steps

  1. Read the Arm AXI4 specification and list every rule you will check as an assertion or scoreboard check.
  2. Build the transaction class with constraints for burst type, length, size and 4 KB boundary.
  3. Build the master driver with independent channel threads and a configurable outstanding limit.
  4. Build the slave agent with a memory model and per-ID response reordering.
  5. Build the passive monitor and an interface with SVA protocol checks.
  6. Add covergroups for burst type x length x size, IDs and back-pressure.
  7. Test the VIP back to back, then on an AXI memory or interconnect DUT.

Deliverables

  • VIP package with agents, sequences, config object and assertions
  • User guide: how to instantiate, configure and extend it
  • Example testbench and regression results
  • Coverage report

How you know it works

  • Assertion checks catch e.g. 10 deliberately injected protocol errors
  • Burst type x length x size cross coverage, e.g. above 90%
  • Zero data mismatches over e.g. 100,000 random transactions
  • VIP reused unchanged on a second DUT

Tools

Open-source cocotb with pyuvm, cocotbext-axi (as a reference), Verilator, SymbiYosys for simple assertions (open Yosys supports only an SVA subset)

Industry Synopsys VCS, Cadence Xcelium, Siemens Questa

Before you start

  • SystemVerilog classes and constraints
  • UVM agent structure
  • AXI4-Lite basics
  • SVA basics

Go further

  • Add AXI4-Stream and AXI4-Lite modes
  • Add exclusive access checks
  • Add a performance monitor for latency and bandwidth

Watch out for

  • Driving channels in one sequential thread, which hides deadlocks and back-pressure bugs.
  • Computing WRAP burst addresses with the INCR formula.

Resume line Developed a reusable AXI4 verification IP with master, slave and protocol assertions, reaching X% burst coverage and reused across Y testbenches.

Proves: Verification

013PCIe Transaction and Data Link Layer VerificationA UVM testbench for the PCIe TLP and DLLP layers that checks packet formats, ACK/NAK replay and flow-control credits.VerificationAdvanced10-12 wks

Goal. Verify a PCIe endpoint's transaction and data link layers above the PHY: TLP encoding, completions, replay on NAK and credit-based flow control. The physical layer is modeled, not verified.

Specification

  • TLP types: memory read, memory write, completion with data, completion without data
  • 3DW and 4DW headers, Max Payload Size e.g. 256 bytes, Max Read Request split into completions
  • Tags for outstanding non-posted requests and a completion timeout check
  • Data link layer: 12-bit sequence numbers, 32-bit LCRC, ACK/NAK DLLPs and replay buffer
  • Flow-control credits for posted, non-posted and completion headers and data
  • Error injection: bad LCRC, wrong sequence number, malformed TLP, unexpected completion

Steps

  1. Scope the DUT: a simple endpoint TLP/DLL layer you write, or an open-source one, with a PIPE-like interface.
  2. Write the verification plan from your PCIe reference text, layer by layer.
  3. Build the TLP transaction class with constraints and pack/unpack functions.
  4. Build a link-partner agent that sends TLPs, ACKs, NAKs and UpdateFC DLLPs.
  5. Build scoreboards for request-completion matching and for replay-buffer behavior.
  6. Add error-injection sequences and check the DUT replays or reports correctly.
  7. Close coverage on TLP types, sizes, credit exhaustion and replay events.

Deliverables

  • Verification plan by layer
  • UVM environment with TLP, DLLP and flow-control components
  • Error-injection test list and results
  • Coverage report with explained holes

How you know it works

  • Every injected LCRC error triggers a NAK and correct replay
  • Zero completion mismatches over e.g. 50,000 requests
  • Coverage of credit-exhausted stalls for all three credit types
  • Functional coverage, e.g. above 90%

Tools

Open-source cocotb with pyuvm, Verilator, Python

Industry Synopsys VCS, Cadence Xcelium, Siemens Questa

Before you start

  • UVM agents and scoreboards
  • CRC computation
  • Layered protocol concepts
  • A completed AXI or Ethernet DV project

Go further

  • Add a configuration-space read/write path
  • Model LTSSM states at a high level
  • Add a performance test for credit-limited bandwidth

Watch out for

  • Trying to verify the full PHY and LTSSM in a student project; scope to TL and DLL.
  • Forgetting that sequence numbers wrap at 4096.

Resume line Verified a PCIe endpoint's transaction and data link layers in UVM, covering ACK/NAK replay and flow-control credits, and found X bugs at Y% coverage.

Proves: Verification

014DDR4 Controller Verification with Timing CheckersA testbench that proves a DDR4 controller never violates JEDEC timing and never corrupts data, using assertions and a memory scoreboard.VerificationAdvanced8-10 wks

Goal. Verify a DDR4 controller at its DFI-style interface with a timing-checker monitor, a data scoreboard and traffic that stresses refresh and bank conflicts.

Specification

  • DUT: the controller from project 4 or an open-source one such as LiteDRAM
  • Timing monitor checks tRCD, tRP, tRAS, tRC, tRRD_S/L, tCCD_S/L, tFAW, tWTR, tRTP, tWR, tRFC
  • Refresh checker: no more than 8 postponed refreshes, all banks precharged before REF
  • Initialization checker for RESET_n, CKE timing and the MRS order
  • Data scoreboard with a reference memory and byte-mask support
  • Traffic: sequential, random, same-bank row conflicts, read-write turnaround storms

Steps

  1. Extract every timing rule from JESD79-4 into a table with the clock value for your speed bin.
  2. Write one SVA property or monitor check per rule, plus per-bank state tracking.
  3. Build host-side sequences for each traffic pattern with constrained-random addresses.
  4. Build the data scoreboard and handle write-read ordering to the same address.
  5. Add a refresh-stress test that keeps the controller busy across many tREFI windows.
  6. Inject bugs into the DUT (shortened tRCD, skipped precharge) to prove each checker fires.
  7. Collect coverage on commands per bank state and timing-boundary hits.

Deliverables

  • Timing-rule table and checker source
  • Testbench with traffic sequences and data scoreboard
  • Bug-injection results showing each checker firing
  • Coverage and regression report

How you know it works

  • Every injected timing bug detected, e.g. 10 of 10
  • Zero data errors over e.g. 1 million operations
  • Coverage of commands issued exactly at the minimum timing boundary, e.g. for every rule
  • Refresh-stress run of e.g. 10,000 tREFI windows with no violation

Tools

Open-source Verilator, cocotb, SymbiYosys, Python

Industry Synopsys VCS, Cadence Xcelium, Siemens Questa, Synopsys VC Formal

Before you start

  • SDRAM timing basics
  • SVA
  • Scoreboards and reference models
  • Reading a JEDEC datasheet

Go further

  • Prove the timing properties formally on the bank FSM
  • Add ECC error injection
  • Measure and report bandwidth from the monitor

Watch out for

  • Checking tFAW per bank instead of across any four ACTs in a rolling window.
  • Relying only on the memory model's warnings instead of your own independent checkers.

Resume line Verified a DDR4 controller with X JEDEC timing checkers and a data scoreboard, detecting all injected timing bugs over Y million operations.

Proves: Verification

015Ethernet MAC Verification in UVMA UVM environment for a 1 Gb/s Ethernet MAC that checks framing, CRC-32, padding, pause frames and error handling.VerificationIntermediate6-8 wks

Goal. Verify the transmit and receive paths of an Ethernet MAC between GMII and AXI4-Stream. Close coverage on frame sizes and error cases.

Specification

  • DUT: an open-source 1G MAC (e.g. the verilog-ethernet project) or your own
  • Frame: 7-byte preamble 0x55, SFD 0xD5, 64-1518 bytes (1522 with VLAN tag), CRC-32 FCS
  • Transmit pads frames shorter than 64 bytes; inter-frame gap at least 12 byte times
  • Receive drops or flags bad FCS, runts and oversize frames
  • IEEE 802.3x pause frames: destination 01-80-C2-00-00-01, EtherType 0x8808, opcode 0x0001
  • GMII agent on the line side, AXI4-Stream agent on the user side

Steps

  1. Write the verification plan: features, checks and coverpoints for TX and RX.
  2. Build a frame transaction class with fields, constraints and a CRC-32 function.
  3. Build GMII and AXI4-Stream agents with drivers and monitors.
  4. Build a scoreboard that predicts the line-side frame from the user-side frame and the reverse.
  5. Add error sequences: bad FCS, runt, oversize, missing SFD and mid-frame errors.
  6. Add pause-frame tests and check that the transmitter stops for the requested quanta.
  7. Close coverage on lengths, VLAN tags, errors and back-to-back frames at minimum IFG.

Deliverables

  • Verification plan
  • UVM environment with GMII and AXI4-Stream agents and scoreboard
  • Regression report and coverage report
  • List of bugs or spec deviations found

How you know it works

  • Frame-length coverage bins from 64 to 1522 bytes, e.g. 100% hit
  • All error types detected by the DUT or flagged by the testbench
  • Zero scoreboard mismatches over e.g. 100,000 frames
  • Measured IFG never below 12 byte times

Tools

Open-source cocotb, cocotbext-eth, Verilator, Icarus Verilog, Python

Industry Synopsys VCS, Cadence Xcelium, Siemens Questa

Before you start

  • UVM agents and scoreboards
  • CRC-32 basics
  • Ethernet frame format
  • SystemVerilog constraints

Go further

  • Add RGMII with DDR timing
  • Verify a 10G MAC with XGMII
  • Add IEEE 1588 timestamp checks

Watch out for

  • Computing CRC-32 with the wrong bit order or without the final inversion.
  • Testing only nominal frames and never back-to-back frames at minimum IFG.

Resume line Verified a 1G Ethernet MAC in UVM with GMII and AXI-Stream agents, reaching X% coverage and finding Y bugs in error handling.

Proves: Verification

016USB 2.0 Full-Speed Device Controller VerificationA testbench that acts as a USB host and verifies a full-speed device controller through packet encoding, control transfers and enumeration.VerificationAdvanced8-10 wks

Goal. Verify a USB 2.0 full-speed (12 Mb/s) device controller from the bit level up to enumeration. Scoped to 2.0 FS because a USB 3.x SuperSpeed PHY is beyond a student project.

Specification

  • Line coding: NRZI with a bit stuffed after six consecutive 1s, SYNC field and EOP
  • Packets: PID with check nibble, CRC5 on tokens, CRC16 on data packets
  • Transactions: SETUP, IN, OUT with ACK, NAK and STALL handshakes
  • DATA0/DATA1 toggle tracking and retry on lost handshakes
  • Control transfers on endpoint 0: GET_DESCRIPTOR, SET_ADDRESS, SET_CONFIGURATION
  • One bulk IN and one bulk OUT endpoint with 64-byte max packet size

Steps

  1. Write the verification plan from USB 2.0 specification chapters 8 (protocol) and 9 (device framework) and the device's descriptors.
  2. Build a host bus-functional model that encodes and decodes NRZI, bit stuffing and CRCs.
  3. Build packet and transaction classes with constraints and error knobs.
  4. Write the enumeration sequence and check each descriptor against expected values.
  5. Add bulk transfer tests with NAK back-pressure, short packets and zero-length packets.
  6. Inject CRC errors, bit-stuff errors and dropped handshakes; check toggle and retry behavior.
  7. Close coverage on PIDs, endpoints, handshakes and error types.

Deliverables

  • Verification plan
  • Host BFM with NRZI, bit stuffing and CRC encode/decode
  • Enumeration and bulk-transfer test suite
  • Coverage report and bug log

How you know it works

  • Device enumerates successfully in e.g. 100% of seeds
  • Every injected CRC or stuffing error rejected by the DUT
  • Zero data errors on bulk transfers over e.g. 10 MB of payload
  • Coverage of PID x handshake x endpoint, e.g. above 90%

Tools

Open-source cocotb, Verilator, Icarus Verilog, Python

Industry Synopsys VCS, Cadence Xcelium, Siemens Questa

Before you start

  • UVM or cocotb testbench structure
  • CRC and line coding
  • Packet-based protocols

Go further

  • Add interrupt and isochronous endpoints
  • Add suspend and resume
  • Prototype the DUT on an FPGA and enumerate on a real PC

Watch out for

  • Forgetting to stuff a bit after six 1s inside the CRC field.
  • Not checking DATA0/DATA1 toggle after a lost ACK.

Resume line Built a USB 2.0 full-speed host BFM and testbench that verified device enumeration and bulk transfers, reaching X% coverage and finding Y bugs.

Proves: Verification

017Functional Coverage Regression DashboardA Python tool that merges coverage from many regression runs and shows trends, holes and pass rates in a static HTML dashboard.VerificationIntermediate4-6 wks

Goal. Build a dashboard that reads per-test coverage and results, merges them, and shows which coverpoints are still unhit and which tests add new coverage.

Specification

  • Inputs: cocotb-coverage YAML/XML exports or Verilator coverage .dat files, plus a pass/fail log per seed
  • Merge coverage across seeds and runs by covergroup, coverpoint and bin
  • Views: overall trend over runs, per-covergroup bars, hole list, per-test contribution
  • Test ranking: the smallest set of seeds that reaches the same coverage
  • Output: a static HTML page with no server, regenerated by one command
  • Runs under e.g. 30 seconds for 500 tests

Steps

  1. Run an existing testbench (e.g. a FIFO or UART) with 100+ seeds and save coverage per seed.
  2. Write a parser for the coverage format into a common Python data model.
  3. Write the merge logic and unit-test it on small hand-made inputs.
  4. Add greedy test ranking that keeps the seeds adding new bins.
  5. Generate the HTML page with charts and a sortable hole table.
  6. Store a summary per run so the trend view grows across regressions.
  7. Use the hole list to write two directed tests and show coverage going up.

Deliverables

  • Python package with parser, merger, ranker and HTML generator
  • Example dashboard generated from a real regression
  • Unit tests for merge and ranking
  • README with input formats and usage

How you know it works

  • Merged totals match the simulator's own merge on e.g. 3 sample runs
  • Ranked seed set reaches the same coverage with e.g. under 30% of seeds
  • Dashboard generation time, e.g. under 30 seconds for 500 tests
  • Two coverage holes closed using the dashboard

Tools

Open-source Python, cocotb-coverage, Verilator (verilator_coverage), pandas, Plotly or Matplotlib

Industry Synopsys VCS with URG, Cadence Xcelium with IMC, Siemens Questa (vcover)

Before you start

  • Python scripting
  • Functional coverage concepts
  • A working testbench with covergroups

Go further

  • Read Accellera UCIS XML exports
  • Add a failure-signature clustering view
  • Run it in a CI pipeline on every commit

Watch out for

  • Merging by bin name only, so bins with the same name in different covergroups collide.
  • Showing coverage percentage without the hole list, which is what engineers actually need.

Resume line Built a Python coverage dashboard that merged X regression seeds, ranked tests and cut the regression set by Y% at equal coverage.

Proves: Verification

018SVA Assertion Library for APB, AXI4-Lite and FIFOsA reusable, parameterized SystemVerilog Assertions library that you bind to any design to check common protocols and structures.VerificationIntermediate4-6 wks

Goal. Write checker modules for APB, AXI4-Lite handshakes, FIFOs, one-hot and Gray-code signals, each with cover properties. Prove they catch bugs by running them in simulation and formal.

Specification

  • APB: PENABLE rises one cycle after PSEL, address and control stable through the access phase until PREADY
  • AXI4-Lite: VALID held until READY, payload stable while waiting, one response per request
  • FIFO: no push when full, no pop when empty, occupancy count matches pushes minus pops
  • Generic: one-hot, one-hot-or-zero, Gray-code single-bit change, no X on outputs after reset
  • Each checker parameterized for width and attached with the bind statement
  • Every assert property paired with a cover property

Steps

  1. List each rule in plain English with a waveform sketch before writing any property.
  2. Write the generic checkers and test them on tiny passing and failing designs.
  3. Write the APB checker and bind it to an APB slave; run directed tests.
  4. Write the AXI4-Lite and FIFO checkers and bind them to existing designs.
  5. Inject one bug per rule and confirm the right assertion fires with a useful message.
  6. Run SymbiYosys on the FIFO and APB slave with the checkers as properties.
  7. Write a short user guide with bind examples.

Deliverables

  • Checker library source with parameters and bind examples
  • Pass and fail demo designs for each checker
  • Bug-injection table showing which assertion caught each bug
  • Formal run logs for at least two designs

How you know it works

  • Every injected bug caught, e.g. 15 of 15
  • Every cover property reached in simulation or formal
  • Formal proof or bounded check depth, e.g. 30 cycles on the FIFO
  • Zero false failures on known-good designs

Tools

Open-source SymbiYosys (SVA subset supported by Yosys), Verilator, Icarus Verilog

Industry Cadence JasperGold, Synopsys VC Formal, Siemens Questa, Synopsys VCS

Before you start

  • SystemVerilog basics
  • APB and valid/ready handshakes
  • Sequential timing diagrams

Go further

  • Add AXI4 burst checks
  • Add a CDC handshake checker
  • Package it for FuseSoC

Watch out for

  • Writing properties that pass vacuously because the antecedent never fires; use cover properties.
  • Ignoring reset with disable iff, causing false failures during reset.

Resume line Wrote a reusable SVA library of X checkers for APB, AXI4-Lite and FIFOs that caught all Y injected bugs in simulation and formal.

Proves: VerificationRTL design

019Formal Verification of a Set-Associative CacheUse model checking to prove a write-back cache always returns the most recently written data and never deadlocks.VerificationAdvanced6-8 wks

Goal. Formally prove data integrity and forward progress for a 2-way set-associative write-back cache using a symbolic-address abstraction. Find bugs that random simulation missed.

Specification

  • DUT: 1 KB, 2-way set-associative, 16-byte lines, write-back, LRU, valid/ready CPU and memory ports
  • Data-integrity property: a read of the tracked symbolic address returns the last value written to it
  • Shadow model tracks one symbolic address and its value instead of the whole memory
  • Liveness proxy: every request completes within N cycles when memory responds within M cycles
  • Environment assumptions on memory latency and request legality written as assume properties
  • Full proof with k-induction where possible; bounded proof depth reported otherwise

Steps

  1. Write the cache, or reuse one, and reduce it to a small formal-friendly size by parameter.
  2. Write assumptions for the CPU and memory interfaces.
  3. Add the symbolic address and shadow value; write the data-integrity assertion.
  4. Run bounded model checking with SymbiYosys and debug counterexample traces in GTKWave.
  5. Add helper invariants (tag-valid consistency, dirty-bit rules) until k-induction passes.
  6. Add the bounded-response property and cover properties for evictions and dirty writebacks.
  7. Inject known bugs (missed dirty bit, wrong LRU update) and record time to counterexample.

Deliverables

  • Formal testbench with assumptions, assertions, covers and helper invariants
  • SymbiYosys .sby files and run scripts
  • Counterexample traces for each bug found
  • Report explaining the symbolic-address technique

How you know it works

  • Data-integrity property proven with k-induction, or bounded to e.g. 40 cycles
  • All cover properties reachable, including dirty eviction
  • Each injected bug found within e.g. 20 cycles of trace
  • Proof runtime, e.g. under 10 minutes

Tools

Open-source SymbiYosys, Yosys, Boolector or Bitwuzla solver, GTKWave

Industry Cadence JasperGold, Synopsys VC Formal, Siemens Questa

Before you start

  • Cache design basics
  • SVA assert, assume and cover
  • Reading waveform counterexamples

Go further

  • Prove the same properties on the MESI system from project 3
  • Add a formal equivalence check between two LRU implementations
  • Track two symbolic addresses to check aliasing

Watch out for

  • Over-constraining assumptions so the proof passes on an empty set of behaviors; check covers.
  • Running the full-size cache, which makes the proof blow up.

Resume line Formally proved data integrity of a 2-way write-back cache using a symbolic-address model in SymbiYosys and found X bugs missed by simulation.

Proves: Verification

020Portable Stimulus (PSS) Scenario Generator for a Small SoCModel SoC-level test intent once with Accellera PSS concepts and generate C tests that exercise DMA, UART and memory in many combinations.VerificationAdvanced8-10 wks

Goal. Describe actions, resources and data flows for a small RISC-V SoC and automatically generate bare-metal C tests that cover legal scenario combinations. Run them in simulation.

Specification

  • Target SoC: RISC-V core, SRAM, one DMA channel, UART and timer on a simple bus
  • Actions: dma_copy, uart_tx, uart_rx_loopback, timer_wait, mem_check
  • Resources: one DMA channel and one UART, so the generator must serialize their use
  • Data-flow objects: a buffer produced by one action and consumed by the next
  • Generator output: self-checking bare-metal C tests with a pass/fail signature in memory
  • Scenario coverage: action pairs, buffer sizes and resource conflicts

Steps

  1. Read the Accellera PSS standard overview and write your scenarios as an activity graph on paper.
  2. Model actions, resources and buffers in PyVSC or a PSS tool, with constraints on sizes and addresses.
  3. Write C templates for each action using the SoC register map.
  4. Generate 50+ tests by solving the scenario model and filling the templates.
  5. Compile with the RISC-V GCC toolchain and run each test on the SoC in Verilator.
  6. Collect scenario coverage and generate more tests to fill gaps.
  7. Retarget the same model to a UVM-sequence or Python output to show portability.

Deliverables

  • Scenario model source with constraints
  • Generator script and C templates
  • Generated test suite with pass/fail results
  • Report comparing scenario coverage with a hand-written test set

How you know it works

  • Generated tests all compile and self-check, e.g. 50 of 50
  • Scenario-pair coverage, e.g. 100% of legal action pairs
  • Bugs found that hand-written tests missed, e.g. X
  • Same model produces a second output format without changes

Tools

Open-source PyVSC, Python, Verilator, riscv-gnu-toolchain

Industry Cadence Perspec System Verifier, Siemens Questa inFact, Synopsys VCS

Before you start

  • Constrained-random verification
  • Bare-metal C on RISC-V
  • SoC bus and register maps
  • Python

Go further

  • Add multi-core scenarios with shared buffers
  • Add power-state actions
  • Run generated tests on an FPGA prototype

Watch out for

  • Modeling individual register writes instead of high-level actions, which defeats the purpose.
  • Ignoring resource locks, so generated tests use the DMA twice at once.

Resume line Built a portable-stimulus scenario generator that produced X self-checking C tests for a RISC-V SoC and found Y bugs missed by directed tests.

Proves: VerificationEmbedded

021RTL-to-GDSII Implementation of a RISC-V CPUTake a small RISC-V core from RTL to a DRC- and LVS-clean GDSII on SKY130 with OpenLane and sign off timing across corners.Physical designIntermediate6-8 wks

Goal. Implement a RV32I core (your own or PicoRV32) through synthesis, floorplan, placement, CTS, routing and signoff. Close timing at the target clock with clean DRC and LVS.

Specification

  • PDK: SKY130 with the sky130_fd_sc_hd standard-cell library, 1.8 V core
  • Target clock e.g. 50 MHz (20 ns) with SDC constraints for inputs, outputs and clock uncertainty
  • Core utilization 40-50%, aspect ratio 1, pins assigned by side
  • Power grid on met4/met5 straps with met1 rails
  • Signoff STA at tt, ss and ff corners with extracted parasitics
  • Clean DRC (Magic and KLayout) and clean LVS (Netgen)

Steps

  1. Write the SDC: create_clock, input and output delays, clock uncertainty and load.
  2. Run OpenLane synthesis and read the Yosys area and cell report.
  3. Set floorplan utilization, pin order and PDN; inspect the floorplan in the OpenROAD GUI.
  4. Run placement and CTS; record skew, buffer count and pre-route worst slack.
  5. Run routing, then extract parasitics and run OpenSTA in all three corners.
  6. Fix violations by changing constraints, utilization or resizing settings, and rerun.
  7. Run DRC and LVS, fix any errors and stream out the final GDSII.

Deliverables

  • OpenLane configuration and SDC files
  • Stage-by-stage QoR table: area, utilization, WNS, TNS, skew, wirelength
  • Final GDSII, layout screenshots and clean DRC/LVS reports
  • Short report of every fix you made and why

How you know it works

  • Setup and hold WNS at least 0 ns in all corners, e.g. at 50 MHz
  • Zero DRC and zero LVS errors
  • Clock skew, e.g. under 200 ps
  • Max transition and max capacitance violations, e.g. zero

Tools

Open-source OpenLane, OpenROAD, Yosys, OpenSTA, Magic, KLayout, Netgen, SKY130 PDK

Industry Cadence Genus, Cadence Innovus, Synopsys Fusion Compiler, Synopsys PrimeTime, Siemens Calibre

Before you start

  • Synthesis basics
  • Setup and hold timing
  • Linux and Tcl
  • Basic SDC

Go further

  • Push frequency until timing fails and explain the limiting path
  • Add an SRAM macro
  • Submit a small version through Tiny Tapeout

Watch out for

  • Setting utilization too high so routing fails, then blaming the tool.
  • Reporting timing only at the typical corner.

Resume line Implemented a RISC-V core from RTL to GDSII on SKY130 with OpenLane, closing timing at X MHz in three corners with zero DRC/LVS errors.

Proves: Physical designSTA / signoff

022Low-Power SoC Floorplan with Power-Domain RegionsFloorplan a small SoC with SRAM macros and a switchable power domain, write its UPF, and compare region layouts on timing and congestion.Physical designAdvanced6-8 wks

Goal. Plan a floorplan with an always-on and a switchable domain and write the matching UPF. Compare three region layouts on timing and congestion.

Specification

  • Design: a small RISC-V SoC on SKY130 with 2 SRAM macros, e.g. sky130_sram_1kbyte_1rw1r_32x256_8
  • Two domains: always-on (timer, wake-up, power controller) and switchable (core and SRAM)
  • Switchable region defined as a voltage-domain area; always-on logic kept near its I/O and supply pins
  • Every signal leaving the switchable domain listed with an isolation clamp value; retention flops identified
  • Rows reserved along the switchable region edge for power switches, implemented only in an industry flow
  • UPF 2.0 file: power domains, supply nets, one power switch, isolation and retention strategies

Steps

  1. List every signal that crosses between the two domains and mark which need isolation or retention.
  2. Write the UPF: domains, supply nets, a power switch, isolation and retention strategies.
  3. Sketch three floorplans that differ in region shape and in where the always-on block sits.
  4. Define each region with OpenROAD's create_voltage_domain, then place the SRAM macros with halos.
  5. Run placement and global routing for each option and record WNS, wirelength and congestion.
  6. Mark reserved power-switch rows and isolation-cell sites on a screenshot of each option.
  7. Choose one floorplan and justify it in a one-page note.

Deliverables

  • UPF file and a power-domain diagram listing every crossing signal
  • Floorplan Tcl scripts for three region options
  • Comparison table: WNS, wirelength and global-route overflow
  • Annotated screenshots showing regions, macros and reserved switch rows

How you know it works

  • Domain-crossing outputs with an isolation decision, e.g. 100% covered in the UPF
  • Global-route overflow, e.g. zero in the chosen floorplan
  • WNS of the chosen option versus the worst option, e.g. X ns better
  • Always-on region area, e.g. under 15% of the core

Tools

Open-source OpenROAD, OpenLane, OpenSTA, KLayout, SKY130 PDK

Industry Cadence Innovus, Synopsys ICC2, Cadence Voltus, Cadence Genus with UPF

Before you start

  • The RTL-to-GDSII flow (project 21)
  • Floorplanning concepts
  • Power-grid basics
  • Low-power concepts (isolation, retention)

Go further

  • Implement the switched domain with power switches and isolation in an industry flow
  • Add separate pdngen grids for each domain (project 28)
  • Write the power-down and power-up sequence for the power controller

Watch out for

  • Placing the always-on block far from the domain boundary, so isolated outputs route a long way.
  • Forgetting that SRAM in a switched domain loses its contents unless retention or save-restore is planned.

Resume line Planned a two-domain SKY130 SoC floorplan with UPF intent, comparing three region layouts and reaching zero route overflow with X ns better WNS.

Proves: Physical design

023Clock Tree Synthesis Study and Skew OptimizationRun clock tree synthesis with different buffers, fanout limits and sink clustering, and measure how each choice changes skew, latency and clock power.Physical designIntermediate4-6 wks

Goal. Build a CTS experiment on one placed design and explain, with numbers, which settings give the best skew, insertion delay and power trade-off.

Specification

  • Design: a placed block of e.g. 2,000-10,000 flip-flops on SKY130
  • Clock: one clock at e.g. 100 MHz with a defined source latency and uncertainty
  • Experiments: buffer cell choice, max fanout, sink clustering size and wire segment length
  • Reports: global skew, insertion latency, buffer count, clock-net wirelength and clock power
  • Post-CTS checks: setup and hold slack, max transition on clock nets
  • At least 6 runs compared in one table

Steps

  1. Place the design and record the clock net's sink count and spread before CTS.
  2. Run baseline CTS in OpenROAD and record skew, latency and buffer count.
  3. Sweep the buffer list, sink clustering and fanout options one at a time.
  4. Run post-CTS repair_timing and record hold fixes for each run.
  5. Estimate clock power from the switching of buffers and clock wire capacitance.
  6. Plot skew against power and latency, and pick the best trade-off.
  7. Explain why the best run wins using the clock tree view in the GUI.

Deliverables

  • CTS Tcl scripts for each experiment
  • Results table and skew-versus-power plot
  • Clock tree screenshots for the best and worst runs
  • One-page explanation of the trade-offs

How you know it works

  • Global skew of the chosen run, e.g. under 100 ps
  • Hold-buffer count after repair, e.g. reduced by X% versus baseline
  • Clock power share of total, reported, e.g. 20-40%
  • Zero max-transition violations on clock nets

Tools

Open-source OpenROAD (TritonCTS), OpenSTA, OpenLane, SKY130 PDK

Industry Cadence Innovus (CCOpt), Synopsys ICC2, Synopsys PrimeTime

Before you start

  • Setup and hold equations
  • Clock skew and latency
  • The RTL-to-GDSII flow (project 21)

Go further

  • Try useful skew to fix a setup-critical path
  • Build an H-tree for comparison
  • Add a generated clock and check its skew group

Watch out for

  • Chasing zero skew while hold violations and clock power grow.
  • Comparing runs with different placement, so CTS is not the only change.

Resume line Ran X CTS experiments on a SKY130 block and cut clock skew to Y ps while reducing hold buffers by Z% versus the baseline.

Proves: Physical designSTA / signoff

024Routing Congestion Analysis and Reduction StudyPush a design into routing congestion, find the hotspots, and remove them with utilization, padding, density and macro-placement changes.Physical designIntermediate4-6 wks

Goal. Take a design that fails or nearly fails routing and bring it to zero overflow and zero DRVs. Document which knob fixed what, with before and after maps.

Specification

  • Design: a block with high pin density such as a crossbar, multiplier array or AES core on SKY130
  • Baseline at high utilization, e.g. 70%, chosen so global routing overflows
  • Knobs: core utilization, placement density, cell padding, macro moves and routing-layer limits
  • Reports: global-route overflow per layer, detailed-route DRV count, wirelength and WNS
  • Congestion heat maps from the OpenROAD GUI for every run
  • Each change applied one at a time

Steps

  1. Run the baseline and save the global-route congestion map and overflow report.
  2. Find the hotspot cells and nets; check if they are high-fanout or high-pin-density cells.
  3. Lower placement density in steps and record overflow and wirelength.
  4. Add cell padding on the hotspot cell types and rerun.
  5. Try lower core utilization and compare die area against routability.
  6. Run detailed routing on the best runs and count DRVs.
  7. Summarize the cost of each fix in area, wirelength and timing.

Deliverables

  • Scripts for each experiment
  • Before and after congestion maps
  • Results table: overflow, DRVs, wirelength, WNS, die area
  • Written root-cause analysis of the hotspot

How you know it works

  • Global-route overflow reduced to e.g. zero
  • Detailed-route DRVs, e.g. zero
  • Area cost of the fix, e.g. under 10% die growth
  • WNS change reported for each fix

Tools

Open-source OpenROAD, OpenLane, OpenSTA, KLayout, SKY130 PDK

Industry Cadence Innovus, Synopsys ICC2, Synopsys Fusion Compiler

Before you start

  • The RTL-to-GDSII flow (project 21)
  • Placement and routing basics
  • Tcl scripting

Go further

  • Add RTL changes (e.g. restructuring a mux tree) and compare with PD-only fixes
  • Use partial placement blockages
  • Compare SKY130 hd and hs libraries

Watch out for

  • Changing several knobs at once, so you cannot tell which one helped.
  • Fixing congestion by lowering utilization only, which wastes area.

Resume line Analyzed and removed routing congestion in a SKY130 block, cutting global-route overflow from X to zero with Y% area cost.

Proves: Physical design

025Static IR-Drop Analysis and Power-Grid TuningDesign and iterate a power delivery network so static IR drop stays within budget, and understand the area cost of every extra strap.Physical designIntermediate4-6 wks

Goal. Build a PDN for a single-domain SKY130 block and measure static IR drop. Tune strap width, pitch and supply pins until drop meets the budget.

Specification

  • Design: a single-domain SKY130 block at 1.8 V, e.g. 0.5-1 mm on a side, rerun from floorplan for each grid
  • Grid: met1 rails, met4 vertical and met5 horizontal straps with vias at every crossing
  • Budget: worst static IR drop e.g. under 5% of VDD (90 mV) on VDD and ground
  • Experiments: strap width, strap pitch, number of supply pins and their locations
  • Power from average switching activity, e.g. 0.1-0.2 toggle rate
  • Report routing tracks lost to the grid for each option

Steps

  1. Build a baseline grid with pdngen and check every standard-cell rail connects.
  2. Run power analysis in OpenSTA with a set activity, then static IR with analyze_power_grid.
  3. Save the IR map and find where the worst drop is relative to supply pins.
  4. Sweep strap pitch and width, and record IR drop and routing-track usage.
  5. Move or add supply pins and rerun.
  6. Check each option still routes cleanly and does not hurt timing.
  7. Choose the grid with the best drop-per-track trade-off and justify it.

Deliverables

  • PDN Tcl scripts for each experiment
  • IR-drop maps for baseline and final grid
  • Table: worst drop, average drop, track usage, WNS
  • Short report on how strap pitch and pin placement affect drop

How you know it works

  • Worst static IR drop, e.g. under 5% of VDD
  • IR-drop reduction versus baseline, e.g. X%
  • Routing resource used by the grid, e.g. under 20% of met4/met5 tracks
  • Zero floating PDN segments

Tools

Open-source OpenROAD (pdngen, PDNSim), OpenSTA, OpenLane, KLayout, SKY130 PDK

Industry Cadence Voltus, Cadence Innovus, Synopsys ICC2, Synopsys PrimeTime

Before you start

  • Ohm's law on metal resistance
  • Static and dynamic power
  • The RTL-to-GDSII flow (project 21)

Go further

  • Run dynamic IR in an industry tool with vectors
  • Check electromigration on the grid
  • Add decap cells near hotspots and measure the effect

Watch out for

  • Reporting only VDD drop and forgetting ground bounce on VSS.
  • Making the grid so dense that signal routing fails.

Resume line Designed and tuned a SKY130 power grid, cutting worst static IR drop by X% to Y mV while keeping grid track usage under Z%.

Proves: Physical design

026Post-Route ECO Timing ClosureTake a routed block that fails timing and close it with targeted ECOs instead of rerunning the whole flow.Physical designAdvanced4-6 wks

Goal. Bring a routed SKY130 block from negative setup and hold slack to zero violations using cell sizing and buffer ECOs. Prove that each change was incremental and did not break routing or DRC.

Specification

  • Start point: a routed block from OpenLane, e.g. PicoRV32 pushed to 10 ns so WNS is around -0.3 ns
  • Library: sky130_fd_sc_hd; allowed fixes are upsizing, downsizing, buffer insertion and hold delay cells
  • Hold fixes use delay cells such as sky130_fd_sc_hd__dlygate4sd3_1, inserted at the capture side
  • Signoff corner set: ss_100C_1v60 for setup and ff_n40C_1v95 for hold, with extracted SPEF
  • ECO budget: change fewer than 2% of instances and keep placement legal without a full re-place
  • Output: ECO Tcl script, updated DEF/ODB, re-extracted SPEF and final STA reports

Steps

  1. Run OpenSTA on the routed design and save baseline WNS, TNS and violating endpoint count for setup and hold.
  2. Group violating paths by cause: long wire, weak driver, high fanout, or too many logic levels.
  3. Write an ECO Tcl script with explicit replace_cell and buffer-insertion commands for the worst 20 paths.
  4. Fix hold only after setup is clean, and check that each hold buffer does not create a new setup violation.
  5. Legalize placement and run incremental detailed routing in OpenROAD, then re-extract parasitics with OpenRCX.
  6. Rerun STA at both corners and repeat until WNS and hold slack are non-negative.
  7. Run DRC and LVS on the final layout and record every iteration in a table.

Deliverables

  • Baseline and final timing reports for setup and hold at each corner
  • ECO Tcl scripts for every iteration, with comments explaining each fix
  • Iteration log table: WNS, TNS, violating endpoints and cells changed
  • Clean DRC and LVS reports for the final GDS
  • One-page note on which fix types worked and why

How you know it works

  • Setup WNS >= 0 at the slow corner (e.g. from -0.30 ns to +0.02 ns)
  • Zero hold violations at the fast corner
  • Instances changed below the budget (e.g. < 2% of cells)
  • No new DRC or LVS errors introduced by the ECO
  • Closure reached in a small number of loops (e.g. <= 4 iterations)

Tools

Open-source OpenROAD (repair_timing for comparison), OpenSTA, OpenRCX, Magic, Netgen, KLayout

Industry Synopsys PrimeTime ECO, Cadence Tempus ECO, Cadence Innovus, Synopsys ICC2, Siemens Calibre

Before you start

  • Reading setup and hold timing reports
  • An OpenLane run to GDS (project 21 or similar)
  • Basic Tcl scripting

Go further

  • Compare your manual ECO against OpenROAD repair_timing on cells changed and final slack
  • In an industry tool, add a metal-only ECO that fixes one path using pre-placed spare cells

Watch out for

  • Fixing hold before setup, then breaking hold again when setup buffers are upsized
  • Trusting STA on stale parasitics instead of re-extracting SPEF after every ECO

Resume line Closed setup and hold timing on a routed SKY130 block from X ns WNS to zero violations, with hand-written ECOs touching under Y% of cells.

Proves: Physical designSTA / signoff

027Macro Placement Strategy for an SRAM-Heavy BlockPlace several SRAM macros in a block, script the strategy, and measure its effect on congestion, wirelength and timing.Physical designAdvanced4-6 wks

Goal. Build a repeatable macro placement script for a block with several SRAM macros. Show with numbers that it beats a naive placement and holds up against the OpenROAD automatic macro placer.

Specification

  • Design: a cache or buffer block with 4-8 SKY130 SRAM macros, e.g. sky130_sram_1kbyte_1rw1r_32x256_8
  • Rules: macros pushed to the core edge, pins facing the standard-cell area, consistent orientation
  • Halo of e.g. 10-20 um around each macro and placement blockage in narrow channels
  • Channel width sized from pin count and routing layers, not by guesswork
  • Three variants compared: naive grid, your scripted placement, and OpenROAD automatic macro placement
  • Same core size, utilization and clock target for all variants

Steps

  1. Synthesize the block with Yosys and list each macro's size, pin side and connectivity to other macros.
  2. Draw a dataflow sketch and decide which macros must sit near each other and near the I/O.
  3. Write a Tcl or Python script that computes macro locations, orientations and halos from parameters.
  4. Place macros, add blockages, then run global placement and global routing for each variant.
  5. Collect wirelength, congestion overflow and post-placement timing for all three variants.
  6. Carry the best variant through CTS and routing to confirm the gain survives.
  7. Write up the trade-offs with layout screenshots and congestion heatmaps.

Deliverables

  • Parameterized macro placement script with a README
  • Layout screenshots and congestion maps for all three variants
  • Comparison table: HPWL, routing overflow, WNS and runtime
  • Final routed DEF/GDS of the best variant with DRC report

How you know it works

  • Lower half-perimeter wirelength than naive placement (e.g. 10-15% lower)
  • Global route overflow close to zero (e.g. < 0.5% overflowed GCells)
  • No macro pin blocked by another macro or by the power grid
  • Post-route WNS equal or better than the automatic placer result

Tools

Open-source Yosys, OpenROAD (rtl_macro_placer for comparison), OpenSTA, KLayout, Python

Industry Cadence Innovus, Synopsys ICC2 or Fusion Compiler, Synopsys PrimeTime

Before you start

  • Floorplanning concepts: core area, utilization, halos and blockages
  • Tcl or Python scripting
  • One complete OpenLane or OpenROAD run

Go further

  • Add a notch or L-shaped region and handle macros around it
  • Score placements automatically and sweep parameters to find the best one

Watch out for

  • Facing macro pins toward the core edge, which forces long detours into the logic
  • Leaving thin channels between macros that cannot be routed or powered

Resume line Scripted macro placement for a block with X SRAM macros, cutting wirelength by Y% and routing overflow by Z% versus a naive floorplan.

Proves: Physical design

028Multi-Domain Power Grid with pdngen Voltage DomainsBuild separate power grids for an always-on and a switchable domain, then check shorts, IR drop and electromigration per supply.Physical designAdvanced4-6 wks

Goal. Build a PDN with one grid per domain using pdngen voltage domains. Show both supplies meet the IR and EM budgets with no shorts between them.

Specification

  • Process: SKY130, 1.8 V, rails on met1, straps on met4 and met5, written as an OpenROAD Tcl script
  • Two supplies: VDD_AON for control logic and VDD_SW for a datapath region; both share VSS
  • pdngen: set_voltage_domain per domain and one define_pdn_grid each, with its own ring and straps
  • IR-drop budget: e.g. 5% of VDD (90 mV) worst static drop on each supply
  • Power switches exist only in UPF and an industry flow; here VDD_SW is a separate supply pin
  • Checks: no shorts between supplies, every row on the right rail, strap current within EM limits

Steps

  1. Define the domains and write the intent in UPF, even if the open flow only uses part of it.
  2. Create the switchable region with create_voltage_domain and leave a gap at its boundary.
  3. Write a pdngen grid for each domain: ring, met1 rails, met4/met5 straps and via stacks.
  4. Run check_power_grid on each supply and an LVS run to prove VDD_AON and VDD_SW never short.
  5. Run static IR for each supply with analyze_power_grid and an activity-based power estimate.
  6. Check current density on the worst straps and vias against the PDK electromigration limits.
  7. Route the full block and confirm the boundary gap does not cause congestion.

Deliverables

  • pdngen script with one grid per voltage domain
  • IR-drop heatmaps for VDD_AON, VDD_SW and VSS
  • UPF file describing the two domains
  • EM check table for the worst straps and vias
  • Short note on boundary spacing and how the domains share VSS

How you know it works

  • Worst static IR drop inside budget on each supply (e.g. < 90 mV at 1.8 V)
  • Zero shorts between VDD_AON and VDD_SW in LVS
  • Every standard-cell row tied to its own domain rail
  • Worst strap current density below the PDK EM limit

Tools

Open-source OpenROAD (pdngen, PDNSim), OpenSTA, KLayout, Magic

Industry Cadence Innovus, Cadence Voltus, Synopsys ICC2

Before you start

  • Single-domain power grid design (project 25)
  • Floorplan concepts
  • Reading pdverse low-power material on power domains

Go further

  • Add dynamic (vectorless) IR analysis in an industry tool if you have access
  • Model power-switch placement and rush current for the switchable domain

Watch out for

  • Letting met1 rails run across the domain boundary, which shorts the two supplies
  • Running IR analysis with a made-up power number instead of a realistic activity-based estimate

Resume line Designed a two-domain SKY130 power grid with pdngen voltage domains, meeting X mV worst IR drop per domain with zero supply shorts.

Proves: Physical design

029Multi-Corner Multi-Mode Timing SignoffSign off one routed block across several PVT corners, RC corners and modes, and explain which scenario limits each check.Physical designIntermediate3-5 wks

Goal. Set up MMMC timing for a routed block and close setup and hold in every required scenario. Produce a signoff summary that names the worst scenario for each check.

Specification

  • Library corners: tt_025C_1v80, ss_100C_1v60 and ff_n40C_1v95 from sky130_fd_sc_hd
  • RC corners: min, nom and max SPEF from parasitic extraction
  • Modes: functional at e.g. 50 MHz and scan shift at e.g. 10 MHz, each with its own SDC
  • Setup checked at slow library and max RC; hold checked at fast library and min RC
  • Checks: setup, hold, max transition, max capacitance and unconstrained endpoints
  • Scenario matrix of at least 6 mode-corner combinations

Steps

  1. Write separate SDC files for functional and scan modes, with case analysis on the scan enable.
  2. Extract min, nom and max SPEF from the routed design.
  3. Define corners in OpenSTA and load the correct library and SPEF for each one.
  4. Run setup, hold and design rule checks for every scenario and save the reports.
  5. Build a matrix of WNS and violation counts and mark which scenario limits each check.
  6. Fix the remaining violations, then rerun all scenarios to confirm no new ones appear.
  7. Report unconstrained paths and explain any intentional false paths.

Deliverables

  • Functional and scan SDC files
  • OpenSTA Tcl scripts for the full scenario matrix
  • Scenario matrix table with WNS, TNS and violation counts
  • Signoff summary listing the limiting corner for setup, hold and transitions

How you know it works

  • All scenarios at zero setup and hold violations (e.g. 6 of 6 scenarios clean)
  • No max transition or max capacitance violations in any corner
  • Zero unconstrained endpoints apart from documented exceptions
  • Full scenario run scripted end to end (e.g. under 10 minutes for the block)

Tools

Open-source OpenSTA, OpenROAD, OpenRCX, Python for report parsing

Industry Synopsys PrimeTime, Cadence Tempus, Synopsys StarRC, Cadence Quantus

Before you start

  • SDC basics: clocks, I/O delays and exceptions
  • Setup and hold equations
  • A routed design to analyze

Go further

  • Add OCV derates or AOCV tables and see how margins change
  • Use a dominance analysis to drop scenarios that never limit timing

Watch out for

  • Checking hold at the slow corner and declaring it clean
  • Using the functional SDC in scan mode, which hides real shift-path violations

Resume line Signed off a routed SKY130 block across X mode-corner scenarios in OpenSTA, closing all setup, hold and transition violations with a scripted MMMC flow.

Proves: STA / signoffPhysical design

030Tiny Tapeout Chip with OpenLaneTake a small design of your own from RTL to a GDS that passes precheck and goes on a real shared shuttle.Physical designIntermediate6-10 wks

Goal. Design, verify and harden a small digital block in one Tiny Tapeout tile, pass all precheck rules and submit it to a shuttle. Then plan how to test the returned chip.

Specification

  • Fits one Tiny Tapeout tile: about 160 x 100 um on the shuttle process (SKY130, GF180 or IHP per shuttle)
  • Pins fixed by the template: 8 inputs, 8 outputs and 8 bidirectional I/Os, plus clock and reset
  • Example design: a UART-controlled PWM generator or a small 8-bit CPU
  • Clock target set to what the I/O can carry, e.g. 10-25 MHz
  • Flow: Tiny Tapeout GitHub Actions running OpenLane, with DRC, LVS and precheck
  • Test plan written for the demo board before submission

Steps

  1. Pick a design that fits the tile and write a one-page specification with the pinout table.
  2. Write the RTL and a cocotb testbench using the Tiny Tapeout template repository.
  3. Run the GitHub Actions flow and read the utilization, timing and DRC results.
  4. Iterate on the RTL or tile count until utilization is safe and timing passes.
  5. View the GDS in KLayout and check the gate-level simulation passes.
  6. Submit to the shuttle and write the bring-up test plan for the demo board.

Deliverables

  • GitHub repo from the Tiny Tapeout template with RTL, tests and info.yaml
  • Passing GitHub Actions logs: GDS, precheck and gate-level test
  • Rendered GDS image and utilization and timing summary
  • Bring-up test plan for the returned chip

How you know it works

  • Precheck passes with zero DRC and LVS errors
  • cocotb tests pass at RTL and gate level (e.g. 100% of planned tests)
  • Utilization inside a safe range (e.g. 40-70% of one tile)
  • Timing met at the stated clock (e.g. 20 MHz with positive slack)

Tools

Open-source Tiny Tapeout template, OpenLane, Yosys, OpenROAD, cocotb, Icarus Verilog, KLayout, Magic, Netgen

Industry Cadence Genus and Innovus, Synopsys Fusion Compiler, Siemens Calibre

Before you start

  • Verilog for synthesis
  • cocotb or another testbench method
  • Basic GitHub and Git use

Go further

  • Use two tiles and add a small SRAM or register file
  • Write a characterization report after the chip returns

Watch out for

  • Choosing a design that needs more pins or area than one tile, then cutting features at the last minute
  • Skipping gate-level simulation, so reset or X-propagation bugs reach silicon

Resume line Taped out a custom X-tile design on a Tiny Tapeout shuttle, from specification and cocotb verification to a DRC- and LVS-clean GDS.

Proves: Physical designRTL design

031LeNet-5 CNN Accelerator on FPGABuild a fixed-point CNN accelerator that classifies MNIST digits on an FPGA and compare it with a software baseline.FPGAAdvanced8-10 wks

Goal. Run an 8-bit quantized LeNet-5 on an FPGA with custom convolution hardware. Match the PyTorch model's accuracy closely and report images per second and resource use.

Specification

  • Model: LeNet-5 style network on 28 x 28 grayscale MNIST, weights and activations quantized to int8
  • Convolution engine with 5 x 5 kernels, line buffers and a parallel MAC array with int32 accumulators
  • Board: e.g. PYNQ-Z2 (Zynq-7020, 220 DSP slices) or an Artix-7 board with 90 DSP slices
  • Clock target: e.g. 100 MHz on Artix-7 or Zynq-7000
  • Input via UART or AXI DMA; output class index on LEDs or UART
  • Weights stored in block RAM, loaded from .mem files generated in Python

Steps

  1. Train LeNet-5 in PyTorch and quantize it to int8, recording float and quantized accuracy.
  2. Write a bit-accurate Python golden model of the quantized network.
  3. Design the convolution, pooling and fully connected units in Verilog with a shared MAC array.
  4. Verify each layer against the golden model with cocotb and Verilator using real test images.
  5. Integrate on the board, stream test images in and read the predicted labels back.
  6. Measure throughput and resource use, then tune parallelism to fit the DSP budget.

Deliverables

  • RTL for conv, pool and dense layers with a block diagram
  • Python training, quantization and golden-model scripts
  • cocotb layer-by-layer tests with match statistics
  • Board demo video and timing, utilization and throughput report

How you know it works

  • Quantized accuracy within 1% of the float model (e.g. 98.5% vs 99.0%)
  • Bit-exact match with the golden model on all test images
  • Throughput measured on the board (e.g. > 1,000 images per second)
  • Timing met at the target clock with DSP use reported (e.g. 100 MHz, 60% DSP)

Tools

Open-source PyTorch, Python, Verilator, cocotb, Yosys and nextpnr for open FPGA parts

Industry AMD Vivado, AMD Vitis HLS, Intel Quartus

Before you start

  • Verilog and pipelining
  • Fixed-point arithmetic
  • Basic CNN theory and Python

Go further

  • Add double buffering so loading the next image overlaps compute
  • Port the same model with hls4ml and compare area and latency

Watch out for

  • Ignoring rounding and saturation rules, so hardware disagrees with the quantized model
  • Making the MAC array wider than the memory bandwidth can feed

Resume line Built an int8 LeNet-5 accelerator on FPGA reaching X% MNIST accuracy and Y images per second at Z MHz, bit-exact with a Python golden model.

Proves: FPGAArchitecture / AI hardwareRTL design

032VGA Text and Graphics ControllerGenerate standard 640 x 480 at 60 Hz VGA timing and display a text console and simple graphics from block RAM.FPGABeginner2-3 wks

Goal. Drive a real monitor at 640 x 480 at 60 Hz with correct sync timing. Display an 80 x 30 text mode from a character buffer and a small bitmap.

Specification

  • Pixel clock 25.175 MHz (25.0 MHz from a PLL or MMCM is accepted by most monitors)
  • Horizontal: 640 visible + 16 front porch + 96 sync + 48 back porch = 800 clocks
  • Vertical: 480 visible + 10 front porch + 2 sync + 33 back porch = 525 lines; both syncs active-low
  • Text mode 80 x 30 characters using an 8 x 16 font ROM
  • Color output on the board's VGA DAC, e.g. 12-bit RGB (4:4:4) on a Basys 3
  • Character buffer writable over UART at e.g. 115200 baud

Steps

  1. Generate the pixel clock with a clocking wizard or PLL and check the frequency in the timing report.
  2. Write horizontal and vertical counters and derive sync, blanking and pixel coordinates.
  3. Simulate one full frame and check porch and sync widths against the timing table.
  4. Add a font ROM and character RAM, and register the pipeline so pixel data lines up with sync.
  5. Add a UART receiver that writes characters into the buffer.
  6. Test on a real monitor and add a bitmap overlay or moving sprite.

Deliverables

  • RTL for timing generator, text engine and UART
  • Testbench with frame timing checks and a GTKWave screenshot
  • Photo or video of the monitor output
  • README with the timing table and resource use

How you know it works

  • Monitor reports 640 x 480 at 60 Hz with no flicker or shifted image
  • Sync and porch widths match the standard exactly in simulation
  • No one-pixel shift between text and sync (pipeline aligned)
  • Small resource use (e.g. < 5% LUTs and 2-4 BRAMs on an Artix-7)

Tools

Open-source Icarus Verilog, Verilator, GTKWave, Yosys and nextpnr for open FPGA boards

Industry AMD Vivado, Intel Quartus

Before you start

  • Counters and FSMs in Verilog
  • Clock basics and timing reports

Go further

  • Add a 320 x 240 pixel framebuffer with 4-bit color
  • Draw lines in hardware with Bresenham's algorithm

Watch out for

  • Forgetting that RAM and ROM reads add latency, so text appears shifted
  • Driving color during blanking, which some monitors reject

Resume line Built a 640x480@60 Hz VGA controller with an 80 x 30 text mode on FPGA, using X% of LUTs and verified on a real monitor.

Proves: FPGARTL design

033HDMI (DVI) Video Output with Real-Time FilteringBuild a 720p TMDS video transmitter on FPGA and add a real-time image filter between the source and the output.FPGAIntermediate4-6 wks

Goal. Output 1280 x 720 at 60 Hz over the HDMI connector using your own TMDS encoder and serializers. Insert a streaming Sobel or grayscale filter without dropping frames.

Specification

  • Video mode 1280 x 720 at 60 Hz, pixel clock 74.25 MHz
  • TMDS encoding (8 bits to 10, transition-minimized and DC-balanced) on three data channels plus a clock channel
  • Serial rate 742.5 Mb/s per lane using 10:1 serialization (e.g. OSERDESE2 in DDR mode at 371.25 MHz)
  • DVI-compatible mode first: no data islands, no audio
  • Filter pipeline: RGB to grayscale, then 3 x 3 Sobel using two line buffers
  • Board with HDMI out, e.g. an Artix-7 or Zynq-7000 board with TMDS pins

Steps

  1. Generate 74.25 MHz and 371.25 MHz clocks from one MMCM so they are phase related.
  2. Write the 720p timing generator and a color-bar test pattern.
  3. Write the TMDS encoder and check it against a reference model for all 256 input values.
  4. Serialize with OSERDES and drive TMDS differential outputs; confirm the monitor locks.
  5. Add the grayscale and Sobel pipeline with line buffers, and delay sync signals to match.
  6. Add a switch to bypass the filter and compare outputs live.

Deliverables

  • RTL for timing, TMDS encoder, serializer wrapper and filter
  • Encoder test against a reference model
  • Timing report showing the serializer clocks are met
  • Video of the monitor showing raw and filtered output

How you know it works

  • Monitor locks at 1280 x 720 at 60 Hz with no sparkles or dropouts
  • TMDS encoder matches the reference for every input byte and control code
  • Filter adds a fixed latency (e.g. 2 lines + a few pixels) with syncs aligned
  • Timing met at 74.25 MHz and 371.25 MHz with positive slack

Tools

Open-source Verilator, cocotb, Python (NumPy) for reference models, GTKWave

Industry AMD Vivado, Intel Quartus

Before you start

  • VGA timing (project 32)
  • Clocking with PLLs or MMCMs
  • Pipelined RTL design

Go further

  • Add HDMI data islands with an AVI InfoFrame
  • Take camera input and filter it live

Watch out for

  • Calling it HDMI when only DVI signalling is sent; be clear in the report
  • Generating the serial clock from a separate PLL, so it is not phase related to the pixel clock

Resume line Built a 720p60 TMDS video transmitter on FPGA with a custom TMDS encoder and a real-time Sobel filter, meeting timing at X MHz.

Proves: FPGARTL design

034FPGA Logic Analyzer with PulseView SupportTurn an FPGA board into a 16-channel logic analyzer with triggers and stream captures to a PC for viewing.FPGAIntermediate3-5 wks

Goal. Capture 16 digital channels at 100 MSa/s with pattern triggers and pre-trigger memory. Upload the data to a PC and view it as waveforms.

Specification

  • 16 input channels, 3.3 V LVCMOS only, each through a two-flop synchronizer
  • Sample rate up to 100 MSa/s with a programmable divider for slower rates
  • Sample depth e.g. 16K samples per channel in block RAM (circular buffer)
  • Triggers: rising or falling edge on a chosen channel, and a value/mask pattern
  • Pre-trigger capture adjustable, e.g. 0-50% of the buffer
  • Upload over USB-UART at e.g. 921600 baud; host script writes a VCD file

Steps

  1. Write the sampler with synchronizers and a clock-enable based rate divider.
  2. Build the circular buffer and the trigger unit, and store the trigger address.
  3. Add a command interface over UART to set rate, mask, pattern and pre-trigger depth.
  4. Write a Python host script that arms the capture, reads data and writes a VCD file.
  5. Verify with a testbench, then capture a real I2C or SPI bus from a microcontroller.
  6. Open the VCD in GTKWave or PulseView and decode the bus.

Deliverables

  • RTL for sampler, trigger, buffer and command interface
  • Python host tool that outputs VCD
  • Captured waveforms of a real I2C or SPI bus
  • README with the command protocol and limits

How you know it works

  • Stable capture at 100 MSa/s with no missing samples in a counter test
  • Trigger position correct to the sample (e.g. 0 samples error in simulation)
  • Real bus decoded correctly (e.g. 100 I2C transactions with no errors)
  • Upload time for a full buffer measured (e.g. < 2 s)

Tools

Open-source Icarus Verilog, cocotb, Python (pyserial), GTKWave, sigrok PulseView

Industry AMD Vivado, Intel Quartus

Before you start

  • FIFO and RAM design in Verilog
  • UART basics
  • Python scripting

Go further

  • Implement the SUMP protocol so PulseView controls the analyzer directly
  • Add run-length compression to extend capture time

Watch out for

  • Connecting 5 V signals straight to FPGA pins
  • Sampling without synchronizers, then chasing random glitches in the data

Resume line Built a 16-channel, 100 MSa/s FPGA logic analyzer with pattern triggers and a Python VCD exporter, and used it to decode real I2C traffic.

Proves: FPGA

035FPGA Digital Down-Converter and AM ReceiverBuild the core of a software-defined radio on FPGA: NCO, mixer, CIC and FIR decimation, and AM demodulation to audio.FPGAAdvanced8-12 wks

Goal. Implement a digital down-converter that tunes one channel from a sampled band, decimates it to audio rate and demodulates AM. Verify it bit-accurately against a Python model before using real RF.

Specification

  • Input: 12-bit samples, e.g. from an external ADC module at 20-40 MSa/s or from recorded test vectors
  • NCO with a 32-bit phase accumulator and a sine/cosine LUT or CORDIC
  • Complex mixer, then a 5-stage CIC decimator with a large ratio (e.g. 256)
  • Compensating FIR filter (e.g. 63 taps) and a final decimate-by-2
  • AM envelope detection with CORDIC magnitude; audio out at the decimated rate, e.g. 39.06 kHz (20 MSa/s / 256 / 2), over I2S or PWM
  • Target band: medium-wave AM in India (531-1602 kHz, 9 kHz channels), within the ADC Nyquist range

Steps

  1. Model the full chain in Python with NumPy and SciPy, and pick bit widths for each stage.
  2. Write the NCO and mixer and check spurious tones in the output spectrum.
  3. Write the CIC with correct register growth and the compensating FIR.
  4. Verify each block bit-exact against the Python model using cocotb and generated test signals.
  5. Add the CORDIC magnitude demodulator and the audio output path.
  6. Run on hardware with an ADC module and an antenna, or replay recorded samples from block RAM.
  7. Measure the frequency response and spurious-free range of the chain.

Deliverables

  • Python reference model and filter design notebook
  • RTL for NCO, mixer, CIC, FIR and demodulator
  • cocotb tests with bit-exact comparison
  • Spectrum plots at each stage and an audio recording of received output

How you know it works

  • Bit-exact match with the Python model for every stage
  • NCO spurious-free dynamic range measured (e.g. > 70 dBc)
  • Passband ripple after CIC compensation (e.g. < 0.5 dB)
  • Tuning step from the 32-bit NCO (e.g. under 0.01 Hz at 40 MSa/s)

Tools

Open-source Python (NumPy, SciPy), GNU Radio for comparison, Verilator, cocotb, GTKWave

Industry AMD Vivado, MATLAB, Intel Quartus

Before you start

  • DSP basics: sampling, aliasing, filters
  • Fixed-point arithmetic
  • Pipelined Verilog

Go further

  • Add FM demodulation with a CORDIC phase discriminator
  • Move the chain to an RFSoC-class board with a direct RF ADC

Watch out for

  • Getting CIC bit growth wrong, so the output overflows silently
  • Testing only with clean tones and never with real noisy signals

Resume line Implemented an FPGA digital down-converter (NCO, CIC, FIR, CORDIC) and AM receiver, bit-exact with a Python model, achieving X dB passband ripple.

Proves: FPGARTL design

036Streaming 1024-Point FFT AcceleratorDesign a pipelined fixed-point FFT that accepts one complex sample per clock and verify its accuracy against NumPy.FPGAIntermediate5-7 wks

Goal. Build a streaming 1024-point FFT core with an AXI-Stream interface and fixed-point scaling. Measure its SQNR against NumPy and compare its resources with a vendor FFT IP.

Specification

  • Transform size 1024 points, radix-2 single-path delay feedback (10 stages)
  • Input and output: 16-bit signed I and Q, AXI-Stream with tvalid, tready and tlast
  • Scaling by 1/2 per stage (or block floating point) to prevent overflow
  • Twiddle factors stored in a ROM generated by a Python script
  • Throughput one complex sample per clock at e.g. 150 MHz on Artix-7
  • Output in bit-reversed order, with an optional reorder buffer

Steps

  1. Write a fixed-point Python model of the radix-2 SDF FFT that matches your hardware rounding.
  2. Design one butterfly stage with its delay line and parameterize it for all stages.
  3. Generate twiddle ROM contents and connect stages into the full pipeline.
  4. Verify with cocotb using impulses, single tones and random noise against numpy.fft.
  5. Add the AXI-Stream wrapper and back-pressure handling.
  6. Synthesize, close timing and compare resources with the vendor FFT IP.

Deliverables

  • Parameterized FFT RTL with AXI-Stream wrapper
  • Python fixed-point model and twiddle generator
  • cocotb test suite with SQNR plots
  • Comparison table with the vendor FFT IP

How you know it works

  • SQNR against numpy.fft for random input (e.g. > 60 dB)
  • Correct output for impulse and tone tests with peak in the right bin
  • Timing met at target clock (e.g. 150 MHz) with one sample per clock
  • DSP and BRAM use within a set margin of vendor IP (e.g. within 20%)

Tools

Open-source Python (NumPy), Verilator, cocotb, GTKWave, Yosys

Industry AMD Vivado (FFT LogiCORE IP for comparison), Intel Quartus, MATLAB

Before you start

  • DFT and FFT theory
  • Fixed-point arithmetic
  • AXI-Stream handshaking

Go further

  • Make it run-time configurable for 64 to 4096 points
  • Implement radix-2^2 SDF and compare multiplier count

Watch out for

  • Rounding differently from the Python model, so mismatches look like random bugs
  • Ignoring tready, which drops samples under back-pressure

Resume line Designed a streaming 1024-point fixed-point FFT with AXI-Stream I/O achieving X dB SQNR at Y MHz, with DSP use within Z% of the vendor IP.

Proves: FPGARTL design

037Encoder-Feedback PID Motor Speed ControllerControl a DC motor's speed with a fixed-point PID loop in FPGA logic, using quadrature encoder feedback and PWM output.FPGAIntermediate3-5 wks

Goal. Hold a DC motor at a commanded RPM under load changes using a hardware PID loop. Tune it and show step-response data.

Specification

  • Motor: small brushed DC motor with a quadrature encoder, driven by an H-bridge such as TB6612FNG
  • PWM at 20 kHz, generated from a 100 MHz clock (5000 counts per period)
  • Quadrature decoder in 4x mode, inputs passed through synchronizers and glitch filters
  • Control loop at 1 kHz with fixed-point gains (e.g. Q16.16) and integrator anti-windup
  • Setpoint and gains written over UART; speed logged back at 100 Hz
  • Safety: current-limited bench supply and a hardware stop switch

Steps

  1. Write and test the PWM generator and quadrature decoder in simulation.
  2. Compute speed from encoder counts per loop period and check it against a tachometer or phone app.
  3. Model the PID in Python with your chosen fixed-point format.
  4. Implement the PID in RTL with saturation and anti-windup, and match it to the Python model.
  5. Tune gains on the real motor using logged step responses.
  6. Test load changes by braking the shaft lightly and record the recovery.

Deliverables

  • RTL for PWM, decoder, PID and UART
  • Python model and tuning notebook
  • Step response plots for several gain sets
  • Wiring diagram and demo video

How you know it works

  • Overshoot on a step change (e.g. < 10%)
  • Settling time to within 2% of setpoint (e.g. < 300 ms)
  • Steady-state speed error (e.g. < 2%)
  • PID RTL matches the Python model bit-exactly in simulation

Tools

Open-source Icarus Verilog, cocotb, Python (NumPy, Matplotlib), Yosys and nextpnr

Industry AMD Vivado, Intel Quartus, MATLAB and Simulink

Before you start

  • Basic control theory (P, I and D terms)
  • Verilog counters and FSMs
  • Fixed-point arithmetic

Go further

  • Add a cascaded position loop on top of the speed loop
  • Port the loop to a microcontroller and compare jitter

Watch out for

  • Integrator windup when the PWM saturates, causing large overshoot
  • Reading raw encoder pins without synchronizers, which miscounts at speed

Resume line Built an FPGA PID speed controller with quadrature feedback and 20 kHz PWM, holding speed within X% with Y% overshoot.

Proves: FPGAEmbedded

038Two-Channel FPGA Oscilloscope with VGA DisplayBuild a working oscilloscope: sample analog inputs, trigger, store and draw waveforms with a grid and measurements on a monitor.FPGAIntermediate6-8 wks

Goal. Capture two analog channels, trigger on a level with hysteresis and draw the traces on a 640 x 480 display. Show automatic measurements of frequency and peak-to-peak voltage.

Specification

  • Low-cost version: on-chip 12-bit XADC at up to 1 MSa/s (e.g. Basys 3 through the XADC Pmod header)
  • Fast version: external dual 8-bit ADC module, e.g. 40 MSa/s, with an attenuating analog front end
  • Trigger: rising or falling edge at a set level, with hysteresis and auto/normal modes
  • Capture depth e.g. 2K samples per channel; time/div by decimation
  • Display 640 x 480 at 60 Hz with a 10 x 8 grid, reusing the VGA timing from project 32
  • Measurements: frequency, Vpp and mean, updated a few times per second

Steps

  1. Read the XADC (or external ADC) and check samples against a known signal from a function generator.
  2. Build the trigger with hysteresis and a capture buffer that freezes after the trigger.
  3. Write the display engine that maps samples to screen rows and draws two colored traces.
  4. Add time/div and volts/div controls on buttons or switches.
  5. Compute frequency and Vpp in hardware or on a soft-core CPU.
  6. Compare readings with a bench oscilloscope across several frequencies.

Deliverables

  • RTL for ADC interface, trigger, buffer and display
  • Front-end schematic if you use an external ADC
  • Photos comparing your display with a bench scope
  • Accuracy table for frequency and Vpp

How you know it works

  • Stable triggered display with no rolling (e.g. jitter < 1 pixel)
  • Frequency reading error versus a bench scope (e.g. < 1%)
  • Vpp reading error (e.g. < 3% of full scale)
  • Usable bandwidth stated honestly (e.g. about 1/10 of sample rate)

Tools

Open-source Verilator, cocotb, GTKWave, Python for test signal generation, LiteX (optional soft core)

Industry AMD Vivado, Intel Quartus

Before you start

  • VGA controller (project 32)
  • Sampling and Nyquist basics
  • Basic analog front-end knowledge

Go further

  • Add an FFT view using the core from project 36
  • Add an XY mode and cursors

Watch out for

  • Feeding signals above the ADC input range without an attenuator
  • Triggering without hysteresis, so noisy signals jitter on screen

Resume line Built a two-channel FPGA oscilloscope with level triggering, VGA display and automatic measurements, accurate to X% against a bench instrument.

Proves: FPGA

039Fixed-Point Hardware Ray TracerRender a scene of spheres and a plane with shading and shadows in pipelined fixed-point hardware, shown live on a monitor.FPGAAdvanced8-10 wks

Goal. Build a pipelined ray-sphere intersection engine that renders a small 3D scene to a framebuffer. Measure rays per second and image error against a C or Python reference renderer.

Specification

  • Resolution 320 x 240, shown on VGA or HDMI with 2x pixel scaling
  • Scene: up to 8 spheres and one ground plane, one point light
  • Fixed-point format e.g. Q16.16 for positions and directions
  • Square root and reciprocal by pipelined iterative units or Newton-Raphson
  • Lambert diffuse shading plus one shadow ray per pixel
  • Framebuffer in block RAM at e.g. 8 bits per pixel

Steps

  1. Write a software reference renderer in C or Python using the same fixed-point format.
  2. Design the ray-sphere intersection pipeline: dot products, discriminant, square root and nearest hit.
  3. Add the shading stage and the shadow ray test against all spheres.
  4. Verify pixel by pixel against the reference for several scenes.
  5. Connect to the framebuffer and display, then add camera or sphere motion from buttons.
  6. Measure rays per second and frames per second, then add parallel pipelines if resources allow.

Deliverables

  • RTL for intersection, shading and framebuffer
  • Reference renderer and image comparison script
  • Rendered images from hardware and software side by side
  • Performance and resource report

How you know it works

  • Image match against the reference (e.g. PSNR > 35 dB)
  • Pipeline throughput (e.g. one ray per clock after fill)
  • Frame rate at 320 x 240 (e.g. > 10 fps)
  • Timing met at target clock (e.g. 100 MHz)

Tools

Open-source Verilator, cocotb, Python (NumPy, Pillow), GCC, GTKWave

Industry AMD Vivado, Intel Quartus

Before you start

  • Vector math and 3D geometry
  • Fixed-point arithmetic
  • Display output (project 32 or 33)

Go further

  • Add reflections with one bounce
  • Use DSP-friendly floating point and compare area

Watch out for

  • Choosing too few fractional bits, causing speckled shadows (shadow acne)
  • Building a non-pipelined design that cannot reach a usable frame rate

Resume line Built a pipelined fixed-point ray tracer on FPGA rendering 320 x 240 scenes at X fps, matching a software reference at Y dB PSNR.

Proves: FPGARTL designArchitecture / AI hardware

040Systolic-Array Inference Engine on ZynqBuild an int8 systolic matrix-multiply engine controlled by the Zynq ARM cores and run a small neural network through it.FPGAAdvanced8-12 wks

Goal. Integrate an int8 GEMM engine with AXI DMA on Zynq, drive it from Python on the ARM and run a small model end to end. Report achieved versus peak GOPS.

Specification

  • 8 x 8 output-stationary systolic array of int8 multipliers with int32 accumulators
  • Peak compute = 2 x 64 x f, e.g. 19.2 GOPS at 150 MHz
  • Control registers over AXI4-Lite; data moved by AXI DMA over AXI-Stream
  • Tiling done in software for matrices larger than 8 x 8
  • Target: e.g. PYNQ-Z2 or another Zynq-7000 board
  • Workload: a small int8 MLP or keyword-spotting model, layers mapped to GEMM

Steps

  1. Write a Python model of tiled int8 GEMM with requantization and check it against NumPy.
  2. Reuse the 8 x 8 array from project 2, or build one, as the compute core.
  3. Verify the array with cocotb using random matrices and corner cases such as -128 x -128.
  4. Wrap it with AXI4-Lite and AXI-Stream ports, connect the AXI DMA and Zynq PS in a block design, and build the bitstream.
  5. Write a Python driver on the ARM that tiles, transfers and runs each layer.
  6. Run the model end to end, profile time spent in DMA versus compute, and tune.

Deliverables

  • RTL for PE, array, controller and AXI wrappers
  • Python driver and tiling code
  • cocotb tests and an end-to-end accuracy check
  • Performance report: achieved GOPS, utilization and bottleneck analysis

How you know it works

  • Bit-exact results against the NumPy int8 model
  • Achieved throughput as a share of peak on large GEMMs (e.g. > 60%)
  • Speed-up over the ARM core running the same layers (e.g. > 10x)
  • Model accuracy unchanged from the software int8 version

Tools

Open-source Verilator, cocotb, Python (NumPy), PYNQ, hls4ml for comparison

Industry AMD Vivado, AMD Vitis and Vitis AI, Intel Quartus

Before you start

  • An RTL matrix engine (project 2) and int8 quantization
  • AXI4-Lite and AXI-Stream
  • Linux and Python basics

Go further

  • Add weight double-buffering so DMA overlaps compute
  • Scale to 16 x 16 and study the memory bandwidth limit

Watch out for

  • Reporting peak GOPS only, while real throughput is limited by DMA
  • Overflowing int32 accumulators or rounding differently from the software model

Resume line Integrated an int8 systolic GEMM engine on Zynq with AXI DMA, reaching X GOPS (Y% of peak) and a Zx speed-up over the ARM core.

Proves: Architecture / AI hardwareFPGARTL design

041Single-Phase Smart Energy MeterMeasure voltage, current, real power and energy on a single-phase load safely, and publish readings to a dashboard.EmbeddedIntermediate4-6 wks

Goal. Build a calibrated single-phase meter that reports Vrms, Irms, real power, power factor and kWh. Compare its readings against a reference meter.

Specification

  • Mains: 230 V, 50 Hz; voltage sensed through a step-down AC transformer, never a direct connection
  • Current sensed with a split-core clamp CT (e.g. 30 A range) with burden resistor
  • Sampling at e.g. 4 kHz per channel (80 samples per 50 Hz cycle) on an STM32 or ESP32 ADC
  • Computed values: Vrms, Irms, real power, apparent power, power factor and cumulative kWh
  • Energy stored in flash or FRAM every few minutes to survive power cuts
  • Readings sent over MQTT every e.g. 10 s to a dashboard

Steps

  1. Design the isolated front end: transformer, CT, burden and DC bias, with a fuse on the primary.
  2. Sample both channels with a timer-triggered ADC and DMA so samples are evenly spaced.
  3. Compute RMS and real power per cycle, and correct phase delay between the channels.
  4. Calibrate gain and phase against a known resistive load and a reference meter.
  5. Add non-volatile energy storage and MQTT publishing.
  6. Test with resistive, inductive (fan) and electronic (phone charger) loads.

Deliverables

  • Schematic with isolation and safety notes
  • Firmware with sampling, metering and MQTT code
  • Calibration procedure and accuracy table per load type
  • Dashboard screenshot over a 24-hour run

How you know it works

  • Real power error against a reference meter (e.g. < 2% on resistive loads)
  • Power factor readings sensible for inductive loads (e.g. within 0.05 of reference)
  • No lost energy count after a power cut
  • 24-hour run with no resets or missed reports

Tools

Open-source GCC (arm-none-eabi), FreeRTOS, Eclipse Mosquitto, Python, KiCad

Industry Keil MDK, IAR Embedded Workbench, STM32CubeIDE

Before you start

  • AC circuit basics (RMS, phase, power factor)
  • C on a microcontroller
  • ADC and timer configuration

Go further

  • Replace the custom math with a metering IC such as ADE7953 and compare results
  • Add harmonic analysis with an FFT

Watch out for

  • Touching or probing the mains side without isolation; work with a mentor present
  • Sampling with software delays instead of a timer, which corrupts RMS and power values

Resume line Built a calibrated single-phase smart energy meter reporting real power within X% of a reference meter and publishing over MQTT.

Proves: Embedded

042RS-485 Modbus Industrial Data LoggerLog 4-20 mA sensors and Modbus RTU devices to an SD card with timestamps, surviving power cuts without corrupting data.EmbeddedIntermediate4-6 wks

Goal. Build a logger that polls Modbus RTU devices and analog loop sensors, timestamps every sample and writes safe CSV files. Prove it loses no data across power cuts.

Specification

  • Modbus RTU master on RS-485 at e.g. 9600 or 19200 baud, polling up to 8 slave devices
  • Two 4-20 mA inputs read across a 150 ohm shunt (0.6-3.0 V) into a 12-bit ADC
  • Battery-backed RTC for timestamps; log interval configurable, e.g. 1 s
  • microSD card with FAT file system, one CSV file per day
  • Hardware watchdog and brown-out detection
  • FreeRTOS tasks for polling, logging and a USB or UART console

Steps

  1. Build the RS-485 interface and test it against a Modbus slave simulator on a PC.
  2. Write the Modbus RTU master with CRC-16 checks, timeouts and retries.
  3. Add the 4-20 mA inputs and scale readings to engineering units, flagging open loops below 3.8 mA.
  4. Write a logging task that buffers samples and syncs the file at a set interval.
  5. Add the watchdog, brown-out handling and a console for configuration.
  6. Run a long test with random power cuts and check file integrity afterwards.

Deliverables

  • Schematic and firmware repo
  • Modbus test logs with CRC error and timeout counts
  • Power-cut test report with file integrity results
  • Sample CSV files and a plotting script

How you know it works

  • No corrupted files after repeated power cuts (e.g. 50 of 50 cuts)
  • Data loss limited to the sync window (e.g. < 10 s of samples per cut)
  • Modbus poll success rate in a long run (e.g. > 99.9% over 72 hours)
  • Loop current accuracy (e.g. within 0.1 mA)

Tools

Open-source GCC (arm-none-eabi), FreeRTOS, FatFs, OpenOCD, Python (pymodbus) as slave simulator

Industry Keil MDK, IAR Embedded Workbench, STM32CubeIDE

Before you start

  • UART and SPI on a microcontroller
  • C programming with interrupts
  • Basic RTOS concepts

Go further

  • Add Modbus TCP over Ethernet
  • Add an isolated RS-485 front end and surge protection

Watch out for

  • Writing every sample straight to the SD card, which wears it and blocks other tasks
  • Missing the 3.5-character silent gap that frames Modbus RTU messages

Resume line Built a FreeRTOS Modbus RTU and 4-20 mA logger that ran X hours at Y% poll success, with no file corruption across Z power cuts.

Proves: Embedded

043Edge AI Person-Detection CameraRun a quantized person-detection model on a microcontroller camera board and report only events, not video.EmbeddedIntermediate4-6 wks

Goal. Deploy an int8 person-detection model on a microcontroller with a camera and measure latency, accuracy and power. Send only detection events over the network.

Specification

  • Board: e.g. ESP32-S3 with an OV2640 camera, or an STM32 board with a camera module
  • Model: int8 person detection on 96 x 96 grayscale images, as in the TensorFlow Lite Micro example
  • Pipeline: capture, downscale, convert to grayscale, infer, threshold
  • Event output over MQTT with a timestamp and confidence; optional thumbnail
  • Memory budget stated: model in flash, tensor arena in RAM or PSRAM
  • Power measured in active and idle states

Steps

  1. Build and run the TensorFlow Lite Micro person-detection example on the board.
  2. Write your own camera capture and preprocessing, and check images by dumping them to a PC.
  3. Measure inference latency and tensor arena size, and tune the arena.
  4. Collect a small local test set (e.g. 200 images) and measure accuracy on it.
  5. Add MQTT event reporting with debounce so one person creates one event.
  6. Measure current with a USB power meter and add a low-power idle mode.

Deliverables

  • Firmware repo with build instructions
  • Latency, memory and power table
  • Local test set results with a confusion matrix
  • Demo video showing events on a dashboard

How you know it works

  • Inference latency per frame (e.g. < 500 ms)
  • Accuracy on your local test set (e.g. > 85%)
  • Average current in idle mode (e.g. reduced by 50% versus always-on)
  • False events per hour in an empty room (e.g. < 1)

Tools

Open-source ESP-IDF, TensorFlow Lite for Microcontrollers, Python, Eclipse Mosquitto

Industry STM32Cube.AI, Edge Impulse, Keil MDK

Before you start

  • C or C++ on microcontrollers
  • Basic neural network concepts
  • Wi-Fi and MQTT basics

Go further

  • Retrain the model on your own images with transfer learning
  • Add a PIR sensor to wake the camera only on motion

Watch out for

  • Testing accuracy only on the model's original dataset, not on your real camera images
  • Running out of RAM because the tensor arena size was guessed

Resume line Deployed an int8 person-detection model on a microcontroller camera with X ms latency and Y% accuracy on a local test set, reporting events over MQTT.

Proves: EmbeddedArchitecture / AI hardware

044LoRa Soil-Moisture Irrigation ControllerBuild a solar-powered field node that reads soil moisture and temperature, controls a valve and reports over LoRa.EmbeddedBeginner3-5 wks

Goal. Make a battery node that waters a plot by soil-moisture thresholds and sends readings over LoRa to a gateway. Show measured sleep current and battery life.

Specification

  • Sensors: capacitive soil moisture probe (analog) and DS18B20 temperature sensor (1-Wire)
  • Actuator: 12 V solenoid valve through a logic-level MOSFET with a flyback diode
  • Radio: LoRa module such as SX1276 at 865-867 MHz (India band), one packet every e.g. 15 min
  • Control: hysteresis between two thresholds, plus a maximum watering time
  • Power: Li-ion cell with a small solar panel and charger
  • Sleep current target e.g. < 100 uA between readings

Steps

  1. Calibrate the moisture probe in dry soil and in saturated soil, and map readings to 0-100%.
  2. Write the control logic with hysteresis and a watering timeout.
  3. Add the LoRa link and a receiver node that prints or stores packets.
  4. Put the microcontroller and sensors into deep sleep and measure current with a multimeter.
  5. Run the node outdoors for a week and log packet delivery and battery voltage.
  6. Add simple commands from the gateway to change thresholds.

Deliverables

  • Schematic and firmware
  • Calibration data for the moisture probe
  • Week-long log of moisture, watering events and battery voltage
  • Current measurements and a battery-life estimate

How you know it works

  • Packet delivery ratio over a week (e.g. > 95%)
  • Sleep current (e.g. < 100 uA)
  • Moisture held within the target band (e.g. 40-60%)
  • No overwatering when the sensor is unplugged (timeout works)

Tools

Open-source Arduino IDE or PlatformIO, ESP-IDF or GCC, Python, KiCad

Industry Keil MDK, STM32CubeIDE, IAR Embedded Workbench

Before you start

  • Basic C and microcontroller GPIO and ADC
  • Simple electronics (MOSFET switching)

Go further

  • Add a LoRaWAN gateway and The Things Network-style network server
  • Use weather data to skip watering before rain

Watch out for

  • Using a resistive moisture probe that corrodes in weeks
  • Leaving sensors powered during sleep, which drains the battery

Resume line Built a solar LoRa irrigation node with X uA sleep current and Y% packet delivery over a week of outdoor testing.

Proves: Embedded

0454S Li-ion Battery Management SystemDesign an EV-style BMS for a 4-cell Li-ion pack: cell monitoring, protection, balancing, state of charge and CAN reporting.EmbeddedAdvanced8-10 wks

Goal. Build a BMS for a 4S pack that protects cells, balances them and estimates state of charge. Report status over CAN and prove each protection trips correctly.

Specification

  • Pack: 4 cells in series (4S), e.g. 18650 NMC, about 16.8 V maximum
  • Analog front end: a 3-5 cell monitor IC such as TI BQ76920, read over I2C
  • Protection thresholds from the cell datasheet, e.g. 4.20 V over-voltage and 2.80 V under-voltage
  • Over-current and short-circuit protection with a shunt and charge/discharge MOSFETs
  • Passive balancing when cell spread exceeds e.g. 20 mV during charge
  • SOC by coulomb counting with OCV correction at rest; CAN messages at 500 kbit/s

Steps

  1. Start with a resistor-ladder cell emulator instead of real cells, so faults are safe to inject.
  2. Bring up the AFE: read cell voltages, pack current and NTC temperatures.
  3. Write the protection state machine with delays and latched faults, and test every trip.
  4. Add passive balancing and log cell spread during charge.
  5. Implement coulomb counting and OCV correction, then compare SOC with a full discharge test.
  6. Define CAN messages and decode them on a PC with a USB-CAN adapter.
  7. Move to real cells only with a fuse, a fire-safe container and supervision.

Deliverables

  • Schematic, firmware and protection state diagram
  • Fault injection test report for every protection
  • SOC accuracy plot over a full discharge
  • CAN message definition (DBC-style table)

How you know it works

  • Every protection trips at its threshold (e.g. within 10 mV and within its set delay)
  • Cell voltage accuracy against a multimeter (e.g. +/- 10 mV)
  • SOC error over a full cycle (e.g. < 5%)
  • Cell spread after balancing (e.g. < 20 mV)

Tools

Open-source GCC (arm-none-eabi), FreeRTOS, OpenOCD, Python (python-can), KiCad

Industry Keil MDK, IAR Embedded Workbench, MATLAB and Simulink, Vector CANoe

Before you start

  • Battery basics (cell voltage, capacity, C-rate)
  • I2C and CAN on a microcontroller
  • State machine design in C

Go further

  • Add an equivalent-circuit model and a Kalman filter for SOC
  • Add active balancing and compare efficiency

Watch out for

  • Testing faults on real cells first; use an emulator, then real cells with a fuse
  • Ignoring current-sense offset, which makes coulomb-counting SOC drift

Resume line Designed a 4S Li-ion BMS with AFE-based monitoring, passive balancing and CAN reporting, achieving X% SOC error and verified trips for Y fault cases.

Proves: Embedded

046Smart Parking Occupancy SystemDetect car presence in parking bays with distance sensors and show live free-slot counts on a web dashboard.EmbeddedBeginner2-4 wks

Goal. Build a set of sensor nodes that detect bay occupancy reliably and report it within seconds. Show free slots on a dashboard and on an entry display.

Specification

  • 3-6 bays, each with a VL53L0X time-of-flight sensor or an HC-SR04 ultrasonic sensor
  • ESP32 nodes publishing occupancy over MQTT on Wi-Fi
  • Debounce: a bay changes state only after e.g. 3 consistent readings
  • Dashboard showing per-bay state and total free slots
  • Entry display (e.g. a small OLED or 7-segment) with the free count
  • Report latency target e.g. < 2 s from car arrival

Steps

  1. Mount one sensor over a test bay and log distances for empty and occupied states.
  2. Choose thresholds and debounce rules from the logged data.
  3. Write node firmware that publishes state changes and a periodic heartbeat over MQTT.
  4. Set up a Mosquitto broker and a simple web or Python dashboard.
  5. Add the entry display that subscribes to the free-slot count.
  6. Test with a toy car model or a real bay, and log false detections.

Deliverables

  • Node firmware and dashboard code
  • Sensor log and threshold choice explained
  • Test log with detection accuracy
  • Demo video

How you know it works

  • Detection accuracy over many arrivals (e.g. > 95% of 100 events)
  • Update latency (e.g. < 2 s)
  • Offline nodes shown on the dashboard within a heartbeat window (e.g. 30 s)

Tools

Open-source Arduino IDE or PlatformIO, ESP-IDF, Eclipse Mosquitto, Python

Industry Keil MDK, STM32CubeIDE

Before you start

  • Basic C or Arduino programming
  • Wi-Fi and I2C basics

Go further

  • Add licence-plate reading at the entry with a camera
  • Run nodes on battery with deep sleep between checks

Watch out for

  • Using a single raw reading, so passing people or objects trigger false states
  • No heartbeat, so a dead node looks like an empty bay

Resume line Built an ESP32 and MQTT parking occupancy system with X% detection accuracy and under Y s update latency across Z bays.

Proves: Embedded

047Wearable Heart-Rate, SpO2 and ECG MonitorAcquire ECG and PPG signals, filter them in firmware, compute heart rate and SpO2, and stream results to a phone over BLE.EmbeddedIntermediate4-6 wks

Goal. Build a battery-powered vital-sign monitor that computes heart rate from ECG and PPG and estimates SpO2. Compare results with a commercial pulse oximeter. This is a learning project, not a medical device.

Specification

  • ECG front end such as AD8232 sampled at e.g. 250-500 Hz by a 12-bit ADC
  • PPG and SpO2 sensor such as MAX30102 over I2C
  • Digital filters: 0.5-40 Hz band-pass and a 50 Hz notch for Indian mains
  • R-peak detection (e.g. Pan-Tompkins) for heart rate
  • BLE streaming to a phone app or a PC script
  • Battery power only while connected to a person (no mains connection)

Steps

  1. Read raw ECG and PPG data and plot it on a PC to check signal quality.
  2. Design the filters in Python, then port them to fixed-point C and compare outputs.
  3. Implement R-peak detection and heart-rate averaging.
  4. Compute SpO2 from the red and IR ratio and calibrate against a commercial oximeter.
  5. Stream values over BLE and display them on a phone or PC.
  6. Test at rest and after light exercise, and record the error.

Deliverables

  • Schematic and firmware
  • Filter design notebook and C implementation
  • Comparison table against a commercial pulse oximeter
  • Clear safety and not-a-medical-device statement in the README

How you know it works

  • Heart-rate error against a reference device (e.g. within +/- 5 bpm)
  • SpO2 error at rest (e.g. within +/- 3%)
  • 50 Hz noise visibly removed (e.g. > 30 dB reduction at 50 Hz)
  • Battery life measured (e.g. > 8 hours streaming)

Tools

Open-source GCC (arm-none-eabi) or ESP-IDF, Zephyr RTOS, Python (SciPy), nRF Connect app

Industry Keil MDK, IAR Embedded Workbench, MATLAB

Before you start

  • Basic signals and filters
  • I2C, ADC and BLE on a microcontroller
  • C programming

Go further

  • Add arrhythmia flags based on RR-interval variation
  • Estimate respiration rate from PPG baseline changes

Watch out for

  • Powering the board from a mains adapter while electrodes touch a person
  • Designing filters in floating point and never checking the fixed-point version

Resume line Built a BLE vital-sign monitor with ECG and PPG processing that tracked heart rate within X bpm and SpO2 within Y% of a commercial oximeter.

Proves: Embedded

048Quadcopter Flight Controller FirmwareWrite flight-controller firmware from scratch: IMU fusion, cascaded PID loops and motor mixing, tested safely on a test rig first.EmbeddedAdvanced10-14 wks

Goal. Stabilize a small quadcopter in angle mode with your own firmware. Show attitude estimates, loop timing and step responses from logged flight or rig data.

Specification

  • MCU: e.g. STM32F4 at 168 MHz with an MPU-6050 or ICM-42688-P IMU over SPI or I2C
  • Attitude estimation with a complementary or Mahony filter at e.g. 1 kHz
  • Cascaded control: outer angle loop and inner rate loop PID
  • Motor output to ESCs using standard PWM or DShot600
  • RC input via PPM or SBUS; failsafe disarm on signal loss
  • Telemetry logging over UART or to flash for tuning

Steps

  1. Read the IMU at a fixed rate with a timer interrupt and check loop timing with a logic analyzer.
  2. Implement the attitude filter and compare it with a reference by rotating the board by hand.
  3. Write the rate loop and motor mixer, and test on a single-axis rig with props mounted safely.
  4. Add the angle loop and tune on the rig using logged step responses.
  5. Add arming checks, RC failsafe and low-battery cut-off.
  6. Fly in an open area with prop guards, starting with low throttle limits.
  7. Compare your logs with Betaflight or PX4 running on the same frame.

Deliverables

  • Firmware repo with module structure (drivers, estimation, control, mixer)
  • Loop timing measurements and jitter plot
  • Rig and flight logs with step response plots
  • Safety checklist and failsafe test results

How you know it works

  • Control loop jitter (e.g. < 10 us at 1 kHz)
  • Attitude hold error in hover (e.g. within +/- 2 degrees)
  • Failsafe disarms within a set time after signal loss (e.g. < 1 s)
  • Step response overshoot on the rig (e.g. < 15%)

Tools

Open-source GCC (arm-none-eabi), OpenOCD, FreeRTOS (optional), Python (Matplotlib), Betaflight or PX4 for comparison

Industry Keil MDK, IAR Embedded Workbench, MATLAB and Simulink

Before you start

  • PID control and basic rigid-body dynamics
  • Timers, interrupts and SPI on an MCU
  • IMU basics

Go further

  • Add a barometer altitude hold
  • Run attitude estimation as an EKF and compare with the complementary filter

Watch out for

  • Testing with props on at the bench; use a rig or remove props until failsafe is proven
  • Running the control loop from a busy main loop instead of a fixed-rate timer

Resume line Wrote quadcopter flight firmware with IMU fusion and cascaded PID at X kHz, holding attitude within Y degrees with under Z us loop jitter.

Proves: Embedded

049Secure Industrial IoT Gateway (Modbus to MQTT)Bridge Modbus field devices to a cloud broker over mutually authenticated TLS, with buffering during network outages.EmbeddedIntermediate5-7 wks

Goal. Build a Linux-based gateway that polls Modbus devices and publishes to MQTT over TLS with client certificates. Prove it loses no data during a network outage.

Specification

  • Hardware: e.g. a Raspberry Pi or other Linux board with an RS-485 adapter and Ethernet
  • Southbound: Modbus RTU and Modbus TCP, polling e.g. 16 devices every 1 s
  • Northbound: MQTT over TLS 1.2 or 1.3 with X.509 client certificates (mutual TLS)
  • Store-and-forward queue on disk with a size limit and ordered replay
  • Device map in a YAML or JSON config file; no code change to add a device
  • Runs as a systemd service with logs and automatic restart

Steps

  1. Set up a local Mosquitto broker with a private CA, server and client certificates.
  2. Write the Modbus poller with timeouts and per-device error counters.
  3. Publish values as JSON on a clear topic structure with timestamps and quality flags.
  4. Add the disk-backed queue and replay on reconnect in time order.
  5. Harden the gateway: non-root service user, firewall rules, no default passwords.
  6. Test outages by unplugging the uplink for an hour and check for gaps.

Deliverables

  • Gateway source code and config format
  • Certificate setup script and security notes
  • Outage test report with message counts before and after
  • Topic and payload documentation

How you know it works

  • Zero lost messages after an outage (e.g. 1-hour outage, 100% replayed in order)
  • Broker rejects a client without a valid certificate
  • Poll cycle stays on time with all devices (e.g. 16 devices at 1 s)
  • Gateway CPU use measured (e.g. < 20% on the board)

Tools

Open-source Python (pymodbus, paho-mqtt) or C, Eclipse Mosquitto, OpenSSL, systemd, Node-RED for dashboards

Industry AWS IoT Core or Azure IoT Hub, Commercial industrial gateway SDKs

Before you start

  • Linux command line and networking
  • Modbus basics (project 42 helps)
  • Python or C

Go further

  • Add OTA updates with signed images
  • Add OPC UA as a second northbound protocol

Watch out for

  • Disabling certificate verification to make TLS work quickly
  • Unbounded queue that fills the disk during a long outage

Resume line Built a Modbus-to-MQTT gateway with mutual TLS and store-and-forward that replayed X% of messages after a 1-hour outage while polling Y devices per second.

Proves: Embedded

050Vibration-Based Predictive Maintenance NodeMeasure machine vibration, extract FFT and statistical features on the node, and flag faults such as imbalance before failure.EmbeddedIntermediate4-6 wks

Goal. Build a sensor node that computes vibration features on-device and detects an induced fault on a small fan or motor. Send compact features, not raw data.

Specification

  • Accelerometer: e.g. ADXL345 over SPI at 3200 Hz output data rate (about 1.6 kHz bandwidth)
  • Frames of 1024 samples, windowed, with FFT using CMSIS-DSP on an ARM Cortex-M4
  • Features: RMS, peak, crest factor, kurtosis and energy in bands around 1x and 2x running speed
  • Anomaly score against a baseline learned from healthy runs
  • Report features every e.g. 60 s over BLE, LoRa or MQTT
  • Test rig: a small fan or DC motor with a removable imbalance weight

Steps

  1. Collect raw vibration from the healthy rig and plot spectra on a PC.
  2. Add a known imbalance (a small weight on one blade) and record how the spectrum changes.
  3. Implement windowing, FFT and feature extraction on the MCU and match the PC results.
  4. Build a baseline from healthy runs and a simple anomaly score (e.g. z-score or Mahalanobis distance).
  5. Report features and alarms over the radio link.
  6. Run healthy and faulty trials and measure detection and false alarm rates.

Deliverables

  • Firmware with DSP and feature code
  • PC notebook comparing on-device and PC features
  • Spectra for healthy and faulty states
  • Trial results with detection and false alarm rates

How you know it works

  • On-device features match PC features (e.g. within 1%)
  • Imbalance detected in trials (e.g. > 90% of faulty runs)
  • False alarms on healthy runs (e.g. < 5%)
  • Processing time per frame (e.g. < 20 ms on the MCU)

Tools

Open-source GCC (arm-none-eabi), CMSIS-DSP, FreeRTOS, Python (NumPy, SciPy)

Industry Keil MDK, STM32Cube.AI, Edge Impulse, MATLAB

Before you start

  • FFT and windowing basics
  • SPI and DMA on a microcontroller
  • Basic statistics

Go further

  • Train a small anomaly model and deploy it with TensorFlow Lite Micro
  • Add bearing fault bands using envelope analysis

Watch out for

  • Sampling below twice the frequency of interest, so fault tones alias
  • Testing only one healthy run, so normal variation looks like a fault

Resume line Built a predictive maintenance node that computed FFT features on-device in X ms and detected induced imbalance in Y% of trials with Z% false alarms.

Proves: Embedded

051Five-Stage Pipelined RV32I CPUA classic IF-ID-EX-MEM-WB RV32I pipeline with forwarding and hazard detection, the core every architecture interview asks you to draw.ArchitectureIntermediate6-8 wks

Goal. Build a 5-stage RV32I core that passes the official rv32ui riscv-tests and runs a C program compiled with GCC. Report CPI and explain every stall it takes.

Specification

  • ISA: RV32I (37 instructions plus FENCE, ECALL and EBREAK as traps or NOPs), little-endian, 32 x 32-bit registers, x0 hardwired to zero
  • Pipeline: IF, ID, EX, MEM, WB with full EX-to-EX and MEM-to-EX forwarding
  • Hazards: 1-cycle load-use stall; branches resolved in EX with a 2-cycle flush and static not-taken prediction
  • Memory: separate single-cycle instruction and data memories (Harvard), byte enables for SB/SH/LB/LBU/LH/LHU
  • Performance counters: cycle, instret and stall-cause counters readable from a debug port
  • Timing target: e.g. 50 MHz on SKY130 after Yosys/OpenSTA, or 100 MHz on an Artix-7 FPGA

Steps

  1. Write a single-cycle RV32I model first, then draw the pipeline diagram with every pipeline register field listed.
  2. Implement IF and ID with the register file reading on the falling edge or with WB-to-ID bypass.
  3. Add EX and the forwarding unit; test back-to-back ADDs that depend on each other.
  4. Add the hazard detection unit for load-use and the flush logic for taken branches and JAL/JALR.
  5. Run the rv32ui riscv-tests in Verilator and compare a commit trace against Spike line by line.
  6. Compile Dhrystone or CoreMark with riscv-gnu-toolchain, run it and break CPI into load-use and branch stalls.
  7. Synthesize with Yosys and find the critical path with OpenSTA; note whether forwarding muxes or the ALU limit fmax.

Deliverables

  • RTL with a pipeline block diagram and a hazard table in the README
  • Script that runs all rv32ui tests and prints pass/fail
  • Spike-vs-RTL commit-trace diff tool
  • Report with CPI breakdown, cell area and fmax

How you know it works

  • All rv32ui-p tests pass, e.g. 100%, with the test-env CSR writes stubbed as NOPs or the env macros patched
  • CPI on Dhrystone e.g. below 1.3
  • Zero mismatches against the Spike trace over e.g. 1 million committed instructions
  • fmax e.g. at least 50 MHz in SKY130 typical corner

Tools

Open-source Verilator, Icarus Verilog, GTKWave, riscv-gnu-toolchain (GCC), Spike, Yosys, OpenSTA

Industry Synopsys VCS, Cadence Xcelium, Synopsys Design Compiler, AMD Vivado

Before you start

  • Verilog RTL and testbenches
  • RISC-V instruction encoding
  • Pipelining and data hazards (Patterson and Hennessy level)

Go further

  • Add the Zicsr extension and machine-mode traps
  • Add the M extension with a multi-cycle divider and measure the CPI impact

Watch out for

  • Forgetting that x0 must never be forwarded as a non-zero value
  • Flushing the wrong stages on JALR, which computes its target from a forwarded register

Resume line Designed a 5-stage pipelined RV32I core with full forwarding that passed all rv32ui riscv-tests and achieved a CPI of X on Dhrystone at Y MHz.

Proves: RTL designArchitecture / AI hardwareVerification

052Dual-Issue In-Order Superscalar CoreExtend a scalar RV32I pipeline to issue two instructions per cycle and measure how much IPC real code actually gains.ArchitectureAdvanced8-10 wks

Goal. Build a 2-wide in-order RV32I core with pairing rules, a 4-read 2-write register file and cross-pipe forwarding. Show the measured IPC against the scalar baseline.

Specification

  • Fetch 64 bits (two instructions) per cycle from an aligned instruction memory
  • Pipe A: ALU, branch and load/store; Pipe B: ALU only (an asymmetric design, like many embedded dual-issue cores)
  • Pairing rules: no RAW dependency inside the pair, at most one memory op, branch only in the older slot
  • Register file: 4 read ports and 2 write ports; younger write wins on a same-destination pair
  • Forwarding network covers both pipes from EX and MEM (up to 4 sources per operand)
  • Counters: dual-issue cycles, single-issue cycles by reason, stall cycles

Steps

  1. Start from a verified 5-stage scalar core and freeze it as the baseline.
  2. Write the pairing checker as a pure combinational block and unit-test it with every hazard pair.
  3. Widen fetch and decode; add a 1-entry skid buffer for the instruction that could not pair.
  4. Build the 4R2W register file and the extended forwarding muxes; fix write-after-write ordering inside a pair.
  5. Run riscv-tests and a random instruction stream with a Spike trace compare.
  6. Measure IPC on Dhrystone, CoreMark and a matrix multiply; log which pairing rule blocks dual issue most often.
  7. Synthesize both cores and compare area and fmax to judge the IPC-per-area trade-off.

Deliverables

  • RTL for the dual-issue core and the scalar baseline
  • Pairing-rule table and a histogram of single-issue reasons
  • Random-instruction test generator and trace-compare script
  • Report comparing IPC, area and fmax of the two cores

How you know it works

  • All rv32ui riscv-tests pass in both cores
  • IPC improvement over scalar e.g. 20-35% on CoreMark
  • Dual-issue rate e.g. above 30% of cycles
  • fmax loss versus scalar e.g. under 15%

Tools

Open-source Verilator, Spike, riscv-gnu-toolchain (GCC), Yosys, OpenSTA, Python

Industry Synopsys VCS, Cadence Xcelium, Synopsys Design Compiler, Cadence Genus

Before you start

  • A working 5-stage pipelined core
  • Data hazards and forwarding
  • Constrained-random testing basics

Go further

  • Make both pipes symmetric and measure the extra area
  • Let the compiler help: reorder code with -O2 vs -O0 and compare dual-issue rate

Watch out for

  • Pairing a load with a dependent ALU op in the same cycle
  • Testing only with directed tests, which never hit the rare double-forward cases

Resume line Extended an RV32I core to dual-issue in-order with a 4R2W register file and 2-pipe forwarding, raising CoreMark IPC by X% for Y% more area.

Proves: RTL designArchitecture / AI hardwareVerification

053Gshare and Tournament Branch PredictorCompare bimodal, gshare and tournament predictors in a trace-driven simulator, then build the winner with a BTB in RTL.ArchitectureIntermediate4-6 wks

Goal. Measure mispredictions per kilo-instruction for three predictors on real traces. Then add gshare and a BTB to a pipelined core and measure the CPI gain.

Specification

  • Bimodal: 1024 entries of 2-bit saturating counters indexed by PC[11:2]
  • Gshare: 10-bit global history XORed with PC[11:2], 1024 counters
  • Tournament: bimodal plus gshare with a 2-bit chooser table
  • BTB: 64-entry direct-mapped with tag, target and valid bit, looked up in IF
  • Return address stack: 8 entries for JAL/JALR call and return
  • Also compare all three at an equal storage budget, e.g. 4 Kbit each, by resizing their tables

Steps

  1. Collect branch traces (PC, taken, target) from Spike running CoreMark, Dhrystone and a sort program.
  2. Write a Python or C++ trace simulator for bimodal, gshare and tournament predictors.
  3. Sweep table size and history length; plot MPKI against storage bits.
  4. Implement gshare, BTB and RAS in RTL with speculative history update and repair on mispredict.
  5. Integrate into a 5-stage core so IF redirects on a predicted-taken BTB hit.
  6. Check the RTL predictor's decisions against the software model on the same trace.

Deliverables

  • Trace simulator with plots of MPKI vs storage
  • Predictor RTL with a self-checking cocotb test against the Python model
  • Integrated core with CPI before and after
  • Short write-up on aliasing and history length

How you know it works

  • MPKI reduction of gshare over bimodal e.g. 20% or more on CoreMark
  • RTL vs model agreement e.g. 100% on 1 million branches
  • Core CPI improvement e.g. 0.1 or more versus static not-taken
  • Return prediction accuracy e.g. above 95% with the RAS

Tools

Open-source Python, Spike, Verilator, cocotb, gem5 (to cross-check predictor configs)

Industry Synopsys VCS, Cadence Xcelium

Before you start

  • Pipelined CPU basics
  • Python or C++ for simulation
  • Finite state machines and saturating counters

Go further

  • Implement a small TAGE-like predictor with 3 tagged tables
  • Add a loop predictor and measure it on nested loops

Watch out for

  • Updating global history only at commit, so back-to-back branches see stale history
  • Comparing predictors with different storage budgets

Resume line Evaluated bimodal, gshare and tournament predictors on CoreMark traces and integrated a gshare+BTB+RAS unit that cut MPKI by X% and CPI by Y.

Proves: Architecture / AI hardwareRTL design

054Tomasulo Dynamic SchedulerBuild Tomasulo's algorithm in RTL: reservation stations, tag-based renaming and a common data bus that wakes up waiting instructions.ArchitectureAdvanced8-10 wks

Goal. Implement a Tomasulo scheduler for RV32IM integer instructions that issues in order and executes out of order. Show measured speedup on code with long-latency multiplies and divides.

Specification

  • Functional units: 1 ALU (1 cycle), 1 pipelined multiplier (3 cycles), 1 iterative divider (about 33 cycles), 1 load unit
  • Reservation stations: e.g. 4 for ALU, 2 for MUL, 1 for DIV, 3 load buffers
  • Register status table maps each architectural register to the tag of its producer
  • Single common data bus with fixed priority arbitration; result broadcast wakes up all matching operands
  • No reorder buffer: exceptions are imprecise, stores issue in order
  • Event log of issue, dispatch, broadcast cycle per instruction for checking

Steps

  1. Hand-simulate a 10-instruction example on paper and record the expected issue, execute and write cycles.
  2. Write a cycle-level Python model of the scheduler that prints the same table.
  3. Implement reservation stations with tag compare and wake-up logic in SystemVerilog.
  4. Add CDB arbitration and the register status table; handle a CDB result and a new issue to the same register in one cycle.
  5. Drive random dependency chains and compare final register state and per-instruction timing with the Python model.
  6. Measure cycles on a mixed MUL/DIV kernel versus an in-order pipeline that stalls on long ops.

Deliverables

  • Python cycle model and SystemVerilog RTL
  • Instruction timing tables for directed examples
  • Random-test harness with register-state compare
  • Report on speedup and the cost of CDB contention

How you know it works

  • Final register state matches the ISA model on e.g. 10,000 random programs
  • Speedup over in-order stall-on-busy e.g. 1.3x or more on a MUL/DIV-heavy kernel
  • CDB conflict rate reported, e.g. under 10% of cycles
  • Wake-up plus select path fmax e.g. at least 75 MHz on Artix-7

Tools

Open-source Python, Verilator, cocotb, GTKWave, Yosys

Industry Synopsys VCS, Cadence Xcelium, AMD Vivado

Before you start

  • Pipelined CPU design
  • RAW, WAR and WAW hazards
  • Tomasulo's algorithm from Hennessy and Patterson

Go further

  • Add a second CDB and measure the gain
  • Add a store buffer with load-store address disambiguation

Watch out for

  • Missing the same-cycle bypass when an operand is broadcast in the cycle it issues
  • Letting a stale tag overwrite the register file after a newer writer issued

Resume line Implemented a Tomasulo scheduler with 10 reservation stations and a common data bus for RV32IM, achieving Xx speedup over an in-order baseline on MUL/DIV kernels.

Proves: Architecture / AI hardwareRTL designVerification

055Out-of-Order Core with Reorder Buffer and Register RenamingA speculative out-of-order RV32I backend with a physical register file, reorder buffer and branch recovery, the structure used in modern high-performance cores.ArchitectureAdvanced12-16 wks

Goal. Build an out-of-order RV32I core that commits in order, recovers from branch mispredictions and passes riscv-tests. Report IPC and the occupancy of each queue.

Specification

  • Front-end: 1-wide fetch with gshare predictor; rename 1 instruction per cycle
  • Renaming: 32-entry RAT, 64 physical registers, free list, RAT checkpoint per in-flight branch (e.g. 4 checkpoints)
  • Reorder buffer: 32 entries, in-order commit, precise exceptions
  • Issue queue: 16 entries, oldest-ready-first select; ALU, branch, MUL and load/store units
  • Load/store queue: 8 loads and 8 stores, store-to-load forwarding, stores write memory only at commit
  • Recovery: on mispredict restore RAT checkpoint and squash younger ROB, IQ and LSQ entries

Steps

  1. Write the microarchitecture spec with structure sizes and a timing diagram for rename, issue, execute and commit.
  2. Build rename (RAT, free list) and ROB first, with in-order execution, and pass riscv-tests.
  3. Add the issue queue with wake-up and select, then let ALU ops run out of order.
  4. Add branch checkpoints and squash logic; test with mispredict-heavy code.
  5. Add the LSQ with store-to-load forwarding and memory-ordering checks.
  6. Compare every committed instruction against Spike over long random and benchmark runs.
  7. Measure IPC and ROB, IQ and LSQ occupancy; resize one structure and show the IPC sensitivity.

Deliverables

  • Microarchitecture spec document with structure sizes
  • RTL and a commit-trace checker against Spike
  • Occupancy and IPC plots for CoreMark and a memory-bound kernel
  • Sensitivity study on ROB or physical register count

How you know it works

  • All rv32ui riscv-tests pass
  • Zero Spike mismatches over e.g. 10 million committed instructions
  • IPC above the 5-stage in-order baseline, e.g. 15-30% on CoreMark
  • Recovery penalty measured, e.g. under 6 cycles from mispredict to correct fetch

Tools

Open-source Verilator, Spike, riscv-gnu-toolchain (GCC), cocotb, gem5 (to compare structure sizing), Yosys

Industry Synopsys VCS, Cadence Xcelium, Synopsys Design Compiler

Before you start

  • Tomasulo scheduling
  • A working pipelined RV32I core
  • Branch prediction
  • Trace-compare verification

Go further

  • Make rename and commit 2-wide
  • Add a memory dependence predictor (store sets) and measure replays

Watch out for

  • Freeing a physical register at rename instead of when the next writer of that architectural register commits
  • Letting a speculative store reach memory before commit

Resume line Built a speculative out-of-order RV32I core with a 32-entry ROB and 64 physical registers, matching Spike over X million instructions at Y IPC on CoreMark.

Proves: Architecture / AI hardwareRTL designVerification

056Instruction Cache with AXI4 Burst RefillA set-associative instruction cache that refills lines over AXI4 bursts, fed by a real CPU fetch stream.ArchitectureIntermediate4-6 wks

Goal. Design an 8 KB 2-way instruction cache with miss handling over an AXI4 read channel. Measure hit rate and miss penalty on real program traces.

Specification

  • Capacity 8 KB, 2-way set-associative, 32-byte lines, so 128 sets; 32-bit address split into 20-bit tag, 7-bit index, 5-bit offset
  • Replacement: 1-bit LRU per set
  • Refill: AXI4 INCR burst of 8 beats x 32 bits (ARLEN=7, ARSIZE=2); critical-word-first needs a WRAP burst instead
  • Hit latency 1 cycle with tag and data arrays read in parallel
  • FENCE.I support: invalidate all lines in 128 cycles or with a flash-clear valid array
  • Stall interface to the core: valid/ready handshake on the fetch port

Steps

  1. Write a Python cache model and run Spike PC traces through it to pick size and associativity.
  2. Draw the miss FSM: IDLE, LOOKUP, MISS_REQ, REFILL, UPDATE, and the AXI4 AR/R handshakes.
  3. Implement tag, valid and data arrays as synchronous SRAM-style memories.
  4. Connect an AXI4 memory model with programmable latency and verify bursts in cocotb.
  5. Plug the cache into a pipelined core and run CoreMark with a 20-cycle memory latency.
  6. Compare hit rate and stall cycles from RTL counters against the Python model.

Deliverables

  • Cache RTL with the miss FSM diagram
  • cocotb testbench with an AXI4 slave model and random latency
  • Hit-rate study across sizes and associativity from the Python model
  • Integrated core results with and without the cache

How you know it works

  • Hit rate on CoreMark e.g. above 98%
  • Miss penalty e.g. 8 beats + memory latency + 2 cycles, measured
  • RTL hit counters match the Python model e.g. exactly on the same trace
  • No AXI protocol violations reported by assertions

Tools

Open-source Python, Spike, Verilator, cocotb, OpenRAM SKY130 SRAM macros (optional), Yosys

Industry Synopsys VCS, Cadence Xcelium, Cadence JasperGold (AXI protocol checks)

Before you start

  • Cache organization (tag, index, offset)
  • AXI4 read channel basics
  • FSM design

Go further

  • Add a next-line prefetch buffer
  • Map data arrays onto an OpenRAM macro and run OpenLane

Watch out for

  • Returning stale data when a fetch hits the line being refilled
  • Mixing up ARLEN (beats minus one) and the beat count

Resume line Designed an 8 KB 2-way instruction cache with AXI4 burst refill that reached X% hit rate on CoreMark and cut fetch stall cycles by Y%.

Proves: RTL designArchitecture / AI hardwareVerification

057Write-Back Data Cache with Pseudo-LRUA 4-way write-back, write-allocate data cache with dirty-line eviction, byte stores and a write-back buffer.ArchitectureIntermediate5-7 wks

Goal. Build a data cache that handles loads, byte and halfword stores, dirty evictions and refills under random traffic. Measure its effect on memory traffic.

Specification

  • Capacity 16 KB, 4-way set-associative, 64-byte lines, so 64 sets
  • Policy: write-back, write-allocate; 1 dirty bit per line
  • Replacement: tree pseudo-LRU with 3 bits per set
  • Byte-enable writes for SB, SH and SW; LB/LBU/LH/LHU sign or zero extension at the core side
  • Write-back buffer of 1 line so the refill can start before the dirty line is written
  • Memory side: AXI4 burst read and write (16 beats x 32 bits)

Steps

  1. Define the FSM for hit, clean miss and dirty miss; write the timing for each case.
  2. Implement arrays, pseudo-LRU update and victim selection.
  3. Add the write-back buffer and AXI4 write channel (AW, W with WLAST, B).
  4. Build a reference memory model in cocotb and drive random loads and stores with random byte enables.
  5. Add a flush operation that writes back all dirty lines and check memory matches the model afterward.
  6. Run a matrix-transpose and a linked-list kernel; record hit rate and bytes written back.

Deliverables

  • Cache RTL and FSM diagram
  • Randomized cocotb test with scoreboard and coverage of hit/clean-miss/dirty-miss
  • Memory-traffic comparison against a write-through version
  • README with the address breakdown and timing tables

How you know it works

  • Zero scoreboard mismatches over e.g. 1 million random accesses
  • Functional coverage e.g. 100% of hit, clean-miss, dirty-miss crossed with byte sizes
  • Write traffic reduction vs write-through e.g. above 50% on a loop-heavy kernel
  • Load hit latency e.g. 1 cycle

Tools

Open-source Verilator, cocotb, Python, GTKWave, Yosys

Industry Synopsys VCS, Cadence Xcelium, Siemens Questa

Before you start

  • Instruction-cache style design
  • AXI4 read and write channels
  • Scoreboard-based testbenches

Go further

  • Make it non-blocking with 2 MSHRs (hit-under-miss)
  • Add a simple MESI snoop port for a 2-core system

Watch out for

  • Overwriting the victim line before its dirty data is captured
  • Pseudo-LRU bits updated on a miss but not on a hit

Resume line Built a 16 KB 4-way write-back cache with pseudo-LRU and AXI4 refill, verified over X million random accesses, with Y% less write traffic than write-through.

Proves: RTL designVerificationArchitecture / AI hardware

058RISC-V Sv32 MMU with TLB and Page-Table WalkerVirtual memory in hardware: a TLB and a hardware page-table walker that follow the RISC-V Sv32 specification.ArchitectureAdvanced6-8 wks

Goal. Implement an Sv32 MMU that translates virtual addresses, raises the correct page faults and runs a small test kernel with user and supervisor pages.

Specification

  • Sv32: 32-bit virtual address = VPN[1] (10 bits), VPN[0] (10 bits), 12-bit page offset; 34-bit physical address
  • Two-level page table, 4 KB pages and 4 MB megapages; satp holds MODE and root PPN
  • PTE bits V, R, W, X, U, G, A, D checked on every access
  • 16-entry fully associative TLB with ASID tag and SFENCE.VMA flush
  • Hardware walker issues up to 2 memory reads per miss
  • Faults: instruction (cause 12), load (13) and store/AMO (15) page faults with stval = faulting address

Steps

  1. Read the RISC-V privileged spec chapter on Sv32 and write the translation algorithm as Python.
  2. Build page tables in memory with a Python script, including megapages and invalid entries.
  3. Implement the TLB lookup and the walker FSM; handle the A and D bits by faulting or by hardware update (choose and document).
  4. Verify translations against the Python model with random virtual addresses.
  5. Add permission checks for U-mode and S-mode, including the SUM and MXR bits if you support them.
  6. Integrate with a core that has CSRs and run a test kernel that maps, unmaps and faults.

Deliverables

  • MMU RTL with walker FSM diagram
  • Python page-table builder and translation model
  • Directed fault tests and random translation tests
  • TLB hit-rate and walk-latency report

How you know it works

  • Translations match the Python model e.g. on 100,000 random addresses
  • Each fault cause (12, 13, 15) triggered and checked by a directed test
  • TLB hit rate on a looping kernel e.g. above 99%
  • Walk latency e.g. 2 memory reads plus 3 cycles for a 4 KB page

Tools

Open-source Python, Verilator, cocotb, Spike (as golden model with Sv32)

Industry Synopsys VCS, Cadence Xcelium, Cadence JasperGold

Before you start

  • RISC-V privileged architecture basics (CSRs, traps)
  • Cache and memory interfaces
  • A pipelined core with trap support

Go further

  • Add a 2-level TLB (L1 4-entry, L2 32-entry)
  • Boot 32-bit Linux with Sv32 paging on an FPGA SoC, as LiteX does with VexRiscv

Watch out for

  • Treating a PTE with R=0 and W=1 as valid; it is reserved and must fault
  • Not checking that a megapage PPN[0] is zero (misaligned superpage)

Resume line Implemented an Sv32 MMU with a 16-entry ASID-tagged TLB and page-table walker, matching a Python model on X translations and covering all page-fault causes.

Proves: Architecture / AI hardwareRTL designVerification

059Stride Hardware PrefetcherEvaluate next-line and PC-indexed stride prefetchers in gem5, then build the stride prefetcher in RTL next to an L1 data cache.ArchitectureIntermediate5-7 wks

Goal. Measure prefetch accuracy, coverage and timeliness for two prefetchers on memory-bound kernels, then implement and verify the better one in hardware.

Specification

  • Next-line prefetcher: on a miss to line L, fetch L+1
  • Stride prefetcher: 16-entry reference prediction table indexed by load PC, storing last address, stride and a 2-bit confidence
  • Prefetch degree 1-4 and distance configurable through CSRs
  • Prefetch buffer of 4 lines, so useless prefetches do not pollute the cache
  • Counters: prefetches issued, useful, late and useless
  • Workloads: array sum, strided matrix column walk, linked-list traversal (should not help)

Steps

  1. Run the three kernels in gem5 with and without its built-in stride prefetcher and record miss rates.
  2. Write your own trace-driven Python model and match gem5 trends.
  3. Design the RTL table, confidence FSM and prefetch request arbiter that yields to demand misses.
  4. Attach it to a data cache with a memory model of e.g. 40-cycle latency.
  5. Verify that a prefetch never returns wrong data and that demand misses keep priority.
  6. Sweep degree and distance; plot speedup, accuracy and extra memory traffic.

Deliverables

  • gem5 configuration scripts and results
  • Python trace model and RTL prefetcher
  • Plots of accuracy, coverage and timeliness per kernel
  • Short analysis of why linked lists defeat stride prefetching

How you know it works

  • Accuracy (useful/issued) e.g. above 80% on array kernels
  • Coverage (misses removed) e.g. above 60% on strided access
  • Cycle speedup e.g. 1.3x or more on the array sum
  • Extra memory traffic e.g. under 20% on linked-list traversal

Tools

Open-source gem5, Python, Verilator, cocotb

Industry Synopsys VCS, Cadence Xcelium

Before you start

  • Cache design
  • Memory latency and bandwidth basics
  • C and Python

Go further

  • Add a stream prefetcher that detects ascending and descending streams
  • Add feedback-directed throttling based on accuracy

Watch out for

  • Counting a prefetch as useful even when it arrived after the demand miss (late)
  • Training the table on prefetch hits as well as demand accesses, which corrupts the stride

Resume line Designed a PC-indexed stride prefetcher evaluated in gem5 and implemented in RTL, achieving X% accuracy and Yx speedup on strided kernels.

Proves: Architecture / AI hardwareRTL design

060RISC-V Vector (RVV Subset) SIMD UnitA 4-lane vector unit that runs a subset of the RISC-V Vector 1.0 extension, so loops like SAXPY execute in a few instructions.ArchitectureAdvanced8-10 wks

Goal. Build a vector coprocessor with VLEN=128 that executes a defined RVV subset, and show measured speedup over scalar code on SAXPY and dot product.

Specification

  • VLEN = 128 bits, 32 vector registers, SEW of 8, 16 and 32 bits, LMUL = 1 (the Zve32x embedded profile)
  • Instructions: vsetvli, vle32.v, vse32.v, vadd.vv, vsub.vv, vmul.vv, vmacc.vv, vredsum.vs, vadd.vx
  • 4 lanes of 32-bit datapath, so one 128-bit operation per cycle at SEW=32
  • Unit-stride loads and stores over a 128-bit memory port
  • Scalar core issues vector instructions into a 4-entry queue; vsetvli handled in the scalar pipe
  • Tail elements handled as tail-agnostic, with masking as a stretch

Steps

  1. Write down the supported instruction subset and encodings from the RVV 1.0 spec.
  2. Build the vector register file as 4 lane slices of 32 registers x 32 bits.
  3. Implement lane ALUs and the reduction tree for vredsum.
  4. Add the load/store unit and the instruction queue from the scalar core.
  5. Verify each instruction against Spike with a matching ISA string, e.g. --isa=rv32im_zve32x_zvl128b.
  6. Write SAXPY and dot product in assembly or with RVV intrinsics in GCC; compare cycles against scalar loops.

Deliverables

  • Supported-instruction table and lane block diagram
  • Vector unit RTL integrated with a scalar core
  • Per-instruction tests and Spike trace comparison
  • Benchmark table: cycles for scalar vs vector

How you know it works

  • Every subset instruction matches Spike e.g. on 1,000 random operand sets each
  • SAXPY speedup e.g. 3x or more over scalar for n = 1024
  • Lane utilization reported per kernel, e.g. above 70% on SAXPY
  • Correct vl handling when n is not a multiple of 4

Tools

Open-source Spike, riscv-gnu-toolchain (GCC with RVV), Verilator, cocotb, Yosys

Industry Synopsys VCS, Cadence Xcelium, Synopsys Design Compiler

Before you start

  • A working scalar RISC-V core
  • Data-level parallelism basics
  • Fixed-width arithmetic and overflow

Go further

  • Add masking (v0 mask register) and vmerge
  • Support LMUL = 2 and measure register pressure on a matrix kernel

Watch out for

  • Ignoring vl and writing past the active elements
  • Assuming the reduction result goes to every element instead of element 0 of vd

Resume line Built a 4-lane RVV 1.0 subset vector unit with VLEN=128, verified against Spike and delivering Xx speedup on SAXPY over scalar code.

Proves: Architecture / AI hardwareRTL designVerification

061INT8 CNN Inference Accelerator ASIC (SKY130)Take a small INT8 CNN from PyTorch to a placed-and-routed SKY130 layout, with a MAC array, on-chip buffers and a layer controller.AI hardwareAdvanced10-12 wks

Goal. Run LeNet-5 style MNIST inference on your accelerator in RTL simulation, bit-exact with a quantized Python model. Then close an OpenLane flow and report area, fmax and power.

Specification

  • Network: LeNet-5 style, 2 conv + 3 fully connected layers, INT8 weights and activations, INT32 accumulators
  • Compute: 8 x 8 output-stationary MAC array (64 MACs)
  • Buffers: weight and activation SRAM, e.g. OpenRAM SKY130 macros or flip-flop banks sized from the layer table
  • Layer controller: microcoded sequence of conv, ReLU, 2x2 max-pool and requantize
  • Host interface: Wishbone or AXI4-Lite registers to load weights, start and read the class
  • Target e.g. 50 MHz in SKY130 at the typical corner

Steps

  1. Train in PyTorch, quantize to INT8 and export integer weights plus per-layer scale and shift.
  2. Write a pure-integer NumPy model and confirm its accuracy matches the quantized PyTorch model.
  3. Count MACs per layer and choose tiling so each layer fits the buffers.
  4. Implement the MAC array, buffers and layer controller; verify layer by layer against NumPy with cocotb.
  5. Run full images and check the predicted class and every intermediate tensor bit-exactly.
  6. Harden with OpenLane on SKY130; report area, fmax and OpenSTA power with a VCD from one inference.
  7. Compute inferences per second and energy per inference from your numbers.

Deliverables

  • Training, quantization and NumPy golden-model scripts
  • RTL, cocotb tests and layer-by-layer compare logs
  • OpenLane run with GDS, timing and area reports
  • Report with latency, throughput and energy per inference

How you know it works

  • Bit-exact match with the NumPy model on e.g. 1,000 test images
  • Accuracy drop from FP32 to INT8 e.g. under 1%
  • Clean DRC and LVS in OpenLane
  • MAC array utilization e.g. above 70% on conv layers

Tools

Open-source PyTorch, NumPy, Verilator, cocotb, Yosys, OpenLane, OpenROAD, OpenSTA, OpenRAM SKY130 macros

Industry Synopsys VCS, Synopsys Design Compiler / Fusion Compiler, Cadence Innovus, Synopsys PrimeTime

Before you start

  • CNN basics (convolution, pooling)
  • Fixed-point and INT8 quantization
  • RTL design and cocotb
  • RTL-to-GDS flow basics

Go further

  • Add zero-skipping for ReLU outputs
  • Submit a reduced version to a Tiny Tapeout or open-PDK shuttle

Watch out for

  • Rounding differently in RTL and Python (truncate vs round-half-up) so outputs drift by 1 LSB
  • Sizing the array before checking that memory bandwidth can feed it

Resume line Designed an INT8 CNN accelerator with a 64-MAC array, bit-exact with the quantized MNIST model, hardened in SKY130 at X MHz and Y mm2.

Proves: RTL designArchitecture / AI hardwarePhysical designVerification

062Transformer Attention AcceleratorCompute softmax(QK^T / sqrt(d)) V in hardware with INT8 matrix units and a fixed-point softmax, the core of every transformer layer.AI hardwareAdvanced8-12 wks

Goal. Build a single-head attention block that takes Q, K and V tiles and returns the output with a measured error versus a PyTorch FP32 reference.

Specification

  • Head dimension d = 64, sequence length up to 128, INT8 Q, K, V with INT32 accumulation
  • QK^T engine: 8 x 8 MAC tile; scaling by 1/sqrt(64) = 1/8 done as a 3-bit shift
  • Softmax: row max subtraction, exp via a 256-entry LUT or piecewise-linear table, fixed-point sum and reciprocal
  • Score buffer holds one 128-element row at a time (row-wise streaming)
  • Second engine multiplies the probability row by V and requantizes to INT8
  • AXI4-Stream input and output for Q, K, V and results

Steps

  1. Write FP32 attention in PyTorch and a fixed-point NumPy model; measure error vs bit width.
  2. Choose LUT size and fraction bits for exp and reciprocal from that error study.
  3. Implement the QK^T tile engine and verify score rows bit-exactly against NumPy.
  4. Implement the softmax unit with max-subtract; test rows with large and equal scores.
  5. Add the PV engine and requantization; run full-sequence tests with random and real (e.g. BERT-like) activations.
  6. Synthesize for an FPGA or SKY130 and report cycles per head, fmax and resources.

Deliverables

  • Fixed-point error study with plots
  • RTL for QK^T, softmax and PV engines
  • cocotb tests comparing against NumPy and PyTorch
  • Throughput and resource report

How you know it works

  • Bit-exact with the fixed-point NumPy model
  • Mean absolute error of output vs FP32 e.g. under 1% of output range
  • Softmax row sums within e.g. 1% of 1.0
  • Cycles per 128-token head reported against the ideal MAC-bound number

Tools

Open-source PyTorch, NumPy, Verilator, cocotb, Yosys

Industry AMD Vivado, Synopsys VCS, Synopsys Design Compiler, Siemens Catapult HLS (alternative route)

Before you start

  • Matrix multiply hardware (systolic or MAC array)
  • Fixed-point arithmetic
  • Transformer attention math

Go further

  • Implement online softmax so the full score row never needs storing (FlashAttention-style tiling)
  • Add causal masking

Watch out for

  • Skipping the max subtraction, which overflows the exp table
  • Measuring error only on random data, which hides the peaky distributions of real attention

Resume line Built an INT8 transformer attention accelerator (d=64, 128 tokens) with a LUT-based fixed-point softmax, within X% of FP32 and Y cycles per head.

Proves: RTL designArchitecture / AI hardwareFPGA

063Quantized Neural Processor with INT8/INT4 RequantizationA programmable processor whose datapath is built around integer-only inference: INT8/INT4 MACs and fixed-point requantization.AI hardwareIntermediate6-8 wks

Goal. Implement integer-only inference as in the TFLite scheme, with INT32 accumulation and multiplier-plus-shift requantization, and run a quantized MLP on MNIST matching the software result.

Specification

  • Data types: INT8 activations, INT8 or packed INT4 weights, INT32 accumulators
  • Requantization: acc x M0 (32-bit fixed-point multiplier) >> n, add zero-point, saturate to INT8
  • Per-channel weight scales for conv and fully connected layers
  • Small instruction set: LOAD, STORE, MAC_VEC, REQUANT, RELU, ARGMAX
  • 8 parallel MAC lanes; INT4 mode packs two weights per byte for 2x weight bandwidth
  • Model: 784-128-10 MLP

Steps

  1. Train the MLP, apply post-training quantization and dump integer weights, M0, n and zero-points.
  2. Write an integer-only Python reference that reproduces the framework's quantized outputs exactly.
  3. Define the instruction set and write the MLP program by hand.
  4. Implement the lanes, requantization unit with rounding and saturation, and the controller.
  5. Verify each instruction, then whole images, against the Python reference.
  6. Compare INT8 and INT4 accuracy, cycles and weight memory size.

Deliverables

  • Quantization and integer reference scripts
  • ISA document and hand-written MLP program
  • RTL with cocotb tests
  • Table of accuracy, cycles and memory for INT8 vs INT4

How you know it works

  • Bit-exact with the integer reference on e.g. all 10,000 MNIST test images
  • INT8 accuracy drop vs FP32 e.g. under 0.5%
  • INT4 weight memory e.g. half of INT8 with accuracy loss reported
  • Lane utilization e.g. above 85% in fully connected layers

Tools

Open-source PyTorch, NumPy, Icarus Verilog, Verilator, cocotb, Yosys

Industry Synopsys VCS, Cadence Xcelium, AMD Vivado

Before you start

  • Two's complement and fixed-point arithmetic
  • Neural network basics
  • Verilog RTL

Go further

  • Add quantization-aware training and compare INT4 accuracy
  • Add a mixed-precision mode chosen per layer

Watch out for

  • Wrong rounding of the right shift (needs round-to-nearest, not truncation) to match the reference
  • Forgetting to saturate before casting INT32 to INT8

Resume line Built an integer-only neural processor with 8 MAC lanes and fixed-point requantization, bit-exact with the quantized MNIST reference and X% accurate in INT4 mode.

Proves: RTL designArchitecture / AI hardwareVerification

064Weight-Stationary Systolic Array for GEMMA 16 x 16 weight-stationary systolic array that multiplies tiled matrices, with measured utilization and a clean RTL-to-GDS run.AI hardwareIntermediate5-7 wks

Goal. Build a parameterized systolic array, run tiled GEMM of any size through it, and show utilization, throughput and the area cost of growing the array.

Specification

  • Array size N x N, parameterized; default 16 x 16 = 256 PEs
  • PE: INT8 x INT8 multiply, INT32 accumulate, weight register, data passes right and partial sums pass down
  • Input skew and output de-skew shift registers so each row and column is aligned in time
  • Tiling controller for M x K x N matrices larger than the array
  • Peak throughput = N^2 MACs per cycle; latency for one tile about 3N cycles
  • Interface: AXI4-Stream for activations, weights and results

Steps

  1. Draw a 3 x 3 array cycle by cycle on paper to understand skew and weight loading.
  2. Write the PE and a 4 x 4 array; check it against NumPy matmul.
  3. Add skew and de-skew buffers and the weight preload path.
  4. Write the tiling controller and verify random M, K, N up to 256 with cocotb.
  5. Measure utilization including fill and drain; try double-buffered weights to hide preload.
  6. Synthesize 4x4, 8x8 and 16x16 versions with Yosys and OpenSTA, or run OpenLane, and plot area and fmax.

Deliverables

  • Parameterized PE and array RTL
  • cocotb GEMM tests with NumPy golden model
  • Utilization analysis for different matrix shapes
  • Area and fmax scaling plots

How you know it works

  • Bit-exact GEMM results for e.g. 500 random shapes
  • Utilization e.g. above 80% for 256 x 256 x 256 GEMM with double buffering
  • Peak and achieved MACs per cycle reported
  • fmax drop from 4x4 to 16x16 e.g. under 10%, because PEs only talk to neighbors

Tools

Open-source NumPy, Verilator, cocotb, Yosys, OpenSTA, OpenLane

Industry Synopsys VCS, Synopsys Design Compiler, Cadence Genus, AMD Vivado

Before you start

  • Verilog with parameters and generate blocks
  • Matrix multiplication and tiling
  • Pipelining

Go further

  • Implement output-stationary dataflow and compare utilization for small K
  • Map onto FPGA DSP slices and compare with LUT-based multipliers

Watch out for

  • Off-by-one skew so one diagonal of results is shifted
  • Ignoring the weight-load time when quoting utilization

Resume line Designed a parameterized 16x16 weight-stationary INT8 systolic array with tiling control that reached X% utilization on large GEMMs at Y MHz.

Proves: RTL designArchitecture / AI hardwarePhysical design

065Edge NPU SoC on FPGA (LiteX + RISC-V)Integrate a small NPU into a RISC-V SoC with DMA and a driver, then run a real edge model end to end on FPGA.AI hardwareAdvanced10-12 wks

Goal. Build a LiteX SoC with a VexRiscv CPU, DRAM or SRAM, a DMA engine and your NPU. Run keyword spotting or a small image classifier through a C driver and report latency.

Specification

  • SoC: LiteX with VexRiscv RV32IM, UART console, on-board DRAM controller (LiteDRAM) where the board supports it
  • NPU: e.g. 8 x 8 INT8 MAC array with 32 KB of on-chip scratchpad in BRAM
  • Control and status registers via LiteX CSR bus; data movement by a DMA master on Wishbone
  • Interrupt on layer completion
  • Workload: a small CNN for keyword spotting (e.g. Google Speech Commands, 10 words) or CIFAR-10
  • Board: any Artix-7 or ECP5 board LiteX supports

Steps

  1. Bring up a stock LiteX SoC on your board and run the BIOS and a hello-world over UART.
  2. Add the NPU as a LiteX module with CSRs and a Wishbone DMA master.
  3. Write a bare-metal C driver: load weights, start a layer, wait for the interrupt.
  4. Run each layer on the CPU and on the NPU; compare outputs byte by byte.
  5. Run the full model and measure end-to-end latency with a cycle counter.
  6. Profile time spent in DMA, compute and CPU-side ops; remove the largest bottleneck.

Deliverables

  • LiteX SoC build scripts and the NPU module
  • C driver and test application
  • Latency breakdown chart (DMA, compute, CPU)
  • Resource utilization report (LUTs, DSPs, BRAMs)

How you know it works

  • NPU output matches CPU reference e.g. on 100% of test inputs
  • End-to-end speedup over CPU-only e.g. 10x or more
  • Model accuracy on board within e.g. 1% of the quantized software model
  • Timing closed at e.g. 100 MHz system clock

Tools

Open-source LiteX, VexRiscv (via LiteX), Yosys + nextpnr for ECP5, Verilator, riscv-gnu-toolchain (GCC), PyTorch

Industry AMD Vivado, Intel Quartus, Synopsys VCS

Before you start

  • A working MAC-array or systolic accelerator
  • Bus protocols (Wishbone or AXI)
  • Embedded C and memory-mapped I/O

Go further

  • Run it under Linux with a kernel driver
  • Add clock gating and measure board power with a USB power meter

Watch out for

  • Cache coherence: the CPU reads stale results because the DMA wrote memory behind its data cache
  • Benchmarking only the NPU kernel and ignoring data movement time

Resume line Integrated an INT8 NPU with DMA into a LiteX RISC-V SoC on FPGA; keyword spotting ran at X ms, Yx faster than the CPU alone.

Proves: FPGAEmbeddedArchitecture / AI hardwareRTL design

066Sparse Matrix-Vector (CSR SpMV) AcceleratorAn accelerator for y = Ax with A in compressed sparse row format, where memory access, not arithmetic, sets the speed.AI hardwareAdvanced6-8 wks

Goal. Build a CSR SpMV engine with multiple processing lanes and show how throughput and bandwidth use change with matrix density and row-length imbalance.

Specification

  • Input format: CSR with row_ptr, col_idx (32-bit) and values (FP32 or INT16 fixed-point)
  • 4 to 8 parallel lanes, each owning a row, with an x-vector cache or banked on-chip copy
  • Streams row_ptr, col_idx and values from memory over AXI4 bursts
  • Load balancer assigns next row to the first free lane
  • Test matrices: random at 1%, 5% and 20% density, plus a few real ones from the SuiteSparse collection
  • Counters: bytes read, useful MACs, lane idle cycles, x-cache hit rate

Steps

  1. Write SpMV in Python with SciPy and compute bytes moved per useful MAC for each test matrix.
  2. Build a roofline: what bandwidth does your memory model give and what MAC rate does that allow?
  3. Implement one lane with the CSR stream reader and accumulator, then replicate it.
  4. Add the row dispatcher and output reorder so y is written in order.
  5. Verify against SciPy on all test matrices; handle empty rows.
  6. Measure achieved bandwidth and MAC rate, and compare with the roofline and a dense GEMV engine.

Deliverables

  • Python reference and roofline analysis
  • Multi-lane SpMV RTL with cocotb tests
  • Plots of throughput vs density and vs lane count
  • Comparison against dense GEMV on the same hardware budget

How you know it works

  • Results within e.g. 1e-5 relative error (FP32) or bit-exact (fixed-point) of SciPy
  • Achieved bandwidth e.g. above 70% of the memory model's peak
  • Speedup over dense GEMV e.g. above 5x at 5% density
  • Lane idle cycles e.g. under 20% on a power-law matrix

Tools

Open-source Python, SciPy, Verilator, cocotb, Yosys

Industry AMD Vivado, Synopsys VCS, Synopsys Design Compiler

Before you start

  • Sparse formats (CSR, COO)
  • AXI4 burst reads
  • Floating-point or fixed-point accumulation

Go further

  • Support 2:4 structured sparsity for DNN weights
  • Add a CSC mode and compare on tall matrices

Watch out for

  • Assuming uniform row lengths; real matrices have long rows that stall one lane
  • Floating-point summation order differs from SciPy, so exact compares fail without a tolerance

Resume line Built a multi-lane CSR SpMV accelerator that reached X% of peak memory bandwidth and Yx speedup over dense GEMV at 5% density.

Proves: Architecture / AI hardwareRTL design

067Binary Neural Network TinyML ProcessorAn ultra-low-power processor that replaces multiplies with XNOR and popcount, with power measured and cut through clock gating.AI hardwareIntermediate6-8 wks

Goal. Build a binary neural network engine (1-bit weights and activations) for a small vision or audio task. Report energy per inference from gate-level power analysis.

Specification

  • Binary layers: XNOR + popcount + threshold compare, 64 bits processed per cycle
  • First and last layers in INT8 (as most BNNs do) using a small MAC unit
  • Weights in on-chip memory, e.g. under 16 KB total
  • Clock gating per layer engine and an idle sleep state
  • Workload: binarized MLP or small CNN on MNIST
  • Target: SKY130, low clock (e.g. 10-25 MHz) for minimum energy

Steps

  1. Train a binarized network in PyTorch with a straight-through estimator; export sign weights and thresholds.
  2. Fold batch-norm into an integer threshold per neuron and check accuracy in a NumPy model.
  3. Implement the XNOR-popcount engine with a pipelined adder tree.
  4. Verify every layer bit-exactly against NumPy with cocotb.
  5. Harden with OpenLane; produce a VCD from one inference and run power analysis in OpenSTA.
  6. Add clock gating and an idle state; compare dynamic and leakage energy before and after.

Deliverables

  • BNN training and threshold-folding scripts
  • RTL and layer-level tests
  • OpenLane run and power reports before and after gating
  • Energy per inference and accuracy table

How you know it works

  • Accuracy on MNIST e.g. above 95% with binary hidden layers
  • Bit-exact match with NumPy model
  • Energy per inference reported in uJ, e.g. at least 30% lower after clock gating
  • Weight memory e.g. under 16 KB

Tools

Open-source PyTorch, NumPy, Verilator, cocotb, Yosys, OpenLane, OpenSTA (power with VCD)

Industry Synopsys Design Compiler, Cadence Genus, Cadence Voltus, Synopsys PrimePower

Before you start

  • Neural network basics
  • Verilog RTL
  • Dynamic and leakage power basics

Go further

  • Add power gating for the INT8 unit with UPF and implement it in an industry flow if you have access
  • Compare against an INT8 version of the same network for energy and accuracy

Watch out for

  • Using vectorless (default activity) power numbers instead of a real VCD
  • Forgetting the bias and batch-norm offset when computing thresholds

Resume line Designed a binary neural network processor with XNOR-popcount datapath in SKY130, reaching X% MNIST accuracy at Y uJ per inference after clock gating.

Proves: RTL designPhysical designArchitecture / AI hardware

068Streaming AI Video Pre-Processing Accelerator (720p60)A real-time video pipeline on FPGA that resizes, normalizes and runs a 3 x 3 convolution feature stage on 720p60 video using line buffers.AI hardwareAdvanced8-10 wks

Goal. Process 1280x720 at 60 frames per second in a fully streaming pipeline, with no frame buffer for the conv stage. Show live output with a motion or edge heat-map overlay.

Specification

  • Input: 1280x720 at 60 Hz, 74.25 MHz pixel clock, from HDMI input or a test-pattern generator
  • AXI4-Stream video with tuser (start of frame) and tlast (end of line)
  • Stages: RGB to grayscale, 2:1 downscale, 3 x 3 conv with programmable INT8 kernel, frame difference for motion
  • Line buffers in BRAM: 2 lines for the 3 x 3 window
  • One pixel per clock, fixed latency of a few lines
  • Output: HDMI with overlay, plus per-frame motion score in a status register

Steps

  1. Build a Python/OpenCV model of every stage and save golden output frames.
  2. Implement a test-pattern generator and the AXI4-Stream video timing.
  3. Write the grayscale and downscale stages and verify against golden frames in simulation.
  4. Build the line-buffer window generator and the 3 x 3 conv; check border handling.
  5. Add frame differencing using a downscaled frame stored in DDR or BRAM.
  6. Close timing at 74.25 MHz, run on the board and capture output to compare with Python.

Deliverables

  • Python golden model and test frames
  • Pipeline RTL with AXI4-Stream interfaces
  • Simulation compare scripts (frame in, frame out)
  • Board demo video and resource and timing report

How you know it works

  • Sustained 60 fps at 720p with zero dropped frames over e.g. 10 minutes
  • Pixel-exact match with the Python model on e.g. 20 test frames
  • Pipeline latency e.g. under 3 lines
  • Timing met at 74.25 MHz with positive slack

Tools

Open-source Python, OpenCV, Verilator, cocotb, Yosys + nextpnr (ECP5 boards)

Industry AMD Vivado, Vitis HLS, Intel Quartus

Before you start

  • AXI4-Stream
  • Video timing (sync, blanking)
  • FPGA timing closure basics
  • Convolution and image filtering

Go further

  • Add a small CNN head on the downscaled stream
  • Support 1080p60 at 148.5 MHz or with 2 pixels per clock

Watch out for

  • Wrong border handling at the first and last lines, which shows up as stripes
  • Using tlast/tuser inconsistently, so frames slip after a backpressure event

Resume line Implemented a streaming 720p60 video pre-processing and 3x3 convolution pipeline on FPGA with line buffers, pixel-exact with the Python model at X% LUT usage.

Proves: FPGARTL design

069Quantized Tiny-YOLO Object Detection on Zynq FPGADeploy a quantized Tiny-YOLO style detector on a Zynq board using HLS or FINN, with the ARM cores handling pre- and post-processing.AI hardwareAdvanced10-12 wks

Goal. Run object detection from a camera or video file on a Zynq FPGA and report frames per second and mAP. Explain where time goes between the ARM cores and the fabric.

Specification

  • Board: Zynq-7000 (e.g. PYNQ-Z2) or Zynq UltraScale+ (e.g. Kria KV260)
  • Model: Tiny-YOLO style detector at 416x416 or a smaller input such as 224x224, quantized to INT8 or lower
  • Route A: Vitis HLS conv engine with AXI4 masters to DDR; Route B: FINN dataflow build from a Brevitas-trained model
  • ARM side (Python on PYNQ or C): image resize, box decoding, non-maximum suppression
  • Dataset: Pascal VOC or a small custom dataset (e.g. 3 classes)
  • Report fps, latency, mAP@0.5 and board power

Steps

  1. Train or fine-tune the model, quantize it and measure mAP in software as the baseline.
  2. Pick a route (HLS or FINN) and justify it from resource limits on your board.
  3. Build the accelerator, generate the bitstream and check per-layer outputs against software.
  4. Write the host code for pre-processing, accelerator calls and NMS.
  5. Run on a test set and measure mAP; run on video and measure fps and latency.
  6. Profile ARM vs fabric time and move one hot step (e.g. resize) into hardware.

Deliverables

  • Training and quantization notebooks
  • HLS sources or FINN build scripts and the bitstream
  • Host application and demo video
  • Table of fps, latency, mAP, power and resources

How you know it works

  • mAP@0.5 on board within e.g. 2 points of the quantized software model
  • Throughput e.g. 10 fps or more at the chosen resolution
  • Accelerator outputs match software layer outputs e.g. bit-exactly
  • Resource use e.g. under 80% LUT and DSP so timing closes

Tools

Open-source PyTorch, Brevitas, FINN, PYNQ, OpenCV

Industry AMD Vivado, Vitis HLS, Vitis AI (alternative route)

Before you start

  • CNN and object detection basics (anchors, NMS)
  • FPGA flow in Vivado
  • HLS pragmas or dataflow concepts
  • Python

Go further

  • Compare against the Vitis AI DPU on a Zynq UltraScale+ board such as the KV260 (the DPU does not support Zynq-7000)
  • Reduce to 4-bit weights and report the accuracy and fps trade-off

Watch out for

  • Quoting fps for the accelerator only, ignoring ARM pre- and post-processing
  • HLS loops not pipelined (II greater than 1), which wastes most of the DSPs

Resume line Deployed a quantized Tiny-YOLO detector on a Zynq FPGA with an HLS accelerator, achieving X fps at Y mAP@0.5 and Z W board power.

Proves: FPGAEmbeddedArchitecture / AI hardware

070Embedding-Lookup Engine for Recommendation ModelsRecommendation models are memory-bound: build the gather-and-reduce engine for embedding tables that dominates their inference time.AI hardwareAdvanced6-8 wks

Goal. Accelerate the sparse embedding stage of a DLRM-style model (gather rows, sum per sample) and show how bandwidth, caching and batching change throughput.

Specification

  • Embedding tables: e.g. 8 tables x 100,000 rows x 64 dimensions, FP16 or INT8, in external memory
  • Operation: for each sample, gather a variable list of row indices per table and sum them (pooled embedding)
  • Index stream in, pooled vectors out, over AXI4-Stream
  • Multiple outstanding AXI4 reads (e.g. 16) to hide memory latency
  • Optional 64 KB hot-row cache exploiting skewed (power-law) access
  • Small bottom and top MLP run on a MAC array or the host

Steps

  1. Write a Python DLRM-style model with synthetic indices that follow a power-law distribution.
  2. Calculate bytes per sample and the bandwidth-bound throughput limit.
  3. Implement the index parser, the read-request generator with an outstanding-read tracker and the reduce unit.
  4. Use a memory model with realistic latency (e.g. 100 cycles) and verify pooled outputs against Python.
  5. Add the hot-row cache and measure its hit rate for different skews.
  6. Sweep outstanding reads and batch size; plot throughput against the bandwidth bound.

Deliverables

  • Python reference and bandwidth analysis
  • Gather-reduce RTL with outstanding-read tracking
  • Throughput vs outstanding-reads and cache-size plots
  • Short report on why recommendation inference is memory-bound

How you know it works

  • Pooled outputs match Python e.g. bit-exactly for INT8
  • Achieved bandwidth e.g. above 75% of the memory model's peak
  • Hot-row cache hit rate e.g. above 50% for a strongly skewed distribution
  • Throughput in samples per second reported vs the analytical bound

Tools

Open-source Python, PyTorch, Verilator, cocotb, gem5 (optional memory-system study)

Industry AMD Vivado, Synopsys VCS, Synopsys Design Compiler

Before you start

  • AXI4 and memory latency concepts
  • Caches
  • Python data modeling

Go further

  • Run on an FPGA board with DDR and compare with the simulation model
  • Add INT4 tables with per-row scale and measure accuracy impact

Watch out for

  • Allowing only one outstanding read, which makes throughput latency-bound
  • Using uniform random indices, which hides the benefit of caching

Resume line Built a DLRM-style embedding gather-reduce engine with 16 outstanding reads and a hot-row cache, reaching X% of peak memory bandwidth and Y samples/s.

Proves: Architecture / AI hardwareRTL designFPGA

0712.4 GHz Inductively Degenerated LNA (SKY130)Design a cascode low-noise amplifier for the 2.4 GHz band in SKY130, trading noise figure, gain, matching and power.Analog & mixed-signalAdvanced8-10 wks

Goal. Design an inductively degenerated cascode LNA matched to 50 ohm at 2.4 GHz. Verify noise figure, gain and linearity across corners in simulation.

Specification

  • Process: SKY130, 1.8 V core NMOS (sky130_fd_pr__nfet_01v8), VDD = 1.8 V
  • Band: 2.400-2.4835 GHz; input match S11 below -10 dB across the band
  • Gain S21 e.g. above 15 dB; noise figure e.g. below 3 dB
  • IIP3 e.g. above -10 dBm; power e.g. below 10 mW
  • Input match: Rin = gm x Ls / Cgs = omega_T x Ls set to 50 ohm, Lg resonates at 2.44 GHz
  • Inductors first ideal with finite Q (e.g. Q = 10), then with on-chip or off-chip inductor values

Steps

  1. Simulate nfet_01v8 to extract gm/Id, fT and Cgs per micron at your bias.
  2. Hand-calculate Ls, Lg, device width and bias current for 50 ohm match and minimum NF.
  3. Build the schematic in Xschem with cascode and output LC tank; run AC and noise in ngspice.
  4. Compute S11 and S21 (ngspice .sp analysis or from port voltages) and tune Lg and the tank.
  5. Run a two-tone transient to find IIP3; check stability (K-factor) across frequency.
  6. Sweep SS, TT, FF corners and -40 to 125 C; note how NF and match shift.

Deliverables

  • Hand-calculation sheet with device sizing
  • Xschem schematics and ngspice decks
  • Plots of S11, S21, NF and IIP3 versus frequency and corner
  • Spec-vs-simulated table and a short discussion of inductor Q

How you know it works

  • S11 e.g. below -10 dB over the full band at TT
  • NF e.g. below 3 dB at 2.44 GHz with Q = 10 inductors
  • S21 e.g. above 15 dB at TT and above 12 dB at SS, 125 C
  • Unconditionally stable (K above 1) e.g. from 0.1 to 10 GHz

Tools

Open-source Xschem, ngspice, SKY130 PDK, Python (for S-parameter plots), Magic (stretch layout)

Industry Cadence Virtuoso, Cadence Spectre (Spectre RF for SP, noise and PSS/PNoise), Siemens Calibre

Before you start

  • MOSFET small-signal model and fT
  • Noise figure and two-port noise basics
  • Smith chart and S-parameters

Go further

  • Lay out the active core in Magic and add extracted parasitics
  • Add a single-to-differential stage for a mixer input

Watch out for

  • Forgetting Cgd and pad capacitance, so the match shifts in frequency
  • Quoting NF with ideal inductors without stating the assumed Q

Resume line Designed a 2.4 GHz cascode LNA in SKY130 with X dB NF, Y dB gain and S11 below -10 dB across PVT at Z mW.

Proves: Analog / mixed-signal

072Low-TC Bandgap Voltage Reference (SKY130)A 1.2 V bandgap reference with start-up circuit, checked across temperature, supply, corners and Monte Carlo mismatch.Analog & mixed-signalIntermediate5-7 wks

Goal. Design an op-amp based bandgap reference in SKY130 with a low temperature coefficient and good supply rejection, then lay it out and verify it post-layout.

Specification

  • Process: SKY130, vertical PNP (sky130_fd_pr__pnp_05v5) with 1:8 emitter ratio, VDD = 1.8 V
  • VREF about 1.2 V; delta VBE = VT x ln(8), about 54 mV at 300 K
  • Temperature coefficient e.g. below 30 ppm/C from -40 to 125 C
  • PSRR e.g. better than 50 dB at DC; line regulation from 1.62 to 1.98 V reported
  • Supply current e.g. below 50 uA
  • Start-up circuit that guarantees the non-zero operating point

Steps

  1. Characterize the PNP VBE vs temperature in ngspice and compute the PTAT gain needed.
  2. Choose the topology (op-amp with PTAT resistor ratio) and size resistors with sky130 poly resistors.
  3. Design a simple two-stage op-amp with enough gain and offset margin; check loop stability.
  4. Add the start-up circuit and prove in a slow supply ramp that the circuit always starts.
  5. Run temperature sweeps at all corners and 200-point Monte Carlo; trim the resistor ratio if needed.
  6. Lay out in Magic with common-centroid PNPs, run DRC and LVS with Netgen, then re-simulate with parasitics.

Deliverables

  • Design equations and sizing notes
  • Xschem schematic, ngspice decks and Magic layout
  • Plots: VREF vs temperature, PSRR vs frequency, start-up transient, Monte Carlo histogram
  • Pre-layout vs post-layout comparison table

How you know it works

  • TC e.g. below 30 ppm/C at TT; reported at all corners
  • Monte Carlo 3-sigma VREF spread e.g. under 1% before trim
  • Start-up succeeds e.g. for ramp times from 1 us to 1 ms
  • Clean DRC and LVS

Tools

Open-source Xschem, ngspice, Magic, Netgen, KLayout, SKY130 PDK

Industry Cadence Virtuoso, Cadence Spectre, Siemens Calibre

Before you start

  • BJT and MOSFET device basics
  • Op-amp design and stability
  • PTAT and CTAT concepts

Go further

  • Add curvature correction and compare TC
  • Design a sub-1 V current-mode bandgap and compare

Watch out for

  • Skipping the start-up check, so the circuit sits at zero current
  • Ignoring op-amp offset, which is amplified by the resistor ratio into VREF error

Resume line Designed and laid out a SKY130 bandgap reference with X ppm/C TC and Y dB PSRR, verified over PVT and 200-run Monte Carlo, DRC/LVS clean.

Proves: Analog / mixed-signal

07310-bit 1 MS/s SAR ADC (SKY130)A charge-redistribution SAR ADC with a split capacitor DAC, StrongARM comparator and synthesized SAR logic, verified with FFT-based ENOB.Analog & mixed-signalAdvanced10-12 wks

Goal. Design a 10-bit SAR ADC at 1 MS/s in SKY130 and report ENOB, DNL, INL and power from transistor-level simulation, including a mixed-signal top level.

Specification

  • Process: SKY130, VDD = 1.8 V, differential input with full-scale range e.g. 1.8 Vpp differential
  • Resolution 10 bits, 1 MS/s; SAR clock e.g. 12-14 MHz (1-2 cycles sampling plus 10 bit cycles)
  • Capacitive DAC: split (bridge) array with MIM caps (sky130_fd_pr__cap_mim_m3_1), total cap sized for kT/C below LSB/4
  • Bootstrapped sampling switch for linearity at the input
  • Dynamic StrongARM latch comparator with noise below LSB/4
  • SAR logic written in Verilog and synthesized with Yosys into SKY130 standard cells

Steps

  1. Build a Python model of the SAR with capacitor mismatch and comparator noise; pick the unit cap from Monte Carlo DNL.
  2. Design the bootstrapped switch and check its on-resistance and settling over the input range.
  3. Design the StrongARM comparator; simulate its input-referred noise and decision time.
  4. Write and synthesize the SAR logic, then co-simulate it with the analog blocks in ngspice using the digital netlist.
  5. Run a coherent-sampling sine test, take an FFT in Python and compute SNDR, SFDR and ENOB.
  6. Run a ramp or histogram test for DNL and INL; repeat at corners.
  7. Lay out the cap array (common-centroid) in Magic and re-check with extracted parasitics.

Deliverables

  • Python behavioral model and mismatch study
  • Schematics, testbenches and synthesized SAR logic
  • FFT, DNL and INL plots at corners
  • Power breakdown (DAC, comparator, logic) and Walden figure of merit

How you know it works

  • ENOB e.g. at least 9 bits at near-Nyquist input
  • DNL e.g. within +/-0.5 LSB and INL within +/-1 LSB
  • Power e.g. below 500 uW at 1 MS/s
  • Walden FoM reported in fJ/conversion-step

Tools

Open-source Xschem, ngspice, Yosys, Magic, Netgen, Python (NumPy FFT), SKY130 PDK

Industry Cadence Virtuoso, Cadence Spectre (AMS Designer for mixed-signal), Siemens Calibre

Before you start

  • Switched-capacitor circuits and kT/C noise
  • Comparator design
  • ADC metrics (SNDR, ENOB, DNL, INL)
  • Basic Verilog

Go further

  • Add redundancy (non-binary DAC) for faster settling
  • Add digital foreground calibration of the MSB capacitors

Watch out for

  • Non-coherent FFT sampling without a window, which fakes a poor ENOB
  • Ignoring the bridge capacitor's parasitic, which creates a large DNL step at the split

Resume line Designed a 10-bit 1 MS/s SAR ADC in SKY130 with a split-cap DAC and StrongARM comparator, simulating X ENOB at Y uW.

Proves: Analog / mixed-signal

074Second-Order Switched-Capacitor Sigma-Delta ADC (GF180)A discrete-time second-order sigma-delta modulator with a CIC decimation filter, for about 12-bit (75 dB SNDR) audio-band conversion.Analog & mixed-signalAdvanced10-12 wks

Goal. Design a second-order 1-bit switched-capacitor modulator in GF180 for a 20 kHz signal band, plus a digital decimation filter, and report SNDR from transistor-level simulation.

Specification

  • Process: GF180MCU 3.3 V devices, VDD = 3.3 V
  • Signal band 20 kHz, OSR = 64, so sampling clock fs = 2 x 20 kHz x 64 = 2.56 MHz
  • Boser-Wooley style loop with integrator gains around 0.5, 1-bit quantizer
  • Ideal SQNR for order 2 at OSR 64 is about 85 dB; target SNDR e.g. at least 75 dB
  • Fully differential OTAs with DC gain e.g. above 60 dB and settling within half a clock phase
  • Decimation: CIC (sinc3) by 64 in Verilog, with a compensating FIR as a stretch

Steps

  1. Model the modulator in Python, plot the noise transfer function and check SQNR vs input level.
  2. Add non-idealities to the model: finite OTA gain, kT/C noise, clock jitter; derive OTA and capacitor specs.
  3. Design the fully differential OTA with common-mode feedback and verify gain, slew and settling.
  4. Build the switched-capacitor integrators with non-overlapping clocks and bottom-plate sampling.
  5. Simulate the full modulator in ngspice for enough samples (e.g. 16k) and compute the output PSD.
  6. Write the sinc3 decimator in Verilog, run the bitstream through it and compare with the Python result.

Deliverables

  • Python behavioral model and spec budget
  • OTA, comparator and modulator schematics and testbenches
  • Output spectrum plots with SNDR and in-band noise
  • Decimation filter RTL and test against Python

How you know it works

  • SNDR e.g. at least 75 dB in a 20 kHz band at -6 dBFS input
  • Modulator stable up to e.g. -3 dBFS input without overload
  • OTA settling error e.g. below 0.1% in half a clock period
  • Decimator output matches Python e.g. bit-exactly

Tools

Open-source Python (NumPy, SciPy), Xschem, ngspice, GF180MCU PDK, Icarus Verilog or Verilator, Yosys

Industry Cadence Virtuoso, Cadence Spectre, Synopsys Design Compiler (decimator)

Before you start

  • Switched-capacitor integrators
  • Fully differential OTA and CMFB design
  • Sampling theory and FFT analysis

Go further

  • Move to a 2-bit quantizer with data-weighted averaging
  • Lay out the modulator in Magic or KLayout with GF180 rules

Watch out for

  • Too few simulated samples, so the noise floor and SNDR are not trustworthy
  • Overlapping clock phases that cause charge sharing in the integrators

Resume line Designed a second-order switched-capacitor sigma-delta ADC in GF180 with a sinc3 decimator, simulating X dB SNDR in a 20 kHz band at OSR 64.

Proves: Analog / mixed-signalRTL design

075Integer-N Charge-Pump PLL with Ring VCO (SKY130)A type-II charge-pump PLL that multiplies a 25 MHz reference to 400 MHz, designed from a loop model down to transistors.Analog & mixed-signalAdvanced10-12 wks

Goal. Design an integer-N PLL in SKY130 with PFD, charge pump, loop filter, ring VCO and divider. Show lock time, phase margin and jitter from simulation.

Specification

  • Process: SKY130, VDD = 1.8 V; reference 25 MHz, output 400 MHz with divide ratio N = 16 (programmable 8-32)
  • VCO: 5-stage current-starved ring, tuning range e.g. 200-800 MHz across corners
  • Phase-frequency detector with reset delay to remove the dead zone
  • Charge pump e.g. 20-50 uA with matched up and down currents
  • Second-order passive loop filter (R, C1, C2); loop bandwidth about 1/20 of the reference (about 1.25 MHz), phase margin about 60 degrees
  • Targets: lock time e.g. under 10 us; rms period jitter reported from transient

Steps

  1. Build a linear phase-domain model in Python; choose Icp, R, C1 and C2 for bandwidth and phase margin.
  2. Design the ring VCO and extract its Kvco curve at all corners.
  3. Design the PFD and charge pump; check current mismatch and dead zone.
  4. Write the divider in Verilog, synthesize it with Yosys, or build it from TSPC flip-flops for speed.
  5. Simulate the full loop with ideal blocks first, then swap in transistor blocks one at a time.
  6. Run the full transistor-level lock transient; measure lock time, reference spur and period jitter.
  7. Repeat at SS and FF corners to show the loop still locks.

Deliverables

  • Python loop model with Bode plot and step response
  • Schematics and testbenches for each block and the full PLL
  • Lock transient, Kvco and jitter plots across corners
  • Spec-vs-simulated table

How you know it works

  • Phase margin e.g. 55-65 degrees in the linear model
  • Locks at 400 MHz at all corners e.g. within 10 us
  • Reference spur e.g. below -40 dBc
  • Measured lock time within e.g. 30% of the Python model prediction

Tools

Open-source Python (NumPy, SciPy), Xschem, ngspice, Yosys, Magic, SKY130 PDK

Industry Cadence Virtuoso, Cadence Spectre (Spectre RF for PSS and phase noise), Siemens Calibre

Before you start

  • Control theory (Bode plots, phase margin)
  • CMOS ring oscillators
  • Digital dividers and flip-flops
  • Transient simulation practice

Go further

  • Add a fractional-N mode with a MASH 1-1-1 sigma-delta modulator on the divider
  • Lay out the VCO and charge pump and re-simulate with parasitics

Watch out for

  • Running full transistor-level lock transients from day one; they take hours, so prove the loop with ideal blocks first
  • Kvco varying across corners, which moves the loop bandwidth and phase margin

Resume line Designed a 25-to-400 MHz charge-pump PLL with a ring VCO in SKY130; it locked within X us at all corners with Y ps rms jitter in simulation.

Proves: Analog / mixed-signal

076Voltage-Mode Buck Converter Controller (SKY130)Design a 1 MHz voltage-mode PWM controller that regulates a 3.3 V to 1.8 V buck converter with an off-chip LC filter.Analog & mixed-signalAdvanced10-12 wks

Goal. Build and simulate a closed-loop buck controller in SKY130 that holds 1.8 V within tolerance from no load to 500 mA. Prove loop stability and clean load-step recovery.

Specification

  • Process: SKY130, 5 V-rated g5v0d10v5 devices for the power stage, 1.8 V devices for control logic
  • Input 3.3 V, output 1.8 V, load 0-500 mA, off-chip LC of 4.7 uH and 22 uF
  • Fixed 1 MHz sawtooth oscillator, PWM comparator, dead-time generator of about 5-10 ns
  • Error amplifier with type-III compensation, since low-ESR ceramic output caps leave a double pole near 15.6 kHz
  • Soft-start ramp of about 1 ms and cycle-by-cycle over-current limit

Steps

  1. Derive duty cycle, inductor ripple (about 0.17 A here) and output ripple by hand before opening any tool.
  2. Model the plant: write the LC double-pole transfer function and pick crossover near 50-100 kHz.
  3. Place type-III poles and zeros, then check the loop in Python or an ngspice averaged model.
  4. Design transistor-level blocks in Xschem: error amp, sawtooth oscillator, comparator, dead-time and gate drivers.
  5. Size the power PMOS and NMOS by trading conduction loss against gate-charge loss at 1 MHz.
  6. Run full switching transients: start-up, 50-to-500 mA load step and line step from 3.0 V to 3.6 V.
  7. Repeat key runs across tt, ss and ff corners and -40 to 125 C, then lay out the error amp.

Deliverables

  • Design note with hand calculations, compensation derivation and Bode plots
  • Xschem schematics and ngspice testbenches for each block and the full loop
  • Efficiency-versus-load curve and load-step waveforms
  • Corner summary table and a Magic layout of at least the error amplifier

How you know it works

  • Phase margin above a target, e.g. > 45 degrees at crossover
  • Output ripple, e.g. < 10 mV peak-to-peak at 500 mA
  • Load-step undershoot, e.g. < 5% of 1.8 V for a 50-to-500 mA step
  • Peak efficiency, e.g. > 85% with ideal external L and C

Tools

Open-source Xschem, ngspice, Magic, Netgen, Python (scipy.signal) for loop analysis, SKY130 PDK

Industry Cadence Virtuoso, Spectre, Siemens Calibre

Before you start

  • Control theory: Bode plots, poles, zeros and phase margin
  • MOSFET operating regions and switching loss
  • A working op-amp design in SPICE

Go further

  • Convert to peak-current-mode control with slope compensation
  • Add pulse-skipping mode for light-load efficiency

Watch out for

  • Simulating only the averaged model and never seeing shoot-through, which a missing dead-time causes in the switching run.
  • Using type-II compensation with ceramic caps, which leaves too little phase near the LC double pole.

Resume line Designed a 1 MHz voltage-mode buck controller in SKY130 with type-III compensation, achieving X% peak efficiency and Y degrees phase margin across PVT.

Proves: Analog / mixed-signal

077Two-Stage Miller CMOS Op-Amp (SKY130)Design, lay out and verify a two-stage Miller-compensated op-amp in SKY130, the classic first analog IC project.Analog & mixed-signalIntermediate6-8 wks

Goal. Hit a written gain, bandwidth and phase-margin spec at the schematic level, then keep it after layout extraction across PVT corners.

Specification

  • Process: SKY130, 1.8 V supply, 1.8 V core devices
  • Load: 2 pF capacitive; open-loop DC gain > 60 dB
  • Unity-gain bandwidth >= 10 MHz with phase margin >= 60 degrees
  • Slew rate >= 10 V/us and quiescent power < 500 uW
  • Input common-mode range and output swing stated in the spec sheet

Steps

  1. Write a one-page spec table first, including load, supply and the corners you will sign off.
  2. Hand-size the stages with the gm/ID method using lookup tables generated from ngspice sweeps.
  3. Choose the Miller cap and a nulling resistor that moves the right-half-plane zero to infinity or into the left half-plane.
  4. Simulate AC, transient step, CMRR, PSRR and input-referred noise in Xschem and ngspice.
  5. Run five corners at -40, 27 and 125 C plus 200-run Monte Carlo for offset.
  6. Draw layout in Magic with a common-centroid input pair and dummies, then pass DRC and Netgen LVS.
  7. Extract parasitics and rerun the AC and step tests to compare pre- and post-layout.

Deliverables

  • Spec sheet with simulated values versus targets
  • Xschem schematic, testbenches and gm/ID scripts
  • Magic layout with clean DRC and LVS reports
  • Pre- versus post-layout comparison table and Monte Carlo offset histogram

How you know it works

  • DC gain, e.g. > 60 dB at all corners
  • Phase margin, e.g. >= 60 degrees post-layout
  • Input offset sigma from Monte Carlo, e.g. < 3 mV
  • Post-layout UGB loss versus schematic, e.g. < 15%

Tools

Open-source Xschem, ngspice, Magic, Netgen, KLayout, SKY130 PDK

Industry Cadence Virtuoso, Spectre, Siemens Calibre

Before you start

  • Small-signal MOSFET model
  • Frequency response and feedback basics
  • Basic SPICE netlists

Go further

  • Add a folded-cascode first stage and compare gain and swing
  • Design a switched-capacitor CMFB for a fully differential version

Watch out for

  • Sizing with square-law equations alone; short-channel SKY130 devices need gm/ID curves.
  • Skipping dummies and common-centroid placement, then blaming the tool for large offset.

Resume line Designed and laid out a two-stage Miller op-amp in SKY130 with X dB gain and Y MHz UGB, keeping phase margin above Z degrees post-layout.

Proves: Analog / mixed-signal

078BJT-Based Temperature Sensor with One-Point TrimBuild a PTAT/CTAT temperature sensor from SKY130 parasitic PNPs and calibrate its error with a single-temperature trim.Analog & mixed-signalAdvanced8-10 wks

Goal. Produce a sensor front-end whose digitized output tracks die temperature from -40 to 125 C within a stated error after one-point calibration.

Specification

  • Process: SKY130, sensing devices are parasitic vertical PNPs (sky130_fd_pr__pnp_05v5)
  • PTAT voltage from delta-VBE with a 1:8 current ratio, about 0.18 mV/K
  • Temperature range -40 to 125 C
  • Ratiometric output mu = alpha*dVBE / (VBE + alpha*dVBE) read by an ideal 12-bit ADC model at first
  • One-point trim of the VBE spread, stored as a digital code

Steps

  1. Derive VBE and delta-VBE versus temperature and choose alpha so the reference sum is nearly flat.
  2. Design bias current sources and a dynamic-element-matched 1:8 current mirror in Xschem.
  3. Simulate VBE, delta-VBE and mu from -40 to 125 C in 5 C steps at tt corner.
  4. Run process corners and Monte Carlo to see the raw spread before trimming.
  5. Write a Python calibration script that trims at 27 C and fits the remaining curvature.
  6. Report error versus temperature for every Monte Carlo sample after trim.
  7. Lay out the PNP array in a common-centroid pattern in Magic and pass DRC and LVS.

Deliverables

  • Derivation notes for PTAT, CTAT and the ratiometric readout
  • Xschem schematics, ngspice decks and the Python calibration script
  • Error-versus-temperature plots before and after trim
  • Magic layout of the PNP and mirror array with LVS report

How you know it works

  • Untrimmed spread across Monte Carlo, reported in C
  • Error after one-point trim, e.g. within +/-1.5 C over -40 to 125 C
  • Supply sensitivity, e.g. < 0.5 C/V
  • Bias power, e.g. < 50 uW

Tools

Open-source Xschem, ngspice, Magic, Netgen, Python (numpy), SKY130 PDK

Industry Cadence Virtuoso, Spectre, Siemens Calibre

Before you start

  • Bipolar device equations and VBE temperature behavior
  • Current mirrors and mismatch
  • A completed op-amp or bandgap simulation

Go further

  • Replace the ideal ADC with a first-order switched-capacitor sigma-delta modulator
  • Add chopping to remove op-amp offset from delta-VBE

Watch out for

  • Ignoring base-current and series-resistance errors, which bend the PTAT line at high temperature.
  • Fitting a separate curvature correction per Monte Carlo sample, which is really multi-point trim and hides real error.

Resume line Designed a SKY130 PNP-based temperature sensor with one-point trim, reaching +/-X C error from -40 to 125 C across Y Monte Carlo samples.

Proves: Analog / mixed-signal

0798-bit Segmented Current-Steering DACDesign an 8-bit current-steering DAC with thermometer-coded MSBs, sized from matching data to meet INL and DNL limits.Analog & mixed-signalAdvanced10-12 wks

Goal. Deliver a SKY130 DAC that converts at 100 MS/s with sub-LSB static linearity and a measured SFDR from transient simulation.

Specification

  • Process: SKY130, 1.8 V supply
  • Resolution 8 bits, segmentation 4 MSBs unary (15 cells) plus 4 LSBs binary
  • Update rate 100 MS/s, differential current output into resistive loads
  • Full-scale current about 1.3 mA, output swing limited so current sources stay saturated
  • Static target INL and DNL < 0.5 LSB; dynamic target SFDR reported at low and near-Nyquist input

Steps

  1. Pick unit-cell current and size the source transistor from Pelgrom matching for the INL yield you want.
  2. Write the binary-to-thermometer decoder in Verilog and check it exhaustively with all 256 codes.
  3. Design the current cell: cascoded source, differential switch pair and a latch that sets crossing point.
  4. Simulate a slow ramp to extract INL and DNL, including Monte Carlo on the unit cells.
  5. Run a sine test at 100 MS/s and compute SFDR and SINAD with an FFT in Python.
  6. Plan a common-centroid current-source array with dummy rows and draw it in Magic.

Deliverables

  • Matching and sizing calculation sheet
  • Decoder RTL, testbench and cell schematics
  • INL/DNL plots and FFT spectra
  • Array floorplan and Magic layout with DRC and LVS reports

How you know it works

  • INL and DNL, e.g. < 0.5 LSB at 99% Monte Carlo yield
  • SFDR, e.g. > 50 dBc for a low-frequency input at 100 MS/s
  • Glitch energy at the mid-code transition, reported in pV*s
  • Analog power, e.g. < 5 mW

Tools

Open-source Xschem, ngspice, Icarus Verilog, Magic, Netgen, Python (numpy FFT), SKY130 PDK

Industry Cadence Virtuoso, Spectre, Siemens Calibre, Synopsys VCS

Before you start

  • Current mirrors and cascodes
  • Mismatch and Monte Carlo basics
  • FFT and data-converter metrics

Go further

  • Add dynamic element matching or random rotation of the unary cells
  • Extend to 10 bits and study area versus segmentation

Watch out for

  • Using non-coherent sampling in the FFT, which smears tones and makes SFDR look worse than it is.
  • Laying the unary array out in a straight line, so gradient error turns into INL.

Resume line Designed an 8-bit segmented current-steering DAC in SKY130 at 100 MS/s with INL below X LSB and Y dBc SFDR.

Proves: Analog / mixed-signal

080Cross-Coupled Charge Pump Voltage GeneratorGenerate a regulated 5 V rail from a 1.8 V supply on-chip, the way flash and EEPROM program voltages are made.Analog & mixed-signalIntermediate6-8 wks

Goal. Design a multi-stage charge pump with a non-overlapping clock and simple regulation that holds 5 V under a 20 uA load.

Specification

  • Process: SKY130, pump devices from the 5 V-rated g5v0d10v5 family, MIM capacitors for pump caps
  • Input 1.8 V, regulated output 5.0 V, load 20 uA plus 50 pF
  • Clock 20 MHz with two non-overlapping phases
  • Regulation by comparator-controlled clock gating (skip mode)
  • Stated rise time to 90% and ripple at full load

Steps

  1. Compare Dickson and cross-coupled stages by hand; note the threshold loss per Dickson stage.
  2. Pick stage count and pump capacitance from Vout = (N+1)Vdd - N*Iload/(f*C).
  3. Design the non-overlapping clock generator and buffers in Xschem.
  4. Build the cross-coupled stages and check every device stays within its rated voltage.
  5. Add a resistive divider, comparator and clock gate to regulate at 5.0 V.
  6. Simulate start-up, ripple and efficiency at 0, 10 and 20 uA across corners.
  7. Lay out one pump stage and its MIM cap in Magic and pass DRC and LVS.

Deliverables

  • Stage-count and capacitor sizing calculations
  • Schematics and ngspice testbenches
  • Start-up, ripple and efficiency plots
  • Device-stress table and a one-stage layout

How you know it works

  • Regulated output, e.g. 5.0 V +/- 3% at 20 uA
  • Rise time to 90%, e.g. < 20 us into 50 pF
  • Ripple, e.g. < 50 mV peak-to-peak
  • No device exceeds its rated gate or drain voltage at any corner

Tools

Open-source Xschem, ngspice, Magic, Netgen, SKY130 PDK

Industry Cadence Virtuoso, Spectre, Siemens Calibre

Before you start

  • MOSFET switches and body effect
  • Capacitor charge sharing
  • A basic comparator design

Go further

  • Add a negative pump for -2 V
  • Use a linear regulator after the pump and compare ripple and efficiency

Watch out for

  • Forgetting well and body biasing, so parasitic junctions forward-bias and the pump stalls.
  • Putting 1.8 V core devices where the swing exceeds their oxide rating.

Resume line Designed a regulated cross-coupled charge pump in SKY130 producing 5.0 V from 1.8 V at X uA with Y mV ripple.

Proves: Analog / mixed-signal

081Scan Chain Insertion Tool in PythonWrite your own netlist tool that swaps flops for scan flops and stitches balanced chains, so you understand what DFT tools do.DFT & testIntermediate5-7 wks

Goal. Take a Yosys gate-level netlist, insert mux-D scan, build N balanced chains, and prove shift works in simulation.

Specification

  • Input: flattened structural Verilog from Yosys mapped to a known cell library (SKY130 or a generic one)
  • Replace each D flop with a mux-D scan flop (SI, SE ports) or a mux plus flop
  • User-set chain count; chain lengths differ by at most one flop
  • Separate chains per clock domain, ports scan_in[i], scan_out[i], scan_enable
  • Output: modified netlist plus a text scan-chain report in a scandef-like format

Steps

  1. Synthesize a small design such as a UART plus timer with Yosys and dump the netlist.
  2. Parse the netlist in Python (pyverilog or a minimal parser) into a cell and net graph.
  3. Identify flops, group them by clock net, and skip any marked as non-scan.
  4. Swap cells, connect SE globally, and stitch chains in a balanced order.
  5. Write a cocotb test that shifts a known pattern through every chain and checks it at scan_out.
  6. Add an optional order based on DEF placement coordinates to cut scan wirelength.

Deliverables

  • Python tool with a command-line interface and README
  • Before and after netlists for two designs
  • cocotb shift test logs
  • Chain report with length per chain and clock domain

How you know it works

  • Scan-shift test passes on all chains, e.g. 100% of flops observed
  • Chain length imbalance, e.g. <= 1 flop
  • Equivalence of functional mode, e.g. Yosys equiv check passes with SE tied low
  • Runtime on a 10k-cell netlist, e.g. < 30 s

Tools

Open-source Python, Yosys, Icarus Verilog, cocotb, Fault (to compare results)

Industry Synopsys DFT Compiler, Cadence Genus / Modus, Siemens Tessent Scan

Before you start

  • Gate-level netlists and Verilog structure
  • Python data structures and graphs
  • What scan and shift/capture modes are

Go further

  • Add lockup latches where a chain crosses clock edges
  • Read placement from DEF and compare wirelength of random versus nearest-neighbor ordering

Watch out for

  • Mixing clock domains in one chain without a lockup latch, which causes hold failures during shift.
  • Breaking functional mode by miswiring SE; always run an equivalence check with SE = 0.

Resume line Built a Python scan-insertion tool that stitched X flops into Y balanced chains and verified shift with cocotb on a Yosys netlist.

Proves: DFT

082March C- MBIST ControllerDesign a memory BIST controller that runs March C- on an SRAM, flags failures and logs the failing address.DFT & testBeginner5-7 wks

Goal. Detect injected stuck-at, transition and coupling faults in a 1K x 32 SRAM model, with pass/fail and a fail log.

Specification

  • Target: 1024 x 32 single-port synchronous SRAM (behavioral model, or an OpenRAM macro)
  • Algorithm March C-: up/down(w0); up(r0,w1); up(r1,w0); down(r0,w1); down(r1,w0); up/down(r0), 10N operations
  • Data backgrounds: solid and checkerboard to catch intra-word coupling
  • Interface: start, done, pass, fail_addr, fail_data; bypass mux for functional access
  • Runs at the functional clock; test time stated for a 100 MHz clock

Steps

  1. Write the March C- element sequence as a table and compute test time: 10 x 1024 cycles per background.
  2. Design the address generator (up/down counter), data generator and comparator in SystemVerilog.
  3. Build the controller FSM that steps through elements and backgrounds.
  4. Write a faulty SRAM model that injects SAF, TF and coupling faults at chosen cells.
  5. Run a regression that injects each fault type and checks MBIST reports it at the right address.
  6. Synthesize the controller with Yosys and compare its area with the 1K x 32 SRAM macro area.

Deliverables

  • RTL for controller, generators and memory wrapper
  • Fault-injection SRAM model and regression scripts
  • Fault-detection table per fault class
  • Synthesis area report and test-time calculation

How you know it works

  • Detection of injected stuck-at and transition faults, e.g. 100%
  • Detection of idempotent coupling faults, reported per type
  • Test time at 100 MHz, e.g. about 0.1 ms per background
  • Controller area, e.g. < 3% of the SRAM macro area

Tools

Open-source Icarus Verilog, Verilator, cocotb, Yosys, OpenRAM (optional macro)

Industry Siemens Tessent MemoryBIST, Synopsys SMS / TestMAX, Cadence Modus

Before you start

  • SystemVerilog FSMs and counters
  • SRAM read/write timing
  • Memory fault models (SAF, TF, CF)

Go further

  • Make the algorithm programmable through a small instruction memory
  • Add IEEE 1687 (IJTAG) style access through a JTAG TAP

Watch out for

  • Writing March C- without the final read element, which misses some coupling faults.
  • Testing only with an ideal memory; without fault injection you never prove detection.

Resume line Designed a March C- MBIST controller for a 1K x 32 SRAM that detected X% of injected faults with Y% area overhead.

Proves: DFTRTL design

083STUMPS Logic BIST with PRPG and MISRAdd logic BIST to a scanned design using an LFSR pattern generator, phase shifter and MISR signature register.DFT & testAdvanced8-10 wks

Goal. Run self-test with pseudo-random patterns and reach a stated stuck-at coverage, with a golden signature and X-bounding.

Specification

  • Architecture: STUMPS (PRPG, phase shifter, parallel scan chains, MISR)
  • 32-bit PRPG with a primitive polynomial, e.g. x^32 + x^22 + x^2 + x + 1
  • XOR phase shifter driving 16 scan chains; 32-bit MISR compacting chain outputs
  • BIST controller: pattern counter, shift/capture sequencing, done and signature compare
  • All X sources (uninitialized memories, tri-states, uncontrolled inputs) bounded before the MISR

Steps

  1. Start from a scanned design (for example project 81 output) and list every X source.
  2. Add X-bounding: hold memory outputs, gate unknown inputs, fix tri-states.
  3. Design PRPG, phase shifter and MISR in RTL; check LFSR period in simulation for small widths.
  4. Fault-simulate random patterns to plot coverage versus pattern count.
  5. Find random-pattern-resistant faults and insert a few observation and control test points.
  6. Generate the golden signature, then confirm injected faults change it.

Deliverables

  • BIST RTL and integration in the scanned design
  • Coverage-versus-patterns plots before and after test points
  • Golden signature file and fault-injection results
  • Area and test-time report

How you know it works

  • Stuck-at coverage, e.g. > 90% after 10k patterns
  • Coverage gain from test points, e.g. +5% or more
  • Signature aliasing check: every injected fault in a sample changes the signature
  • BIST area overhead, e.g. < 10%

Tools

Open-source Yosys, Icarus Verilog, Verilator, Fault, Python fault simulator (project 86)

Industry Siemens Tessent LogicBIST, Synopsys TestMAX, Cadence Modus

Before you start

  • Scan design and test modes
  • LFSRs and GF(2) arithmetic
  • Fault simulation basics

Go further

  • Add a reseeding scheme to hit hard faults
  • Add transition-fault testing with at-speed capture

Watch out for

  • Leaving a single X reaching the MISR, which corrupts the signature for every run.
  • Driving adjacent chains straight from adjacent LFSR bits without a phase shifter, which correlates patterns.

Resume line Implemented STUMPS logic BIST with a 32-bit PRPG and MISR, reaching X% stuck-at coverage in Y patterns after test-point insertion.

Proves: DFTRTL design

084Stuck-At and Transition ATPG FlowGenerate and validate manufacturing test patterns for a scanned design, and explain every fault left undetected.DFT & testIntermediate5-7 wks

Goal. Produce stuck-at and transition-delay patterns, simulate them against the netlist, and report coverage with a fault-class breakdown.

Specification

  • Design under test: an ITC'99 or ISCAS'89 benchmark, or a small RISC-V core, after scan insertion
  • Fault models: single stuck-at and transition delay (launch-on-capture)
  • Scan configuration: e.g. 4-8 chains, one test clock, scan enable as a dedicated pin
  • Output: patterns in a simulation testbench format plus coverage reports
  • Fault classes reported: detected, possibly detected, ATPG-untestable, redundant, not controlled or observed

Steps

  1. Insert scan with Fault or a commercial tool, and run test design-rule checks.
  2. Run stuck-at ATPG, then transition ATPG in an industry tool or grade launch-on-capture pairs with your own simulator.
  3. Simulate the patterns on the gate-level netlist with Icarus or VCS and confirm zero mismatches.
  4. Inject a few known faults in the netlist and confirm the patterns fail them.
  5. Study undetected faults: trace why each class is untestable and fix one cause in RTL.
  6. Compare coverage and pattern count before and after the fix.

Deliverables

  • Scripted ATPG flow (Makefile or Tcl)
  • Coverage reports for stuck-at and transition
  • Pattern-simulation logs with zero mismatches
  • Write-up on untestable faults and the fix applied

How you know it works

  • Stuck-at test coverage, e.g. > 98%
  • Transition coverage, e.g. > 85%
  • Pattern-simulation mismatches, e.g. 0
  • Pattern count change after the testability fix, reported in %

Tools

Open-source Fault (scan insertion and stuck-at ATPG only), Yosys, Icarus Verilog; a two-pattern fault simulator (extend project 86) for transition grading

Industry Synopsys TestMAX ATPG / TetraMAX, Siemens Tessent FastScan, Cadence Modus, Synopsys VCS

Before you start

  • Scan design concepts
  • Stuck-at and transition fault models
  • Gate-level simulation

Go further

  • Add launch-on-shift patterns and compare coverage and scan-enable timing needs
  • Run fault diagnosis on a deliberately failing pattern

Watch out for

  • Quoting fault coverage and test coverage as the same number; they treat untestable faults differently.
  • Skipping pattern simulation, so timing or X issues show up only on the tester.

Resume line Built an ATPG flow on a scanned benchmark reaching X% stuck-at and Y% transition coverage with zero simulation mismatches.

Proves: DFT

085IEEE 1149.1 Boundary Scan (JTAG) TAPImplement a standard JTAG TAP controller with boundary-scan cells, IDCODE and a BSDL file, then test it on an FPGA.DFT & testBeginner4-6 wks

Goal. Build an IEEE 1149.1-compliant TAP that a real JTAG adapter can drive to read IDCODE and run EXTEST on board pins.

Specification

  • Pins: TCK, TMS, TDI, TDO, optional TRST*
  • 16-state TAP FSM exactly as in IEEE 1149.1
  • Instructions: BYPASS (all ones), SAMPLE/PRELOAD, EXTEST, IDCODE
  • 32-bit IDCODE register with LSB fixed to 1
  • Boundary-scan cells on e.g. 8 inputs and 8 outputs; BSDL file describing the register

Steps

  1. Draw the 16-state TAP diagram and write the FSM in Verilog.
  2. Add instruction register, bypass register, IDCODE register and the boundary-scan chain.
  3. Write a testbench with a JTAG driver task that walks every state and instruction.
  4. Check that five TCK cycles with TMS high reach Test-Logic-Reset from any state.
  5. Write the BSDL file by hand for your cell order.
  6. Put it on an FPGA and read IDCODE with a JTAG adapter and OpenOCD.

Deliverables

  • TAP RTL and testbench
  • BSDL file
  • Waveforms of each instruction
  • FPGA demo log showing IDCODE and an EXTEST pin toggle

How you know it works

  • All 16 TAP states reached in simulation, e.g. 100% state and transition coverage
  • IDCODE read correctly on hardware
  • EXTEST drives and samples board pins correctly
  • TDO changes on the falling edge of TCK as required

Tools

Open-source Icarus Verilog, Verilator, GTKWave, OpenOCD, Yosys plus nextpnr for small FPGAs

Industry AMD Vivado, Intel Quartus, Siemens Questa, Siemens Tessent BoundaryScan

Before you start

  • FSM design in Verilog
  • Shift registers and clocking
  • Basic FPGA flow

Go further

  • Add a user data register that reads an on-chip MBIST status (project 82)
  • Add IEEE 1149.6 style AC-coupled test cells

Watch out for

  • Updating TDO on the rising edge of TCK; the standard requires the falling edge.
  • Letting boundary cells disturb functional mode when the TAP is idle.

Resume line Implemented an IEEE 1149.1 TAP with X boundary-scan cells and a BSDL file, verified in simulation and on FPGA using OpenOCD.

Proves: DFTRTL designFPGA

086Bit-Parallel Stuck-At Fault SimulatorWrite a fault simulator for ISCAS'85 circuits that grades test vectors and shows how coverage grows with patterns.DFT & testIntermediate4-6 wks

Goal. Simulate collapsed single stuck-at faults with 64-way bit-parallel evaluation and fault dropping, and report fault coverage.

Specification

  • Input: ISCAS'85 .bench netlists (c17, c432, c880, c6288)
  • Fault model: single stuck-at-0 and stuck-at-1 on every line, including fanout branches
  • Fault collapsing by equivalence for AND, OR, NAND, NOR and NOT gates
  • Engine: levelized logic simulation with 64 patterns per machine word
  • Fault dropping once a fault is detected

Steps

  1. Write a .bench parser and levelize the circuit topologically.
  2. Build a good-machine simulator and check it against a known truth table for c17.
  3. Generate the fault list, then collapse equivalent faults and record the ratio.
  4. Implement serial fault simulation first as a reference.
  5. Add 64-way bit-parallel pattern simulation and check it matches the serial result.
  6. Plot coverage versus random pattern count and list the hardest faults.

Deliverables

  • Simulator source in Python or C++ with tests
  • Collapsed and uncollapsed fault counts per circuit
  • Coverage-versus-patterns plots
  • Runtime comparison of serial and bit-parallel modes

How you know it works

  • Serial and parallel results match, e.g. 0 differences
  • Speed-up of parallel over serial, e.g. > 20x on c880
  • Coverage on c432 with 1k random patterns, reported
  • Fault collapse ratio, reported per circuit

Tools

Open-source Python (numpy) or C++, Yosys (to convert Verilog to .bench-like netlists), Fault (to cross-check)

Industry Synopsys TestMAX / TetraMAX, Siemens Tessent FastScan, Cadence Modus

Before you start

  • Boolean logic and gate evaluation
  • Python or C++ programming
  • Graphs and topological sort

Go further

  • Add PODEM to generate vectors for faults random patterns miss
  • Add transition-fault simulation for two-pattern tests

Watch out for

  • Modeling faults only on gate outputs, which misses fanout-branch faults.
  • Not levelizing, so gates evaluate before their inputs settle.

Resume line Built a 64-way bit-parallel stuck-at fault simulator that ran X times faster than serial and graded coverage on ISCAS'85 circuits.

Proves: DFT

087SECDED ECC and Built-In Memory RepairProtect an SRAM with Hamming SECDED ECC and repair hard faults with spare rows and columns chosen on-chip.DFT & testAdvanced8-10 wks

Goal. Correct single-bit and detect double-bit errors on 64-bit words, and allocate spares from MBIST fail data to repair the array.

Specification

  • ECC: (72,64) Hamming SECDED, 8 check bits per 64-bit word
  • Memory: 1024 x 72 array with 2 spare rows and 2 spare columns
  • Built-in redundancy analysis (BIRA) fed by an MBIST fail log
  • Repair data stored in a fuse or register model and applied by address remap
  • Status outputs: corrected, uncorrectable, repair_ok, repair_fail

Steps

  1. Build the 8 x 72 parity-check matrix and verify that all single-bit syndromes are unique and nonzero.
  2. Write encoder and decoder RTL; test every single-bit and a sample of double-bit errors.
  3. Write a must-repair analysis: a row with more than 2 fails needs a spare row.
  4. Allocate remaining spares with a simple greedy or exhaustive search for small fail counts.
  5. Add row and column remap logic and rerun MBIST to confirm the repaired array passes.
  6. Measure repair rate across random fail maps with a Python Monte Carlo.

Deliverables

  • ECC encoder and decoder RTL with exhaustive single-error tests
  • BIRA and remap RTL
  • Python Monte Carlo of repair rate versus fail count
  • Area and timing report for the decoder path

How you know it works

  • Single-bit correction, e.g. 100% of 72 positions
  • Double-bit detection, e.g. 100% in random tests
  • Repair rate for 4 random fails, reported from Monte Carlo
  • Decoder path delay in synthesis, e.g. fits a 200 MHz cycle

Tools

Open-source Icarus Verilog, Verilator, cocotb, Yosys, OpenSTA, Python

Industry Siemens Tessent MemoryBIST, Synopsys SMS, Synopsys Design Compiler, Synopsys PrimeTime

Before you start

  • Linear codes and parity
  • MBIST concepts (project 82)
  • RTL datapath design

Go further

  • Compare greedy allocation with an exact branch-and-bound search
  • Add a background scrubbing engine that rewrites corrected words

Watch out for

  • Treating ECC as repair; ECC hides soft errors but hard faults still need spares.
  • Not counting the ECC check-bit columns as repairable, so faults there go unrepaired.

Resume line Designed a (72,64) SECDED ECC and BIRA repair engine with 2 spare rows and columns, repairing X% of random fail maps with Y% area overhead.

Proves: DFTRTL design

088EDT-Style Scan Compression EngineBuild a linear decompressor and XOR compactor so a few tester pins feed many short internal scan chains.DFT & testAdvanced8-10 wks

Goal. Cut scan data volume and test time by a measured ratio, with care bits encoded by solving linear equations over GF(2).

Specification

  • 4 scan input pins feeding 64 internal chains through an LFSR-based decompressor and phase shifter
  • XOR spatial compactor from 64 chains to 4 scan outputs
  • X-masking logic per chain, controlled by mask bits loaded with the pattern
  • Encoder in Python solves care bits as linear equations over GF(2)
  • Baseline for comparison: the same design with 4 long uncompressed chains

Steps

  1. Split the scanned design into 64 balanced chains.
  2. Design the decompressor RTL and derive its symbolic equations for each chain bit.
  3. Take ATPG cubes with don't-cares and encode them using Gaussian elimination in Python.
  4. Design the XOR compactor and X-mask, then check that single errors stay visible.
  5. Simulate encoded patterns through the decompressor and check every care bit lands correctly.
  6. Compare data volume, shift cycles and coverage against the uncompressed baseline.

Deliverables

  • Decompressor, compactor and mask RTL
  • Python GF(2) encoder with tests
  • Encoding success rate versus care-bit density
  • Comparison table of data volume and test cycles

How you know it works

  • Shift-cycle reduction, e.g. about 16x from chain-length ratio
  • Encoding success rate, e.g. > 99% of cubes
  • Coverage loss versus baseline, e.g. < 0.5%
  • Errors masked by compactor aliasing, reported

Tools

Open-source Python (numpy, galois or own GF(2) code), Yosys, Icarus Verilog, Fault

Industry Siemens Tessent TestKompress, Synopsys TestMAX DFTMAX, Cadence Modus

Before you start

  • Scan and ATPG (projects 81 and 84)
  • Linear algebra over GF(2)
  • LFSR design

Go further

  • Add continuous-flow encoding across shift cycles like a ring generator
  • Add a MISR-based response compactor and compare X tolerance

Watch out for

  • Ignoring care-bit density limits; dense cubes have no solution and must be split.
  • Letting an X reach the XOR compactor, which hides real fails in the same output group.

Resume line Built a 4-to-64 chain scan compression engine with a GF(2) pattern encoder, cutting test data volume by X times with under Y% coverage loss.

Proves: DFT

089Push-Button Scan Insertion Flow with Test DRCAutomate scan insertion for a multi-clock design with test DRC checks, lockup latches and a regression that proves it.DFT & testIntermediate4-6 wks

Goal. Create a scripted flow that inserts scan, fixes DFT rule violations and outputs a verified netlist and reports for every run.

Specification

  • Design: two or more clock domains with async resets, e.g. a UART plus SPI peripheral block
  • Test-mode controls: test_mode pin forcing clock and reset controllability
  • Lockup latches where a chain crosses between clock domains or edges
  • Scan configuration file: chain count, max chain length, scan ports
  • Flow driven by one Makefile target that runs synthesis, scan, checks and simulation

Steps

  1. Write RTL test-mode muxes for internal clocks and async resets.
  2. Script scan insertion in Tcl for the industry tool, or with Fault and the OpenROAD DFT module.
  3. Run test DRC and fix each violation class: uncontrolled clocks, async resets, combinational loops.
  4. Insert lockup latches at clock-domain crossings in the chain and check hold during shift.
  5. Auto-generate a shift-and-capture simulation test from the scan report.
  6. Run the flow in CI on every commit and diff the coverage and chain reports.

Deliverables

  • Makefile and Tcl or Python flow scripts
  • DRC violation log before and after fixes
  • Scan chain reports and simulation logs
  • CI configuration and a sample run summary

How you know it works

  • Test DRC violations after fixes, e.g. 0
  • Scannable flop ratio, e.g. > 98%
  • Flow run from RTL to verified scan netlist, e.g. one command under 10 minutes
  • Shift simulation passes on every chain

Tools

Open-source Yosys, Fault, OpenROAD (DFT module), Icarus Verilog, Make, GitHub Actions

Industry Synopsys DFT Compiler / TestMAX, Cadence Genus / Modus, Siemens Tessent Scan

Before you start

  • Tcl for EDA tools
  • Scan basics (project 81)
  • Clock domains and async resets

Go further

  • Add on-chip clock controller (OCC) logic for at-speed capture
  • Hand the scanned netlist to OpenROAD and reorder chains after placement

Watch out for

  • Fixing DRC violations by excluding flops from scan, which quietly lowers coverage.
  • Forgetting that async reset must be held inactive during shift.

Resume line Automated a scan insertion flow with test DRC and lockup latches on a multi-clock design, reaching X% scannable flops with zero DRC violations.

Proves: DFT

090Wafer-Sort Yield Analysis DashboardTurn wafer-sort test data into wafer maps, bin Paretos and yield-model fits that a test or yield engineer can act on.DFT & testBeginner3-5 wks

Goal. Build a Python dashboard that loads die-level test results, shows yield by wafer and lot, and flags spatial failure patterns.

Specification

  • Input: die-level CSV (lot, wafer, x, y, bin, parametric values) or STDF V4 parsed with pystdf
  • Views: wafer map, bin Pareto, yield trend by lot, parametric histograms with limits
  • Yield models: Poisson Y = exp(-A*D0), Murphy, and negative binomial with clustering factor alpha
  • Process capability (Cpk) for each parametric test
  • Spatial pattern flags: edge ring, center, scratch line, cluster

Steps

  1. Generate a synthetic data set with known defect density and clustering, so you can check your fits.
  2. Load and clean data with pandas; handle retests and keep the final bin per die.
  3. Draw wafer maps and bin Paretos in Plotly.
  4. Fit D0 for each yield model and compare against the value you seeded.
  5. Add simple spatial classifiers, such as edge-die fail ratio versus center.
  6. Wrap everything in a Streamlit or Dash app with lot and wafer filters.

Deliverables

  • Dashboard source with a README and screenshots
  • Synthetic data generator
  • Notebook comparing yield-model fits
  • Short report on one spatial signature and its likely cause

How you know it works

  • Recovered D0 within a tolerance of the seeded value, e.g. +/- 10%
  • Edge-ring wafers flagged correctly, e.g. > 90% on synthetic data
  • Dashboard load time for 50 wafers, e.g. < 5 s
  • Cpk computed for every parametric test

Tools

Open-source Python (pandas, numpy, scipy), Plotly, Streamlit or Dash, pystdf

Industry JMP, Siemens Tessent YieldInsight, In-house fab yield systems

Before you start

  • Python and pandas
  • Basic statistics
  • What wafer sort and binning are

Go further

  • Add a CNN classifier for wafer-map patterns trained on synthetic maps
  • Link failing bins to scan diagnosis results

Watch out for

  • Counting retested dies twice, which inflates both pass and fail counts.
  • Fitting Poisson yield to clustered defects, which underestimates yield on large dies.

Resume line Built a wafer-sort yield dashboard in Python with wafer maps and yield-model fits, recovering defect density within X% on synthetic data.

Proves: DFTFab & OSAT

091Chiplet AI Accelerator with Die-to-Die LinkPartition a systolic-array accelerator into chiplets and model whether the die-to-die link becomes the bottleneck.ResearchAdvanced10-14 wks

Goal. Compare a monolithic and a 4-chiplet accelerator on a real CNN layer set, and build an RTL die-to-die adapter with flow control.

Specification

  • Compute: 4 chiplets, each a 16x16 INT8 systolic array with local SRAM
  • Die-to-die: UCIe-like parallel link, e.g. 16 lanes at 16 GT/s per lane, state your assumed pJ/bit from a cited paper
  • Workload: ResNet-18 or MobileNet convolution layers, tiled across chiplets
  • Model: Python cycle-approximate simulator for compute, SRAM and link traffic
  • RTL: link adapter with credit-based flow control, CRC and retry

Steps

  1. Write the monolithic baseline model and check MAC counts per layer by hand.
  2. Choose tiling across 4 chiplets and count bytes crossing each link per layer.
  3. Add link bandwidth, latency and energy to the model and find layers that become link-bound.
  4. Design the adapter RTL: flit packing, credits, CRC-16 and replay buffer.
  5. Verify the adapter with cocotb, including injected bit errors and back-pressure.
  6. Sweep lane count and data rate, then write the trade-off conclusions.

Deliverables

  • Python performance model with layer-level reports
  • Adapter RTL and cocotb testbench
  • Plots of throughput and energy versus link bandwidth
  • Short paper-style report with assumptions cited

How you know it works

  • Throughput loss of chiplet versus monolithic, e.g. < 15% on chosen layers
  • Link energy share of total, reported per layer
  • Adapter recovers all injected CRC errors, e.g. 0 lost flits
  • Adapter meets a stated target clock, e.g. 100 MHz in SKY130

Tools

Open-source Python, Verilator, cocotb, Yosys, OpenROAD, gem5 (optional)

Industry Synopsys VCS, Cadence Xcelium, Synopsys Fusion Compiler, Cadence Genus

Before you start

  • Systolic arrays and dataflow
  • RTL with valid/ready interfaces
  • Python modeling

Go further

  • Compare weight-stationary and output-stationary dataflows across chiplets
  • Add a thermal or power-density estimate per chiplet

Watch out for

  • Quoting link numbers without stating the source and package type; standard and advanced packages differ a lot.
  • Modeling only compute and ignoring the SRAM refills that drive link traffic.

Resume line Modeled a 4-chiplet INT8 accelerator and built a credit-based die-to-die adapter, showing X% throughput loss versus monolithic at Y GT/s.

Proves: Architecture / AI hardwareRTL design

092Spiking Neural Network Core on FPGABuild a time-multiplexed leaky integrate-and-fire neuron core that runs a trained spiking network on MNIST.ResearchAdvanced10-12 wks

Goal. Run inference for a small SNN on an FPGA and report accuracy, latency and energy per inference against a software model.

Specification

  • 256 LIF neurons, time-multiplexed through one or a few update units
  • 256 x 256 synapse crossbar with 4-bit weights in block RAM
  • 16-bit fixed-point membrane potential, leak by right shift, threshold and reset
  • Address-event representation (AER) input and output spike interface
  • Network trained in snnTorch, weights quantized and exported to a memory file

Steps

  1. Train a two-layer SNN on MNIST in snnTorch and record float accuracy.
  2. Quantize weights to 4 bits and membrane to 16 bits; re-check accuracy in Python.
  3. Write a bit-exact Python reference model of the neuron update.
  4. Design the neuron update unit, synapse memory and AER router in Verilog.
  5. Compare RTL spikes to the reference model on 100 images, spike by spike.
  6. Implement on an FPGA and measure throughput and power from the vendor estimator.

Deliverables

  • Training and quantization notebook
  • RTL with a bit-exact reference model
  • FPGA build scripts and utilization report
  • Accuracy, latency and energy table versus the software model

How you know it works

  • Accuracy drop after quantization, e.g. < 2%
  • RTL versus reference spike mismatch, e.g. 0
  • Latency per image, reported in timesteps and microseconds
  • Energy per inference from the FPGA power estimate

Tools

Open-source Python (snnTorch, PyTorch), Verilator, cocotb, Yosys plus nextpnr

Industry AMD Vivado, Intel Quartus, Siemens Questa

Before you start

  • Neural network basics
  • Fixed-point arithmetic
  • FPGA RTL and block RAM use

Go further

  • Add on-chip STDP learning
  • Exploit spike sparsity to skip zero events and report the energy gain

Watch out for

  • Rounding differently in RTL and Python, so accuracy numbers do not match and bugs hide.
  • Updating all neurons every cycle and losing the event-driven advantage.

Resume line Designed a 256-neuron LIF SNN core on FPGA running MNIST at X% accuracy with Y us latency, bit-exact with a Python model.

Proves: Architecture / AI hardwareFPGARTL design

0938T Compute-in-Memory SRAM Macro (SKY130)Design a small SRAM array that computes binary dot products on its read bitlines, and measure how variation limits accuracy.ResearchAdvanced12-14 wks

Goal. Show a 64x64 compute-in-memory array in SKY130 performing multiply-accumulate in the analog domain, with a column ADC and error analysis.

Specification

  • Process: SKY130, 1.8 V; 8T bitcell with a decoupled read port to avoid read disturb
  • Array 64 rows x 64 columns, binary weights stored, binary inputs on read wordlines
  • MAC by read-bitline discharge over a fixed time window, up to 15 rows active, so counts 0-15 fit a 4-bit ADC
  • Per-column 4-bit flash or SAR ADC (behavioral first, then transistor-level for one column)
  • Error reported against an ideal integer dot product

Steps

  1. Simulate one 8T cell and confirm read stability and write margin at corners.
  2. Build one column and plot bitline voltage versus the number of active rows, from 0 to 15.
  3. Choose the discharge window and ADC references for the most uniform step size.
  4. Run Monte Carlo on cell current and record MAC error distribution.
  5. Model the full 64x64 array in Python using the extracted column transfer curve.
  6. Map a small binary network layer and report accuracy loss from analog error.

Deliverables

  • Cell and column schematics with testbenches
  • Transfer curves and Monte Carlo error histograms
  • Python array model and network accuracy study
  • Layout of the bitcell and one column in Magic

How you know it works

  • Column MAC error, e.g. < 1 LSB for 90% of Monte Carlo samples
  • Energy per MAC operation, reported in fJ
  • Network accuracy drop versus digital, e.g. < 3%
  • Read disturb: no stored bit flips at any corner

Tools

Open-source Xschem, ngspice, Magic, Netgen, Python, SKY130 PDK, OpenRAM (for comparison)

Industry Cadence Virtuoso, Spectre, Siemens Calibre

Before you start

  • SRAM cell operation and margins
  • Analog transient simulation
  • Basic neural network quantization

Go further

  • Add multi-bit inputs by pulse-width modulation of the read wordline
  • Compare charge-domain accumulation with capacitors

Watch out for

  • Activating too many rows so the bitline saturates and the transfer curve flattens.
  • Reporting results only at the tt corner when the method is limited by variation.

Resume line Designed a 64x64 8T compute-in-memory SRAM in SKY130 with X fJ per MAC and under Y LSB column error across Monte Carlo.

Proves: Analog / mixed-signalArchitecture / AI hardware

094Optical NoC Architecture StudyModel a 16-core photonic network-on-chip with microring WDM links and compare it honestly with an electrical mesh.ResearchAdvanced8-12 wks

Goal. Produce a loss and power budget for an optical NoC and a latency and energy comparison against an electrical mesh on synthetic and real traffic.

Specification

  • 16 cores in a 4x4 layout; electrical baseline is a 2D mesh with XY routing
  • Optical design: SWMR or MWSR crossbar with WDM, e.g. 16 wavelengths per waveguide
  • Loss budget: waveguide loss per cm, crossings, ring through and drop loss, coupler loss, detector sensitivity
  • Laser power derived from worst-case path loss; include ring thermal tuning power
  • Traffic: uniform random, transpose, hotspot and traces from gem5

Steps

  1. Collect loss and power parameters from published papers and cite each value.
  2. Write a Python worst-path loss calculator and derive required laser power.
  3. Model the optical crossbar and its arbitration as a custom BookSim2 topology or in your own Python model.
  4. Run the electrical mesh baseline in BookSim2 or gem5 Garnet with the same traffic.
  5. Compare latency versus injection rate and energy per bit, including laser and tuning power.
  6. Find the crossover where optics wins, and say where it does not.

Deliverables

  • Parameter table with citations
  • Loss and power calculator
  • Simulator configs and result plots
  • Report with a clear verdict and limitations

How you know it works

  • Saturation throughput gain over mesh, reported for each traffic pattern
  • Energy per bit including static laser and tuning power
  • Worst-case optical path loss in dB, with margin, e.g. >= 3 dB
  • Sensitivity of results to ring tuning power, shown as a sweep

Tools

Open-source Python, BookSim2, gem5 (Garnet)

Industry Synopsys OptoCompiler, In-house architecture simulators

Before you start

  • NoC routing and flow control
  • Basic optics: loss in dB and WDM
  • Python simulation

Go further

  • Add a hybrid design with optical long links and electrical local links
  • Model thermal drift and its effect on ring tuning power

Watch out for

  • Leaving out static laser and thermal tuning power, which makes optics look far better than it is.
  • Mixing parameters from different papers without checking they assume the same process.

Resume line Modeled a 16-core optical NoC with a cited loss budget and showed X% latency reduction at Y pJ/bit versus an electrical mesh.

Proves: Architecture / AI hardware

095Secure Boot Hardware Root of TrustBuild a small root of trust that verifies firmware signatures before boot, using immutable ROM, OTP keys and a hash engine.ResearchAdvanced12-14 wks

Goal. Boot a RISC-V core only when its firmware hash and signature check out, and show rollback and debug-unlock attacks are blocked.

Specification

  • SHA-256 hardware engine (64 rounds per 512-bit block) with a memory-mapped interface
  • Signature check with ECDSA P-256 over the SHA-256 digest in boot-ROM firmware (Ed25519 would need SHA-512)
  • OTP model holding a public-key hash, a monotonic anti-rollback counter and lifecycle state
  • Lifecycle states, e.g. test, development, production, with JTAG disabled in production
  • Fail-safe: any check failure halts boot and sets a sticky status register

Steps

  1. Write a threat model: what the attacker can touch and what you protect.
  2. Design and verify SHA-256 RTL against NIST test vectors.
  3. Integrate the hash engine, OTP model and boot ROM with a small RISC-V core such as PicoRV32 or Ibex.
  4. Write boot-ROM code that hashes the image, checks the key hash and verifies the signature.
  5. Add anti-rollback and lifecycle-based debug lock, then write attack tests for each.
  6. Use assertions or formal checks to prove the core cannot run code before verification passes.

Deliverables

  • Threat model document
  • RTL for hash engine, OTP model and boot control
  • Boot ROM source and signing script
  • Attack test results: tampered image, old version, debug unlock attempt

How you know it works

  • SHA-256 matches NIST vectors, e.g. 100%
  • Tampered and rolled-back images rejected, e.g. 100% of tests
  • Boot verification time for a 64 KB image, reported in cycles
  • Formal property 'no fetch before verify' proven

Tools

Open-source Verilator, cocotb, SymbiYosys, Yosys, RISC-V GCC, OpenTitan (as reference)

Industry Synopsys VCS, Cadence JasperGold, Synopsys VC Formal, Cadence Xcelium

Before you start

  • RISC-V basics and bare-metal C
  • Hash functions and public-key signatures
  • RTL bus interfaces

Go further

  • Add a simple power-trace leakage test on the hash engine in simulation
  • Add measured boot that extends hashes into a PCR-like register

Watch out for

  • Leaving a debug path or ROM patch mechanism that bypasses verification.
  • Comparing digests with an early-exit loop, which leaks timing.

Resume line Built a secure-boot root of trust with a SHA-256 engine that rejected all tampered test images and verified a 64 KB image in X cycles.

Proves: RTL designVerificationArchitecture / AI hardware

096Hardware Trojan Detection by Rare-Node AnalysisFind hidden trigger logic in gate-level netlists by locating rarely switching nodes and generating tests that activate them.ResearchAdvanced8-10 wks

Goal. Detect inserted Trojans in Trust-Hub benchmarks with a rare-node and N-detect test method, and report false positives honestly.

Specification

  • Benchmarks: Trust-Hub AES and ISCAS-based Trojan-inserted netlists plus their Trojan-free versions
  • Rare-node threshold: signals with a 0 or 1 probability below e.g. 0.1% in random simulation
  • Testability measures with SCOAP controllability and observability
  • Test generation: N-detect style, activating each rare node at least N times
  • Metrics: trigger coverage, Trojan coverage and false-positive count

Steps

  1. Synthesize clean and Trojan-inserted benchmarks with Yosys to a common gate library.
  2. Run 1 million random vectors in a fast simulator and record signal probabilities.
  3. Compute SCOAP values and rank candidate trigger nodes.
  4. Generate N-detect vectors that drive rare nodes to their rare values.
  5. Simulate the Trojan netlists and measure how many triggers fire and payloads reach outputs.
  6. Compare against random testing and report false positives on clean designs.

Deliverables

  • Python analysis and test-generation scripts
  • Rare-node lists per benchmark
  • Comparison table: random versus N-detect trigger coverage
  • Report of misses and why they were missed

How you know it works

  • Trigger coverage gain over random vectors, e.g. 10x more triggers fired
  • Trojan detection rate on chosen benchmarks, reported
  • False-positive nodes in Trojan-free designs, reported
  • Test length, e.g. < 100k vectors

Tools

Open-source Yosys, Icarus Verilog or Verilator, Python (networkx), Trust-Hub benchmarks

Industry Synopsys VCS, Cadence JasperGold (security path verification), Synopsys TestMAX

Before you start

  • Gate-level netlists and simulation
  • SCOAP and fault-model basics
  • Python scripting

Go further

  • Add a side-channel method: compare simulated switching power of suspect and golden designs
  • Use formal checks to prove a rare node can never reach a key output

Watch out for

  • Calling every rare node a Trojan; normal logic such as counters' high bits is also rare.
  • Testing only on the benchmarks you tuned the threshold on.

Resume line Detected X of Y Trust-Hub Trojans using rare-node analysis and N-detect tests, firing Z times more triggers than random vectors.

Proves: VerificationDFT

097Ring-Oscillator PUF Key Generator on FPGABuild a ring-oscillator PUF on FPGA, measure its quality across boards and conditions, and derive a stable key.ResearchIntermediate6-8 wks

Goal. Report uniformity, uniqueness and reliability for an RO PUF on at least two boards. Derive a repeatable 128-bit key and state its true entropy.

Specification

  • Array of e.g. 1,024 identical ring oscillators, placed with fixed location constraints
  • Frequency comparison of 512 disjoint pairs with counters, giving 512 raw response bits
  • Quality metrics: uniformity, inter-chip Hamming distance (uniqueness), intra-chip Hamming distance (reliability)
  • Helper-data error correction with a 5x repetition code and majority vote, leaving about 100 corrected bits
  • Key derived by hashing the corrected bits to 128 bits; report that true entropy is below 128 bits

Steps

  1. Design one RO and a counter, and lock placement so every RO has the same routing.
  2. Replicate the array and add the comparison and readout over UART.
  3. Collect responses from each board many times and compute the three metrics in Python.
  4. Repeat at different supply or temperature conditions if you can vary them safely.
  5. Implement the repetition-code fuzzy extractor and check key stability over 1000 reads.
  6. Write up limits, including that arbiter PUFs are vulnerable to machine-learning modeling attacks.

Deliverables

  • RTL with placement constraints
  • Data collection and metric scripts
  • Metric table across boards and conditions
  • Key stability results and helper-data format

How you know it works

  • Uniformity, e.g. close to 50%
  • Uniqueness (inter-chip HD), e.g. 45-55%
  • Reliability (intra-chip HD), e.g. < 5% before correction
  • Key failure rate after correction, e.g. 0 in 1000 reads

Tools

Open-source Yosys plus nextpnr, Icarus Verilog, Python (numpy)

Industry AMD Vivado, Intel Quartus

Before you start

  • FPGA flow and placement constraints
  • Counters and UART
  • Basic statistics

Go further

  • Replace the repetition code with a BCH code and compare helper-data size
  • Build an arbiter PUF and attack it with logistic regression

Watch out for

  • Letting the tool place ROs freely, so routing differences swamp process variation.
  • Reporting uniqueness from one board; you need several devices for inter-chip distance.

Resume line Built an RO PUF on FPGA with X% uniqueness and Y% intra-chip error, deriving a stable 128-bit key across Z reads.

Proves: FPGARTL design

098Approximate Arithmetic RISC-V CoreAdd approximate adders and multipliers to a RISC-V core as custom instructions and measure the energy versus quality trade-off.ResearchAdvanced8-10 wks

Goal. Show energy savings on image kernels from approximate arithmetic while keeping output quality above a stated PSNR.

Specification

  • Base: RV32IM core such as PicoRV32 or a core of your own
  • Custom instructions in the custom-0 opcode space: approximate add and multiply
  • Approximate units: lower-part OR adder (LOA) and truncated multiplier with configurable k bits
  • Error metrics: error rate, mean error distance, mean relative error distance
  • Benchmarks: Gaussian blur and Sobel edge detection on 64x64 grayscale images

Steps

  1. Model each approximate unit in Python and sweep k to plot error metrics.
  2. Design the units in Verilog and check them bit-exact against the Python model.
  3. Add decode and execute support for the custom instructions in the core.
  4. Write the kernels in C with inline assembly for the custom instructions.
  5. Measure output PSNR against exact runs for several k values.
  6. Synthesize and run power analysis with switching activity from the real kernels.

Deliverables

  • Python error models and sweep plots
  • Modified core RTL and custom-instruction tests
  • Benchmark C code and output images
  • Energy versus PSNR Pareto plot

How you know it works

  • Multiplier power saving, e.g. > 30% at a chosen k
  • Image quality, e.g. PSNR > 30 dB on both kernels
  • Core still passes riscv-tests for RV32IM
  • Area of approximate units versus exact units, reported

Tools

Open-source Verilator, Yosys, OpenROAD, OpenSTA, RISC-V GCC, Python

Industry Synopsys Design Compiler, Synopsys PrimePower, Cadence Genus, Cadence Voltus

Before you start

  • RISC-V pipeline basics
  • Arithmetic circuits
  • C and inline assembly

Go further

  • Make the approximation level configurable at run time through a CSR
  • Add voltage over-scaling as a second knob in the study

Watch out for

  • Measuring power with random vectors instead of activity from the real kernels.
  • Breaking the exact instructions while adding custom decode; rerun the full ISA tests.

Resume line Added approximate add and multiply instructions to an RV32IM core, saving X% multiplier power with PSNR above Y dB on image kernels.

Proves: Architecture / AI hardwareRTL design

099Qubit Control Pulse GeneratorDesign the digital core of a superconducting-qubit controller: NCOs, IQ pulse shaping, sequencer and readout discrimination.ResearchAdvanced10-14 wks

Goal. Build an FPGA-proven controller for 4 qubits that plays shaped pulses with phase tracking and returns a measured state with low feedback latency.

Specification

  • 4 channels, each with a 32-bit phase-accumulator NCO for an intermediate frequency
  • IQ modulation of envelopes from waveform memory, e.g. Gaussian and DRAG, 16-bit samples
  • Parallel datapath, e.g. 4 samples per 250 MHz clock for a 1 GS/s DAC stream
  • Sequencer with timed instructions, virtual-Z phase updates and conditional branches
  • Readout: digital down-conversion, boxcar integration and threshold state discrimination

Steps

  1. Model NCO, modulation and readout in Python with a simple qubit response model.
  2. Design the NCO with phase continuity and check spurs with an FFT.
  3. Design waveform memory, IQ mixer and the 4-sample parallel datapath.
  4. Write the sequencer instruction set and an assembler in Python.
  5. Build the readout chain and measure latency from last sample to branch decision.
  6. Run on an FPGA with a DAC or loopback and capture pulses and decisions.

Deliverables

  • Python reference model
  • RTL for NCO, modulator, sequencer and readout
  • Assembler and example pulse programs
  • Latency and spectral-purity results

How you know it works

  • NCO spur-free dynamic range, e.g. > 70 dBc
  • Feedback latency, e.g. < 200 ns from readout end to branch
  • Bit-exact match with Python model, e.g. 0 sample mismatches
  • Timing closure at the parallel clock, e.g. 250 MHz

Tools

Open-source Python (numpy, scipy), Verilator, cocotb, Yosys, OpenROAD (ASIC estimate)

Industry AMD Vivado, Synopsys VCS, Synopsys Fusion Compiler, Cadence Genus

Before you start

  • DSP: NCOs, mixing, FIR filters
  • Pipelined RTL at high clock rates
  • Python modeling

Go further

  • Synthesize the core to an ASIC flow and estimate power for cryogenic operation
  • Add multiplexed readout of 4 qubits on one line

Watch out for

  • Resetting the phase accumulator between pulses, which breaks phase coherence across a sequence.
  • Ignoring pipeline latency in the feedback budget until the end.

Resume line Designed a 4-channel qubit control core with 32-bit NCOs and DRAG pulse shaping, reaching X ns feedback latency at Y MHz on FPGA.

Proves: RTL designFPGAArchitecture / AI hardware

100Configurable Open-Source RISC-V SoCAssemble a configurable RISC-V SoC that boots software on an FPGA and hardens a reduced version to GDSII on SKY130.ResearchAdvanced12-16 wks

Goal. Produce one SoC generator with FPGA and ASIC targets, run firmware on both in simulation, and show the ASIC version clean through signoff checks.

Specification

  • CPU: VexRiscv or a Rocket core, RV32IMC or RV64GC by configuration
  • Bus: Wishbone or AXI; peripherals UART, SPI, GPIO, timer, interrupt controller
  • Memory: boot ROM, on-chip SRAM; DRAM controller on the FPGA target only
  • Software: bare-metal firmware and Zephyr; Linux as stretch on the FPGA target
  • ASIC target: reduced config without DRAM, hardened with OpenLane on SKY130

Steps

  1. Generate the SoC with LiteX or Chipyard and boot a hello-world in Verilator.
  2. Add a custom peripheral with its register map and driver.
  3. Run on an FPGA board and boot Zephyr over UART.
  4. Write cocotb or firmware-driven tests for each peripheral.
  5. Strip DRAM, map SRAM to macros, and run OpenLane on SKY130.
  6. Close timing and pass DRC and LVS, then document area, frequency and power.

Deliverables

  • SoC configuration files and build scripts for both targets
  • Custom peripheral RTL, driver and tests
  • FPGA boot logs and utilization report
  • OpenLane run reports with DRC, LVS and timing summaries

How you know it works

  • Firmware boots on FPGA and in RTL simulation
  • ASIC timing closure, e.g. 50 MHz at the slow corner
  • DRC and LVS violations, e.g. 0
  • Configurations built from one source, e.g. at least two

Tools

Open-source LiteX, Chipyard, Verilator, cocotb, OpenLane, OpenROAD, Magic, KLayout, SKY130 PDK

Industry Synopsys VCS, Cadence Genus, Cadence Innovus, Synopsys PrimeTime, AMD Vivado

Before you start

  • RISC-V ISA and bare-metal C
  • Bus protocols such as Wishbone or AXI
  • RTL-to-GDS flow basics

Go further

  • Boot Linux on the FPGA target with VexRiscv SMP
  • Submit a reduced tile to a Tiny Tapeout or open-PDK shuttle

Watch out for

  • Building the ASIC with the FPGA config, so DRAM or vendor primitives break synthesis.
  • Skipping peripheral tests and debugging every bug through firmware prints.

Resume line Built a configurable RISC-V SoC that boots Zephyr on FPGA, and hardened a reduced version on SKY130 at X MHz with zero DRC/LVS violations.

Proves: RTL designPhysical designArchitecture / AI hardwareFPGA