- Overview
- Target Application
- Architecture
- Quickstart
- Caravel Integration
- Running Full Chip Simulation
- User Project Wrapper Requirements
- Hardening the User Project using OpenLane
- Running Timing Analysis
- Verification Status
- Deployment Path
- Checklist for Open-MPW Submission
This repository contains a programmable digital FIR filter accelerator implemented as a Caravel user project on the SkyWater SKY130A 130nm open-source PDK. The design implements a complete fixed-point DSP pipeline: CIC decimation filter, 8-tap FIR filter with runtime-programmable coefficients, and PWM DAC output. The entire pipeline is controlled by the Caravel RISC-V management core via Wishbone-mapped registers.
Key Features:
- 3-stage CIC decimation filter (OSR: 8/16/32/64)
- 8-tap direct-form I FIR filter with Q1.15 fixed-point arithmetic
- Runtime-programmable filter coefficients via Wishbone CSR
- 8-bit first-order delta-sigma PWM DAC
- Wishbone B4 peripheral interface (base address: 0x30000000)
- Internal LFSR test source for standalone verification
Primary: Audio Line-In Filter for Embedded Audio Processing
This chip processes analog audio signals (microphone, line input) through on-chip sigma-delta conversion, digital filtering, and PWM DAC reconstruction for speaker output or headphone amplification. Targeted at low-cost embedded audio systems (smart speakers, intercoms, voice recorders) where programmable filter profiles are required without external DSP chips.
Signal Path:
- Analog audio input (20 Hz to 20 kHz) connects to external first-order sigma-delta modulator (MAX9814 or similar)
- 1-bit bitstream at 640 kHz enters chip via GPIO[8]
- CIC decimator reduces sample rate to 40 kHz (OSR=16)
- 8-tap FIR applies programmable filtering (equalizer, notch filter, voice band isolation)
- PWM DAC outputs analog-reconstructed audio via GPIO[9] to RC filter + audio amplifier (LM386)
Alternative Applications:
- Vibration sensor filtering: Process MEMS accelerometer sigma-delta output for structural health monitoring (50 Hz to 10 kHz bandpass)
- Power line noise rejection: 50/60 Hz notch filter for sensor signal cleanup in industrial environments
- Biomedical signal conditioning: ECG/EMG frontend with programmable bandwidth (0.5 Hz to 150 Hz)
Caravel Management SoC
+---------------------+
| RISC-V (PicoRV32) |
| | |
| Wishbone Bus |
+----------+----------+
|
+---------------+--------------+
| wb_csr |
| (Control & Status Registers)|
+---+------+------+--------+---+
| | | |
OSR coeffs ctrl bypass
| | | |
GPIO[8] ------+ | | | |
+---> [bit_in MUX] | |
LFSR ---------+ | | |
v | |
+----------------+ | |
| cic_decimator |<---+ |
| 3-stage, OSR | |
+-------+--------+ |
| 16-bit, fs_low |
v |
+----------------+ |
| fir_filter |<-------------+
| 8-tap Q1.15 |<-- coeff_addr/data
+-------+--------+
| 16-bit
v
+----------------+
| pwm_dac |
| 8-bit 1st ord |
+-------+--------+
| 1-bit PWM
v
GPIO[9] ---> RC filter ---> Analog output
| Block | File | Description |
|---|---|---|
wb_csr |
rtl/digital/wishbone_csr/wb_csr.v |
Wishbone B4 peripheral CSR. Decodes address offsets, drives all control signals, captures status. Single-cycle ACK. |
cic_decimator |
rtl/digital/cic/cic_decimator.v |
3-stage CIC filter. Integrators run at full clock rate. Comb sections triggered by decimation pulse at clk / OSR. 16-bit internal word width. |
fir_filter |
rtl/digital/fir/fir_filter.v |
8-tap direct-form I FIR. Combinational MAC with registered output. Q1.15 coefficients. Initialized to identity (passthrough) on reset. Runtime-loadable via CSR. |
pwm_dac |
rtl/digital/pwm_dac/pwm_dac.v |
First-order delta-sigma PWM modulator. 8-bit accumulator, carry-out is the output bit. |
lfsr |
rtl/digital/lfsr/lfsr.v |
16-bit Galois LFSR, polynomial x^16 + x^14 + x^13 + x^11 + 1. Seed 0xACE1 on reset. Used as a test bitstream source in place of external hardware. |
Base address: 0x30000000 (Caravel Wishbone user space). All registers are 32-bit. Unused bits read 0, ignored on write.
| Offset | Name | Bits | R/W | Reset | Description |
|---|---|---|---|---|---|
0x00 |
CTRL |
[0] |
R/W | 1 | enable - gates the entire pipeline |
[1] |
R/W | 0 | bypass_fir - routes CIC output directly to PWM DAC |
||
[2] |
R/W | 0 | bypass_cic - routes raw bitstream to FIR input |
||
[3] |
R/W | 0 | soft_rst - synchronous reset for all datapath registers |
||
[4] |
R/W | 0 | use_lfsr - selects internal LFSR instead of GPIO[8] |
||
0x04 |
OSR |
[6:0] |
R/W | 16 | CIC decimation ratio. Valid: 8, 16, 32, 64 |
0x08 |
COEFF_ADDR |
[2:0] |
R/W | 0 | FIR tap index (0 to 7) |
0x0C |
COEFF_DATA |
[15:0] |
R/W | 0 | FIR coefficient in Q1.15. Write pulses coeff_wr to load into tap COEFF_ADDR |
0x10 |
STATUS |
[0] |
R | - | data_valid - high for one cycle per FIR output sample |
0x14 |
PWM_DATA |
[7:0] |
R/W | 0x80 | Direct PWM value when bypass_fir = 1 |
Example: Loading FIR coefficients (8-tap moving average)
#define CSR_BASE 0x30000000
// Load h[k] = 1/8 = 0x1000 in Q1.15 for all 8 taps
for (int i = 0; i < 8; i++) {
*(volatile uint32_t*)(CSR_BASE + 0x08) = i; // COEFF_ADDR
*(volatile uint32_t*)(CSR_BASE + 0x0C) = 0x1000; // COEFF_DATA (triggers load)
}
*(volatile uint32_t*)(CSR_BASE + 0x04) = 16; // OSR = 16
*(volatile uint32_t*)(CSR_BASE + 0x00) = 0x01; // enable- Docker: Linux | Windows | Mac with Intel Chip | Mac with M1 Chip
- Python 3.8+ with PIP
-
Clone the repository:
git clone https://github.com/Mummanajagadeesh/fir-accel-caravel-soc.git cd fir-accel-caravel-soc -
Set up your local environment:
export PDK_ROOT=~/pdks export PDK=sky130A export OPENLANE_ROOT=~/OpenLane export CARAVEL_ROOT=$(pwd)/caravel export UPRJ_ROOT=$(pwd) make setup
This command installs:
- caravel_lite
- Management core for simulation
- OpenLane for design hardening
- PDK
- Timing scripts
-
Run RTL simulation on individual blocks:
# PWM DAC testbench iverilog -o sim/digital/pwm_dac_sim \ rtl/digital/pwm_dac/pwm_dac.v sim/digital/tb_pwm_dac.v && \ vvp sim/digital/pwm_dac_sim # CIC decimator testbench iverilog -o sim/digital/cic_sim \ rtl/digital/cic/cic_decimator.v sim/digital/tb_cic.v && \ vvp sim/digital/cic_sim # FIR filter testbench iverilog -o sim/digital/fir_sim \ rtl/digital/fir/fir_filter.v sim/digital/tb_fir.v && \ vvp sim/digital/fir_sim # Top-level integration testbench iverilog -o sim/digital/top_sim \ verilog/rtl/user_project_wrapper.v \ rtl/digital/wishbone_csr/wb_csr.v \ rtl/digital/cic/cic_decimator.v \ rtl/digital/fir/fir_filter.v \ rtl/digital/pwm_dac/pwm_dac.v \ rtl/digital/lfsr/lfsr.v \ sim/digital/tb_top.v && \ vvp sim/digital/top_sim
-
Harden the design using OpenLane:
cd openlane # Harden user project (RTL to GDS) make wrapped_filter \ OPENLANE_ROOT=$OPENLANE_ROOT \ PDK_ROOT=$PDK_ROOT \ PDK=sky130A \ CARAVEL_ROOT=$CARAVEL_ROOT \ UPRJ_ROOT=$UPRJ_ROOT
-
Run timing analysis:
make extract-parasitics make create-spef-mapping make caravel-sta
[!NOTE] To update timing scripts, run
make setup-timing-scripts. -
Run the precheck locally:
make precheck make run-precheck
-
Submit your project at Efabless Open Shuttle Program.
The FIR accelerator is instantiated as mprj_wrapper inside user_project_wrapper.v. The wrapper connects:
- Wishbone bus interface (clk, rst, stb, cyc, we, sel, adr, dat, ack)
- GPIO signals:
io_in[8](bitstream input),io_out[9](PWM output) - Logic analyzer interface (unused, available for debug)
- Power pins (VCCD1, VSSD1)
Key files:
verilog/rtl/user_project_wrapper.v- Top-level Caravel wrapperverilog/rtl/mprj_wrapper.v- FIR accelerator integration moduleverilog/gl/user_project_wrapper.v- Gate-level netlist (post-hardening)
Specify the power-on default configuration for each GPIO in Caravel in verilog/rtl/user_defines.v.
GPIO Mapping:
| GPIO | Direction | Function |
|---|---|---|
io_in[8] |
Input | Bitstream input (external sigma-delta modulator in normal mode) |
io_out[9] |
Output | PWM DAC output (connect to RC lowpass filter for analog recovery) |
| All others | Hi-Z | Unused, io_oeb = 1 |
GPIO[5] to GPIO[37] require configuration, while GPIO[0] to GPIO[4] are preset and cannot be changed.
The Caravel layout includes an empty golden wrapper in the user space. Your hardened user_project_wrapper will be integrated into the Caravel layout during tapeout.
GDS Layout Preview:
The layout shows the full Caravel user project wrapper area (2920 x 3520 um). The orange rectangle is the user project boundary. Pin labels along the left and right edges correspond to the 38 Caravel GPIO signals. The dense colored region in the lower-left corner is the hardened digital logic (FIR filter, CIC decimator, PWM DAC, Wishbone CSR, and LFSR) placed and routed in Sky130 standard cells. The blue fill throughout the remainder of the area is the met1 PDN covering the full user project space.
Ensure your hardened user_project_wrapper meets the requirements in User Project Wrapper Requirements.
Refer to ReadTheDocs for adding cocotb tests.
-
Install the simulation environment:
make setup-cocotb
-
Run RTL simulation:
make cocotb-verify-<test_name>-rtl
-
After physical implementation, run full gate-level simulations to verify your design:
make cocotb-verify-<test_name>-gl
To add cocotb tests, refer to Adding cocotb test.
Your hardened user_project_wrapper must match the golden user_project_wrapper in:
- Area (2.920um x 3.520um)
- Top module name "user_project_wrapper"
- Pin Placement
- Pin Sizes
- Core Rings Width and Offset
- PDN Vertical and Horizontal Straps Width
You can change the PDN Vertical and Horizontal Pitch & Offset.
We run an XOR check between your hardened user_project_wrapper GDS and the golden wrapper GDS as part of the mpw-precheck tool.
Install OpenLane with:
make openlaneFor more detailed instructions, refer to the ReadTheDocs.
There are three options for hardening the user project macro using OpenLane:
-
Option 1: Harden the user macro(s) first, then insert it into the user project wrapper with no standard cells at the top level.
Example: caravel_user_project
-
Option 2: Flatten the user macro(s) with the user_project_wrapper.
-
Option 3: Place multiple macros in the wrapper along with standard cells at the top level.
Example: clear
For more details, refer to the Knowledgebase article.
For this project, we used a flattened approach: the FIR accelerator digital blocks are synthesized and placed directly within the user_project_wrapper.
To reproduce this process, run:
cd openlane
# Harden wrapped_filter (contains all digital logic)
make wrapped_filter \
OPENLANE_ROOT=$OPENLANE_ROOT \
PDK_ROOT=$PDK_ROOT \
PDK=sky130A \
CARAVEL_ROOT=$CARAVEL_ROOT \
UPRJ_ROOT=$UPRJ_ROOTOpenLane Flow Steps:
| Step | Tool | Description |
|---|---|---|
| Lint | Verilator | RTL lint checks |
| Synthesis | Yosys | RTL to gate-level netlist |
| STA (pre-layout) | OpenSTA | Timing on synthesized netlist |
| Floorplan | OpenROAD | Die area, pin placement, PDN |
| Placement | OpenROAD | Global and detailed placement |
| CTS | OpenROAD | Clock tree synthesis |
| Routing | TritonRoute | Global and detailed routing |
| RC Extraction | OpenRCX | Parasitics from routed layout |
| STA (post-layout) | OpenSTA | Final timing sign-off |
| DRC | Magic | Design rule check |
| LVS | Netgen | Layout vs schematic |
| Antenna | OpenROAD | Metal antenna check |
| GDS | Magic | Final GDS stream output |
Key configuration (openlane/wrapped_filter/config.json):
{
"CLOCK_PERIOD": 25,
"DIE_AREA": "0 0 2800 1760",
"FP_CORE_UTIL": 35,
"PL_TARGET_DENSITY": 0.4,
"MAX_FANOUT_CONSTRAINT": 16,
"RT_MAX_LAYER": "met4"
}For more information, refer to the OpenLane Documentation.
To pass precheck, a custom LVS configuration file (lvs_config.json) is needed for your design. The configuration file should include:
Required variables:
- TOP_SOURCE: Top source cell name.
- TOP_LAYOUT: Top layout cell name.
- LAYOUT_FILE: Layout GDS data file.
- LVS_SPICE_FILES: List of spice files.
- LVS_VERILOG_FILES: List of Verilog files (child modules should be listed before parent modules).
Optional variables:
- INCLUDE_CONFIGS: List of configuration files to read recursively.
- EXTRACT_FLATGLOB: List of cell names to flatten before extraction.
- EXTRACT_ABSTRACT: List of cells to extract as abstract devices.
- LVS_FLATTEN: List of cells to flatten before comparing.
- LVS_NOFLATTEN: List of cells not to flatten in case of a mismatch.
- LVS_IGNORE: List of cells to ignore during LVS.
Note
Missing files and undefined variables result in fatal errors.
Install the mpw-precheck by running:
make precheckRun the precheck with:
make run-precheckTo disable LVS/Soft/ERC connection checks:
DISABLE_LVS=1 make run-precheckUpdate the Makefile for your project:
make setup-timing-scriptsRun timing analysis:
make extract-parasitics
make create-spef-mapping
make caravel-staA summary of timing results is provided at the end.
Digital RTL Simulation (Icarus Verilog): PASS
| Testbench | Module Under Test | Status | Key Metrics |
|---|---|---|---|
tb_pwm_dac.v |
PWM DAC | PASS | 5/5 test patterns, <1% duty cycle error |
tb_cic.v |
CIC decimator | PASS | DC gain = 4096 (theory match), settling time verified |
tb_fir.v |
FIR filter | PASS | Step response correct, Q1.15 arithmetic validated |
tb_wb_csr.v |
Wishbone CSR | PASS | All register r/w operations pass, ACK timing correct |
tb_top.v |
Full integration | PASS | End-to-end datapath functional |
tb_gl_wrapper.v |
Gate-level + SDF | PASS | Post-layout simulation with timing, all tests pass |
Physical Verification: PASS
| Check | Tool | Result | Evidence |
|---|---|---|---|
| Magic DRC | Magic 8.3 | 0 violations | signoff/user_project_wrapper/openlane-signoff/drc.rpt |
| LVS | Netgen | Clean (18,329 nets matched) | signoff/user_project_wrapper/openlane-signoff/*lvs.rpt |
| Setup timing | OpenSTA | No violations (slack: +8.2 ns) | signoff/user_project_wrapper/openlane-signoff/*rcx_sta.max.rpt |
| Hold timing | OpenSTA | No violations (slack: +0.4 ns) | signoff/user_project_wrapper/openlane-signoff/*rcx_sta.min.rpt |
| Antenna violations | OpenROAD | 2 warnings (non-critical) | Below Sky130A DRM threshold |
| GDS size | - | 95 MB | gds/user_project_wrapper.gds |
| Die area | - | 2920 x 3520 um | Matches Caravel golden wrapper |
| Standard cell library | - | sky130_fd_sc_hd | Sky130A high-density standard cells |
| Target clock period | - | 25 ns (40 MHz) | Meets audio sample rate requirements |
Critical Path Analysis:
- Critical path: FIR multiply-accumulate tree (16-bit x 8 taps)
- Setup slack: +8.2 ns at typical corner (33% margin)
- Hold slack: +0.4 ns at typical corner
- Clock skew: <200 ps
Silicon to System Integration (Audio Line-In Filter Application)
- Caravel QFN-64 package with fabricated FIR accelerator in user project area
- Clock: 40 MHz (25 ns period), internal RC oscillator + PLL from Caravel management core
- Power: 3.3V digital (VCCD), supplied via Caravel regulators
- I/O: GPIO[8] input, GPIO[9] PWM output
Design files in pcba/ directory:
- Schematic: KiCad
fir_accel_breakout.kicad_sch - BOM: 14 components (Caravel chip, passives, headers) - see
pcba/BOM.md - Key external components:
- RC lowpass filter (R=10k, C=100nF, fc=159 Hz) on GPIO[9] for PWM DAC reconstruction
- Decoupling capacitors (100nF on VCCD, VDDA)
- 4-pin UART header for firmware debug (Caravel management core serial console)
- 2-pin headers for GPIO[8] input and analog output
- Board size: 60mm x 40mm (2-layer FR4, 1.6mm thickness)
- Connectors: 2.54mm pitch headers, standard 0402 passives for assembly
External Signal Chain (off-board):
- Input stage: Microphone preamplifier + MAX9814 sigma-delta ADC (1-bit, 640 kHz) -> GPIO[8]
- Output stage: GPIO[9] -> RC filter -> LM386 audio amplifier -> 8-ohm speaker
Design files in mechanicals/ directory:
- CAD source: OpenSCAD parametric model (
enclosure.scad) - STL files:
enclosure_base.stl,enclosure_lid.stl - Manufacturing: FDM 3D printing (PLA/PETG, 0.2mm layer height, 20% infill)
- PCB mounting: 4x M2.2 self-tapping screws into integrated standoffs
- Cutouts: Connector access on all four sides (GPIO, UART, power)
RISC-V firmware (C code, compiled with GCC RISC-V toolchain):
- Initialize Wishbone CSR (base address 0x30000000)
- Load FIR coefficients for target filter profile (8 taps, Q1.15 format)
- Configure CIC decimation ratio (OSR=16 for 640 kHz to 40 kHz)
- Enable datapath (CTRL[0]=1)
- Continuous operation (no CPU intervention required after setup)
- Bench test: Apply 1 kHz sine wave to MAX9814 input, verify filtered output on GPIO[9] with oscilloscope
- Frequency response: Sweep 20 Hz to 20 kHz, measure passband ripple and stopband attenuation
- Audio quality: Subjective listening test with voice/music input
- Low-cost voice intercom: Fixed 300-3400 Hz bandpass (telephone quality)
- Vibration monitor: MEMS accelerometer input, 50-10 kHz bandpass for machinery fault detection
- ECG frontend: 0.5-150 Hz bandpass, 50/60 Hz notch filter for power line rejection
- ✔️ The project repo follows the directory structure in this repo.
- ✔️ Top level macro is named
user_project_wrapper. - ✔️ Full Chip Simulation passes for RTL and GL (6 testbenches, all PASS).
- ✔️ Hardened Macros are LVS and DRC clean (0 DRC violations, 18,329 nets matched).
- ✔️ Contains a gate-level netlist for
user_project_wrapperatverilog/gl/user_project_wrapper.v. - ✔️ Hardened
user_project_wrappermatches the pin order. - ✔️ Matches the fixed wrapper configuration.
- ✔️ Design passes the mpw-precheck.
- ✔️ Timing analysis shows positive slack (Setup: +8.2 ns, Hold: +0.4 ns).
- ✔️ PCBA schematic and BOM provided in
pcba/directory. - ✔️ Mechanicals (3D-printable enclosure) provided in
mechanicals/directory. - ✔️ Apache 2.0 license with SPDX headers in all source files.
- ✔️ Public GitHub repository: https://github.com/Mummanajagadeesh/fir-accel-caravel-soc
1. Audio DSP
- Parametric equalizer: Program FIR taps for shelving/peaking filters at runtime
- Adaptive noise cancellation: Update coefficients via firmware based on ambient noise profile
- Voice activity detection: Bandpass filter + threshold detection on STATUS register
2. Vibration Filtering
- Structural health monitoring: Bandpass 50 Hz to 10 kHz for accelerometer input
- Fault detection in rotating machinery: Notch filter at rotation frequency harmonics
- Seismic sensor frontend: 0.1 Hz to 50 Hz highpass for earthquake detection
3. Edge Signal Cleanup
- Industrial sensor interfaces: 50/60 Hz power line rejection for thermocouple, RTD, strain gauge
- ECG/EMG biomedical frontend: 0.5 Hz to 150 Hz bandpass with 50/60 Hz notch
- Sensor fusion: Combine multiple MEMS sensors with weighted FIR taps for redundancy
Phase 2: Analog Frontend (Sigma-Delta Modulator)
- Replace external MAX9814 ADC with on-chip first-order sigma-delta modulator
- Schematic in Xschem using Sky130 primitives (nfet_01v8, pfet_01v8, cap_mim_m3_1)
- Transient simulation in NGSpice to verify modulator stability and SNR (target: >60 dB)
- Manual layout in Magic VLSI with DRC and LVS signoff
- Post-layout parasitic extraction and re-simulation
- Integration into Caravel wrapper using Caravan analog I/O pads
Phase 3: Full-Chip Validation
- Caravel cocotb testbench for full SoC simulation (RISC-V firmware + digital datapath)
- FPGA prototype on iCE40 or Lattice ECP5 for real-time audio testing
- PCB fabrication and assembly for bench validation
Phase 4: Tapeout
- Efabless chipIgnite shuttle submission
- Post-silicon characterization (frequency response, SNR, power consumption)
| Tool | Version | Purpose |
|---|---|---|
| OpenLane | 1.0.2 (superstable) | RTL to GDS flow |
| Sky130A PDK | 78b7bc32 | Process design kit |
| Yosys | bundled | Synthesis |
| OpenROAD | bundled | Place and route |
| Magic VLSI | 8.3.105 | DRC, LVS, GDS |
| Netgen | bundled | LVS netlist comparison |
| Icarus Verilog | 11.0 | RTL simulation |
| NGSpice | 36 | SPICE simulation (Phase 2) |
| KLayout | 0.29.2 | GDS viewer |
| Docker image | efabless/openlane:2023.07.19-1 | Reproducible flow environment |
Licensed under the Apache License, Version 2.0. See LICENSE for details.
The Caravel harness and management core are copyright Efabless Corporation, also under Apache 2.0.
For detailed technical documentation including DSP theory, fixed-point arithmetic, simulation results, and hardware specifications, see docs/README.md.






