Verilog-A pwl implementation using arrays for time/voltage input
`include "disciplines.vams"
module pwl(out);
output out;
electrical out;
parameter integer N = 1 from [2:inf);parameter real t[1:N] = {N{0}};
parameter real y[1:N] = {N{0}};
analog begin : blk
integer nxt_i;
real yp, tp, slope;
integer err;
@(initial_step) begin
nxt_i = 1;
yp = y[1];
tp = 0.0;
end
@(timer(t[nxt_i])) begin
yp = y[nxt_i];
tp = t[nxt_i];
if(nxt_i < N) begin
nxt_i = nxt_i + 1;
if(t[nxt_i] - tp <= 0) begin
err = 1;
$debug("Non monotonic time sequence: t[%d] == %e, t[%d] == %e", nxt_i-1, tp, nxt_i, t[nxt_i]);
$finish;
end
if(!err)
slope = (y[nxt_i] - yp)/(t[nxt_i] - tp);
end
end
if(!err)
V(out) <+ yp + slope*($realtime - tp);
end
endmodule
System-Verilog pwl implementation
module strpwl(p, n);
electrical p, n;
inout p, n;
parameter string pwl = "";
parameter dcval = 0.0;
analog function real scanval;
input s;
inout pos;
string s;
integer pos;
integer ipos;
string valstr;
begin
ipos = pos;
while(pos < s.len() && s.substr(pos, pos) != ",")
pos = pos+1;
valstr = s.substr(ipos, pos-1);
if(1 == $sscanf(valstr, "%g", scanval))
pos = pos+1;
else
pos = -1; // Error indicator
end
endfunction
integer pos = 0;
real tnext, vnext;
real tprev = 0.0;
real vprev = dcval;
real slope;
integer err;
analog initial begin : blk
real retVal;
tprev = 0.0;
vprev = dcval;
tnext = scanval(pwl, pos);
vnext = scanval(pwl, pos);
if (tnext-tprev != 0.0)
slope = (vnext - vprev)/(tnext - tprev);
$strobe(tnext, vnext);
end
analog begin
@(timer(tnext)) begin
tprev = tnext;
vprev = vnext;
tnext = scanval(pwl, pos);
vnext = scanval(pwl, pos);
if(pos > 0)
begin
if(tnext - tprev <= 0) begin
err = 1;
$debug("Non monotonic time sequence.");
$finish;
end
if(!err)
slope = (vnext - vprev)/(tnext - tprev);
end
end
if(!err)
V(p, n) <+ vprev + slope*($abstime - tprev);
end
endmodule