DIRECTORY AMBridge USING [TVForSignal], BasicTime USING [GMT, Now, Period], CD USING [CreateDrawRef, Design, DrawProc, DrawRef, Instance, InstanceList, Layer, Number, Object, Technology], CDBasics USING [Extend, MapRect], CDCommandOps USING [DoWithResource, RegisterWithMenu], CDDirectory USING [Fetch, Name], CDErrors USING [IncludeMessage, RemoveMessages], CDIO USING [ReadDesign], CDOps USING [InstList, LayerRope, ToRope], CDProperties USING [GetDesignProp, GetObjectProp, PutDesignProp, RegisterProperty], CDSequencer USING [Command, ImplementCommand, UseAbortFlag], CDValue USING [Fetch], CDViewer USING [CreateViewer, ViewerList, ViewersOf], Commander USING [CommandProc, Register], CommandTool USING [NextArgument], Core USING [Wire], CoreClasses USING [recordCellClass, RecordCellType], CoreGeometry USING [GetObject], CoreIO USING [PropReadProc, PropWriteProc, ReadAtom, ReadRope, RegisterProperty, ReportSaveCellType, RestoreCellType, WriteAtom, WriteRope], CoreOps USING [CopyWire, GetCellTypeName, GetShortWireName, PrintCellType, SetShortWireName], CoreProperties USING [GetProp, propPrint, PropPrintProc, Props, PutProp, RegisterProperty, StoreProperties], CoreView USING [debugViewer, DestroyView, GeometryView, StartIncrementalView, Viewer], CStitching USING [DumpCache], DesignRules USING [DesignRuleError, GetRuleSet, FetchRulesID, Rules], Drc USING [CheckDesignRules, CoreCell, coreInconsistent, DRV, DRVkey, ErrorRect, Layout, Tech, Wire], DrcCmosb USING [cMosBcompleteKey, cMosBsimpleKey, FlushTechCache, NewTechnology], DrcDebug USING [debug, dLog], ExtractOps USING [IsSchematic], FS USING [ComponentPositions, Error, ExpandName], IO USING [atom, card, GetID, int, PutF, PutF1, PutFR, PutFR1, RIS, ROS, rope, RopeFromROS, STREAM, time], PrincOpsUtils USING [], PrintTV USING [Print], Process USING [priorityBackground, SetPriority], Rope USING [Cat, Equal, IsEmpty, ROPE, Substr], RuntimeError USING [UNCAUGHT], SimpleMailer USING [SendMessage], Sinix USING [Extract, Mode], SinixOps USING [GetExtractMode], SinixRawCMosB USING [mode], TerminalIO USING [PutRope, PutRopes, PutF, PutF1], UserCredentials USING [Get], UserProfile USING [Boolean, CallWhenProfileChanges, ProfileChangedProc], ViewerOps USING [SetNewVersion]; DrcCommandImpl: CEDAR PROGRAM IMPORTS AMBridge, BasicTime, CD, CDBasics, CDCommandOps, CDDirectory, CDErrors, CDIO, CDOps, CDProperties, CDSequencer, CDValue, CDViewer, Commander, CommandTool, CoreClasses, CoreGeometry, CoreIO, CoreOps, CoreProperties, CoreView, CStitching, DesignRules, Drc, DrcCmosb, DrcDebug, ExtractOps, FS, IO, PrintTV, Process, Rope, RuntimeError, SimpleMailer, Sinix, SinixOps, SinixRawCMosB, TerminalIO, UserCredentials, UserProfile, ViewerOps ~ BEGIN OPEN DrcCmosb; ROPE: TYPE ~ Rope.ROPE; tryRaw: BOOL _ FALSE; violationsInTopCell: BOOL _ FALSE; timing: BOOL _ UserProfile.Boolean ["Genista.Timing", FALSE]; religion: BOOL _ UserProfile.Boolean ["Genista.EmulateSoS", FALSE]; failureReason: ROPE; failureTorch: REF ANY; failureSignal: UNSAFE ERROR ANY RETURNS ANY; Misc: TYPE ~ REF Stuff; Stuff: TYPE ~ RECORD [design: CD.Design, geom: Drc.Layout, inst: CD.Instance _ NIL]; TimeStamp: TYPE ~ REF Titius; Titius: TYPE ~ RECORD [caius: BasicTime.GMT]; regressionDesign: ROPE _ "[DATools]Saguaro>DragonRules.dale"; layoutViewer: CoreView.Viewer; stateHandle: Misc _ NEW [Stuff _ [NIL, SinixOps.GetExtractMode[$cmosB].decoration, NIL]]; lastCore: Drc.CoreCell _ NIL; lastKey: ATOM; status: RECORD [errors: REF CARDINAL, start: BasicTime.GMT, currentCell: REF ROPE]; comesFromCdFile: ATOM ~ CoreProperties.RegisterProperty [$DrcComesFromCdFile]; ruleKey: ATOM ~ CoreProperties.RegisterProperty [$DrcRules]; sessionKey: ATOM ~ CoreProperties.RegisterProperty [$DrcEnumerationSession]; notMe: BOOL ~NOT UserCredentials.Get[].name.Equal ["Beretta.pa", FALSE]; neverEver: ERROR [signal: SIGNAL ANY RETURNS ANY] ~ CODE; -- a signal never ever raised Execute: PROC [comm: CDSequencer.Command] ~ BEGIN ENABLE BEGIN Drc.coreInconsistent => BEGIN failureReason _ reason; failureTorch _ torch; GOTO failure END; neverEver --RuntimeError.UNCAUGHT-- => BEGIN TRUSTED {failureSignal _ LOOPHOLE [signal, SIGNAL ANY RETURNS ANY]}; GOTO alienFailure END END; state: Misc ~ NEW [Stuff]; abort: REF BOOL _ NEW [BOOL _ FALSE]; ExtractAndCheck: PROC [comm: CDSequencer.Command] ~ BEGIN startTime1, startTime2, lapTime, stopTime: BasicTime.GMT; usedRuleKey: ATOM _ DesignRules.FetchRulesID [state.design]; -- saved in Core rules: DesignRules.Rules; techE: Sinix.Mode _ SinixOps.GetExtractMode [state.design.technology]; techD: Drc.Tech; violations: CARDINAL _ 0; cDFileName: ROPE ~ NARROW [CDValue.Fetch [state.design, $CDxLastFile]]; coreFileName: ROPE; state.design.name _ BuildId [state.design.name, cDFileName, "Design"]; coreFileName _ Rope.Cat ["[]<>Temp>DRC>PreGenista>", state.design.name]; IF (techE = NIL) THEN BEGIN TerminalIO.PutRope [Rope.Cat ["The technology ", state.design.technology.name, " is not implemented in Sinix or Drc.\n"]]; RETURN END; IF tryRaw THEN techE _ SinixRawCMosB.mode; state.geom _ stateHandle.geom _ techE.decoration; rules _ DesignRules.GetRuleSet [usedRuleKey ! DesignRules.DesignRuleError => CONTINUE]; IF (rules = NIL) THEN BEGIN TerminalIO.PutRope ["The design does not specify a set of design rules. Using VTI rule set.\n"]; usedRuleKey _ $vti; rules _ DesignRules.GetRuleSet [usedRuleKey ! DesignRules.DesignRuleError => CONTINUE]; usedRuleKey _ $Vti; IF (rules = NIL) THEN rules _ DesignRules.GetRuleSet [usedRuleKey ! DesignRules.DesignRuleError => CONTINUE]; usedRuleKey _ $VTI; IF (rules = NIL) THEN rules _ DesignRules.GetRuleSet [usedRuleKey] END; techD _ DrcCmosb.NewTechnology [IF religion THEN cMosBsimpleKey ELSE cMosBcompleteKey, rules]; IF (comm.key = $DrcSelMinimal) THEN techD.verifyCell _ NIL; FOR all: CD.InstanceList _ CDOps.InstList [state.design], all.rest WHILE all # NIL DO IF all.first.selected THEN BEGIN whatTheUserMeant: ROPE _ CDDirectory.Name [all.first.ob, state.design]; rickThinksItsSchematics: BOOL ~ ExtractOps.IsSchematic [state.design, all.first.ob]; pos: FS.ComponentPositions; IF NOT whatTheUserMeant.IsEmpty THEN BEGIN [whatTheUserMeant, pos] _ FS.ExpandName [whatTheUserMeant ! FS.Error => GOTO illegalName]; whatTheUserMeant _ whatTheUserMeant.Substr [start: pos.ext.start, len: pos.ext.length]; EXITS illegalName => BEGIN TerminalIO.PutF ["\nThe name %g is illegal or a non-allowed pattern. Suggested replacement: %g.mask\n", IO.rope [whatTheUserMeant], IO.rope [BuildId [whatTheUserMeant, "Cell", "Cell"]]]; whatTheUserMeant _ NIL END END; SELECT TRUE FROM whatTheUserMeant.Equal ["mask", FALSE] => NULL; -- c'est bon whatTheUserMeant.Equal ["sch", FALSE], whatTheUserMeant.Equal ["icon", FALSE] => BEGIN TerminalIO.PutRope ["\nCells with extension and are ignored unless Rick thinks it is not schematics.\n"]; IF rickThinksItsSchematics THEN LOOP END; ENDCASE => BEGIN start: ROPE ~ UserCredentials.Get[].name.Cat [" is a user out there, who has a design ", comm.design.name, " on file ", cDFileName]; extendedName: ROPE ~ CDOps.ToRope[all.first.ob].Cat[" (the user meant ", CDDirectory.Name [all.first.ob, state.design], ")"]; IF rickThinksItsSchematics THEN BEGIN TerminalIO.PutF1 ["\nIn theory, cells without an extension are not allowed.\nIn this case, however, Rick thinks that %g is a schematics cell, so it is ignored.\n", IO.rope [extendedName]]; LOOP END; TerminalIO.PutF1 ["\nIn theory, cells without extension are not allowed.\nIn this case, however, Rick thinks that %g is not a schematics cell, so it is checked anyway.\n", IO.rope [extendedName]] END; TRUSTED {Process.SetPriority [Process.priorityBackground]}; startTime1 _ BasicTime.Now []; WITH Sinix.Extract [obj: all.first.ob, mode: techE].result SELECT FROM coreCell: Drc.CoreCell => BEGIN v: REF CARDINAL _ NIL; fakeActual: Drc.Wire ~ CoreOps.CopyWire [coreCell.public]; stamp: TimeStamp _ NEW [Titius]; lapTime _ BasicTime.Now []; lastCore _ coreCell; lastKey _ techD.checkedBy; coreCell.properties _ CoreProperties.PutProp [coreCell.properties, comesFromCdFile, cDFileName]; coreCell.properties _ CoreProperties.PutProp [coreCell.properties, ruleKey, usedRuleKey]; IF (comm.key # $DrcSel) THEN BEGIN compositeName: ROPE ~ coreFileName.Cat ["-", BuildId [CDDirectory.Name [all.first.ob, state.design], CDOps.ToRope [all.first.ob], "Cell"], ".Core"]; [] _ CoreIO.ReportSaveCellType [cellType: coreCell, fileName: compositeName]; TerminalIO.PutF ["\nExtraction saved on %g\n", IO.rope [compositeName]] END; FOR i: NAT IN [0 .. fakeActual.size) DO givenName: ROPE ~ CoreOps.GetShortWireName [fakeActual[i]]; fakeActual[i] _ CoreOps.SetShortWireName [fakeActual[i], IF givenName.IsEmpty THEN IO.PutFR1 ["External", IO.int [i]] ELSE givenName] ENDLOOP; IF DrcDebug.debug THEN BEGIN IF (layoutViewer # NIL) THEN CoreView.DestroyView [layoutViewer]; IF (CoreView.debugViewer # NIL) THEN CoreView.DestroyView [CoreView.debugViewer]; layoutViewer _ CoreView.GeometryView [coreCell, techE.decoration, abort]; CoreView.debugViewer _ CoreView.StartIncrementalView [coreCell, techE.decoration, abort] END; CDProperties.PutDesignProp [state.design, $DrcCoreCircularity]; -- remove IF DrcDebug.debug THEN BEGIN CoreOps.PrintCellType [coreCell, DrcDebug.dLog]; DrcDebug.dLog.PutF ["\n"]; END; status.errors _ NEW [CARDINAL _ 0]; status.currentCell _ NEW [ROPE]; status.start _ startTime2 _ BasicTime.Now[]; violations _ Drc.CheckDesignRules [cell: coreCell, external: fakeActual, viaFlatness: (comm.key = $DrcSel), tech: techD, stopFlag: abort, lap: status.errors, currentCell: status.currentCell, layout: state.geom]; stopTime _ BasicTime.Now []; IF timing THEN TerminalIO.PutF [ format: "\nNumber of new design violations found: %l%g%l\n", v1: IO.rope ["b"], v2: IO.card [violations], v3: IO.rope ["B"]]; IF DrcDebug.debug THEN VerifyObjects [state.design, all.first.ob]; IF timing THEN BEGIN TerminalIO.PutF1 ["\nElapsed time for extraction: %g", IO.rope [TimeToRope [startTime1, lapTime]]]; TerminalIO.PutF1 ["\nElapsed time for DRC: %g", IO.rope [TimeToRope [startTime2, stopTime]]]; TerminalIO.PutF1 ["\nTotal elapsed time: %g\n", IO.rope [TimeToRope [startTime1, stopTime]]] END; IF (violations > 0) THEN v _ NEW [CARDINAL _ violations]; CDProperties.PutDesignProp [state.design, $DrcNr, v]; CDProperties.PutDesignProp [state.design, $DrcCoreCircularity, coreCell]; -- a circularity, but I do not have a better idea at the moment CStitching.DumpCache []; stamp.caius _ BasicTime.Now []; IF (violations > 0) THEN BEGIN FOR vl: CDViewer.ViewerList _ CDViewer.ViewersOf [state.design], vl.rest WHILE vl # NIL DO ViewerOps.SetNewVersion [vl.first] ENDLOOP END; state.inst _ all.first; IF violationsInTopCell THEN CDErrors.RemoveMessages [design: state.design, ob: state.inst.ob, owner: Drc.DRVkey]; EnumerateCore [coreCell, BackAnnotation, stamp, state, abort]; status.errors _ NIL; status.currentCell _ NIL END; w: Core.Wire => ERROR; ENDCASE => NULL -- e.g., cell contains text or schematics END -- if selected ENDLOOP END; -- ExtractAndCheck TerminalIO.PutF1 ["DRC (Genista). %g\n", IO.rope [SELECT comm.key FROM $DrcSel => "Verify all rules.", $DrcSelVia => "Do not verify via flatness rules.", $DrcSelMinimal => "Do not verify via flatness nor well rules.", ENDCASE => "There is an implementation error"]]; state.design _ comm.design; CDSequencer.UseAbortFlag [state.design, abort]; [] _ CDCommandOps.DoWithResource [ExtractAndCheck, comm, $Drc]; TerminalIO.PutRope ["Drc done.\n"]; EXITS failure => BEGIN TerminalIO.PutRopes [failureReason, ". Core structure inconsistent. DRC aborted.\n"] END; alienFailure => TRUSTED BEGIN msg: ROPE; ros: IO.STREAM ~ IO.ROS []; lastCore.properties _ CoreProperties.PutProp [lastCore.properties, lastKey, NIL]; PrintTV.Print [tv: AMBridge.TVForSignal [failureSignal], put: ros, verbose: TRUE]; msg _ ros.RopeFromROS []; TerminalIO.PutRopes [msg, "\n\t*** Session miscarried ***\n"]; IF notMe THEN [] _ SimpleMailer.SendMessage [from: "Genista", to: LIST ["Beretta.PA"], subject: "Crash", body: msg] ELSE ERROR END END; -- Execute EachCell: TYPE ~ PROC [cell: Drc.CoreCell, data: REF ANY _ NIL]; EnumerateCore: PROC [cell: Drc.CoreCell, action: EachCell, session: TimeStamp, data: REF ANY _ NIL, stopFlag: REF BOOL] ~ BEGIN IF (session # NIL) THEN BEGIN visited: TimeStamp ~ NARROW [CoreProperties.GetProp [cell.properties, sessionKey], TimeStamp]; IF (visited = NIL) OR (session.caius # visited.caius) THEN cell.properties _ CoreProperties.PutProp [cell.properties, sessionKey, session] ELSE RETURN END; SELECT cell.class FROM CoreClasses.recordCellClass => BEGIN cellData: CoreClasses.RecordCellType ~ NARROW [cell.data]; FOR sub: NAT IN [0 .. cellData.size) DO IF stopFlag^ THEN ERROR ABORTED; EnumerateCore [cellData.instances[sub].type, action, session, data, stopFlag] ENDLOOP; action [cell, data] END; ENDCASE => NULL END; -- EnumerateCore BackAnnotation: EachCell ~ BEGIN state: Misc ~ NARROW [data]; cdCell: CD.Object ~ CoreGeometry.GetObject [state.geom, cell]; drv: Drc.DRV ~ NARROW [CoreProperties.GetProp [cell.properties, Drc.DRVkey]]; IF NOT violationsInTopCell THEN CDErrors.RemoveMessages [design: state.design, ob: cdCell, owner: Drc.DRVkey]; IF (drv # NIL) THEN FOR v: LIST OF Drc.ErrorRect _ drv.places, v.rest WHILE v # NIL DO IF violationsInTopCell THEN [] _ CDErrors.IncludeMessage [design: state.design, ob: state.inst.ob, rect: CDBasics.MapRect [CDBasics.Extend [v.first.r, 4], state.inst.trans], message: v.first.msg, owner: Drc.DRVkey] ELSE [] _ CDErrors.IncludeMessage [design: state.design, ob: cdCell, rect: CDBasics.Extend [v.first.r, 4], message: v.first.msg, owner: Drc.DRVkey] ENDLOOP END; -- BackAnnotation ProblemMessage: EachCell ~ BEGIN state: Misc ~ NARROW [data]; cdCell: CD.Object ~ CoreGeometry.GetObject [state.geom, cell]; IF (CoreProperties.GetProp [cell.properties, Drc.DRVkey] # NIL) THEN BEGIN TerminalIO.PutRopes [CDDirectory.Name [cdCell, state.design], " is not verified correctly ("]; TerminalIO.PutRopes [NARROW [CDProperties.GetObjectProp [cdCell, $rule], ROPE], ")\n"] END END; -- ProblemMessage UncheckedMessage: EachCell ~ BEGIN state: Misc ~ NARROW [data]; cdCell: CD.Object ~ CoreGeometry.GetObject [state.geom, cell]; drv: Drc.DRV ~ NARROW [CoreProperties.GetProp [cell.properties, Drc.DRVkey]]; IF (drv = NIL) OR (drv.count # 1) THEN BEGIN description: ROPE ~ NARROW [CDProperties.GetObjectProp [cdCell, $rule]]; flat: BOOL ~ (CDProperties.GetObjectProp [cdCell, $flat] # NIL); IF flat THEN TerminalIO.PutF ["%g is verified flat (%g)\n", IO.rope [CDDirectory.Name [cdCell, state.design]], IO.rope [description]] ELSE TerminalIO.PutF ["%g is not verified correctly (%g)\n", IO.rope [CDDirectory.Name [cdCell, state.design]], IO.rope [description]] END END; -- UncheckedMessage Repeal: EachCell ~ BEGIN cell.properties _ CoreProperties.PutProp [cell.properties, lastKey]; cell.properties _ CoreProperties.PutProp [cell.properties, Drc.DRVkey] END; -- Repeal RemoveCdErrors: PROC [comm: CDSequencer.Command] ~ BEGIN TerminalIO.PutRope ["Removing Genista's error rectangles from selected cells.\n"]; FOR all: CD.InstanceList _ CDOps.InstList [comm.design], all.rest WHILE all # NIL DO IF all.first.selected THEN CDErrors.RemoveMessages [design: comm.design, ob: all.first.ob, owner: Drc.DRVkey] ENDLOOP END; -- RemoveCdErrors List: PROC [comm: CDSequencer.Command] ~ BEGIN violations: REF CARDINAL ~ NARROW [CDProperties.GetDesignProp [comm.design, $DrcNr]]; IF (violations = NIL) THEN TerminalIO.PutRope ["No new violations found last time.\n"] ELSE TerminalIO.PutF1 ["Number of design rule violations found last time: %g\n", IO.card[violations^]]; END; -- List PrintDRV: EachCell ~ BEGIN drv: Drc.DRV ~ NARROW [CoreProperties.GetProp [cell.properties, Drc.DRVkey]]; IF (drv # NIL) THEN BEGIN cellName: ROPE ~ CoreOps.GetCellTypeName [cell]; l: CD.Number ~ NARROW [data, CD.Technology].lambda; TerminalIO.PutF ["\ncell %g, %g violations:\n", IO.rope [cellName], IO.int [drv.count]]; FOR e: LIST OF Drc.ErrorRect _ drv.places, e.rest WHILE e # NIL DO TerminalIO.PutF ["%g at [(%g, %g); (%g, %g)] \n", IO.rope [e.first.msg], IO.int [e.first.r.x1/l], IO.int [e.first.r.y1/l], IO.int [e.first.r.x2/l], IO.int [e.first.r.y2/l]] ENDLOOP END END; -- PrintDRV ListAll: PROC [comm: CDSequencer.Command] ~ BEGIN coreCell: Drc.CoreCell ~ NARROW [CDProperties.GetDesignProp [comm.design, $DrcCoreCircularity]]; abort: REF BOOL _ NEW [BOOL _ FALSE]; stamp: TimeStamp _ NEW [Titius]; ListDRV: PROC [comm: CDSequencer.Command] ~ BEGIN EnumerateCore [coreCell, PrintDRV, stamp, comm.design.technology, abort] END; -- ListDRV TerminalIO.PutRope ["Design rule violations stored in Core:\n"]; CDSequencer.UseAbortFlag [comm.design, abort]; stamp.caius _ BasicTime.Now []; IF (coreCell = NIL) THEN TerminalIO.PutRope ["None recorded.\n"] ELSE [] _ CDCommandOps.DoWithResource [ListDRV, comm, $Drc] END; -- ListAll RegressionTest: PROC ~ BEGIN state: Misc ~ NEW [Stuff]; dummy: REF BOOL ~ NEW [BOOL _ FALSE]; test: CD.Design ~ CDIO.ReadDesign [regressionDesign]; usedRuleKey: ATOM; rules: DesignRules.Rules; techE: Sinix.Mode; techD: Drc.Tech; ok, ko: CD.Object; IF (test = NIL) THEN GOTO maintenanceProblem; techE _ SinixOps.GetExtractMode [test.technology]; usedRuleKey _ DesignRules.FetchRulesID [test]; IF (usedRuleKey = NIL) THEN usedRuleKey _ $Dragon; rules _ DesignRules.GetRuleSet [usedRuleKey]; techD _ DrcCmosb.NewTechnology [IF religion THEN cMosBsimpleKey ELSE cMosBcompleteKey, rules]; IF (techD = NIL) THEN GOTO maintenanceProblem; state.geom _ techE.decoration; ok _ CDDirectory.Fetch [test, "ok.mask"].object; IF (ok = NIL) THEN GOTO maintenanceProblem; TerminalIO.PutRope ["\n"]; WITH Sinix.Extract [obj: ok, mode: techE].result SELECT FROM coreCell: Drc.CoreCell => BEGIN status.errors _ NEW [CARDINAL _ 0]; status.start _ BasicTime.Now []; status.currentCell _ NEW [ROPE]; IF (Drc.CheckDesignRules [cell: coreCell, tech: techD, viaFlatness: TRUE, external: coreCell.public, stopFlag: dummy, lap: status.errors, currentCell: status.currentCell, layout: state.geom] > 0) THEN EnumerateCore [coreCell, ProblemMessage, NIL, state, dummy] END; ENDCASE => ERROR; TerminalIO.PutRope ["\n"]; ko _ CDDirectory.Fetch [test, "ko.mask"].object; IF (ko = NIL) THEN GOTO maintenanceProblem; WITH Sinix.Extract [obj: ko, mode: techE].result SELECT FROM coreCell: Drc.CoreCell => BEGIN status.errors _ NEW [CARDINAL _ 0]; status.start _ BasicTime.Now []; status.currentCell _ NEW [ROPE]; [] _ Drc.CheckDesignRules [cell: coreCell, tech: techD, viaFlatness: TRUE, external: coreCell.public, stopFlag: dummy, lap: status.errors, currentCell: status.currentCell, layout: state.geom]; EnumerateCore [coreCell, UncheckedMessage, NIL, state, dummy] END; ENDCASE => ERROR; status.errors _ NIL; status.currentCell _ NIL; EXITS maintenanceProblem => BEGIN TerminalIO.PutRope ["Please inform DRC maintainers that the self verification is broken.\n"] END END; -- RegressionTest VerifyRect: CD.DrawProc ~ BEGIN specialLayers: CD.Layer = 5; -- combined, highLightShade, highLightError, pinRepresentation lambda: CD.Number ~ pr.design.technology.lambda; IF (ob.class.objectType = $Rect) AND (ob.layer >= specialLayers) AND (CDProperties.GetObjectProp [ob, $DrcTrace] = NIL) THEN DrcDebug.dLog.PutF [format: "Failed to check rectangle at [%g, %g] %l %g%l\n", v1: IO.int [trans.off.x / lambda], v2: IO.int [trans.off.y / lambda], v3: IO.rope ["b"], v4: IO.rope [CDOps.LayerRope[ob.layer]], v5: IO.rope ["B"]] END; -- VerifyRect VerifyObjects: PROC [design: CD.Design, obj: CD.Object] ~ BEGIN drawRef: CD.DrawRef _ CD.CreateDrawRef [[design: design]]; drawRef.drawChild _ VerifyRect; obj.class.drawMe [drawRef, obj] END; -- VerifyObjects EmulateSoS: UserProfile.ProfileChangedProc ~ BEGIN religion _ UserProfile.Boolean ["Genista.EmulateSoS", FALSE] END; -- EmulateSoS Timing: UserProfile.ProfileChangedProc ~ BEGIN timing _ UserProfile.Boolean ["Genista.Timing", FALSE] END; -- Timing RedoDrc: Commander.CommandProc ~ BEGIN fileName: ROPE ~ CommandTool.NextArgument [cmd]; usedRules: ATOM; IF fileName.IsEmpty THEN RETURN [$Failure, "Please specify a full path file name, such as []<>Temp>DRC>PreGenista>designName"]; lastCore _ CoreIO.RestoreCellType [fileName]; IF (lastCore = NIL) THEN RETURN [$Failure, "There is no Core data structure with this name (specify a full name, like []<>Temp>DRC>PreGenista>designName)"]; usedRules _ NARROW [CoreProperties.GetProp [lastCore.properties, ruleKey], ATOM]; IF (usedRules = NIL) THEN RETURN [$Failure, "The Core data structure does not specify a design rule set."]; BEGIN violations: CARDINAL _ 0; rules: DesignRules.Rules _ DesignRules.GetRuleSet [usedRules]; fakeActual: Drc.Wire ~ CoreOps.CopyWire [lastCore.public]; techD: Drc.Tech _ DrcCmosb.NewTechnology [cMosBcompleteKey, rules]; startTime: BasicTime.GMT; cDFileName: ROPE ~ NARROW [CoreProperties.GetProp [lastCore.properties, comesFromCdFile]]; IF NOT (CommandTool.NextArgument[cmd].Equal ["wells", FALSE]) THEN techD.verifyCell _ NIL; lastCore _ lastCore.class.recast [lastCore]; FOR i: NAT IN [0 .. fakeActual.size) DO givenName: ROPE ~ CoreOps.GetShortWireName [fakeActual[i]]; fakeActual[i] _ CoreOps.SetShortWireName [fakeActual[i], IF givenName.IsEmpty THEN IO.PutFR1 ["External", IO.int [i]] ELSE givenName] ENDLOOP; status.errors _ NEW [CARDINAL _ 0]; status.start _ startTime _ BasicTime.Now []; status.currentCell _ NEW [ROPE]; [] _ Drc.CheckDesignRules [cell: lastCore, external: fakeActual, tech: techD, layout: stateHandle.geom, stopFlag: NIL, lap: status.errors, currentCell: status.currentCell]; msg _ Rope.Cat ["Elapsed time for DRC: ", TimeToRope [startTime, BasicTime.Now []]]; CStitching.DumpCache []; IF NOT cDFileName.IsEmpty THEN BEGIN abort: REF BOOL _ NEW [BOOL _ FALSE]; stateHandle.design _ CDIO.ReadDesign [cDFileName]; IF (stateHandle.design # NIL) THEN BEGIN stamp: TimeStamp _ NEW [Titius]; stamp.caius _ BasicTime.Now []; EnumerateCore [lastCore, BackAnnotation, stamp, stateHandle, abort]; [] _ CDViewer.CreateViewer [design: stateHandle.design] END END; status.errors _ NIL; status.currentCell _ NIL; END END; -- RedoDrc Hack: PROC ~ BEGIN CDCommandOps.RegisterWithMenu [menu: $DRCMenu, entry: "Small input DRC (Genista)", key: $DrcSel, proc: Execute, queue: doQueue]; CDCommandOps.RegisterWithMenu [menu: $DRCMenu, entry: "Large input DRC (Genista)", key: $DrcSelVia, proc: Execute, queue: doQueue]; CDCommandOps.RegisterWithMenu [menu: $DRCMenu, entry: "Minimal DRC (Genista)", key: $DrcSelMinimal, proc: Execute, queue: doQueue]; CDCommandOps.RegisterWithMenu [menu: $DRCMenu, entry: "List violations (Genista)", key: $DrcAll, proc: ListAll, queue: doQueue]; CDCommandOps.RegisterWithMenu [menu: $DRCMenu, entry: "Violation count (Genista)", key: $DrcDir, proc: List, queue: doQueue]; CDCommandOps.RegisterWithMenu [menu: $DRCMenu, entry: "Remove error rects (Genista)", key: $DrcRemove, proc: RemoveCdErrors, queue: doQueue] END; -- Hack StatusReport: Commander.CommandProc ~ BEGIN IF (status.errors = NIL) THEN msg _ "Drc is idle." ELSE BEGIN msg _ IO.PutFR ["Last drc started %g\nelapsed time: %g,\nworking on: %g\nproblems found so far: %g.", IO.time [status.start], IO.rope [TimeToRope [status.start, BasicTime.Now[]]], IO.rope [status.currentCell^], IO.card [status.errors^]] END END; -- StatusReport RepealDrcFlags: Commander.CommandProc ~ BEGIN IF (lastCore = NIL) THEN msg _ "There is no Core data structure" ELSE BEGIN abort: REF BOOL ~ NEW [BOOL _ FALSE]; EnumerateCore [lastCore, Repeal, NIL, , abort]; msg _ "Design rule violations stored in Core repealed" END END; -- RepealDrcFlags BuildId: PROC [pretendent, alternative, ifAllFails: ROPE] RETURNS [id: ROPE] ~ BEGIN ifAllFails _ IO.GetID [IO.RIS [ifAllFails] ! RuntimeError.UNCAUGHT => {ifAllFails _ "Foo"; CONTINUE}]; alternative _ IO.GetID [IO.RIS [alternative] ! RuntimeError.UNCAUGHT => {alternative _ ifAllFails; CONTINUE}]; id _ IO.GetID [IO.RIS [pretendent] ! RuntimeError.UNCAUGHT => {id _ IO.GetID [IO.RIS [UserCredentials.Get[].name]].Cat ["-", alternative]; CONTINUE}] END; -- BuildId TimeToRope: PROC [from, to: BasicTime.GMT] RETURNS [time: ROPE] ~ BEGIN TwoPosInt: PROC [i: INT] RETURNS [ROPE] ~ BEGIN RETURN [SELECT i FROM = 0 => "00", < 10 => Rope.Cat ["0", IO.PutFR1 [value: IO.int [i]]], ENDCASE => IO.PutFR1 [value: IO.int [i]]] END; sec: INT _ BasicTime.Period [from, to]; min: INT _ sec / 60; h: INT ~ min / 60; min _ min MOD 60; sec _ sec MOD 60; RETURN [TwoPosInt[h].Cat [":", TwoPosInt[min], ":", TwoPosInt[sec]]] END; -- TimeToRope PrintCdFileName: CoreProperties.PropPrintProc ~ BEGIN to.PutF1 [format: "Cell extracted from %g. ", value: IO.rope [NARROW[val,ROPE]]] END; -- PrintCdFileName RopeReadWrapping: CoreIO.PropReadProc ~ BEGIN RETURN [CoreIO.ReadRope [h]] END; -- RopeReadWrapping RopeWriteWrapping: CoreIO.PropWriteProc ~ BEGIN CoreIO.WriteRope [h, NARROW [value, ROPE]] END; -- RopeWriteWrapping PrintRuleKey: CoreProperties.PropPrintProc ~ BEGIN to.PutF1 [format: "Design rules: %g. ", value: IO.atom [NARROW[val,ATOM]]] END; -- PrintRuleKey AtomReadWrapping: CoreIO.PropReadProc ~ BEGIN RETURN [CoreIO.ReadAtom [h]] END; -- AtomReadWrapping AtomWriteWrapping: CoreIO.PropWriteProc ~ BEGIN CoreIO.WriteAtom [h, NARROW [value, ATOM]] END; -- AtomWriteWrapping Registrations: PROC ~ BEGIN IF NOT CDProperties.RegisterProperty [$DrcNr, $gbb] THEN DrcCmosb.FlushTechCache; [] _ CDProperties.RegisterProperty [$DrcCoreCircularity, $gbb]; CoreProperties.StoreProperties [prop: comesFromCdFile, properties: CoreProperties.Props [[CoreProperties.propPrint, NEW [CoreProperties.PropPrintProc _ PrintCdFileName]]]]; [] _ CoreIO.RegisterProperty [prop: comesFromCdFile, write: RopeWriteWrapping, read: RopeReadWrapping]; CoreProperties.StoreProperties [prop: ruleKey, properties: CoreProperties.Props [[CoreProperties.propPrint, NEW [CoreProperties.PropPrintProc _ PrintRuleKey]]]]; [] _ CoreIO.RegisterProperty [prop: ruleKey, write: AtomWriteWrapping, read: AtomReadWrapping]; CDSequencer.ImplementCommand [key: $DrcSel, proc: Execute, queue: doQueue]; CDSequencer.ImplementCommand [key: $DrcSelVia, proc: Execute, queue: doQueue]; CDSequencer.ImplementCommand [key: $DrcSelMinimal, proc: Execute, queue: doQueue]; CDSequencer.ImplementCommand [key: $DrcAll, proc: ListAll, queue: doQueue]; CDSequencer.ImplementCommand [key: $DrcDir, proc: List, queue: doQueue]; CDSequencer.ImplementCommand [key: $DrcRemove, proc: RemoveCdErrors, queue: doQueue]; Commander.Register [key: "DrcRepeal", proc: RepealDrcFlags, doc: "undoes last DRC by Genista"]; Commander.Register [key: "DrcEmpty", proc: RepealDrcFlags, doc: "undoes last DRC by Genista"]; Commander.Register [key: "DrcRedo", proc: RedoDrc, doc: "runs Genista on a Core file. Typical file names are of the form []<>Temp>DRC>PreGenista>designName"]; Commander.Register [key: "DrcCdCmosB", proc: RedoDrc, doc: "runs Genista on a Core file. Typical file names are of the form []<>Temp>DRC>PreGenista>designName"]; Commander.Register [key: "DrcStatus", proc: StatusReport, doc: "reports the current status of the drc"]; UserProfile.CallWhenProfileChanges [EmulateSoS]; UserProfile.CallWhenProfileChanges [Timing] END; -- Registrations Registrations; IF DrcDebug.debug THEN Hack; TerminalIO.PutRope ["DRC package Genista installed.\n"]; IF UserProfile.Boolean ["Genista.RegressionTest", FALSE] THEN RegressionTest END. From: Barth.pa Subject: Bad Guy To: Beretta Reply-To: Barth Extract.df has an interface, ExtractOps, which has a routine, IsSchematic which given an object decides if it is a schematic cell. The current heuristic is fairly stupid but please change Genista to use it so that these bad guy messages stop coming. We can improve the heuristic, e.g. by looking at the name, as people complain. You should probably emit a warning message on TerminalIO saying that the cell has not been checked. Rick DrcCommandImpl.mesa Copyright Σ 1987, 1988 by Xerox Corporation. All rights reserved. Rewritten by gbb January 12, 1987 11:53:06 am PST gbb January 22, 1988 10:18:32 am PST Jean-Marc Frailong December 7, 1987 9:28:41 pm PST Interface to ChipNDale. Called by ChipNDale upon activation of the command. Protected procedure. [] _ CDErrors.IncludeMessage [design: state.design, ob: all.first.ob, rect: CDBasics.MapRect [all.first.ob.bbox, all.first.trans], message: "Cells without extension are not allowed and not checked", owner: Drc.DRVkey]; IF notMe THEN [] _ SimpleMailer.SendMessage [from: "Genista", to: LIST ["Barth.PA"], subject: "Bad Guy", body: start.Cat [" which contains a cell named ", extendedName, ". This time I did not cut the wires on his backplane and I even checked his cell because Don was completely pissed off by having to rename cells before he can run a DRC on them. If you do not agree see Don Curry."]] If the user does a full check, it is likely he is doing a set af many small cells, so do not bother saving them. Do it only if new errors are found. You might object with that and are welcome to change it. Enumerates the cell and does action on each subcell. If session = NIL a cell is visited only once, otherwise it is visited on every instance. [cell: Drc.CoreCell, data: REF ANY _ NIL] Annotates the ChipNDale design with the design rule violations. [cell: Drc.CoreCell, data: REF ANY _ NIL] Asserts that correct cells are not flagged for violations [cell: Drc.CoreCell, data: REF ANY _ NIL] Asserts that correct cells are not flagged for violations [cell: Drc.CoreCell, data: REF ANY _ NIL] Called by ChipNDale upon activation of the command. Called by ChipNDale upon activation of the command. [cell: Drc.CoreCell, data: REF ANY _ NIL] Called by ChipNDale upon activation of the command. Protected procedure. Makes a DRC run over the test file to assess the correctness of the implementation. The test file is not ready as yet. [pr: CD.DrawRef, ob: CD.Object, trans: CD.Transformation_[], readOnlyInstProps: CD.PropList_NIL] Traverses the cell and reports undiscovered rectangles. [cmd: Commander.Handle] RETURNS [result: REF ANY _ NIL, msg: ROPE _ NIL] Having a menu entry is a privilege that is not easily received. CDSequencer.ImplementCommand [key: $GismoVFSel, proc: Execute, queue: doQueue]; CDSequencer.ImplementCommand [key: $WellContactsCheck, proc: List, queue: doQueue]; CDSequencer.ImplementCommand [key: $GismoDIWSel, proc: ListAll, queue: doQueue]; TerminalIO.PutRope ["Genista: DRC via ViaFlatness; errors via DiffInWell. Do not Install Gismos !\n"] [cmd: Commander.Handle] RETURNS [result: REF ANY _ NIL, msg: ROPE _ NIL] [cmd: Commander.Handle] RETURNS [result: REF ANY _ NIL, msg: ROPE _ NIL] Build an old fashioned hansome name. Although the INT returned BasicTime.Period is the same as GMT and might hence be loopholed to use IO.time from Conversions, the latter uses BasicTime.Unpack which allows only values that give a valid date. gbb May 1, 1987 4:26:11 pm PDT Added check of cell name convention and automatic notification to Rick Barth of trepassers. changes to: DIRECTORY, IMPORTS, ~, ExtractAndCheck (local of Execute), coreCell (local of ExtractAndCheck, local of Execute), RedoDrc, PrintCdFileName, Registrations gbb May 13, 1987 4:35:30 pm PDT Optimized back-annotation and error queries. Key to used design rules is now stored into Core data structure and retrieved from there by the Redo command. changes to: DIRECTORY, ~, ExtractAndCheck (local of Execute), coreCell (local of ExtractAndCheck, local of Execute), EnumerateCore, BackAnnotation, ListDRV (local of ListAll), RegressionTest, coreCell (local of RegressionTest), RedoDrc, RepealDrcFlags, PrintRuleKey, AtomReadWrapping, AtomWriteWrapping, Registrations gbb May 21, 1987 4:23:31 pm PDT Catching all uncaught signals and reporting them in a user-friendlier way,i.e., byting the implementor instead of the user. changes to: DIRECTORY, IMPORTS, ~, Execute gbb May 27, 1987 11:57:42 am PDT Uses raw exrtract in all cases except minimal DRC. changes to: DIRECTORY, IMPORTS, ExtractAndCheck (local of Execute) gbb September 18, 1987 5:40:33 pm PDT Added procedure to remove ChipNDale error rectangles from selected cells changes to: RemoveCdErrors, List, Hack, Registrations gbb October 26, 1987 1:44:30 pm PST Date: 26 Oct 87 10:45:41 PST changes to: ~, ExtractAndCheck (local of Execute), DIRECTORY, IMPORTS, Reply, Rick gbb January 20, 1988 6:54:04 pm PST Annotate back all violations in the same cell. changes to: ~, coreCell (local of ExtractAndCheck, local of Execute), BackAnnotation Κ˜šœ™JšœB™BIcode™1K™$K™2K˜—Icode2šΟl™šΟk ˜ Kšœ žœ˜Kšœ žœžœ˜#Kšžœžœg˜oKšœ žœ˜!Kšœ žœ$˜6Kšœ žœ˜ Kšœ žœ"˜0Kšžœžœ˜Kšœžœ˜*Kšœ žœA˜SKšœ žœ+˜˜>Kšœžœž˜-Kšžœ˜—Kšœžœ˜Kšžœžœ )˜9Kšžœ ˜——Jšž˜—Kšžœ ˜—Mš œ)žœžœ žœ”žœ)˜ŠKšœ˜Kšœ/˜/Kšœ?˜?Kšœ#˜#šž˜šœ ž˜KšœT˜TKšž˜—šœžœž˜Kšœžœ˜ Kš œžœžœžœžœ˜KšœLžœ˜QKšœLžœ˜RKšœ˜Kšœ>˜>Kšžœžœ5žœ-˜sKšžœž˜ Kšž˜——Lšžœ  ˜—Lš œ žœžœžœžœžœ˜@š‘ œžœBžœžœžœ žœžœž˜Kšœ@ΟmœM™Žšžœ žœžœž˜KšœžœC˜^šžœ žœžœ!ž˜:KšœO˜O—KšžœΠbk˜ Kšžœ˜—šžœ ž˜šœž˜$Kšœ'žœ ˜:šžœžœžœž˜'Kšžœ žœžœžœ˜ KšœM˜MKšžœ˜—Kšœ˜Kšžœ˜—Kšžœž˜—Kšžœ ˜—š‘œ ž˜ Kšœžœžœžœ™)K™?Kšœžœ˜Kšœžœ4˜>Kšœ žœžœ8˜Mšžœžœž˜KšœN˜N—šžœžœž˜š žœžœžœ$žœžœž˜Bšžœž˜KšœΊ˜Ί—šž˜KšœŽ˜Ž—Jšž˜——Kšžœ ˜—š‘œ ž˜ Kšœžœžœžœ™)K™9Kšœžœ˜Kšœžœ4˜>šžœ9žœžœž˜JKšœ^˜^Kšœžœ.žœ ˜VKšž˜—Kšžœ ˜—š‘œ ž˜"Kšœžœžœžœ™)K™9Kšœžœ˜Kšœžœ4˜>Kšœ žœžœ8˜Mš žœžœžœžœž˜,Kšœ žœžœ.˜HKšœžœ1žœ˜@Kšžœžœ0žœ1žœ˜…Kšžœ9žœ1žœ˜†Kšž˜—Kšžœ ˜—š‘œ ž˜Kšœžœžœžœ™)KšœD˜DKšœF˜FKšžœ  ˜—š‘œžœž˜8K™3JšœR˜Rš žœžœ7žœžœž˜Tšžœž˜KšœR˜R—Jšž˜—Kšžœ ˜—š‘œžœž˜.K™3Kšœ žœžœžœ4˜UKšžœžœžœ<˜VKšžœMžœ˜gKšžœ ˜ —š‘œ ž˜Kšœžœžœžœ™)Kšœ žœžœ8˜Mšžœžœžœž˜Kšœ žœ"˜0Kšœžœ žœžœ˜3Kšœ0žœžœ˜Xš žœžœžœ$žœžœž˜BJš œ3žœžœžœžœžœ˜­Jšž˜—Jšž˜—Kšžœ  ˜—š‘œžœž˜1K™3KšœžœA˜`Lš œžœžœžœžœžœ˜%Kšœžœ ˜ š‘œžœž˜1K™KšœH˜HKšžœ  ˜—Mšœ@˜@Kšœ.˜.Kšœ˜Kšžœ žœžœ(˜@Kšžœ7˜;Kšžœ  ˜—š‘œžœž˜K™vKšœžœ ˜Kš œžœžœžœžœžœ˜%Kšœžœ žœ˜5Kšœ žœ˜,Kšœ#˜#Kšœžœ˜Mšžœ žœžœžœ˜-Kšœ2˜2Kšœ.˜.Kšžœžœžœ˜2Kšœ-˜-Kšœ žœ žœžœ˜^Kšžœ žœžœžœ˜.Kšœ˜Kšœ0˜0Kšžœžœžœžœ˜+Kšœ˜šžœ-žœž˜<šœž˜Kšœžœžœ'˜DKšœžœžœ˜ KšžœBžœ|žœ*žœ˜„Kšžœ˜—Kšžœžœ˜—Kšœ˜Kšœ0˜0Kšžœžœžœžœ˜+šžœ-žœž˜<šœž˜Kšœžœžœ'˜DKšœžœžœ˜ KšœEžœw˜ΐKšœ+žœ˜=Kšžœ˜—Kšžœžœ˜—Kšœžœžœ˜.šž˜šœž˜Kšœ\˜\Kšž˜——Kšžœ ˜—š‘ œžœ ž˜Kš œžœžœžœ'žœ žœ™aKšœžœ  >˜[Kšœžœ&˜0š žœžœžœ/žœž˜|Kš œSžœ!žœ!žœžœ'žœ ˜γ—Kšžœ  ˜—š ‘ œžœ žœžœ ž˜?K™7Kšœ žœ žœ"˜:Kšœ˜Jšœ˜Kšžœ  ˜—š‘ œ#ž˜2Lšœ6žœ˜˜>Kšœ:˜:KšœC˜CKšœžœ˜Kšœ žœžœA˜Zšžœžœ0žœž˜BKšœžœ˜—Kšœ,˜,šžœžœžœž˜'Kšœ žœ,˜;Kš œ9žœžœžœžœ žœ ˜…Kšžœ˜—Kšœžœžœ3˜PKšœžœžœ˜ Kšœ ’œYžœ7˜¬KšœT˜TKšœ˜šžœžœžœž˜$Lš œžœžœžœžœžœ˜%Kšœžœ˜2šžœžœžœž˜(Kšœžœ ˜ Kšœ˜KšœD˜DKšœ7˜7Kšž˜—Kšžœ˜—Kšœžœžœ˜.Kšž˜—Kšžœ  ˜—š‘œžœž˜Kšœ?™?Kšœ€˜€Kšœƒ˜ƒKšœƒ˜ƒKšœ€˜€Kšœ}˜}KšœŒ˜ŒLšœO™OKšœS™SKšœP™PKšœe™eLšžœ ˜ —š‘ œž˜+Kš œžœ žœžœžœžœžœ™HKšžœžœžœ˜2šžœž˜ Kš œžœ^žœžœ4žœžœ˜μKšž˜—Kšžœ ˜—š‘œž˜-KšΠck=ž₯™HKšžœ žœžœ(˜@šžœž˜ Kš œžœžœžœžœžœ˜%Kšœ!žœ ˜/Kšœ6˜6Kšž˜—Kšžœ ˜—š ‘œžœ'žœžœžœž˜TKš $™$Kš œ žœžœžœžœžœ˜fKš œžœžœžœžœžœ˜nKšœžœžœžœžœ žœžœžœ7žœ˜•Kšžœ ˜—š ‘ œžœžœžœžœž˜GKšœ Πekœ Οeœ¦œ%¦§œ§ œ§œ1™Νš ‘ œžœžœžœžœž˜/Kšžœžœžœ%žœžœ žœžœžœ ˜ƒKšžœ˜—Kšœžœ˜'Kšœžœžœ ˜'Kšœ žœžœ˜#Kšžœ>˜DKšžœ  ˜—š‘œ!ž˜5Kšœ5žœžœžœ˜PKšžœ ˜—š‘œž˜-Kšžœ˜Kšžœ ˜—š‘œž˜/Kšœžœ žœ˜*Kšžœ ˜—š‘ œ!ž˜2Kšœ/žœžœžœ˜JKšžœ ˜—š‘œž˜-Kšžœ˜Kšžœ ˜—š‘œž˜/Kšœžœ žœ˜*Kšžœ ˜—š‘ œžœž˜Kšžœžœ.žœ˜QKšœ?˜?Mšœtžœ5˜¬Kšœg˜gMšœlžœ2˜‘Kšœ_˜_MšœK˜KKšœN˜NKšœR˜RKšœK˜KKšœH˜HKšœU˜UMšœ_˜_Kšœ^˜^Kšœž˜žKšœ‘˜‘Mšœh˜hMšœ0˜0Kšœ+˜+Kšžœ ˜—Lšœ˜Kšžœžœ˜Lšœ8˜8Lšžœ0žœžœ˜L—Lšžœ˜™K™[Kšœ Οr&œ¨ œ-¨)™₯—™K™,Kšœ`§œ ™mKš œ ¨œ¨ œ-¨(œ¨œ¨[™½—™K™{Kšœ ¨™*—™ K™2Kšœ ¨#œ™B—™%K™HKšœ ¨)™5—™#KšΠbsœ™Jš©œ ˜Jš©œ ˜Jš©œ ˜ Jš©œ˜Ibodyšœ―˜―J˜Kšœ ¨œ¨!™R—™#K™.Kšœ ¨ œ-¨™T——…—lφš