Add additional examples of Verilog co-simulation and share the Verilog

source and large parts of the example circuits between Verilator and
Icarus Verilog.  Verilog source file adc.v has improved style:
all assignments in the always block are now non-blocking.
This commit is contained in:
Giles Atkinson 2024-06-10 11:40:37 +01:00 committed by Holger Vogt
parent 64a9a0bfbc
commit 35968d1da6
16 changed files with 405 additions and 113 deletions

View File

@ -0,0 +1,10 @@
Verilog-controlled simple timer.
* This is the model for an RS flip-flop implemented by Icarus Verilog.
.model vlog_ff d_cosim simulation="ivlng" sim_args=["555"]
* The bulk of the circuit is in a shared file.
.include ../verilator/555.shared
.end

View File

@ -0,0 +1,46 @@
The circuits in this directory illustrate the use of the d_cosim
XSPICE code model as a container for a Verilog simulation using
Icarus Verilog. Icarus Verilog must be built with the --enable-libvvp option,
so that its simulation engine is available as a dynamic library.
The Verilog source code and included parts of the circuit definitions
can be found in the adjacent "verilator" directory.
The example circuits are:
555.cir: The probably familiar NE555 oscillator provides a minimal example
of combined simulation with SPICE and Verilog.
The digital part of the IC, a simple SR flip-flop, is expressed in Verilog.
delay.v: A very simple example of using delays in Verilog to generate
waveform outputs.
pwm.c: Verilog delays controlling a pulse-width modulated output generate
an approximate sine wave.
adc.cir: Slightly more complex Verilog describes the controlling part
of a switched-capacitor ADC.
Before a simulation can be run, the associated Verilog code must be compiled:
iverilog -o 555 ../verilator/555.v
Similar compilations are needed to prepare the other examples.
The simulations require additional dynamic libraries, ivlng.so (or ivlng.DLL)
and ivlng.vpi: they are expected to be in the usual installation location.
To use the versions in a built source tree that has not been installed,
the .model definitions in the circuit files must be changed to the ugly:
.model vlog_ff d_cosim sim_args=["555"]
+ simulation = "../../../release/src/xspice/verilog/.libs/ivlng"
+ lib_args = [ "libvvp"
+ "../../../release/src/xspice/verilog/.libs/ivlngvpi.so" ]
Or for Windows builds using MSVC:
.model vlog_ff d_cosim sim_args=["555"]
+ simulation = "..\..\..\visualc\xspice\verilog\ivlng.DLL"
+ lib_args = [ "libvvp"
+ "..\..\..\visualc\xspice\verilog\shim.vpi" ]

View File

@ -0,0 +1,10 @@
Simulation of a switched-capacitor SAR ADC with Verilator and d_cosim
* Model line for the digital control implemented by Icarus Verilog.
.model dut d_cosim simulation="ivlng" sim_args=["adc"]
* The bulk of the circuit is in a shared file.
.include ../verilator/adc.shared
.end

View File

@ -0,0 +1,10 @@
* Waveform generation by Verilog delays
adut null [ d4 d3 d2 d1 d0 ] ring
.model ring d_cosim simulation="ivlng" sim_args = [ "delay" ]
.control
tran 20u 100u
plot d4 d3 d2 d1 d0 digitop
.endc
.end

View File

@ -0,0 +1,12 @@
* Waveform generation by PWM in Verilog
adut null [ out ] pwm_sin
.model pwm_sin d_cosim simulation="ivlng" sim_args = [ "pwm" ]
r1 out smooth 100k
c1 smooth 0 1u
.control
tran 1m 2
plot out-3.3 smooth
.endc
.end

View File

@ -0,0 +1,11 @@
Verilog-controlled simple timer.
* This is the model for an RS flip-flop implemented by Verilator.
.model vlog_ff d_cosim simulation="./555"
* The bulk of the circuit is in a shared file.
.include 555.shared
.end

View File

@ -0,0 +1,60 @@
* This file is not intended to be used directly, but by 555.cir.
* That allows it to be shared by different implemnetations.
* This sub-circuit simulates the NE555 timer IC, with the very simple
* digital part as a Verilog module.
.subckt NE555 trigger threshold reset control output discharge vcc ground
* Resistor chain
r1 vcc control 5k
r2 control trigger_ref 5k
r3 trigger_ref ground 5k
* Two XSPICE ADC instances serve as comparators.
.model comparator adc_bridge(in_low = -0.0001 in_high = 0.0001)
athresh_comparator [%vd threshold control] [over_threshold] comparator
atrigger_comparator [%vd trigger_ref trigger] [under_trigger] comparator
* A tiny Verilog module supplies the flip-flop.
* The model is supplied by the outer circuit file.
averilog [ under_trigger over_threshold reset ] [ output qbar ] vlog_ff
* The discharge transistor and its base resistor.
rbase qbar discharge_base 10k
qdischarge discharge discharge_base ground npn_transistor
.model npn_transistor npn
.ends ; Ends subcircuit NE555
* The usual 555 oscillator with threshold connected to discharge.
.param vcc=12
X555 trigger_threshold trigger_threshold reset control output discharge vcc 0 ne555
r1 vcc discharge 10k
r2 discharge trigger_threshold 10k
Ct trigger_threshold 0 1uF ic=0
* A resistive load forces analog output.
rload output 0 1k
* A voltage source for power.
Vcc vcc 0 {vcc}
* Pulse the Reset signal low for 2uS each 51mS
Vpulse reset 0 PULSE {vcc} 0.2 0 1u 1u 2u 51m
.control
tran 10u 200m uic
plot trigger_threshold output x555.under_trigger-3 x555.over_threshold-1.5
.endc

View File

@ -0,0 +1,26 @@
// Very simple logic for a 555 timer simulation
`timescale 1us/100ns
module VL555(Trigger, Threshold, Reset, Q, Qbar);
input wire Trigger, Threshold, Reset; // Reset is active low.
output reg Q;
output wire Qbar;
wire ireset, go;
assign Qbar = !Q;
// The datasheet implies that Trigger overrides Threshold.
assign go = Trigger & Reset;
assign ireset = (Threshold & !Trigger) | !Reset;
initial begin
Q = 0;
end
always @(posedge(go), posedge(ireset)) begin
Q = go;
end
endmodule

View File

@ -1,10 +1,32 @@
The circuit adc.cir in this directory illustrates the use of the d_cosim
XSPICE code model as a container for a Verilog simulation. Before the
simulation can be run, the Verilog code must be compiled by Verilator
using the command:
The circuits in this directory illustrate the use of the d_cosim
XSPICE code model as a container for a Verilog simulation, using the
Verilator compiler. The example circuits are:
ngspice vlnggen adc.v
555.cir: The probably familiar NE555 oscillator provides a minimal example
of combined simulation with SPICE and Verilog. The digital part of the IC,
a simple SR flip-flop, is expressed in Verilog.
That should create a shared library file, adc.so (or adc.DLL on Windows)
delay.v: A very simple example of using delays in Verilog to generate
waveform outputs.
pwm.c: Verilog delays controlling a pulse-width modulated output generate
an approximate sine wave.
adc.cir: Slightly more complex Verilog describes the controlling part
of a switched-capacitor ADC.
Before a simulation can be run, the associated Verilog code must be compiled
by Verilator using a command script that is included with ngspice:
ngspice vlnggen 555.v
That should create a shared library file, 555.so (or 555.DLL on Windows)
that will be loaded by the d_cosim code model. The compiled Verilog code that
it contains will be executed during simulation.
it contains will be executed during simulation. Similar compilations
are needed to prepare the other examples, but for Verilog with delays the
command looks like:
ngspice vlnggen -- --timing delay.v
(The "--" prevents "--timing" from being treated as a ngspice option, so it is
passed on to Verilator.)

View File

@ -1,103 +1,10 @@
Simulation of a switched-capacitor SAR ADC with Verilator and d_cosim
.subckt sar_adc input vref start valid d5 d4 d3 d2 d1 d0 clk
* Model line for the digital control implemented by Verilator.
* A transmission gate connects the input to the capacitor set.
.model dut d_cosim simulation="./adc"
xsample input iin sample vref tgate
rin iin test_v 1k
* The bulk of the circuit is in a shared file.
* Capacitors and controlling inverters
xb5 test_v vref d5 ccap c=1p
xb4 test_v vref d4 ccap c={1p / 2}
xb3 test_v vref d3 ccap c={1p / 4}
xb2 test_v vref d2 ccap c={1p / 8}
xb1 test_v vref d1 ccap c={1p / 16}
xb0 test_v vref d0 ccap c={1p / 32}
clast test_v 0 {1p / 32}
* An XSPICE ADC bridge functions as a comparator.
acomp [%vd(test_v vref)] [comp] comparator
.model comparator adc_bridge in_low=0 in_high=0
* The digital portion of the circuit is specified in compiled Verilog.
* Outputs inverted to cancel the inverter in subcircuit ccap,
* and produce the correct numerical output value.
adut [ Clk Comp Start] [Sample Valid ~d5 ~d4 ~d3 ~d2 ~d1 ~d0] null dut
.model dut d_cosim simulation="./adc.so"
.ends // SUBCKT sar_adc
* Some MOS transistors complete the circuit.
* Models from https://homepages.rpi.edu/~sawyes/AIMSPICE_TutorialManual.pdf
.model p1 pmos
+ level=2 vto=-0.5 kp=8.5e-6 gamma=0.4 phi=0.65 lambda=0.05 xj=0.5e-6
.model n1 nmos
+ level=2 vto=0.5 kp=24e-6 gamma=0.15 phi=0.65 lambda=0.015 xj=0.5e-6
* Use those for an inverter.
.subckt ainv in out vdd
mn out in 0 0 n1
mp out in vdd vdd p1
.ends
* A transmission gate modelled by a switch.
.subckt mos_tgate a b ctl vdd
mn a ctl b b n1
xinv ctl ictl vdd ainv
mp b ictl a a p1
.ends
.subckt tgate a b ctl vdd
switch a b ctl 0 tg
.model tg sw vt=1.5 ron=2k
.ends
* The per-bit subcircuit in the adc
.subckt ccap in vcc ctl c=10p
xinv ctl tail vcc ainv
cb in tail {c}
.ends
**** End of the ADC and its subcircuits. Begin test circuit ****
.param vcc=3.3
vcc vcc 0 {vcc}
* Digital clock signal
aclock 0 clk clock
.model clock d_osc cntl_array=[-1 1] freq_array=[1Meg 1Meg]
* A simple DAC so that the result may be compared to the input.
r5 d5 sum 2
r4 d4 sum 4
r3 d3 sum 8
r2 d2 sum 16
r1 d1 sum 32
r0 d0 sum 64
vamm sum 0 0
* Pulse the Start signal high for 1.3uS each 10uS
Vpulse Start 0 PULSE 0 {vcc} 0.2u 10n 10n 1.3u 10u
Vtest input 0 PULSE 0 3 0 200u 200u 1u 401u
* The ADC for testing
xtest input vcc start valid d5 d4 d3 d2 d1 d0 clk sar_adc
.control
tran 100n 250u
plot input xtest.test_v vamm#branch clk/2 start/3 xtest.sample/3 valid
.endc
.include adc.shared
.end

View File

@ -0,0 +1,107 @@
* This file is not intended to be used directly, but by adc.cir.
* That allows it to be shared by different implemnetations.
* Simulation of a switched-capacitor SAR ADC with Verilator and d_cosim
.subckt sar_adc input vref start valid d5 d4 d3 d2 d1 d0 clk
* A transmission gate connects the input to the capacitor set.
xsample input iin sample vref tgate
rin iin test_v 1k
* Capacitors and controlling inverters
xb5 test_v vref d5 ccap c=1p
xb4 test_v vref d4 ccap c={1p / 2}
xb3 test_v vref d3 ccap c={1p / 4}
xb2 test_v vref d2 ccap c={1p / 8}
xb1 test_v vref d1 ccap c={1p / 16}
xb0 test_v vref d0 ccap c={1p / 32}
clast test_v 0 {1p / 32}
* An XSPICE ADC bridge functions as a comparator.
acomp [%vd(test_v vref)] [comp] comparator
.model comparator adc_bridge in_low=0 in_high=0
* The digital portion of the circuit is specified in compiled Verilog.
* Outputs inverted to cancel the inverter in subcircuit ccap,
* and produce the correct numerical output value. The model definition
* is supplied by the calling circuit file.
adut [ Clk Comp Start] [Sample Valid ~d5 ~d4 ~d3 ~d2 ~d1 ~d0] dut
.ends // SUBCKT sar_adc
* Some MOS transistors complete the circuit.
* Models from https://homepages.rpi.edu/~sawyes/AIMSPICE_TutorialManual.pdf
.model p1 pmos
+ level=2 vto=-0.5 kp=8.5e-6 gamma=0.4 phi=0.65 lambda=0.05 xj=0.5e-6
.model n1 nmos
+ level=2 vto=0.5 kp=24e-6 gamma=0.15 phi=0.65 lambda=0.015 xj=0.5e-6
* Use those for an inverter.
.subckt ainv in out vdd
mn out in 0 0 n1
mp out in vdd vdd p1
.ends
* A transmission gate modelled by a switch.
.subckt mos_tgate a b ctl vdd
mn a ctl b b n1
xinv ctl ictl vdd ainv
mp b ictl a a p1
.ends
.subckt tgate a b ctl vdd
switch a b ctl 0 tg
.model tg sw vt=1.5 ron=2k
.ends
* The per-bit subcircuit in the adc
.subckt ccap in vcc ctl c=10p
xinv ctl tail vcc ainv
cb in tail {c}
.ends
**** End of the ADC and its subcircuits. Begin test circuit ****
.param vcc=3.3
vcc vcc 0 {vcc}
* Digital clock signal
aclock 0 clk clock
.model clock d_osc cntl_array=[-1 1] freq_array=[1Meg 1Meg]
* A simple DAC so that the result may be compared to the input.
r5 d5 sum 2
r4 d4 sum 4
r3 d3 sum 8
r2 d2 sum 16
r1 d1 sum 32
r0 d0 sum 64
vamm sum 0 0
* Pulse the Start signal high for 1.3uS each 10uS
Vpulse Start 0 PULSE 0 {vcc} 0.2u 10n 10n 1.3u 10u
Vtest input 0 PULSE 0 3 0 200u 200u 1u 401u
* The ADC for testing
xtest input vcc start valid d5 d4 d3 d2 d1 d0 clk sar_adc
.control
tran 100n 250u
plot input xtest.test_v vamm#branch clk/2 start/3 xtest.sample/3 valid
.endc
.end

View File

@ -1,5 +1,7 @@
// Digital control for a successive approximation ADC with switched capacitors.
`timescale 100ns/100ns
module adc(Clk, Comp, Start, Sample, Done, Result);
input wire Clk, Comp, Start;
output reg Sample, Done;
@ -22,14 +24,12 @@ module adc(Clk, Comp, Start, Sample, Done, Result);
if (Running) begin
if (Sample) begin
Sample <= 0;
SR[Bits - 1] = 1;
Result[Bits - 1] = 1;
SR[Bits - 1] <= 1;
Result[Bits - 1] <= 1;
end else if (SR != 0) begin
if (Comp)
Result &= ~SR;
SR >>= 1;
Result |= SR;
if (SR == 0) begin
Result <= (Comp ? (Result & ~SR) : Result) | (SR >> 1);
SR <= SR >> 1;
if (SR == 1) begin
Running <= 0;
Done <= 1;
end
@ -38,8 +38,8 @@ module adc(Clk, Comp, Start, Sample, Done, Result);
Running <= 1;
Sample <= 1;
Done <= 0;
SR = 0;
Result = 0;
SR <= 0;
Result <= 0;
end
end
endmodule

View File

@ -0,0 +1,11 @@
* Waveform generation by Verilog delays
*
adut null [ d4 d3 d2 d1 d0 ] ring
.model ring d_cosim simulation="./delay"
.control
tran 20u 100u
plot d4 d3 d2 d1 d0 digitop
.endc
.end

View File

@ -0,0 +1,14 @@
`timescale 1us/100ns
module delay(out);
output reg [4:0] out;
reg t;
initial out = 0;
always begin
#1;
t = out[4];
out <<= 1;
out[0] = ~t;
end
endmodule; // delay

View File

@ -0,0 +1,12 @@
* Waveform generation by PWM in Verilog
adut null [ out ] pwm_sin
.model pwm_sin d_cosim simulation="./pwm"
r1 out smooth 100k
c1 smooth 0 1u
.control
tran 1m 2
plot out-3.3 smooth
.endc
.end

View File

@ -0,0 +1,34 @@
`timescale 1us/100ns
//`include "constants.vams"
`define M_TWO_PI 6.28318530717958647652
module pwm(out);
output reg out;
parameter Cycles = 1000, Samples = 1000;
integer i, j, width;
real sine;
initial begin
i = 0;
j = 0;
width = Cycles / 2;
out = 0;
end
always begin
#1;
++i;
if (i == width)
out = 0;
if (i == Cycles) begin
i = 0;
++j;
if (j == Samples)
j = 0;
sine = $sin(j * `M_TWO_PI / Samples);
width = $rtoi(Samples * (1.0 + sine) / 2.0);
out = (width == 0) ? 0 : 1;
end
end
endmodule // pwm