From 3b04f3a6beb1f7f7cd628990bd4eb33bc4f96a29 Mon Sep 17 00:00:00 2001 From: Joppe Blondel Date: Wed, 8 Oct 2025 18:01:03 +0200 Subject: [PATCH] Added lvds and sampler --- project.cfg | 4 + rtl/arch/gw1/lvds_comparator.v | 17 ++++ rtl/arch/spartan-6/lvds_comparator.v | 20 +++++ rtl/core/lvds_comparator.v | 13 ++++ rtl/core/sigmadelta_sampler.v | 23 ++++++ sim/overrides/sigmadelta_sampler.v | 111 +++++++++++++++++++++++++++ 6 files changed, 188 insertions(+) create mode 100644 rtl/arch/gw1/lvds_comparator.v create mode 100644 rtl/arch/spartan-6/lvds_comparator.v create mode 100644 rtl/core/lvds_comparator.v create mode 100644 rtl/core/sigmadelta_sampler.v create mode 100644 sim/overrides/sigmadelta_sampler.v diff --git a/project.cfg b/project.cfg index a587a71..10ba9b3 100644 --- a/project.cfg +++ b/project.cfg @@ -29,6 +29,8 @@ xst_opts = -vlgincdir rtl #files_vhdl = files_verilog = rtl/toplevel/top_generic.v rtl/core/nco_q15.v + rtl/core/sigmadelta_sampler.v + rtl/arch/spartan-6/lvds_comparator.v files_con = boards/mimas_v1/constraints.ucf files_other = rtl/util/conv.vh @@ -42,4 +44,6 @@ ivl_opts = -Irtl #files_sysverilog = files_verilog = sim/tb/tb_nco_q15.v rtl/core/nco_q15.v + rtl/core/lvds_comparator.v + sim/overrides/sigmadelta_sampler.v files_other = rtl/util/conv.vh \ No newline at end of file diff --git a/rtl/arch/gw1/lvds_comparator.v b/rtl/arch/gw1/lvds_comparator.v new file mode 100644 index 0000000..8424b20 --- /dev/null +++ b/rtl/arch/gw1/lvds_comparator.v @@ -0,0 +1,17 @@ +`timescale 1ns/1ps + +// ============================================================================= +// LVDS comparator +// Instantiating a GW1 TLVDS_IBUF +// ============================================================================= +module lvds_comparator( + input wire a, + input wire b, + output wire o +); + TLVDS_IBUF lvds_buf ( + .O(o), + .I(a), + .IB(b) + ); +endmodule \ No newline at end of file diff --git a/rtl/arch/spartan-6/lvds_comparator.v b/rtl/arch/spartan-6/lvds_comparator.v new file mode 100644 index 0000000..844b544 --- /dev/null +++ b/rtl/arch/spartan-6/lvds_comparator.v @@ -0,0 +1,20 @@ +`timescale 1ns/1ps + +// ============================================================================= +// LVDS comparator +// Instantiating a spartan-6 IBUFDS +// ============================================================================= +module lvds_comparator( + input wire a, + input wire b, + output wire o +); + IBUFDS #( + .DIFF_TERM("FALSE"), + .IOSTANDARD("LVDS33") + ) lvds_buf ( + .O(o), + .I(a), + .IB(b) + ); +endmodule \ No newline at end of file diff --git a/rtl/core/lvds_comparator.v b/rtl/core/lvds_comparator.v new file mode 100644 index 0000000..e60285f --- /dev/null +++ b/rtl/core/lvds_comparator.v @@ -0,0 +1,13 @@ +`timescale 1ns/1ps + +// ============================================================================= +// LVDS comparator +// Simple pass-though model +// ============================================================================= +module lvds_comparator( + input wire a, + input wire b, + output wire o +); + assign o = a; +endmodule \ No newline at end of file diff --git a/rtl/core/sigmadelta_sampler.v b/rtl/core/sigmadelta_sampler.v new file mode 100644 index 0000000..ff61655 --- /dev/null +++ b/rtl/core/sigmadelta_sampler.v @@ -0,0 +1,23 @@ +`timescale 1ns/1ps + +// ============================================================================= +// Sigma-Delta sampler +// Samples A>B at clk +// ============================================================================= +module sigmadelta_sampler( + input wire clk, + input wire a, + input wire b, + output wire o +); + + wire comp_out; + lvds_comparator comp ( + .a(a), .b(b), .o(comp_out) + ); + + reg registered_comp_out; + always @(posedge clk) registered_comp_out <= o; + assign o = registered_comp_out; + +endmodule \ No newline at end of file diff --git a/sim/overrides/sigmadelta_sampler.v b/sim/overrides/sigmadelta_sampler.v new file mode 100644 index 0000000..5c56c4b --- /dev/null +++ b/sim/overrides/sigmadelta_sampler.v @@ -0,0 +1,111 @@ +`timescale 1ns/1ps + +// ============================================================================= +// Sigma-Delta sampler +// Simulates an RC circuit between O and B and a sine at A +// ============================================================================= +module sigmadelta_sampler( + input wire clk, + input wire a, + input wire b, + output wire o +); + + // Sine source (A input / P) + parameter real F_HZ = 1.5e3; // input sine frequency (1 kHz) + parameter real AMP = 1.5; // sine amplitude (V) + parameter real VCM = 1.65; // common-mode (V), centered in 0..3.3V + + // Comparator behavior + parameter real VTH = 0.0; // threshold on (vp - vn) + parameter real VHYST = 0.05; // symmetric hysteresis half-width (V) + parameter integer ADD_HYST = 0; // 1 to enable hysteresis + + // 1-bit DAC rails (feedback into RC) + parameter real VLOW = 0.0; // DAC 0 (V) + parameter real VHIGH = 3.3; // DAC 1 (V) + + // RC filter (B input / N) + parameter real R_OHMS = 3300.0; // 3.3k + parameter real C_FARADS = 220e-12; // 220 pF + + // Integration step (ties to `timescale`) + parameter integer TSTEP_NS = 10; // sim step in ns (choose << tau) + + // ===== Internal state (simulation only) ===== + real vp, vn; // comparator A/B inputs + real v_rc; // RC node voltage (== vn) + real v_dac; // DAC output voltage from O + real t_s; // time in seconds + real dt_s; // step in seconds + real tau_s; // R*C time constant in seconds + real two_pi; + reg q; // comparator latched output (pre-delay) + reg out; + reg sampler; + + initial sampler <= 1'b0; + always @(posedge clk) begin + sampler <= out; + end + assign o = sampler; + + + // Helper task: update comparator with optional hysteresis + task automatic comp_update; + real diff; + begin + diff = (vp - vn); + + if (ADD_HYST != 0) begin + // simple symmetric hysteresis around VTH + if (q && (diff < (VTH - VHYST))) q = 1'b0; + else if (!q && (diff > (VTH + VHYST))) q = 1'b1; + // else hold + end else begin + q = (diff > VTH) ? 1'b1 : 1'b0; + end + end + endtask + + initial begin + // Init constants + two_pi = 6.283185307179586; + tau_s = R_OHMS * C_FARADS; // ~7.26e-7 s + dt_s = TSTEP_NS * 1.0e-9; + + // Init states + t_s = 0.0; + q = 1'b0; // start low + out = 1'b0; + v_dac= VLOW; + v_rc = (VHIGH + VLOW)/2.0; // start mid-rail to reduce start-up transient + vn = v_rc; + vp = VCM; + + // Main sim loop + forever begin + #(TSTEP_NS); // advance discrete time step + t_s = t_s + dt_s; + + // 1) Update DAC from previous comparator state + v_dac = sampler ? VHIGH : VLOW; + + // 2) RC low-pass driven by DAC: Euler step + // dv = (v_dac - v_rc) * dt/tau + v_rc = v_rc + (v_dac - v_rc) * (dt_s / tau_s); + vn = v_rc; + + // 3) Input sine on A + vp = VCM + AMP * $sin(two_pi * F_HZ * t_s); + + // 4) Comparator decision (with optional hysteresis) + comp_update(); + + // 5) Output with propagation delay + out = q; + end + end + + +endmodule \ No newline at end of file