This repository was created as part of a semester thesis at the Integrated Systems Laboratory (IIS), ETH Zurich, focusing on open-source ultrasound pulser IP development for the PULP platform. It was developed by Nico Canzani under the supervision of Federico Villani and Alessandro Ottaviano.
Pulser is a SystemVerilog-based project that generates precisely timed output pulses with fully configurable parameters. It includes:
- A complete RTL implementation (
pulser.sv
&pulser_core.sv
) - A simulation environment and testbench
- Auto-generated register files (via HJSON +
regtool.py
) - Auto-generated C-header for software control (not included, can be generated)
- A top-level bus interface (OBI) for easy integration
- Up to 16 pulsers
-
Clone the repository
git clone https://github.com/nicoca20/pulser.git cd pulser
-
Generate Register Files
# Generate SystemVerilog register banks under rtl/regs/ regtool.py -r -t rtl/regs/ data/pulser_core.hjson regtool.py -r -t rtl/regs/ data/pulser_general.hjson # Generate C headers under sw/ regtool.py -D data/pulser_core.hjson -o sw/pulser_core_reg_defs.h regtool.py -D data/pulser_general.hjson -o sw/pulser_general_reg_defs.h
-
Simulate pulser_core
- Testbench:
sim/tb_pulser_core.sv
- Run your simulator (e.g., VCS, Questa, or Verilator) on
tb_pulser_core.sv
.
- Testbench:
-
Integrate into SoC
- Connect the top-level
pulser
module’s OBI interface to your interconnect. - Use the auto-generated C header (
sw/pulser_core_reg_defs.h
) to read/write registers.
- Connect the top-level
-
Parameterizable Pulse Generator
- Supports multiple independent pulse instances (
N_PULSER_INST
). - Configurable durations, duty-cycles, and stop behavior.
- Supports multiple independent pulse instances (
-
Register-Mapped Interface
- Exposes all control/configuration registers via OBI (Open Bus Interface).
- Auto-generated register definitions (HJSON → SV/C).
-
Software-Controllable
- Start/Stop mechanisms for each pulser instance.
- Shared “general” register to enable/disable clocks and synchronusly start / stop pulsers.
-
Clock Gating
- Per-instance clock gating to minimize power when idle.
-
Simulation Environment
pulser_core
testbench with waveform dumping.- Golden Model, written in python.
- Example sequences demonstrating F1, F2, and stop pulses.
Two primary modules form the Pulser design:
-
pulser
(Top-Level Wrapper)- Instantiates multiple
pulser_core
units (one per pulse channel). - Demultiplexes OBI register requests to each core’s register bank.
- Provides a “general” register set for clock enable, global start/stop.
- Instantiates multiple
-
pulser_core
(Pulse Generation Logic)- Implements a finite-state machine (FSM) to generate precise pulses.
- Supports two frequencies (F1 & F2), plus a final inverted “stop” pulse.
- Outputs a single-bit
pulse_o
per instance. - returns current FSM-state.
All register files are generated from two HJSON files:
data/pulser_core.hjson
data/pulser_general.hjson
The diagram below shows a conceptual single-pulser_core
setup with its register interface (not an actual instantiation in RTL). It illustrates how the core, register file, and clock gating fit together.
periph_to_reg
: Bridges OBI-style bus to internalreg_req
/reg_rsp
.pulser_core_reg_top
: Register bank housing control (start/stop) and config (F1, F2) fields.pulser_core
: FSM-driven pulse generator.tc_clk_gating
: Cell to disablepulser_core
's clock.
In a real instantiation (e.g. N_PULSER_INST = 2
), a multiplexer/demultiplexer routes register accesses to the correct core. A “general” register bank controls clock enables and global settings. Components in blue are replicated for each instance.
periph_to_reg
(shared)pulser_core_reg_top
(one per instance)pulser_general_reg_top
(shared)pulser_core
(one per instance)tc_clk_gating
(one per instance)
For detailed instructions on configuring and operating the Pulser, see the Pulser Configuration Guide.
All registers are defined in HJSON under data/
and generated via regtool.py
:
- Core registers:
pulser_core.hjson
- General registers:
pulser_general.hjson
# Core register bank (rtl/regs/pulser_core_reg_pkg.sv etc.)
regtool.py -r -t rtl/regs/ data/pulser_core.hjson
# General register bank (rtl/regs/pulser_general_reg_pkg.sv etc.)
regtool.py -r -t rtl/regs/ data/pulser_general.hjson
# Core C definitions (sw/pulser_core_reg_defs.h)
regtool.py -D data/pulser_core.hjson -o sw/pulser_core_reg_defs.h
# General C definitions (sw/pulser_general.hjson)
regtool.py -D data/pulser_general.hjson -o sw/pulser_general_reg_defs.h
The version of regtool.py
used is from the pulp-platform/carfield repository, commit 0136ff9
.
The following files are released under Solderpad v0.51 (SHL-0.51
) (see LICENSE):
tb/
rt/*.sv
data/
The following files are released under Creative Commons Attribution 4.0 International
License (CC-BY-4.0
) (see doc/LICENSE):
doc/*.drawio
doc/*.svg
The rtl/regs/*
files are generated by a fork of lowRISC's regtool
and licensed under Apache License 2.0 (Apache-2.0
) (see see rtl/regs/LICENSE):
rtl/regs/
In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.