549 Ring Oscillator PVT Sensor & TRNG (GF180)

549 : Ring Oscillator PVT Sensor & TRNG (GF180)

Design render
  • Author: Prof. Santhosh Sivasubramani, IIT Delhi
  • Description: GF180mcuD port of 5 SPI-configurable ring oscillators (7/11/15/21/31 gf180 stages) with 16-bit frequency counter, auto gate timer, configurable prescaler, XOR jitter TRNG, per-RO health history, differential RO beat-frequency mode, and frequency-bounds health monitor for cross-foundry PVT characterization
  • GitHub repository
  • Open in 3D viewer
  • Clock: 50000000 Hz

How it works

This design is the GF180mcuD port of our SKY130 ring-oscillator PVT sensor (tt_um_santhosh_ring_osc). It implements five gatable ring oscillators (7, 11, 15, 21, and 31 gf180mcu_fd_sc_mcu7t5v0__inv_1 inverter-chain stages, each with a gf180mcu_fd_sc_mcu7t5v0__nand2_1 enable gate) together with a 16-bit frequency counter, a three-stage CDC synchronizer, an auto gate timer, a configurable prescaler, an XOR-jitter true random number generator (TRNG), a frequency-bounds health monitor, and a differential (beat-frequency) measurement mode. It is intended for cross-foundry PVT characterization: pairing this tile with the SKY130 sibling on the same chip family lets us compare ring-oscillator frequency, TRNG statistics, and aging drift between the two nodes from identical RTL.

All oscillator stages are tagged with (* keep, dont_touch *) so that the synthesis and placement flows preserve them as physical inverter/NAND chains rather than optimizing them into constant nets.

The block supports two control modes, selected by ui_in[6] (spi_mode):

  • Parallel mode (spi_mode=0)ro_sel[2:0] (ui_in[2:0]) chooses one of the five ROs, cnt_enable (ui_in[3]) starts/stops counting, a rising edge on cnt_clear_latch (ui_in[4]) latches the 16-bit count and clears the accumulator, and byte_sel (ui_in[5]) multiplexes uo_out between the low (0) and high (1) bytes of the latched count. uio_out[4] is the overflow flag, uio_out[5] exposes the raw RO output, uio_out[6] the synchronized RO output, and uio_out[7] is meas_done from the auto gate timer.
  • SPI mode (spi_mode=1) — a 16-bit SPI slave (Mode 0, MSB first; CS on uio_in[0], MOSI on uio_in[1], MISO on uio_out[2], SCK on uio_in[3]) exposes a register file:
Addr Name Access Description
0x00 reg_ctrl R/W [0]=auto_gate_start (self-clear); [1]=clear_meas_done; [2]=clear_health_history (self-clear, new on GF)
0x01 reg_ro_sel R/W [2:0] RO select
0x02 reg_ro_en R/W [4:0] per-RO enable — reset default 0x1F
0x03 reg_gate_l R/W gate-time low byte
0x04 reg_gate_h R/W gate-time high byte
0x05 reg_prescale R/W [1:0] prescaler (÷8/÷16/÷32/÷64; reset default ÷16)
0x06 reg_status R [0]=gate_active, [1]=overflow, [2]=meas_done
0x07 reg_count_l R latched count [7:0]
0x08 reg_count_h R latched count [15:8]
0x09 reg_trng_ctrl R/W [0]=trng_en, [1]=health_en, [2]=diff_mode
0x0A reg_diff_sel R/W [2:0] RO_B selector for beat/XOR modes
0x0B reg_health_lo R/W expected frequency lower bound
0x0C reg_health_hi R/W expected frequency upper bound
0x0D reg_trng_data R 8-bit XOR-jitter byte
0x0E reg_health_status R [0]=below, [1]=above, [2]=stuck, [3]=ok, [4]=trng_valid
0x0F reg_hh_stuck R per-RO stuck history (sticky; new on GF)
0x10 reg_hh_below R per-RO below-lo history (sticky; new on GF)

The raw RO is synchronized into the system clock domain through a 3-stage flip-flop synchronizer (with an optional ÷8/÷16/÷32/÷64 prescaler ahead of it) before being rising-edge detected and counted. When diff_mode is set, two user-selected ROs are XORed prior to counting, producing the beat frequency |f_A − f_B|, which is very sensitive to local PVT mismatch. The TRNG collects XOR jitter bits into an 8-bit register readable at reg_trng_data; the health monitor flags the selected RO against reg_health_lo/reg_health_hi bounds into reg_health_status.

New on GF: per-RO health history

GF180 1×1 tile area (~55 712 µm²) holds more gates than SKY130 1×1 (~17 954 µm²) after process-scaling, so on this port we re-enable a feature that was deferred on the SKY submission: two sticky 5-bit history registers (reg_hh_stuck, reg_hh_below) that latch a bit per RO whenever that RO is the currently-selected one and is flagged stuck or below-lo by the health monitor. The registers survive until explicitly cleared by writing reg_ctrl[2]=1 (self-clearing pulse). This makes aging and fault detection possible without continuously polling from the host.

How to test

  1. Apply reset (rst_n low for ≥10 clock cycles, then release).
  2. Simple parallel measurement: set spi_mode=0, write ro_sel[2:0] to select RO (0=7, 1=11, 2=15, 3=21, 4=31), pulse cnt_enable high for the desired gate time, pulse cnt_clear_latch high for ≥1 cycle to latch the count, then toggle byte_sel and read uo_out to retrieve the low and high bytes of the 16-bit count. Check uio_out[4] for overflow.
  3. SPI-timed measurement: set spi_mode=1, write reg_gate_l/h with the desired gate cycle count, set reg_ctrl[0]=1 to start the auto gate timer, poll reg_status (or watch uio_out[7] = meas_done) for completion, and read reg_count_l / reg_count_h. Write reg_ctrl[1]=1 to clear meas_done before the next run.
  4. TRNG: in SPI mode, set reg_trng_ctrl[0]=1 and enable at least two ROs; read reg_trng_data (0x0D) to consume 8 jitter-XOR bits.
  5. Health monitor: set reg_trng_ctrl[1]=1, write reg_health_lo/reg_health_hi to the expected frequency window, and read reg_health_status (0x0E) after each gate. For long-term audits, sweep all 5 ROs and read reg_hh_stuck (0x0F) / reg_hh_below (0x10); write reg_ctrl[2]=1 to clear.
  6. Differential mode: set reg_trng_ctrl[2]=1, set reg_ro_sel to RO_A and reg_diff_sel to RO_B, then gate as usual — the count represents |f_A − f_B|.

A cocotb test suite (23 tests in test/test.py) exercises parallel counting, SPI register roundtrip, auto gate timing, prescaler selection, TRNG/health/differential modes, uio_oe direction control, and the new GF-only health-history registers and self-clearing reg_ctrl[2]. All tests pass on the RTL. Gate-level simulation is intentionally skipped in CI because the real gf180mcu inverter-chain ring oscillators produce ≈10⁹ events/s of simulated time and are not tractable in icarus.

External hardware

No external hardware is required for core operation. For SPI control, an SPI master (microcontroller or FPGA) is connected to uio[0] (CS), uio[1] (MOSI), uio[2] (MISO), uio[3] (SCK) at any clock rate up to half the system clock. Optional: an oscilloscope on uio_out[5] (raw RO) and uio_out[6] (synced RO) for direct frequency observation, and any 8-bit digital sink (logic analyzer or microcontroller GPIO) on uo_out[7:0] for reading the latched count byte in parallel mode.

IO

#InputOutputBidirectional
0ro_sel[0]freq_count[0]spi_cs_n
1ro_sel[1]freq_count[1]spi_mosi
2ro_sel[2]freq_count[2]spi_miso
3cnt_enablefreq_count[3]spi_sck
4cnt_clear_latchfreq_count[4]overflow
5byte_selfreq_count[5]ro_raw_out
6spi_modefreq_count[6]ro_synced
7freq_count[7]meas_done

Chip location

Controller Mux Mux Mux Mux Mux Mux Mux Mux Mux Mux Mux Mux Mux Mux Mux tt_um_chip_rom (Chip ROM) tt_um_factory_test (Tiny Tapeout Factory Test) tt_um_utoss_riscv (UTOSS RISC-V core) tt_um_memory_game_top (Number Memory Game) tt_um_danielpenas42 (Ball Display) tt_um_machinelearning (7-Segment Neural Predictor) tt_um_microlane_demo (microlane demo project) tt_um_pixel_processor (Tiny Pixel Processor) tt_um_jpigdon_gps_accelerator_top (GPS_Accelerator) tt_um_rgb_mixer (rgb_mixer) tt_um_bgao43 (Tiny TPU Systolic Array) tt_um_main (Pong in Verilog) tt_um_joannec34_teenytpu (teenytpu) tt_um_apa102_ws2812_squidgeefish (APA102 to WS2812 Translator) tt_um_uacj_bouncing_DVD_screensaver (Custom DVD Screensaver for VGA) tt_um_logoUACJ_MOGA (VGA_screensaver_UACJ) tt_um_grace_spi_led_driver (SPI-Controlled 8-Channel LED Driver) tt_um_rebeccargb_universal_decoder (Universal Binary to Segment Decoder) tt_um_rebeccargb_hardware_utf8 (Hardware UTF Encoder/Decoder) tt_um_happyhop_deadcast2 (happyhop) tt_um_dino7 (Dino-7: 7-Segment Runner Game) tt_um_arty3_mac_engine (Simple MAC Engine w/ Postproc) tt_um_uacj (Custom DVD Screensaver for VGA) tt_um_algofoogle_dottee (DOTTEE VGA demo (TTGF26a)) tt_um_mattvenn_signal_generator (Simple Signal Generator) tt_um_urish_simon (Simon Says memory game) tt_um_tpu (Tensor Processing Unit For GF) tt_um_gojimmypi_ttgf_UART_FSM_TRNG_Lab (Hardware Entropy Explorer: UART/SPI TRNG and PUF) tt_um_wokwi_465483277165299713 (First Tinytapeout) tt_um_prem_pipeline_test (Programmable_Pipeline-RISC-V) tt_um_wokwi_467219410242853889 (Tiny Tapeout testtest 111233) tt_um_wokwi_465549494272929793 (Pacos first design) tt_um_wokwi_465731371445677057 (Arturo's first Wokwi design) tt_um_wokwi_465732744934845441 (Tiny Tapeout Template_1234) tt_um_wokwi_465736492859711489 (Tiny Tapeout Workshop JuanF) tt_um_wokwi_465731430225727489 (Rafa’s first Wokwi design) tt_um_wokwi_465731458365332481 (7 segment Display Fli-Flop Try-out) tt_um_wokwi_465732744245929985 (DiseñoCursoTiny) tt_um_wokwi_465731490568160257 (Matt’s first Wokwi design) tt_um_wokwi_465736691688630273 (test1) tt_um_wokwi_465731458628527105 (Mi copia del Tiny Tapeout) tt_um_wokwi_465731520738845697 (El primer diseño) tt_um_wokwi_465731521356457985 (Tiny Tapeout Template Copy) tt_um_gen1_digital_companion_tile (Gen1 Digital Companion Tile) tt_um_wokwi_465732827753495553 (Tiny Tapeout Template Ayman) tt_um_wokwi_465731394728267777 (Julian_Proyecto) tt_um_wokwi_465731458535202817 (Tiny Tapeout Template Copy) tt_um_wokwi_465732847401723905 (Basic Circuit) tt_um_wokwi_465731452481768449 (El primer diseño de Matt para Wokwi) tt_um_wokwi_465731502018614273 (Tiny Tapeout Template flip flop) tt_um_wokwi_465732616714924033 (Tiny Tapeout RJAP) tt_um_wokwi_465731575275296769 (ocxpkeWokwiDesign) tt_um_wokwi_465732880722332673 (Pedro Template) tt_um_wokwi_465731858252480513 (Paula's first Wokwi design) tt_um_wokwi_465731455677830145 (Tiny Tapeout JMCG) tt_um_wokwi_465737601403996161 (Tiny Number Simon) tt_um_ttmul (Balanced Ternary Multiplier) tt_um_wokwi_465731466664816641 (Tiny Tapeout Workshop Malaga 2jun2026) tt_um_8bit_risc_cpu (8-bit RISC CPU) tt_um_wokwi_451184391728659457 (Simple Sprinkler) tt_um_fhw_appel_spiPWMio (spiPWMio) tt_um_divadnauj_GB_serv_soc_wb (serv_soc_wb) tt_um_8bitcustomcomputer (SAP 8 Bit Computer) tt_um_bioimpedance (Very Low Resource Digital Implementation of Bioimpedance Analysis) tt_um_mgj_bist8 (BIST-8: Built-In Self-Test for 8-bit CLA Adder) tt_um_roberto_tiny_radar_tile (BioPulse Tile) tt_um_systolic_mac_2x2 (2x2 Systolic Array Matrix Multiplier) tt_um_peg_top (2x2 CNN Accelerator PE Grid with UART) tt_um_AlvaroRub_ringcounter (Counter16Outputs) tt_um_wokwi_465731440267947009 (Antonio's first Wokwi design) tt_um_wokwi_465732706576877569 (Guille's first Wokwi design.) tt_um_wokwi_465731481873367041 (MIPS-Lite 8-bit Processor) tt_um_wokwi_465736612213902337 (Juan`s first Worki design) tt_um_wokwi_465731439156454401 (Rhyloo’s first Wokwi design) tt_um_wokwi_465732536551273473 (Tiny Tapeout Marcos Fernandez) tt_um_wokwi_465737290543084545 (Tiny Tapeout Template) tt_um_wokwi_465630130495825921 (ram 1 bit Copy) tt_um_wokwi_465731403724006401 (sdft wokwi 1) tt_um_top (RHD2164-MCU-SPI Bridge) tt_um_line_follower_arvaloez (Line Follower Robot controller) tt_um_xoroshiro64plus_v2 (xoroshiro64) tt_um_ohuettenhofer_tiny_qsim (Tiny Quantum Circuit Simulator) tt_um_santhosh_ring_osc_gf (Ring Oscillator PVT Sensor & TRNG (GF180)) tt_um_santhosh_stoch_stdp_pair_gf (Stochastic neuron + STDP controller (merged, GF180)) tt_um_santhosh_rsd_char_gf (RRAM Characterization Platform (DC sweep + endurance + retention + histogram, GF180)) tt_um_santhosh_xbar_ctrl_gf (Memristive Crossbar Peripheral Controller (GF180)) tt_um_joseph_bf (BF) tt_um_hydrocomms (FSK Modem) tt_um_systolic_array (2x2 MAC Systolic array with DFT) tt_um_kluterirv_rv32e_core (Minimal RV32E SoC with UART Loader) tt_um_algofoogle_ttgf26a_vco (VCO driven by DAC) tt_um_fer_logo_music_vga (UNIZG-FER VGA project) tt_um_maqsudbek_dyadic_pwm (Dyadic PWM) tt_um_waferspace_vga_screensaver (Wafer.space Logo VGA Screensaver) tt_um_htfab_vga_tester (Video mode tester)