diff --git a/CON/io.cst b/CON/io.cst index f543489..775c6e1 100644 --- a/CON/io.cst +++ b/CON/io.cst @@ -4,13 +4,17 @@ //Tool Version: V1.9.12 //Part Number: GW1NSR-LV4CQN48PC7/I6 //Device: GW1NSR-4C -//Created Time: Wed 10 01 13:41:57 2025 +//Created Time: Wed 10 01 18:02:30 2025 +IO_LOC "adc1_A" 39,40; +IO_PORT "adc1_A" IO_TYPE=LVDS25 PULL_MODE=NONE BANK_VCCIO=3.3; +IO_LOC "adc1_O" 41; +IO_PORT "adc1_O" IO_TYPE=LVCMOS33 PULL_MODE=NONE DRIVE=8 BANK_VCCIO=3.3; IO_LOC "led" 10; IO_PORT "led" IO_TYPE=LVCMOS33 PULL_MODE=NONE DRIVE=8 BANK_VCCIO=3.3; -IO_LOC "button" 14; -IO_PORT "button" IO_TYPE=LVCMOS18 PULL_MODE=UP BANK_VCCIO=1.8; IO_LOC "reset_n" 15; IO_PORT "reset_n" IO_TYPE=LVCMOS18 PULL_MODE=UP BANK_VCCIO=1.8; IO_LOC "clk" 45; IO_PORT "clk" IO_TYPE=LVCMOS33 PULL_MODE=UP BANK_VCCIO=3.3; +IO_LOC "button" 14; +IO_PORT "button" IO_TYPE=LVCMOS18 PULL_MODE=UP BANK_VCCIO=1.8; diff --git a/CON/timing.sdc b/CON/timing.sdc index 3cdddf5..28e6257 100644 --- a/CON/timing.sdc +++ b/CON/timing.sdc @@ -5,3 +5,4 @@ //Created Time: 2025-10-01 16:50:37 create_clock -name CLK_IN -period 37.037 -waveform {0 18.518} [get_ports {clk}] create_clock -name CLK_120 -period 8.333 -waveform {0 4.167} [get_nets {clk_120}] +create_clock -name CLK_15 -period 66.666 -waveform {0 33.333} [get_nets {clk_15}] diff --git a/HW/sampling.v b/HW/sampling.v new file mode 100644 index 0000000..71ea1b2 --- /dev/null +++ b/HW/sampling.v @@ -0,0 +1,43 @@ +`timescale 1ns/1ps + +module sampling( + input wire adc_A, + input wire adc_B, + output wire adc_O, + + input wire clk, + input wire reset_n +); + wire sigmadelta_sample; + + sigmadelta_sampler m_sdsampler( + .clk(clk), + .A(adc_A), + .B(adc_B), + .out(sigmadelta_sample) + ); + assign adc_O = sigmadelta_sample; + + // RC model, output is y_next_q15 + // ------------------------------ + reg signed [15:0] y_q15; + wire signed [15:0] x_q15 = sigmadelta_sample ? 16'sh7fff : 16'sh0000; + wire signed [15:0] e_q15 = x_q15 - y_q15; + wire signed [31:0] prod_q30 = $signed(16'sh0b00) * $signed(e_q15); // factor should be 0b3b, used bit simplified here + wire signed [15:0] delta_q15 = prod_q30 >>> 15; + wire signed [15:0] y_next_q15 = y_q15 + delta_q15; + + // Optional clamp to [0, 0x7FFF] (keeps GTKWave tidy) + function signed [15:0] clamp01_q15(input signed [15:0] v); + if (v < 16'sd0000) clamp01_q15 = 16'sd0000; + else if (v > 16'sh7FFF) clamp01_q15 = 16'sh7FFF; + else clamp01_q15 = v; + endfunction + + always @(posedge clk or negedge reset_n) begin + if (!reset_n) y_q15 <= 16'sd0000; + else y_q15 <= clamp01_q15(y_next_q15); + end + // ------------------------------ + +endmodule \ No newline at end of file diff --git a/HW/sigmadelta_sampler.v b/HW/sigmadelta_sampler.v new file mode 100644 index 0000000..54b2861 --- /dev/null +++ b/HW/sigmadelta_sampler.v @@ -0,0 +1,24 @@ +`timescale 1ns/1ps + +module sigmadelta_sampler( + input wire clk, + input wire A, + input wire B, + output wire out +); + + wire O; + reg out_r; + + TLVDS_IBUF m_cmp( + .I(A), + .IB(B), + .O(O) + ); + + always @(posedge clk) begin + out_r = O; + end + assign out = out_r; + +endmodule \ No newline at end of file diff --git a/HW/toplevel.v b/HW/toplevel.v index 66b605b..7efc05d 100644 --- a/HW/toplevel.v +++ b/HW/toplevel.v @@ -3,23 +3,35 @@ module toplevel( input wire clk, input wire reset_n, + input wire button, - output wire led + output wire led, + + input wire adc1_A, + input wire adc1_B, + output wire adc1_O ); reg led_v; + wire led_i; wire clk_120; + wire clk_15; gw_pllvr m_pll( .clkout(clk_120), .reset(!reset_n), .clkin(clk) ); + gw_clkdiv8 m_clkdiv8( + .clkout(clk_15), + .hclkin(clk_120), + .resetn(reset_n) + ); always @(posedge clk_120 or negedge reset_n) begin if (!reset_n) begin led_v <= 1'b0; end else begin - led_v <= button; + led_v <= led_i; end end assign led = led_v; diff --git a/IP/gw_clkdiv8/gw_clkdiv8.ipc b/IP/gw_clkdiv8/gw_clkdiv8.ipc new file mode 100644 index 0000000..3ba63d3 --- /dev/null +++ b/IP/gw_clkdiv8/gw_clkdiv8.ipc @@ -0,0 +1,12 @@ +[General] +file=gw_clkdiv8 +ipc_version=4 +module=gw_clkdiv8 +target_device=gw1nsr4c-009 +type=clock_clkdiv +version=1.0 + +[Config] +Calibration=false +Division_Factor=8 +Language=0 diff --git a/IP/gw_clkdiv8/gw_clkdiv8.mod b/IP/gw_clkdiv8/gw_clkdiv8.mod new file mode 100644 index 0000000..d05d4ce --- /dev/null +++ b/IP/gw_clkdiv8/gw_clkdiv8.mod @@ -0,0 +1,14 @@ +-series GW1NSR +-device GW1NSR-4C +-device_version +-package QFN48P +-part_number GW1NSR-LV4CQN48PC7/I6 + + +-mod_name gw_clkdiv8 +-file_name gw_clkdiv8 +-path /data/joppe/projects/modem/IP/gowin_clkdiv/ +-type CLKDIV +-file_type vlg +-division_factor 8 +-calib false \ No newline at end of file diff --git a/IP/gw_clkdiv8/gw_clkdiv8.v b/IP/gw_clkdiv8/gw_clkdiv8.v new file mode 100644 index 0000000..c032d4f --- /dev/null +++ b/IP/gw_clkdiv8/gw_clkdiv8.v @@ -0,0 +1,29 @@ +//Copyright (C)2014-2025 Gowin Semiconductor Corporation. +//All rights reserved. +//File Title: IP file +//Tool Version: V1.9.12 +//Part Number: GW1NSR-LV4CQN48PC7/I6 +//Device: GW1NSR-4C +//Created Time: Wed Oct 1 18:23:11 2025 + +module gw_clkdiv8 (clkout, hclkin, resetn); + +output clkout; +input hclkin; +input resetn; + +wire gw_gnd; + +assign gw_gnd = 1'b0; + +CLKDIV clkdiv_inst ( + .CLKOUT(clkout), + .HCLKIN(hclkin), + .RESETN(resetn), + .CALIB(gw_gnd) +); + +defparam clkdiv_inst.DIV_MODE = "8"; +defparam clkdiv_inst.GSREN = "false"; + +endmodule //gw_clkdiv8 diff --git a/IP/gw_clkdiv8/gw_clkdiv8_tmp.v b/IP/gw_clkdiv8/gw_clkdiv8_tmp.v new file mode 100644 index 0000000..1b2a916 --- /dev/null +++ b/IP/gw_clkdiv8/gw_clkdiv8_tmp.v @@ -0,0 +1,18 @@ +//Copyright (C)2014-2025 Gowin Semiconductor Corporation. +//All rights reserved. +//File Title: Template file for instantiation +//Tool Version: V1.9.12 +//Part Number: GW1NSR-LV4CQN48PC7/I6 +//Device: GW1NSR-4C +//Created Time: Wed Oct 1 18:23:11 2025 + +//Change the instance name and port connections to the signal names +//--------Copy here to design-------- + + gw_clkdiv8 your_instance_name( + .clkout(clkout), //output clkout + .hclkin(hclkin), //input hclkin + .resetn(resetn) //input resetn + ); + +//--------Copy end------------------- diff --git a/SIM/sampling_tb.v b/SIM/sampling_tb.v new file mode 100644 index 0000000..a9e2624 --- /dev/null +++ b/SIM/sampling_tb.v @@ -0,0 +1,27 @@ +`timescale 1ns/1ps + +module sampling_tb; + reg clk; + reg reset_n; + + sampling m_sampling( + .clk(clk), + .reset_n(reset_n) + ); + + initial begin + $dumpfile("sampling_tb.vcd"); + $dumpvars (0, sampling_tb); + + clk <= 1'b0; + reset_n <= 1'b0; + #50 reset_n <= 1'b1; + + #1000000 + $finish; + end + + //15 MHz clock + always #33.33 clk = ~clk; + +endmodule \ No newline at end of file diff --git a/SIM/sigmadelta_sampler.v b/SIM/sigmadelta_sampler.v new file mode 100644 index 0000000..c497048 --- /dev/null +++ b/SIM/sigmadelta_sampler.v @@ -0,0 +1,106 @@ +`timescale 1ns/1ps + +module sigmadelta_sampler( + input wire clk, + input wire A, + input wire B, + output wire out +); + // ===== Tunable parameters ===== + // Sine source (A input / P) + parameter real F_HZ = 2.0e3; // 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 O; + reg sampler; + + initial sampler <= 1'b0; + always @(posedge clk) begin + sampler <= O; + end + assign out = 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 + O = 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 + O = q; + end + end + +endmodule \ No newline at end of file diff --git a/SIM/toplevel_tb.v b/SIM/toplevel_tb.v index 276dd40..8264bac 100644 --- a/SIM/toplevel_tb.v +++ b/SIM/toplevel_tb.v @@ -9,8 +9,12 @@ module toplevel_tb; toplevel m_toplevel( .clk(clk), .reset_n(reset_n), + .button(button), - .led(led) + .led(led), + + .adc1_A(1'b0), + .adc1_B(1'b0) ); initial begin @@ -30,11 +34,11 @@ module toplevel_tb; #185 button <= 1'b0; - #400 + #2000000 $finish; end - always #37 clk = ~clk; + always #18.5 clk = ~clk; // Simulation stuff // PLL quickstart @@ -47,6 +51,7 @@ module toplevel_tb; force toplevel_tb.m_toplevel.m_pll.pllvr_inst.LOCK = 1'b1; force toplevel_tb.m_toplevel.m_pll.pllvr_inst.CLKOUT = tb_pll_clk; force toplevel_tb.m_toplevel.m_pll.pllvr_inst.CLKOUTP = tb_pll_clk; + force toplevel_tb.m_toplevel.m_pll.pllvr_inst.RESET = 1'b1; end `endif // SDF annotation diff --git a/modem.gprj b/modem.gprj index df13a1e..35001ef 100644 --- a/modem.gprj +++ b/modem.gprj @@ -5,7 +5,9 @@ 5 gw1nsr4c-009 + + diff --git a/modem.gprj.user b/modem.gprj.user index b6a562f..903ca6c 100644 --- a/modem.gprj.user +++ b/modem.gprj.user @@ -22,6 +22,6 @@ - - 312e30313131000000ff00000000fd000000020000000000000100000002befc0200000001fc00000039000002be0000008401000018fa000000010200000002fb0000001c0044006f0063006b00650072002e00530075006d006d0061007200790100000000ffffffff0000006b00fffffffb0000001c0044006f0063006b00650072002e004e00650074006c0069007300740100000000ffffffff0000005d00ffffff00000003000004f6000000fefc0100000001fc00000000000004f60000007b00fffffffa00000001010000000bfb0000001c0044006f0063006b00650072002e004d0065007300730061006700650100000000ffffffff0000005c00fffffffb0000002c0044006f0063006b00650072002e0049002f004f002e0043006f006e00730074007200610069006e007400730100000000ffffffff0000004a00fffffffb000000380044006f0063006b00650072002e005000720069006d00690074006900760065002e0043006f006e00730074007200610069006e007400730100000000ffffffff0000004a00fffffffb000000300044006f0063006b00650072002e00470072006f00750070002e0043006f006e00730074007200610069006e007400730100000000ffffffff0000004a00fffffffb000000360044006f0063006b00650072002e005200650073006f0075007200630065002e005200650073006500720076006100740069006f006e0100000000ffffffff0000004a00fffffffb000000380044006f0063006b00650072002e0043006c006f0063006b002e004e00650074002e0043006f006e00730074007200610069006e007400730100000000ffffffff0000004a00fffffffb000000420044006f0063006b00650072002e00470043004c004b002e005000720069006d00690074006900760065002e0043006f006e00730074007200610069006e007400730100000000ffffffff0000004a00fffffffb000000420044006f0063006b00650072002e00480043004c004b002e005000720069006d00690074006900760065002e0043006f006e00730074007200610069006e007400730100000000ffffffff0000004a00fffffffb000000440044006f0063006b00650072002e00470043004c004b0032002e005000720069006d00690074006900760065002e0043006f006e00730074007200610069006e007400730000000000ffffffff0000004a00fffffffb000000460044006f0063006b00650072002e00480043004c004b00350041002e005000720069006d00690074006900760065002e0043006f006e00730074007200610069006e007400730000000000ffffffff0000004a00fffffffb0000002e0044006f0063006b00650072002e0056007200650066002e0043006f006e00730074007200610069006e007400730100000000ffffffff0000004a00ffffff000003f0000002be00000004000000040000000800000008fc000000010000000200000001000000180054006f006f006c004200610072002e00460069006c00650100000000ffffffff0000000000000000 + 000000ff00000001fd0000000200000000000001000000029ffc0200000001fc000000360000029f0000000000fffffffaffffffff0200000003fb00000030004600700067006100500072006f006a006500630074002e00500061006e0065006c002e00440065007300690067006e0100000000ffffffff0000000000000000fb00000032004600700067006100500072006f006a006500630074002e00500061006e0065006c002e00500072006f00630065007300730100000000ffffffff0000000000000000fb00000036004600700067006100500072006f006a006500630074002e00500061006e0065006c002e0048006900650072006100720063006800790100000000ffffffff000000000000000000000003000004f60000010afc0100000001fc00000000000004f6000000a100fffffffa000000000100000002fb00000032004600700067006100500072006f006a006500630074002e00500061006e0065006c002e00470065006e006500720061006c0100000000ffffffff0000004c00fffffffb0000002e004600700067006100500072006f006a006500630074002e00500061006e0065006c002e004900730073007500650100000000ffffffff000000a100ffffff000003f00000029f00000004000000040000000800000008fc000000010000000200000004000000220043006f00720065002e0054006f006f006c006200610072002e00460069006c00650100000000ffffffff0000000000000000000000220043006f00720065002e0054006f006f006c006200610072002e004500640069007401000000a8ffffffff0000000000000000000000240043006f00720065002e0054006f006f006c006200610072002e0054006f006f006c00730100000174ffffffff0000000000000000000000280043006f00720065002e0054006f006f006c006200610072002e00500072006f0063006500730073010000024fffffffff0000000000000000 + 312e30313131000000ff00000000fd00000002000000000000010000000193fc0200000001fc00000039000001930000008401000018fa000000010200000002fb0000001c0044006f0063006b00650072002e00530075006d006d0061007200790100000000ffffffff0000006b00fffffffb0000001c0044006f0063006b00650072002e004e00650074006c0069007300740100000000ffffffff0000005d00ffffff0000000300000500000000fefc0100000001fc00000000000005000000007b00fffffffa00000001010000000bfb0000001c0044006f0063006b00650072002e004d0065007300730061006700650100000000ffffffff0000005c00fffffffb0000002c0044006f0063006b00650072002e0049002f004f002e0043006f006e00730074007200610069006e007400730100000000ffffffff0000004a00fffffffb000000380044006f0063006b00650072002e005000720069006d00690074006900760065002e0043006f006e00730074007200610069006e007400730100000000ffffffff0000004a00fffffffb000000300044006f0063006b00650072002e00470072006f00750070002e0043006f006e00730074007200610069006e007400730100000000ffffffff0000004a00fffffffb000000360044006f0063006b00650072002e005200650073006f0075007200630065002e005200650073006500720076006100740069006f006e0100000000ffffffff0000004a00fffffffb000000380044006f0063006b00650072002e0043006c006f0063006b002e004e00650074002e0043006f006e00730074007200610069006e007400730100000000ffffffff0000004a00fffffffb000000420044006f0063006b00650072002e00470043004c004b002e005000720069006d00690074006900760065002e0043006f006e00730074007200610069006e007400730100000000ffffffff0000004a00fffffffb000000420044006f0063006b00650072002e00480043004c004b002e005000720069006d00690074006900760065002e0043006f006e00730074007200610069006e007400730100000000ffffffff0000004a00fffffffb000000440044006f0063006b00650072002e00470043004c004b0032002e005000720069006d00690074006900760065002e0043006f006e00730074007200610069006e007400730000000000ffffffff0000004a00fffffffb000000460044006f0063006b00650072002e00480043004c004b00350041002e005000720069006d00690074006900760065002e0043006f006e00730074007200610069006e007400730000000000ffffffff0000004a00fffffffb0000002e0044006f0063006b00650072002e0056007200650066002e0043006f006e00730074007200610069006e007400730100000000ffffffff0000004a00ffffff000003fa0000019300000004000000040000000800000008fc000000010000000200000001000000180054006f006f006c004200610072002e00460069006c00650100000000ffffffff0000000000000000 diff --git a/scripts/program.sh b/scripts/program.sh new file mode 100755 index 0000000..1cf6e66 --- /dev/null +++ b/scripts/program.sh @@ -0,0 +1 @@ +openFPGALoader impl/pnr/modem.fs \ No newline at end of file diff --git a/scripts/run_all.tcl b/scripts/run_all.tcl old mode 100644 new mode 100755 diff --git a/scripts/run_sim.sh b/scripts/run_sim.sh index c790714..fb5af09 100755 --- a/scripts/run_sim.sh +++ b/scripts/run_sim.sh @@ -6,10 +6,18 @@ cvc +acc \ +show_canceled_e +suppress_warns+653+3102 \ - -v SIM/prim_tsim.v \ +define+FAST_PLL_SIM \ + -v SIM/prim_tsim.v \ + \ IP/gw_pllvr/gw_pllvr.v \ + IP/gw_clkdiv8/gw_clkdiv8.v \ HW/toplevel.v \ - SIM/toplevel_tb.v \ + HW/sampling.v \ + \ + SIM/sigmadelta_sampler.v \ + \ + SIM/sampling_tb.v \ + SIM/globals.v \ +librescan -./cvcsim \ No newline at end of file +./cvcsim + # SIM/toplevel_tb.v \ \ No newline at end of file