I think veriloga is your friend.
I've built things like veriloga widgets that watch one node for zero
crossings and compute a "present frequency" and produce it as a
voltage on a pin. I'm sure something similar for risetime would be
trivial (although you want to stay away from nanovolts as this will
be buried in simulator accuracy mud - so scale for volts=nS or
something, see code).
Then you attach your veriloga code to a veriloga view, make a
symbol view, add "veriloga" to a priority position in your switch-
view and stop-view lists, and bickety-bam, continuous print or
plot of your risetimes, all of 'em, just like the voltage it now is.
// VerilogA
// freq = instantaneous frequency of last 2 rising or last 2 falling edges
// freq Scale = 1V / GHz,
`include "constants.h"
`include "discipline.h"
module freqCounter(in,freq);
input in;
output freq;
electrical in,freq;
real cr1,cr2,f,T1,T2,V1,V2,cr;
analog begin
@ (initial_step) begin
cr1=0;
cr2=0;
f=0;
T1=0;
V1=0;
end
@ (cross (V(in))) begin
T2=$abstime;
V2=V(in);
if (T1>0 && V2-V1!=0) cr=T1-(V1*(T2-T1)/(V2-V1));
if (cr1>0 && cr>cr1) f=1.0/(1E9*(cr-cr1)); scaled 1V=1GHz
cr1=cr2;
cr2=cr;
end
T1=$abstime;
V1=V(in);
V(freq) <+ transition(f);
end
endmodule
I've also made one that just prints to a hard coded output
file. Which one would be more useful to you, I couldn't say.
// VerilogA for verilogTools, printFreq, veriloga
`include "constants.h"
`include "discipline.h"
module printFreq(vin,MHz);
input vin;
output MHz;
voltage vin,MHz;
integer rise;
integer out_file;
real lastrise,thisrise,freq;
analog begin
@ ( initial_step ) begin
rise=0;
lastrise=0;
thisrise=0;
freq=0;
out_file = $fopen("%C:h/zero_cross_%I.csv");
// $fstrobe(out_file,"# Generated by Spectre from instance `%M'");
V(MHz) <+ 0;
end
@ (cross (V(vin),+1) ) begin
rise=rise+1;
thisrise=$abstime;
freq=1/(thisrise-lastrise+1E-99);
lastrise=thisrise;
$fstrobe(out_file, "Rise,%d,%g,%g",rise,thisrise,freq);
end
V(MHz) <+ freq/1E6;
@ ( final_step ) begin
$fclose( out_file );
end
end
endmodule