<> <> <> <> <> <<-- ChipNDale user interface routines>> DIRECTORY Parquet, ParquetInternal, CDMenus USING [CreateEntry, GetMenu, CreateMenu, ImplementMenuCommand], StretchLines, Commander USING [CommandProc, Register], TerminalIO USING [WriteRope, WriteInt, RequestRope, UserAbort, UserSaysYes], ExprRead, CDIO USING [WriteDesign, ReadDesign, GetWorkingDirectory, SetWorkingDirectory], CDSequencer USING [Command, ImplementCommand], CD, CDOps USING [AddAnObject, CreateDesign], CDImports USING [Import, GetImport, DoImport], Rope USING [ROPE, Equal, Cat, IsEmpty], FileNames USING [CurrentWorkingDirectory], FS USING [FileInfo, ExpandName, Error], Process USING [SetPriority, priorityBackground], SymTab USING [Ref, Create, Fetch, Pairs, Store, EachPairAction]; ParquetImplB: CEDAR PROGRAM IMPORTS CD, CDMenus, ExprRead, Commander, TerminalIO, CDIO, CDOps, CDImports, Rope, CDSequencer, SymTab, FileNames, FS, Process, Parquet, ParquetInternal EXPORTS Parquet = BEGIN OPEN Parquet, ParquetInternal; generatorTable: SymTab.Ref; GeneratorRec: TYPE = RECORD [ proc: ModuleGeneratorProc, needsTiles: BOOL _ TRUE ]; markScale: INT = 2; markWidth: INT = 16; markHeight: INT = 6; arrowSize: INT = 4; <<-- Top-level command routines>> <<>> <<-- register a module generator with the tiler>> RegisterGenerator: PUBLIC PROC[generatorName: Rope.ROPE, proc: ModuleGeneratorProc, needsTiles: BOOL] RETURNS [BOOL] = BEGIN ptr: REF GeneratorRec ~ NEW[GeneratorRec _ [proc: proc, needsTiles: needsTiles]]; RETURN[SymTab.Store[generatorTable, generatorName, ptr]]; END; ProduceModule: PROC[context: Context, intoPos: CD.Position, fromFile: BOOL] RETURNS [BOOL]= BEGIN ENABLE { TerminalIO.UserAbort => GOTO abort; CD.Error => BEGIN TerminalIO.WriteRope["\nChipNDale raised an error flag: '"]; TerminalIO.WriteRope[explanation]; TerminalIO.WriteRope["'\n"]; <<-- let the system slide into the debugger>> END; ExprRead.Error => { TerminalIO.WriteRope[msg]; TerminalIO.WriteRope["'\n"]; GOTO abort; }; }; PrintGenerator: SymTab.EachPairAction = BEGIN <<-- PROC [key: Key, val: Val] RETURNS [quit: BOOL]>> TerminalIO.WriteRope[" "]; TerminalIO.WriteRope[key]; TerminalIO.WriteRope["\n"]; RETURN[FALSE]; END; generatorName: Rope.ROPE; needsTiles: BOOL; found: BOOL; generatorProc: ModuleGeneratorProc; module: Module; mod: Mod; tilesName: Rope.ROPE _ NIL; cellName: Rope.ROPE; errs: INT; IF context = NIL OR context.eventualOwner = NIL THEN ERROR; <<-- Find the name of the module generator>> IF fromFile THEN { ok: BOOL _ FALSE; badFile: BOOL _ FALSE; errorMsg: Rope.ROPE _ NIL; inFile: Rope.ROPE; <<-- get file name>> inFile _ TerminalIO.RequestRope[Rope.Cat["\nEnter name of a file describing the module (", context.workingDirectoryToUse, ") : "]]; inFile _ FS.ExpandName[inFile, context.workingDirectoryToUse].fullFName; [] _ FS.FileInfo[inFile !FS.Error => IF error.group = user THEN { badFile _ TRUE; CONTINUE }]; IF badFile THEN BEGIN TerminalIO.WriteRope[Rope.Cat["Could not open file '", inFile, "'.\n"]]; GOTO abort; END; <<-- read file>> errorMsg _ NIL; context.parameters _ ExprRead.ReadFile[inFile ! ExprRead.Error => {errorMsg _ msg; CONTINUE}]; IF errorMsg # NIL THEN { TerminalIO.WriteRope["Error while reading file: '"]; TerminalIO.WriteRope[errorMsg]; TerminalIO.WriteRope["'.\n"]; GOTO abort; }; <<-- get ModuleGenerator name>> generatorName _ ExprRead.FetchRope[context.parameters, "ModuleGenerator", TRUE ! ExprRead.Error => {errorMsg _ msg; CONTINUE}].val; IF errorMsg # NIL THEN { TerminalIO.WriteRope["Error while reading file: '"]; TerminalIO.WriteRope[errorMsg]; TerminalIO.WriteRope["'.\n"]; GOTO abort; }; IF generatorName = NIL THEN { TerminalIO.WriteRope["File does not include a 'ModuleGenerator _ xxx' line.\n"]; GOTO abort; }; } ELSE { generatorName _ TerminalIO.RequestRope["\nEnter name of a module generator: (hit return for options) "]; IF Rope.Equal[generatorName, ""] THEN BEGIN TerminalIO.WriteRope["These generators are currently running:\n"]; [] _ SymTab.Pairs[generatorTable, PrintGenerator]; TerminalIO.WriteRope[" --------\n"]; RETURN[FALSE]; END; }; <<-- Find the module generator given its name>> { ptr: REF ANY; genRef: REF GeneratorRec; [found, ptr] _ SymTab.Fetch[generatorTable, generatorName]; IF ~found THEN BEGIN TerminalIO.WriteRope["Module generator '"]; TerminalIO.WriteRope[generatorName]; TerminalIO.WriteRope["' is not currently running.\n"]; GOTO abort; END; genRef _ NARROW[ptr]; generatorProc _ genRef.proc; needsTiles _ genRef.needsTiles; }; <<-- Get the tiles, if needed>> IF needsTiles THEN { IF fromFile THEN { <<-- get TileSet import name>> errorMsg: Rope.ROPE _ NIL; IF context.tiles = NIL THEN { tilesName _ ExprRead.FetchRope[context.parameters, "TileSet", TRUE ! ExprRead.Error => {errorMsg _ msg; CONTINUE}].val; IF errorMsg # NIL THEN { TerminalIO.WriteRope["Could not read TileSet parameter: '"]; TerminalIO.WriteRope[errorMsg]; TerminalIO.WriteRope["'.\n"]; GOTO abort; }; }; IF tilesName = NIL THEN { TerminalIO.WriteRope["File does not include a 'TileSet _ xxx' line.\n"]; GOTO abort; }; } ELSE { IF context.tiles = NIL THEN { tilesName _ TerminalIO.RequestRope["\nEnter name of the imported design containing the tiles: \n(hit return for the top-level design, or type the name of an imported design) "]; }; }; <<>> <<-- Find the tile set given the name>> IF context.tiles = NIL THEN { IF Rope.IsEmpty[tilesName] THEN context.tiles _ context.eventualOwner ELSE { import: REF CDImports.Import _ CDImports.GetImport[context.eventualOwner, tilesName, $false]; IF import = NIL THEN { TerminalIO.WriteRope[Rope.Cat["Could not find imported design called '", tilesName, "'.\n"]]; GOTO abort; }; context.tiles _ import.importee; }; }; }; cellName _ TerminalIO.RequestRope["What do you want to call the resulting cell? "]; <<>> <<-->> Process.SetPriority[Process.priorityBackground]; module _ generatorProc[context]; <<-->> IF module = NIL THEN BEGIN TerminalIO.WriteRope["A NIL module was produced by the generator.\n"]; GOTO abort; END; { <<-- did we get a module back?>> err: BOOL _ FALSE; mod _ CheckValid[module ! Parquet.Error => {err _ TRUE; CONTINUE}]; IF err THEN BEGIN TerminalIO.WriteRope["An invalid module was produced by the generator!\nMaybe it returned something that was converted to a tile?\n"]; GOTO abort; END; }; IF mod.topCell = NIL THEN BEGIN TerminalIO.WriteRope["A garbaged module was returned by the generator!\n"]; GOTO abort; END; TerminalIO.WriteRope["Checking module . . . "]; errs _ CheckModule[module]; IF errs > 0 THEN BEGIN TerminalIO.WriteInt[errs]; TerminalIO.WriteRope[" ERRORS were found in the generated module, suspect areas are indicated by highlighting.\n"] END ELSE TerminalIO.WriteRope["looks OK to me.\n"]; TerminalIO.WriteRope["Creating ChipNDale cell '"]; TerminalIO.WriteRope[cellName]; TerminalIO.WriteRope["' ..."]; { ob: CD.ObPtr; ob _ ModuleIntoCell[module: module, name: cellName, applicationsPerScreenDot: 100]; IF ob = NIL THEN ERROR; CDOps.AddAnObject[context.eventualOwner, ob, intoPos]; }; RETURN[TRUE]; EXITS abort => { TerminalIO.WriteRope["Parquet exiting, no module was generated.\n"]; RETURN[FALSE]; }; END; GetWorkingDirectory: PROC [design: CD.Design] RETURNS [Rope.ROPE] = BEGIN wDir: Rope.ROPE _ CDIO.GetWorkingDirectory[design]; IF Rope.IsEmpty[wDir] THEN wDir _ FileNames.CurrentWorkingDirectory[]; RETURN[wDir]; END; RunTilerDirectly: Commander.CommandProc = BEGIN fromFile: BOOL; tilesName, designName: Rope.ROPE _ NIL; context: Context _ NEW[ContextRec]; <<-- load in the tiles>> context.workingDirectoryToUse _ FileNames.CurrentWorkingDirectory[]; tilesName _ TerminalIO.RequestRope[Rope.Cat["Enter name of file containg the tiles (", context.workingDirectoryToUse, ") : "]]; tilesName _ FS.ExpandName[tilesName, context.workingDirectoryToUse].fullFName; context.tiles _ CDIO.ReadDesign[tilesName]; CDIO.SetWorkingDirectory[context.tiles, context.workingDirectoryToUse]; IF context.tiles = NIL THEN { TerminalIO.WriteRope["Could not load the tiles.\n"]; RETURN[]; } ELSE TerminalIO.WriteRope["Tiles loaded.\n"]; <<-- create design for output>> designName _ TerminalIO.RequestRope[Rope.Cat["Enter name for output file (", context.workingDirectoryToUse, ") : "]]; context.eventualOwner _ CDOps.CreateDesign[context.tiles.technology]; CDIO.SetWorkingDirectory[context.eventualOwner, context.workingDirectoryToUse]; <<-- import the tiles>> IF ~CDImports.DoImport[context.eventualOwner, context.tiles, $true] THEN { TerminalIO.WriteRope["Could not import the tile set!\n"]; RETURN[]; }; <<-- go for it>> fromFile _ TerminalIO.UserSaysYes["From file?", "Do you want to run the module generator from a file (alternate way is to run interactively)?\n", TRUE]; IF ProduceModule[context, [0, 0], fromFile] THEN { TerminalIO.WriteRope["\nWritting ChipNDale file ...."]; IF ~CDIO.WriteDesign[context.eventualOwner, designName] THEN TerminalIO.WriteRope["\nOOPS!!! Could not write the ChipNDale file, at least I tried.\n"] ELSE TerminalIO.WriteRope["\nDone.\n"]; }; END; RunTiler: PROC [comm: CDSequencer.Command] = BEGIN fromFile: BOOL _ TerminalIO.UserSaysYes["From file?", "Do you want to run a module generator from a file (alternative is to run interactively)?\n", TRUE]; context: Context _ NEW[ContextRec]; context.workingDirectoryToUse _ GetWorkingDirectory[comm.design]; context.eventualOwner _ comm.design; [] _ ProduceModule[context, comm.pos, fromFile]; END; RunTilerFromFile: PROC [comm: CDSequencer.Command] = BEGIN context: Context _ NEW[ContextRec]; context.workingDirectoryToUse _ GetWorkingDirectory[comm.design]; context.eventualOwner _ comm.design; [] _ ProduceModule[context, comm.pos, TRUE]; END; RunTilerWithoutFile: PROC [comm: CDSequencer.Command] = BEGIN context: Context _ NEW[ContextRec]; context.workingDirectoryToUse _ GetWorkingDirectory[comm.design]; context.eventualOwner _ comm.design; [] _ ProduceModule[context, comm.pos, FALSE]; END; NoOp: Commander.CommandProc = BEGIN END; Init: PROC[] = BEGIN tilerMenu: REF _ CDMenus.GetMenu[$ModuleMenu]; generatorTable _ SymTab.Create[case: FALSE]; IF tilerMenu=NIL THEN tilerMenu _ CDMenus.CreateMenu["Module Generator Menu", $ModuleMenu]; CDMenus.ImplementMenuCommand[$ModuleMenu, tilerMenu]; CDSequencer.ImplementCommand[$RunTiler, RunTiler]; CDSequencer.ImplementCommand[$RunTilerFromFile, RunTilerFromFile]; CDSequencer.ImplementCommand[$RunTilerWithoutFile, RunTilerWithoutFile]; CDMenus.CreateEntry[menu: $ModuleMenu, entry: "Run module generator interactively", key: $RunTilerWithoutFile]; CDMenus.CreateEntry[menu: $ModuleMenu, entry: "Run module generator from file", key: $RunTilerWithoutFile]; END; <<-- Main body>> <<>> Init[]; <<-- register a command.>> Commander.Register[key: "GenerateModule", proc: RunTilerDirectly, doc: "Run a module generator"]; <<-- register a command so that we won't get ".load file failed to register command">> Commander.Register[key: "Parquet", proc: NoOp, doc: "Does nothing"]; END.