<> <> <> <> DIRECTORY CD, CDAtomicObjects, CDBasics, CDCallSpecific, CDIO, CDLRUCache, CDOrient, RefTab, Rope, RuntimeError, TokenIO; CDAtomicObjectsImpl: CEDAR MONITOR IMPORTS CD, CDBasics, CDCallSpecific, CDIO, CDLRUCache, CDOrient, RefTab, RuntimeError, TokenIO EXPORTS CDAtomicObjects SHARES CD = --want access technology of ObjectProcs BEGIN <<--This module helps the implementation of a wide class of atomic ChipNDale>> <<--objects, which do not have children and are shared between designs. Despite>> <<--its name this are not the only atomic object classes. >> DrawRec: TYPE = CDAtomicObjects.DrawRec; <<--RECORD [r: CD.DesignRect, lev: CD.Layer _ CD.highLightError];>> DrawList: TYPE = CDAtomicObjects.DrawList; <<--LIST OF DrawRec;>> AtomicObsPtr: TYPE = CDAtomicObjects.AtomicObsPtr; <<--REF AtomicObsRec;>> AtomicObsRec: TYPE = CDAtomicObjects.AtomicObsRec; <<--RECORD [ >> <<-- rList: DrawList_NIL, --do not change directly>> <<-- sList: DrawList_NIL, --do not change directly>> <<-- ir: CD.DesignRect, --do not change directly>> <<-- data: REF_NIL --for free use by class implementor>> <<-- ];>> <<>> FillObjectProc: TYPE = CDAtomicObjects.FillObjectProc; <<--PROC [ob: CD.ObPtr] RETURNS [mustFail: BOOL _ FALSE];>> <<--read (and even rewrite) size, layer>> <<--calls IncorporateRect>> <<--do not read or write ir>> <<--rList, sList will be initialized to NIL>> ------------ classTable: RefTab.Ref = RefTab.Create[41]; ClassEntry: TYPE = RECORD[ tech: CD.Technology, fillProc: FillObjectProc, p: REF CD.ObjectProcs_NIL ]; GetClassEntry: PROC [class: ATOM, tech: CD.Technology] RETURNS [ce: REF ClassEntry_NIL] = INLINE BEGIN p: REF CD.ObjectProcs = CD.FetchObjectProcs[class, tech]; IF p#NIL THEN ce _ NARROW[ classTable.Fetch[p].val ] END; ------------ cache1: CDLRUCache.LRUCache = CDLRUCache.Create[size: 37, aequivalenceProc: AequivalenceAO]; cache2: CDLRUCache.LRUCache = CDLRUCache.Create[size: 37, aequivalenceProc: AequivalenceAO]; cache3: CDLRUCache.LRUCache = CDLRUCache.Create[size: 37, aequivalenceProc: AequivalenceAO]; myRectPtr: CD.RectPtr = NEW[CD.RectRecord]; AequivalenceAO: PROC [mySpecific, other: REF ANY] RETURNS [BOOL] = { <<--Insider info: mySpecific is already in the cache; other is the one to be inserted>> RETURN [~ISTYPE[mySpecific, CD.RectPtr]] }; ------------ CreateAtomicOb: PUBLIC PROC [class: ATOM, size: CD.DesignPosition, tech: CD.Technology, lev: CD.Layer_CD.combined] RETURNS [ob: CD.ObPtr_NIL] = <<--NIL if not done>> BEGIN ENABLE UNWIND => NULL; ce: REF ClassEntry = GetClassEntry[class, tech]; size _ CDBasics.MaxPoint[size, [1, 1]]; IF ce#NIL THEN { cache: CDLRUCache.LRUCache _ SELECT size.x+size.y FROM <=30 => cache1, --any minimal size ndiff construct <=60 => cache2, --any minimal size pdiff construct ENDCASE => cache3; --long crazy stuff aop: AtomicObsPtr = NEW[AtomicObsRec _ [ir: CDBasics.empty]]; ob1: CD.ObPtr _ cache.UnusedOrNew[]; ob1.p _ ce.p; ob1.size _ size; ob1.layer _ lev; ob1.specificRef _ aop; IF ce.fillProc[ob1 ! RuntimeError.UNCAUGHT => GOTO xx].mustFail THEN RETURN [NIL]; ob _ cache.ReplaceByAequivalent[ob1]; <<--as efficiencyhack, the object is now already in the lru cache, inspite>> <<--of not yet beeing checked.>> <<--If object is bad, however, the technology implementing code is bad, and therefore>> <<--we do not really feel responsible for the design...>> IF ob=ob1 THEN TRUSTED { --new entry <<--TRUSTED because we LOOPHOLE;>> <<--LOOPHOLE because we change the ob's objectprocs in case the fillProc>> <<--change the p field>> IF ~CDBasics.Inside[aop.ir, CDBasics.RectAt[[0, 0], ob.size]] OR CDBasics.empty=aop.ir OR (aop.rList=NIL AND aop.sList=NIL) THEN GOTO xx; <<--now check if we should change the objectprocs to be more general>> IF aop.sList#NIL AND ce.p.drawMe=XDrawAO AND ce.p.quickDrawMe=XDrawAO THEN { p: REF CD.ObjectProcs = LOOPHOLE[ob.p]; --get rid of readonly p.drawMe _ p.quickDrawMe _ DrawAO; }; IF aop.ir#CDBasics.RectAt[[0, 0], ob.size] THEN { IF aop.ir.x1<0 OR aop.ir.y1<0 OR aop.ir.x2>ob.size.x OR aop.ir.y2>ob.size.y THEN GOTO xx; IF ce.p.showMeSelected=XShowSelectedAO THEN { p: REF CD.ObjectProcs = LOOPHOLE[ob.p]; --get rid of readonly p.showMeSelected _ ShowSelectedAO; } }; }; }; EXITS xx => RETURN WITH ERROR CD.Error[other, "Error in technology, implementing creation of atomic object"]; END; RegisterAtomicObClass: PUBLIC PROC [class: ATOM, fillProc: FillObjectProc, description: Rope.ROPE_NIL, tech: CD.Technology_NIL] RETURNS [type: REF CD.ObjectProcs _ NIL] = <<--drawMe, quickDrawMe are considered variables and should not >> <<--be changed by class implementor.>> BEGIN ce: REF ClassEntry _ NEW[ClassEntry_[ tech: tech, fillProc: fillProc ]]; done: BOOL_TRUE; ce.p _ type _ CD.RegisterObjectType[class, tech ! CD.Error => {done _ FALSE; CONTINUE}]; IF ~done THEN RETURN WITH ERROR CD.Error[doubleRegistration]; done _ RefTab.Insert[classTable, type, ce]; type.drawMe _ type.quickDrawMe _ XDrawAO; type.internalRead _ ReadAO; type.internalWrite _ WriteAO; type.oldInsideRect _ type.interestRect _ InsideAO; type.showMeSelected _ XShowSelectedAO; type.wireTyped _ FALSE; type.description _ description; CDCallSpecific.Register[$Lengthen, type, LengthenAO]; END; Incorporate: PUBLIC PROC [ob: CD.ObPtr, r: CD.DesignRect, lev: CD.Layer, inside: BOOL _ TRUE, save: BOOL _ FALSE] = BEGIN aop: AtomicObsPtr = NARROW[ob.specificRef]; IF inside THEN aop.ir _ CDBasics.Surround[aop.ir, r]; IF save THEN aop.sList _ CONS[[r, lev], aop.sList] ELSE aop.rList _ CONS[[r, lev], aop.rList]; END; -------------- ReadAO: CD.InternalReadProc --PROC [] RETURNS [ObPtr]-- = BEGIN x: INT = TokenIO.ReadInt[]; y: INT = TokenIO.ReadInt[]; code: ATOM = TokenIO.ReadAtom[]; lev: CD.Layer = CDIO.ReadLayer[]; tech: CD.Technology = CDIO.DesignInReadOperation[].technology; RETURN [ CreateAtomicOb[code, [x, y], tech, lev] ] END; WriteAO: CD.InternalWriteProc -- PROC [me: ObPtr] -- = BEGIN TokenIO.WriteInt[me.size.x]; TokenIO.WriteInt[me.size.y]; TokenIO.WriteAtom[me.p.objectType]; CDIO.WriteLayer[me.layer]; END; XDrawAO: PROC [aptr: CD.ApplicationPtr, pos: CD.DesignPosition, orient: CD.Orientation, pr: CD.DrawRef] = <<--faster, hacked routine without saveRects>> BEGIN aop: AtomicObsPtr = NARROW[aptr.ob.specificRef]; FOR p: DrawList _ aop.rList, p.rest WHILE p#NIL DO pr.drawRect[ CDOrient.MapRect[ itemInCell: p.first.r, cellSize: aptr.ob.size, cellInstOrient: orient, cellInstPos: pos], p.first.lev, pr] ENDLOOP; END; DrawAO: PROC [aptr: CD.ApplicationPtr, pos: CD.DesignPosition, orient: CD.Orientation, pr: CD.DrawRef] = BEGIN aop: AtomicObsPtr = NARROW[aptr.ob.specificRef]; FOR p: DrawList _ aop.rList, p.rest WHILE p#NIL DO pr.drawRect[ CDOrient.MapRect[ itemInCell: p.first.r, cellSize: aptr.ob.size, cellInstOrient: orient, cellInstPos: pos], p.first.lev, pr] ENDLOOP; FOR p: DrawList _ aop.sList, p.rest WHILE p#NIL DO pr.saveRect[ CDOrient.MapRect[ itemInCell: p.first.r, cellSize: aptr.ob.size, cellInstOrient: orient, cellInstPos: pos], p.first.lev, pr] ENDLOOP; END; ShowSelectedAO: PROC [aptr: CD.ApplicationPtr, pos: CD.DesignPosition, orient: CD.Orientation, pr: CD.DrawRef] = BEGIN aop: AtomicObsPtr = NARROW[aptr.ob.specificRef]; pr.outLineProc[ CDOrient.MapRect[ itemInCell: aop.ir, cellSize: aptr.ob.size, cellInstOrient: orient, cellInstPos: pos], pr] END; XShowSelectedAO: PROC [aptr: CD.ApplicationPtr, pos: CD.DesignPosition, orient: CD.Orientation, pr: CD.DrawRef] = BEGIN pr.outLineProc[CDOrient.RectAt[pos, aptr.ob.size, orient], pr] END; InsideAO: PROC [ob: CD.ObPtr] RETURNS [CD.DesignRect] = BEGIN RETURN [NARROW[ob.specificRef, AtomicObsPtr].ir] END; LengthenAO: CDCallSpecific.CallProc = <<--PROC [design: CD.Design, aptr: CD.ApplicationPtr, x: REF] >> <<--RETURNS [done: BOOL_TRUE, removeMe: BOOL_FALSE, include: CD.ApplicationList_NIL,>> <<--repaintMe: BOOL_FALSE, repaintInclude: BOOL_FALSE]>> BEGIN ToPosition: PROC [x: REF] RETURNS [p: CD.DesignPosition] = <<--y field defaults to lambda, x field defaults to 0>> <<--[0, 0] if not done>> BEGIN IF x=NIL THEN p _ [0, CD.lambda] ELSE WITH x SELECT FROM rp: REF CD.DesignPosition => p _ rp^; rn: REF CD.DesignNumber => p _ [0, rn^]; ENDCASE => p _ [0, 0]; END; <<>> <<--LengthenAO>> amount: CD.DesignPosition = ToPosition[x]; IF amount.y=0 AND amount.x=0 THEN done _ FALSE ELSE { sz: CD.DesignPosition _ CDBasics.AddPoints[aptr.ob.size, amount]; new: CD.ObPtr _ CreateAtomicOb[size: sz, class: aptr.ob.p.objectType, lev: aptr.ob.layer, tech: aptr.ob.p.technology]; done _ new#NIL AND new#aptr.ob AND new.size#aptr.ob.size; IF done THEN { aptr.ob _ new; repaintMe _ TRUE; } }; END; END.