/* Rosemary.c */ #include "CoreBasics.h" #include "Core.h" #include "CoreFlat.h" #include "Rosemary.h" #define roseFixedWirePropName "roseFixedWire" String RoseLevelNames[RoseLevelCount]={"L", "H", "X"}; /* 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->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; }; }; 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); }; case up : if (driveThrough >= otherWire->switchDrive && driveThrough > otherWire->upDrive) { otherWire->upDrive=driveThrough; PushWireByStrength(simulation, otherWire, driveThrough); }; case down : if (driveThrough >= otherWire->switchDrive && driveThrough > otherWire->downDrive) { otherWire->downDrive=driveThrough; PushWireByStrength(simulation, otherWire, driveThrough); }; }; 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); };