/* Rosemary.c */
#include "CoreBasics.h"
#include "Core.h"
#include "CoreFlat.h"
#include "Rosemary.h"
#define roseFixedWirePropName "roseFixedWire"
String RoseLevelNames[RoseLevelCount]={"L", "H", "X"};
String RoseDriveNames[RoseDriveCount]={"inspect", "expect", "n", "cw", "cmw", "c", "cms", "cs", "f", "dw", "dmw", "d", "dms", "ds", "i"};
/* Instantiation and Relaxation */
Atom roseFixedWireProp;
void RoseFixedWirePrint(property, value, indent, level, cr)
Atom property;
Ref value;
Nat indent;
Nat level;
Bool cr;
{
RoseLevel *lev=(RoseLevel *)value;
StringPrintIndent(indent, cr);
printf("%s: %s", roseFixedWirePropName, RoseLevelNames[(Nat)(*lev)]);
};
Wire RoseSetFixedWire(wire, level)
Wire wire;
RoseLevel level;
{
RoseLevel *levelRef=New(RoseLevel *, RoseLevel);
*levelRef=level;
PutWireProp(wire, roseFixedWireProp, levelRef);
return(wire);
};
Wire RoseSetNamedFixedWire(cellType, name, level)
CellType cellType;
String name;
RoseLevel level;
{
return(RoseSetFixedWire(FindWire(cellType->public, name), level));
};
RoseWire LookUpRoseWire(coreWire, bindings, coreToRoseWires)
Wire coreWire;
HashTable bindings;
HashTable coreToRoseWires;
{
FlatWire leftUpper=(FlatWire)HashTableGet(bindings, coreWire);
return((RoseWire)HashTableGet(coreToRoseWires, leftUpper));
};
typedef struct AllocateWireContextRec {
HashTable bindings;
FlatCellTypeRec flatCell;
HashTable coreToRoseWires;
} AllocateWireContextRec;
typedef AllocateWireContextRec *AllocateWireContext;
void AllocateWire(coreWire, context)
Wire coreWire;
Ref context;
{
AllocateWireContext c=(AllocateWireContext)context;
FlatWire flatWire=nil;
if (c->bindings!=nil) flatWire=(FlatWire)HashTableGet(c->bindings, coreWire);
if (flatWire==nil) {
FlatWireRec wireKey;
wireKey.flatCell=c->flatCell;
wireKey.wire=coreWire;
if (HashTableGet(c->coreToRoseWires, &wireKey)==nil) {
RoseLevel *wireFixedRef=(RoseLevel *)GetWireProp(coreWire, roseFixedWireProp);
RoseWire roseWire=New(RoseWire, RoseWireRec);
roseWire->nextPerturbedWire=nil;
roseWire->previousPerturbedWire=nil;
roseWire->nextRecomputed=nil;
roseWire->nextVicinityWire=nil;
roseWire->probes=nil;
roseWire->channels=nil;
roseWire->notOffChannels=nil;
roseWire->gates=nil;
roseWire->wireSize=RoseCharge;
roseWire->wireLevel=X;
roseWire->mark=false;
roseWire->flatWire=New(FlatWire, FlatWireRec);
*(roseWire->flatWire)=wireKey;
if (wireFixedRef!=nil) {
roseWire->switchDrive=roseWire->wireSize=RoseInfinite;
roseWire->wireLevel=(*wireFixedRef);
};
HashTablePut(c->coreToRoseWires, roseWire->flatWire, roseWire);
};
};
};
void FlattenCell(cell, target, flatCell, instance, index, parent, flatParent, data, bindings)
CellType cell;
FlatCellTypeRec target;
FlatCellTypeRec flatCell;
CellInstance instance;
Nat index;
CellType parent;
FlatCellTypeRec flatParent;
Ref data;
HashTable bindings;
{
RoseSimulation simulation=(RoseSimulation)data;
if (cell->class==transistorCellClass) {
HashTable coreToRoseWires=simulation->coreToRoseWires;
Wire public=cell->public;
Transistor coreTransistor=(Transistor)cell->data;
RoseTransistor roseTransistor=New(RoseTransistor, RoseTransistorRec);
roseTransistor->gate=LookUpRoseWire(public->elements[(Nat)gate], bindings, coreToRoseWires);
roseTransistor->gate->gates=ListCons(roseTransistor->gate->gates, roseTransistor);
roseTransistor->ch1=LookUpRoseWire(public->elements[(Nat)ch1], bindings, coreToRoseWires);
roseTransistor->ch1->channels=ListCons(roseTransistor->ch1->channels, roseTransistor);
roseTransistor->ch1->notOffChannels=ListCons(roseTransistor->ch1->notOffChannels, roseTransistor);
roseTransistor->ch2=LookUpRoseWire(public->elements[(Nat)ch2], bindings, coreToRoseWires);
roseTransistor->ch2->channels=ListCons(roseTransistor->ch2->channels, roseTransistor);
roseTransistor->ch2->notOffChannels=ListCons(roseTransistor->ch2->notOffChannels, roseTransistor);
roseTransistor->transistorType=coreTransistor->type;
roseTransistor->conductivity=RoseDrive;
roseTransistor->flatCellType=flatCell;
}
else if (cell->class==recordCellClass) {
AllocateWireContextRec context;
RecordCellType cellTypeRCT=(RecordCellType)cell->data;
context.bindings=bindings;
context.flatCell=flatCell;
context.coreToRoseWires=simulation->coreToRoseWires;
VisitRootAtomics(cellTypeRCT->internal, AllocateWire, &context);
NextBoundCellType(cell, target, flatCell, instance, index, parent, flatParent, data, bindings, FlattenCell);
}
else NextBoundCellType(cell, target, flatCell, instance, index, parent, flatParent, data, bindings, FlattenCell);
};
Nat CountVicinity (wire, currentCount)
RoseWire wire;
Nat currentCount;
{
Nat newCount=currentCount + 1;
List rts=wire->channels;
wire->mark=true;
while (rts) {
RoseTransistor tran=(RoseTransistor)rts->first;
RoseWire otherWire=tran->ch1;
if (otherWire==wire) otherWire=tran->ch2;
if (otherWire->wireSize!=RoseInfinite && !otherWire->mark) newCount=CountVicinity(otherWire, newCount);
rts=rts->rest;
};
return(newCount);
};
Ref ComputeMaxVicinity(key, value, context)
Ref key;
Ref value;
Ref context;
{
RoseWire roseWire=(RoseWire)value;
Nat *maxVicinity=(Nat *)context;
if (roseWire->wireSize!=RoseInfinite && !roseWire->mark) *maxVicinity=Max(*maxVicinity, CountVicinity(roseWire, 0));
return(value);
};
typedef enum Conductance {on, off, unknown} Conductance;
Conductance TranOn (tran, gateValue)
RoseTransistor tran;
RoseLevel gateValue;
{
Conductance cond;
switch (tran->transistorType) {
case nE : switch (gateValue) {
case L : cond=off; break;
case H : cond=on; break;
case X : cond=unknown; break;
};
break;
case pE : switch (gateValue) {
case L : cond=on; break;
case H : cond=off; break;
case X : cond=unknown; break;
};
break;
case nD : cond=on; break;
};
return(cond);
};
void Perturb(simulation, wire)
RoseSimulation simulation;
RoseWire wire;
{
if (wire->nextPerturbedWire==nil && wire->previousPerturbedWire==nil && simulation->perturbed!=wire && (wire->wireSize)<RoseInfinite) {
RoseWire currentHead=simulation->perturbed;
wire->nextPerturbedWire=currentHead;
if (currentHead!=nil) currentHead->previousPerturbedWire=wire;
simulation->perturbed=wire;
};
};
Ref EstablishWireInvariants(key, value, context)
Ref key;
Ref value;
Ref context;
{
RoseWire roseWire=(RoseWire)value;
RoseSimulation simulation=(RoseSimulation)context;
List rts=roseWire->channels;
roseWire->mark=false;
Perturb(simulation, roseWire);
roseWire->notOffChannels=nil;
while (rts) {
RoseTransistor roseTransistor=(RoseTransistor)rts->first;
if (TranOn(roseTransistor, roseTransistor->gate->wireLevel)!=off) roseWire->notOffChannels=ListCons(roseWire->notOffChannels, roseTransistor);
rts=rts->rest;
};
return(value);
};
void EstablishInvariants(simulation)
RoseSimulation simulation;
{
HashTableUpdate(simulation->coreToRoseWires, EstablishWireInvariants, simulation);
};
RoseSimulation RoseInstantiate(cellType)
CellType cellType;
{
RoseSimulation simulation=New(RoseSimulation, RoseSimulationRec);
Nat maxVicinity=0;
RoseStrength strength;
simulation->cellType=cellType;
simulation->coreToRoseWires=HashTableCreate(1019, FlatWireHash, FlatWireEqual);
FlattenCell(cellType, allFlatCells, rootCellType, nil, NatLast, nil, rootCellType, simulation, nil);
HashTableUpdate(simulation->coreToRoseWires, ComputeMaxVicinity, &maxVicinity);
for (strength=RoseInspect; strength<=RoseInfinite; strength++) {
simulation->vicinityByStrength[strength].wires=NewSeq(RoseWires, RoseWiresRec, RoseWire, maxVicinity);
simulation->vicinityByStrength[strength].wires->size=maxVicinity;
simulation->vicinityByStrength[strength].firstFree=0;
};
EstablishInvariants(simulation);
return(simulation);
};
void PushWireByStrength(simulation, wire, thisDrive)
RoseSimulation simulation;
RoseWire wire;
RoseStrength thisDrive;
{
simulation->vicinityByStrength[thisDrive].wires->elements[ simulation->vicinityByStrength[thisDrive].firstFree]=wire;
simulation->vicinityByStrength[thisDrive].firstFree=simulation->vicinityByStrength[thisDrive].firstFree+1;
};
RoseStrength UpDownStrength(wire, notLevel)
RoseWire wire;
RoseLevel notLevel;
{
RoseStrength strength;
if (wire->wireLevel==notLevel) strength=RoseNone;
else strength=wire->wireSize;
return(strength);
};
typedef enum PushWhat {upDown, up, down} PushWhat;
void FindVicinity(simulation, wire, what)
RoseSimulation simulation;
RoseWire wire;
PushWhat what;
{
RoseStrength wireSize;
RoseTransistors rts=wire->notOffChannels;
RoseProbePrimitives rps=wire->probes;
switch (what) {
case upDown : wireSize=wire->wireSize; break;
case up : wireSize=UpDownStrength(wire, L); break;
case down : wireSize=UpDownStrength(wire, H); break;
};
wire->mark=true;
while (rts) {
RoseTransistor tran=(RoseTransistor)rts->first;
Conductance tranCond=TranOn(tran, tran->gate->wireLevel);
RoseWire otherWire=tran->ch1;
if (otherWire==wire) otherWire=tran->ch2;
if (otherWire->wireSize==RoseInfinite) {
if (((what==upDown && tranCond==on) || (what==up && otherWire->wireLevel!=L) || (what==down && otherWire->wireLevel!=H)) && wireSize < tran->conductivity) wireSize=tran->conductivity;
}
else if (!otherWire->mark) FindVicinity(simulation, otherWire, what);
rts=rts->rest;
};
while (rps) {
RoseProbePrimitive probe=(RoseProbePrimitive)rps->first;
if (((what==upDown && probe->drive>RoseNone) || (what==up && probe->level!=L) || (what==down && probe->level!=H)) && wireSize < probe->drive) wireSize=probe->drive;
rps=rps->rest;
};
if (what!=upDown && wireSize < wire->switchDrive) wireSize=RoseNone;
PushWireByStrength(simulation, wire, wireSize);
switch (what) {
case upDown : wire->switchDrive=wireSize; break;
case up : wire->upDrive=wireSize; break;
case down : wire->downDrive=wireSize; break;
};
};
void PushStrength(simulation, what)
RoseSimulation simulation;
PushWhat what;
{
RoseStrength thisDrive;
for (thisDrive=RoseInfinite-1; ; thisDrive--) {
Nat firstFreeWire;
while (firstFreeWire=simulation->vicinityByStrength[thisDrive].firstFree) {
RoseWire wire=simulation->vicinityByStrength[thisDrive].wires->elements[firstFreeWire-1];
RoseStrength whatDrive;
RoseTransistors rts=wire->notOffChannels;
wire->mark=false;
simulation->vicinityByStrength[thisDrive].firstFree=firstFreeWire-1;
switch (what) {
case upDown : whatDrive=wire->switchDrive; break;
case up : whatDrive=wire->upDrive; break;
case down : whatDrive=wire->downDrive; break;
}
if (thisDrive==RoseNone || thisDrive < whatDrive) continue;
while (rts) {
RoseTransistor tran=(RoseTransistor)rts->first;
Conductance tranCond=TranOn(tran, tran->gate->wireLevel);
RoseStrength driveThrough=Min(thisDrive, tran->conductivity);
RoseWire otherWire=tran->ch1;
if (otherWire==wire) otherWire=tran->ch2;
switch (what) {
case upDown : if (tranCond==on && driveThrough > otherWire->switchDrive) {
otherWire->switchDrive=driveThrough;
PushWireByStrength(simulation, otherWire, driveThrough);
};
break;
case up : if (driveThrough >= otherWire->switchDrive && driveThrough > otherWire->upDrive) {
otherWire->upDrive=driveThrough;
PushWireByStrength(simulation, otherWire, driveThrough);
};
break;
case down : if (driveThrough >= otherWire->switchDrive && driveThrough > otherWire->downDrive) {
otherWire->downDrive=driveThrough;
PushWireByStrength(simulation, otherWire, driveThrough);
};
break;
};
rts=rts->rest;
};
};
if (thisDrive==RoseNone) break;
};
};
void CheckAddOrRemove(channel, tran, wasNotOff, isNotOff)
RoseWire channel;
RoseTransistor tran;
Bool wasNotOff;
Bool isNotOff;
{
if (channel->channels!=nil) {
if (wasNotOff && !isNotOff) {
RoseTransistors trail=nil;
RoseTransistors rts=channel->notOffChannels;
while (rts) {
if ((RoseTransistor)rts->first==tran) {
if (trail==nil) channel->notOffChannels=rts->rest;
else trail->rest=rts->rest;
break;
};
trail=rts;
rts=rts->rest;
};
}
else if (!wasNotOff && isNotOff) channel->notOffChannels=ListCons(channel->notOffChannels, tran);
};
};
void UpdateRecomputed(simulation, recomputed)
RoseSimulation simulation;
RoseWire recomputed;
{
RoseWire thisWire=recomputed;
while (thisWire) {
RoseLevel wireLevel;
if (thisWire->upDrive==RoseNone && thisWire->downDrive>=RoseForce) wireLevel=L;
else if (thisWire->downDrive==RoseNone && thisWire->upDrive>=RoseForce) wireLevel=H;
else wireLevel=X;
if (thisWire->wireLevel!=wireLevel) {
RoseTransistors rts=thisWire->gates;
while (rts) {
RoseTransistor tran=(RoseTransistor)rts->first;
Bool wasNotOff=TranOn(tran, thisWire->wireLevel)!=off;
Bool isNotOff=TranOn(tran, wireLevel)!=off;
Perturb(simulation, tran->ch1);
Perturb(simulation, tran->ch2);
CheckAddOrRemove(tran->ch1, tran, wasNotOff, isNotOff);
CheckAddOrRemove(tran->ch2, tran, wasNotOff, isNotOff);
rts=rts->rest;
};
thisWire->wireLevel=wireLevel;
};
thisWire=thisWire->nextRecomputed;
};
};
typedef struct FastFindVicinityContextRec {
RoseSimulation simulation;
RoseLevel sameValue;
Bool allSameValue;
Bool singleInfiniteNoUnknownConductance;
Bool infiniteFound;
RoseLevel infiniteValue;
RoseWire recomputed;
RoseWire vicinityWire;
} FastFindVicinityContextRec;
typedef FastFindVicinityContextRec *FastFindVicinityContext;
void FastFindVicinity(wire, context)
RoseWire wire;
FastFindVicinityContext context;
{
RoseTransistors rts=wire->notOffChannels;
wire->mark=true;
if (wire->wireLevel!=context->sameValue || wire->probes!=nil) {
context->allSameValue=false;
context->singleInfiniteNoUnknownConductance=false;
};
while (rts) {
RoseTransistor tran=(RoseTransistor)rts->first;
Conductance tranCond=TranOn(tran, tran->gate->wireLevel);
RoseWire otherWire=tran->ch1;
if (otherWire==wire) otherWire=tran->ch2;
if (tranCond==unknown) context->singleInfiniteNoUnknownConductance=false;
if (otherWire->wireSize==RoseInfinite) {
if (context->infiniteFound && context->infiniteValue!=otherWire->wireLevel) context->singleInfiniteNoUnknownConductance=false;
context->infiniteFound=true;
context->infiniteValue=otherWire->wireLevel;
if (otherWire->wireLevel!=context->sameValue) context->allSameValue=false;
}
else if (!otherWire->mark) FastFindVicinity(otherWire, context);
rts=rts->rest;
};
{
RoseWire next=wire->nextPerturbedWire;
RoseWire previous=wire->previousPerturbedWire;
if (next!=nil) next->previousPerturbedWire=previous;
if (previous!=nil) previous->nextPerturbedWire=next;
if (context->simulation->perturbed==wire) context->simulation->perturbed=next;
wire->nextPerturbedWire=nil;
wire->previousPerturbedWire=nil;
wire->nextRecomputed=context->recomputed;
context->recomputed=wire;
wire->nextVicinityWire=context->vicinityWire;
context->vicinityWire=wire;
};
};
void ForceUpDown(vicinityWire, up, down)
RoseWire vicinityWire;
RoseStrength up;
RoseStrength down;
{
RoseWire thisWire=vicinityWire;
while (thisWire) {
thisWire->mark=false;
thisWire->upDrive=up;
thisWire->downDrive=down;
thisWire=thisWire->nextVicinityWire;
};
};
void UpdatePerturbed(simulation)
RoseSimulation simulation;
{
FastFindVicinityContextRec context;
context.simulation=simulation;
context.recomputed=nil;
while (simulation->perturbed) {
RoseWire wire=simulation->perturbed;
context.sameValue=wire->wireLevel;
context.vicinityWire=nil;
context.infiniteFound=false;
context.infiniteValue=X;
context.singleInfiniteNoUnknownConductance=true;
context.allSameValue=true;
FastFindVicinity(wire, &context);
if (context.infiniteFound && context.singleInfiniteNoUnknownConductance) {
switch (context.infiniteValue) {
case L : ForceUpDown(context.vicinityWire, RoseNone, RoseInfinite); break;
case H : ForceUpDown(context.vicinityWire, RoseInfinite, RoseNone); break;
};
}
else if (context.allSameValue) {
RoseStrength strength;
if (context.infiniteFound) strength=RoseInfinite;
else strength=RoseCharge;
switch (context.sameValue) {
case L : ForceUpDown(context.vicinityWire, RoseNone, strength); break;
case H : ForceUpDown(context.vicinityWire, strength, RoseNone); break;
case X : ForceUpDown(context.vicinityWire, strength, strength); break;
};
}
else {
RoseWire thisWire=context.vicinityWire;
while (thisWire) {
thisWire->mark=false;
thisWire=thisWire->nextVicinityWire;
};
FindVicinity(simulation, wire, upDown);
PushStrength(simulation, upDown);
FindVicinity(simulation, wire, up);
PushStrength(simulation, up);
FindVicinity(simulation, wire, down);
PushStrength(simulation, simulation, down);
};
};
UpdateRecomputed(simulation, context.recomputed);
};
void RoseSettle(simulation)
RoseSimulation simulation;
{
simulation->settle=simulation->settle+1;
while (simulation->perturbed) {
simulation->step=simulation->step+1;
UpdatePerturbed(simulation);
};
};
RoseProbe RoseCreateProbe(simulation, flatWire)
RoseSimulation simulation;
FlatWireRec flatWire;
{
RoseProbe probe;
FlatWire fw=New(FlatWire, FlatWireRec);
*fw=flatWire;
/* This is an interim hack that requires the argument to be an atomic, canonical wire. */
probe=NewSeq(RoseProbe, RoseProbeRec, RoseProbePrimitive, 1);
probe->size=1;
probe->elements[0]=New(RoseProbePrimitive, RoseProbePrimitiveRec);
probe->elements[0]->wire=(RoseWire)HashTableGet(simulation->coreToRoseWires, fw);
if (probe->elements[0]->wire==nil) Die;
probe->elements[0]->wire->probes=ListCons(probe->elements[0]->wire->probes, probe->elements[0]);
probe->simulation=simulation;
return(probe);
};
RoseProbe RoseBindProbe(simulation, cellType, name, flatCell)
RoseSimulation simulation;
CellType cellType;
String name;
FlatCellTypeRec flatCell;
{
FlatWireRec flatWire;
flatWire.flatCell=flatCell;
flatWire.wireRoot=internal;
flatWire.validPath=false;
flatWire.wire=FindWire(cellType->public, name);
return(RoseCreateProbe(simulation, flatWire));
};
RoseLevel RoseGL(probe)
RoseProbe probe;
{
if (probe->size!=1) Die;
return(probe->elements[0]->wire->wireLevel);
};
void RosePL(probe, level, drive)
RoseProbe probe;
RoseLevel level;
RoseStrength drive;
{
Nat i;
for (i=0; i<probe->size; i++) {
probe->elements[i]->level=level;
probe->elements[i]->drive=drive;
Perturb(probe->simulation, probe->elements[i]->wire);
};
};
/* Initialization */
void RoseInitialize()
{
roseFixedWireProp=PropertyRegister(roseFixedWirePropName, nil);
};