I somehow got stuck on some ECRC project promoting cooperation between companies and as my part did some work on porting a chip design package (HCAB), characterizing chips, writting output routines for a huge Versatec plotter and to a tape for manufacture, and yakking away on a committee trying to get some standardizaton between a collection of different cell design databases.
Somewhere along the line I wrote an interpreter for a chip characterization program which automatically ran SPICE with different values stuck in and interpreted the results. An enormous amount of time was being wasted by people doing this by hand - it could take a week for a single chip and I hoped to reduce this to half an hour. My interpreter didn't get far as I was moved before it all worked well, and maybe it was a bit over-clever. Anyway everyone should try their hand at designing a new language sometime ;-)
The language was designed to be SPICE friendly in its syntax and to be able to use FORTRAN subroutines - I think I was being influenced by ADA at the time as well. The data and program was all held in dynamically allocated arrays which formed a tree structure but could never form a cycle so freeing could be done easily and automatically. References were in fact 'locators' - an array of integers saying the stack level, then the field or index number going down the structures. There was no sharing of substructures except if they were constant.
Anyway here is an example I've dredged up:
// defaults const volt' vdd_volts = 5v const float' tempdc = 110 const float' vdd_resistance = 1ohm const float' vss_resistance = 1ohm const time' time_step = 1nsec const time' max_setup_time = 2onsec const time' max_hold_time = 20nsec const time' max _response_time = 20nsec const volt' logic_1_input = O.99*vdd_volts const volt' logic_0_input = 0.02*vdd_volts const volt' logic_1_low = 0.80*vdd_volts const volt' logic_0_high = 0.20*vdd_volts const time' rising_edge = 2nsec const time' falling_edge = 2nsec const float' output_nodal_capacitance = 0.lpf const volt' rise_time_mark_low = 0.10*vdd_volts const volt' rise_time_mark_high = O.90*vdd_volts const float' acceptable_transition_degradation_factor = 2 const volt' measurement_level = 0.50*vdd_volts // sweep default if GO is used sweep time from 0 to max_response_time by time_step // define vdd and vis pins // set up cell_vdd and cell_vss // put in source voltage resistances // put in power voltage macro power(pin'vdd. pin'vss) local pin'vddx=newpin(), pin'vssx=newpin() var pin'cell_vdd=vdd var pin'cell_vss=vss gen "RVDD" vdd vddx vdd_resistance gen "RVSS" vss vssx vss_resistance gen "VSSX" vssx vddx vdd_volts endmacro // define input pins // put into list cell_inputs macro inputs list'pins var list'cell_inputs = pins endmacro // define output pins // put into list cell_outputs // add a capacitance to each output macro outputs list'pins var list'cell_outputs = pins local int'i=1 label loop if i>bound'pins return endif gen concat("COUT",pins[i]) pins cell_vdd output_nodal_capacitance i=i+1 goto loop endmacro // define unused pins // put into list cell_unused // put in resistance to vdd macro unused list'pins var list'cell_unused = pins local int'i=1 label loop if i>bound'pins return endif gen concat("RX",pins[i]) pins[i] cell_vdd 1OOOohms i=i+1 goto loop endmacro // generate a pulse for hold time measurement // will not reach v2 if width is negative, just get a spike macro pwl'rise_fall(volt'v1 volt'v2 + time'delay=O + time'rise=rising_edge + tlme'fall=falling_edge + time'width=0) if width >= 0 return pwl(O v1 delay v1 delay+rise v2 delay+rise+width v2 + delay+rise+width+fall v1) elsf rise+width <= 0 return v1 else local float'x=(rise+width)/rise return pwl(0 v1 delay v1 delay+rise+width x*(v2-vl)+vl + delay+rise+width+x*fall v1) endif endmacro // A first stab at calculating hold time macro hold(pin'in pwl'init pin'out + time'from time'to time'by ref'hold_time) local time'low time'high time'mid low=from high=to label loop mid=(low+high)/2 TEST gen "vhold" in cell_vss pwl(O init + from rise_fall(0 vdd_volts width=mid-from)) sweep time from 0 to to by by keep v(out) GO if find(v(out)>=4.7) high = mid else low=mid endif ENDTEST if high-low > by goto loop endif *hold_time = mid-from endmacro