<> <> <> <> <<>> <<>> DIRECTORY CoreCreate, CoreProperties, IO, Logic, LogicUtils, Ports, Random, Rope, Rosemary, SloIODevice, TerminalIO; <<>> SloIODeviceImpl: CEDAR PROGRAM IMPORTS CoreCreate, IO, LogicUtils, Random, Rope, Rosemary, TerminalIO EXPORTS SloIODevice = BEGIN <> debugOn: BOOL _ FALSE; asynchBehaviour: BOOL _ FALSE; --Only set in simulation mode <> ENetName: CoreCreate.ROPE = Rosemary.Register[roseClassName: "EthernetController", init: ENetInit, evalSimple: ENetMaxModeSimple]; eNetVdd, eNetGnd, eNetNotS0, --DMA status bits eNetNotS1, eNetNotMX, --Maximum mode (tied low) eNetRESET, eNetCA, --82586 Channel Attention (input) eNetINT, --Interrupt IOP controller (output) eNetHOLD, --SloBus request (output) eNetHLDA, --SloBus grant (input) eNetREADY, --(=ALE) DMA transfer begin (input) eNetARDY, --Asynch ready line eNetCLK, eNetNotBHE, eNetA16, eNetA17, eNetA18, eNetA19, eNetA20, eNetA21, eNetA22, eNetA23, eNetADBus: NAT; eNetADBits: NAT _ 16; EthernetController: PUBLIC PROC RETURNS [ct: CoreCreate.CellType] = { ct _ CoreCreate.Cell[ name: ENetName, public: CoreCreate.Wires["Vdd", "Gnd", Rope.Cat["nS0", "nS1", "nMX", "RESET", "CA"], "INT", "HOLD", "HLDA", "READY", "ARDY", "CLK", "nBHE", CoreCreate.Seq["ADBus", eNetADBits]], instances: NIL ]; [] _ Rosemary.BindCellType[cellType: ct, roseClassName: ENetName]; [eNetVdd, eNetGnd, eNetCLK] _ LogicUtils.PortIndexes[ct.public, "Vdd", "Gnd", "CLK"]; [eNetNotS0, eNetNotS1, eNetNotMX, eNetRESET, eNetCA, eNetINT, eNetHOLD, eNetHLDA, eNetREADY, eNetARDY, eNetNotBHE, eNetADBus] _ LogicUtils.PortIndexes[ct.public, "nS0", "nS1", "nMX", "RESET", "CA", "INT", "HOLD", "HLDA", "READY", "ARDY", "nBHE", "ADBus"]; --Inputs LogicUtils.InitPorts[ct, l, none, "Vdd", "Gnd", "RESET", "CA", "HLDA", "READY", "nMX", "CLK"]; --Outputs LogicUtils.InitPorts[ct, l, drive, "INT", "HOLD", "nS0", "nS1", "nBHE"]; --16-bit bidirectional muxed Address/Data LogicUtils.InitPorts[ct, c, none, "ADBus"]; }; IntrptStatus: TYPE = {readReq, writeReq, seenCA, none}; ENetState: TYPE = REF ENetStateRec; ENetStateRec: TYPE = RECORD [ <<--internal flags>> intrptStatus: IntrptStatus _ none, busGranted: BOOL _ FALSE, sentAddr: BOOL _ FALSE, dataReady: BOOL _ FALSE, getData: BOOL _ FALSE, sendData: BOOL _ FALSE, dataOut: BOOL _ FALSE, dataIn: BOOL _ FALSE, processFrame: BOOL _ FALSE, resetPending: BOOL _ FALSE, dataWCycle: NAT _ 0, dataRCycle: NAT _ 0, frameClocks: NAT _ 0, tick: NAT _0, prevActivity: ATOM _ $None, <<--registers>> addrReg: CARDINAL _ 60000, dataReg: CARDINAL _ 0, val: Ports.LevelSequence ]; ENetInit: Rosemary.InitProc = { state: ENetState _ NEW[ENetStateRec]; state.prevActivity _ $None; state.val _ NEW[Ports.LevelSequenceRec[eNetADBits]]; LogicUtils.SetLS[state.val, X]; stateAny _ state; }; ENetMaxModeSimple: Rosemary.EvalProc = { <> state: ENetState _ NARROW[stateAny]; { p[eNetADBus].d _ none; { LoCLK: PROC RETURNS [lo: BOOL] = { lo _ p[eNetCLK].l = L; }; HiCLK: PROC RETURNS [hi: BOOL] = { hi _ p[eNetCLK].l = H; }; GenAddress: PROC = { p[eNetADBus].d _ drive; p[eNetADBus].c _ state.addrReg; }; GenData: PROC = { p[eNetADBus].d _ drive; p[eNetADBus].c _ state.dataReg; }; DataInCycle: PROC = { p[eNetADBus].d _ drive; state.dataReg _ p[eNetADBus].c; p[eNetADBus].d _ none; --tri-state }; DataOutCycle: PROC = { p[eNetADBus].d _ drive; p[eNetADBus].c _ state.dataReg _ 4000; p[eNetADBus].d _ none; }; AcquireSloBus: PROC = { NoteActivity[$RequestingSloBus]; IF NOT state.busGranted THEN p[eNetHOLD].l _ H; IF p[eNetHLDA].l = H THEN { state.busGranted _ TRUE; } ELSE RETURN; }; ReleaseSloBus: PROC = { NoteActivity[$ReleasingSloBus]; p[eNetHOLD].d _ drive; p[eNetHOLD].l _ L; state.busGranted _ FALSE; }; ReadTransfer: PROC = { NoteActivity[$DMARead]; SELECT TRUE FROM p[eNetREADY].l = L => { IF NOT state.sentAddr THEN { --t=t0 GenAddress[]; state.dataRCycle _ state.dataRCycle.SUCC; --t=t1 state.sentAddr _ TRUE; } ELSE RETURN; --Wait state }; p[eNetREADY].l = H => { IF state.sentAddr THEN { <<--Tri-state the bus drivers >> p[eNetADBus].d _ none; state.dataRCycle _ state.dataRCycle.SUCC; --t=t2, t3 IF state.dataRCycle=3 THEN { state.sentAddr _ FALSE; state.getData _ TRUE; --sample on t=t4 only }; }; IF state.getData THEN { IF state.dataRCycle=3 THEN { DataInCycle[]; state.getData _ FALSE; state.dataIn _ TRUE; state.dataRCycle _ state.dataRCycle.SUCC; --t=t4 }; }; }; ENDCASE => NULL; }; --ReadTransfer WriteTransfer: PROC = { NoteActivity[$DMAWrite]; SELECT TRUE FROM p[eNetREADY].l = L => { IF NOT state.sentAddr THEN { --t=t0 GenAddress[]; state.dataWCycle _ state.dataWCycle.SUCC; --t=t1 state.sentAddr _ TRUE; }; }; p[eNetREADY].l = H => { IF state.sendData THEN { DataOutCycle[]; state.dataWCycle _ state.dataWCycle.SUCC; --t=t3 (t4 termination on HiCLK) }; IF state.sentAddr THEN { <<--Tri-state the bus drivers >> p[eNetADBus].d _ none; state.dataWCycle _ state.dataWCycle.SUCC; --t=t2 state.sentAddr _ FALSE; state.sendData _ TRUE; }; }; ENDCASE => NULL; }; --WriteTransfer CheckFrameInterrupt: PROC = { IF state.processFrame THEN RETURN ELSE SELECT Random.ChooseInt[rs: rs, min: 1, max: 6] FROM 1, 3, 5 => state.processFrame _ TRUE; --set false during LoCLK ENDCASE => NULL; }; WatchDogTiming: PROC [forTicks: NAT _ 0] RETURNS [watching: BOOL _ FALSE] = { IF state.tick=forTicks+1 THEN RETURN ELSE { state.tick _ state.tick.SUCC; watching _ TRUE; }; }; ResetWatchDog: PROC = { state.tick _ 0; }; NoteActivity: PROC [activity: ATOM] = { IF NOT debugOn THEN RETURN; IF activity#state.prevActivity THEN { TerminalIO.WriteF1["\nENC: %g", IO.atom[activity]]; state.prevActivity _ activity; } ELSE RETURN; }; ResetENetController: PROC = { <<-- Reset ports -->> p[eNetCA].d _ drive; p[eNetCA].l _ L; p[eNetINT].d _ drive; p[eNetINT].l _ L; <<-- Reset flags -->> state.intrptStatus _ none; state.busGranted _ FALSE; state.sentAddr _ FALSE; state.dataReady _ FALSE; state.getData _ FALSE; state.sendData _ FALSE; state.dataOut _ FALSE; state.dataIn _ FALSE; state.processFrame _ FALSE; state.resetPending _ FALSE; state.dataWCycle _ 0; state.dataRCycle _ 0; state.frameClocks _ 0; state.tick _ 0; state.dataReg _ 0; NoteActivity[$NowReset]; }; <> IF LoCLK[] THEN { <> SELECT TRUE FROM p[eNetRESET].l = H AND NOT state.resetPending => { IF NOT WatchDogTiming[forTicks: 4] THEN { state.resetPending _ TRUE; ResetWatchDog[]; }; }; state.resetPending => { NoteActivity[$ResetPending]; IF NOT WatchDogTiming[forTicks: 6] THEN { ResetENetController[]; } ELSE IF state.processFrame THEN state.resetPending _ FALSE; }; state.processFrame => { -- from the 82586 RU NoteActivity[$FrameProcessing]; p[eNetINT].d _ drive; p[eNetINT].l _ H; IF state.frameClocks < 173+4 THEN { IF NOT state.busGranted THEN AcquireSloBus[]; <<*** Intel 80586: 66/173 cycles are unused for read/write altho' bus is held>> WriteTransfer[]; --frame state.frameClocks _ state.frameClocks.SUCC; } ELSE { ReleaseSloBus[]; state.getData _ state.dataIn _ state.processFrame _ FALSE; state.dataRCycle _ state.frameClocks _ 0; }; }; p[eNetCA].l = H => {-- generates DMA Read request <> IF NOT WatchDogTiming[forTicks: 1] THEN { state.intrptStatus _ readReq; p[eNetCA].d _ drive; p[eNetCA].l _ L; --override IOP signal p[eNetINT].l _ L; --protocol requires this ResetWatchDog[]; }; }; state.intrptStatus=readReq => { SELECT TRUE FROM NOT state.busGranted => AcquireSloBus[]; state.dataIn => { ReleaseSloBus[]; --drops HOLD state.intrptStatus _ none; state.getData _ state.dataIn _ FALSE; state.dataRCycle _ 0; }; ENDCASE => ReadTransfer[]; }; state.intrptStatus=writeReq => { p[eNetINT].d _ drive; p[eNetINT].l _ H; SELECT TRUE FROM NOT state.busGranted => AcquireSloBus[]; state.dataOut => { ReleaseSloBus[]; state.intrptStatus _ none; state.dataOut _ FALSE; state.dataWCycle _ 0; }; ENDCASE => WriteTransfer[]; }; ENDCASE => NULL; }; --end of LoCLK branch IF HiCLK[] THEN { IF p[eNetREADY].l = H AND state.sendData AND state.dataWCycle = 3 THEN { state.dataOut _ TRUE; state.sendData _ FALSE; --terminates on first half of t4 }; IF asynchBehaviour THEN CheckFrameInterrupt[]; --sets flag }; --end of HiCLK branch }}}; --ENetMaxModeSimple <<>> <> HardDiskName: CoreCreate.ROPE = Rosemary.Register[roseClassName: "HardDiskController", init: HDiskInit, evalSimple: HDiskSimple]; hDiskVdd, hDiskGnd, hDiskRESET, hDiskNotCS, --Chip select hDiskINTR, --Interrupt IOP controller (output) hDiskBREQ, --SloBus request (output) hDiskBACK, --SloBus grant (input) hDiskNotREADY, --DMA transfer begin (input) hDiskNotBHE, hDiskALE, hDiskALEN, --Upper ALE hDiskNotRD, hDiskNotWR, hDiskDTNotR, --Data Tx/Rx hDiskNotDEN, --Data enable hDiskBNotW, hDiskANotS, --Asynch/synch hDiskCLK, hDiskA0, --Slave mode only (selects odd/even byte of internal regs) hDiskA1, --Slave mode (1-3; selects internal regs) hDiskA2, hDiskA3, ADBus: NAT; hDiskADBits: NAT _ 16; HardDiskController: PUBLIC PROC RETURNS [ct: CoreCreate.CellType] = { ct _ CoreCreate.Cell[ name: HardDiskName, public: CoreCreate.Wires["Vdd", "Gnd", "RESET", "nCS", "INTR", "BREQ", "BACK", "nREADY", "CLK", CoreCreate.Seq["ADBus", hDiskADBits]], instances: NIL ]; [] _ Rosemary.BindCellType[cellType: ct, roseClassName: HardDiskName]; [hDiskVdd, hDiskGnd, hDiskRESET, hDiskNotCS, hDiskINTR, hDiskBREQ, hDiskBACK, hDiskNotREADY, hDiskCLK, ADBus] _ LogicUtils.PortIndexes[ct.public, "Vdd", "Gnd", "RESET", "nCS", "INTR", "BREQ", "BACK", "nREADY", "CLK", "ADBus"]; LogicUtils.InitPorts[ct, l, none, "Vdd", "Gnd", "RESET", "nCS", "BACK", "nREADY", "CLK"]; --inputs LogicUtils.InitPorts[ct, l, drive, "INTR", "BREQ"]; --outputs LogicUtils.InitPorts[ct, c, none, "ADBus"]; --16-bit; bidirectional muxed Address/Data }; HDiskState: TYPE = REF HDiskStateRec; HDiskStateRec: TYPE = RECORD [ <<--internal flags>> intrptStatus: IntrptStatus _ none, busGranted: BOOL _ FALSE, sentAddr: BOOL _ FALSE, dataReady: BOOL _ FALSE, getData: BOOL _ FALSE, sendData: BOOL _ FALSE, dataOut: BOOL _ FALSE, dataIn: BOOL _ FALSE, processFrame: BOOL _ FALSE, resetPending: BOOL _ FALSE, dataWCycle: NAT _ 0, dataRCycle: NAT _ 0, frameClocks: NAT _ 0, tick: NAT _0, prevActivity: ATOM _ $None, <<--registers>> addrReg: CARDINAL _ 50000, dataReg: CARDINAL _ 0, val: Ports.LevelSequence ]; HDiskInit: Rosemary.InitProc = { state: HDiskState _ NEW[HDiskStateRec]; state.prevActivity _ $None; state.val _ NEW[Ports.LevelSequenceRec[hDiskADBits]]; LogicUtils.SetLS[state.val, X]; stateAny _ state; }; HDiskSimple: Rosemary.EvalProc = {{{ }}}; <<>> <<>> <<>> <> SerialCommName: CoreCreate.ROPE = Rosemary.Register[roseClassName: "SerialCommController", init: SerialCommInit, evalSimple: SerialCommSimple]; SerialCommController: PUBLIC PROC RETURNS [ct: CoreCreate.CellType] = { }; SerialCommInit: Rosemary.InitProc = { }; SerialCommSimple: Rosemary.EvalProc = {{{ }}}; <<>> <> CIOName: CoreCreate.ROPE = Rosemary.Register[roseClassName: "CounterIOUnit", init: CIOInit, evalSimple: CIOSimple]; CounterIOUnit: PUBLIC PROC RETURNS [ct: CoreCreate.CellType] = { }; CIOInit: Rosemary.InitProc = { }; CIOSimple: Rosemary.EvalProc = {{{ }}}; <<>> <> IOPName: CoreCreate.ROPE = Rosemary.Register[roseClassName: "IOPController", init: IOPInit, evalSimple: IOPSimple]; sloVdd, sloGnd, sloReset, sloInt, --Interrupt device (output) sloIntr, --Interrupt service request (input) sloHold, --SloBus request (input) sloHlda, --SloBus grant (output) sloReady, --DMA transfer begin (output) sloClk, sloADBus: NAT; sloBits: NAT _ 16; IOPController: PUBLIC PROC RETURNS [ct: CoreCreate.CellType] = { ct _ CoreCreate.Cell[ name: IOPName, public: CoreCreate.Wires["Vdd", "Gnd", "iopRESET", "iopINT", "iopINTR", "iopHOLD", "iopHLDA", "iopREADY", "iopCLK", CoreCreate.Seq["ADBUS", sloBits]], instances: NIL ]; [] _ Rosemary.BindCellType[cellType: ct, roseClassName: IOPName]; [sloVdd, sloGnd, sloReset, sloInt, sloIntr, sloHold, sloHlda, sloReady, sloClk, sloADBus] _ LogicUtils.PortIndexes[ct.public, "Vdd", "Gnd", "iopRESET", "iopINT", "iopINTR", "iopHOLD", "iopHLDA", "iopREADY", "iopCLK", "ADBUS"]; LogicUtils.InitPorts[ct, l, none, "Vdd", "Gnd", "iopINTR", "iopHOLD"]; --inputs LogicUtils.InitPorts[ct, l, force, "iopRESET", "iopINT", "iopHLDA", "iopREADY", "iopCLK"]; --outputs LogicUtils.InitPorts[ct, c, none, "ADBUS"]; --16-bit; bidirectional muxed Address/Data }; IOPState: TYPE = REF IOPStateRec; IOPStateRec: TYPE = RECORD [ <<--control tasks>> eNetTask: BOOL _ FALSE, hardDiskTask: BOOL _ FALSE, serialCommTask: BOOL _ FALSE, <<--flags>> intrptStatus: IntrptStatus _ none, busGranted: BOOL _ FALSE, addrCycle: BOOL _ FALSE, dynaRequest: BOOL _ FALSE, addrReady: BOOL _ FALSE, dataReady: BOOL _ FALSE, driveData: BOOL _ FALSE, latchData: BOOL _ FALSE, dataOut: BOOL _ FALSE, dataIn: BOOL _ FALSE, dataWCycle: NAT _ 0, dataRCycle: NAT _ 0, tick: NAT _0, prevActivity: ATOM _ $Reset, <<--registers>> iopAddrReg: CARDINAL _ 0, --generated by IO devices iopDataReg: CARDINAL _ 0, val: Ports.LevelSequence ]; IOPInit: Rosemary.InitProc = { state: IOPState _ NEW[IOPStateRec]; state.prevActivity _ $Reset; state.val _ NEW[Ports.LevelSequenceRec[sloBits]]; LogicUtils.SetLS[state.val, X]; stateAny _ state; }; IOPSimple: Rosemary.EvalProc = { state: IOPState _ NARROW[stateAny]; { p[sloADBus].d _ none; { junkAddr: CARDINAL _ 0; SloClockLo: PROC RETURNS [lo: BOOL] = { lo _ p[sloClk].l = L; }; SloClockHi: PROC RETURNS [hi: BOOL] = { hi _ p[sloClk].l = H; }; SloTiming: PROC [forTicks: NAT _ 0] RETURNS [timing: BOOL _ FALSE] = { IF state.tick=forTicks+1 THEN RETURN ELSE { state.tick _ state.tick.SUCC; timing _ TRUE; }; }; ResetSloTimer: PROC = { state.tick _ 0; }; IF SloClockHi[] THEN { --activation goes out on high; latched by device on low SELECT TRUE FROM state.eNetTask => { <> <> SELECT TRUE FROM p[sloIntr].l = H AND NOT state.addrCycle => { --initiates write transfer IF p[sloHold].l = H THEN { IF NOT SloTiming[5] THEN { --busy for 5 cycles p[sloHlda].d _ drive; --grant SloBus p[sloHlda].l _ H; p[sloADBus].d _ none; --tristate drivers state.addrCycle _ TRUE; ResetSloTimer[]; }; }; }; state.dynaRequest => { state.driveData _ TRUE; }; state.addrCycle => { IF NOT SloTiming[1] THEN { --wait 1 bus cycle <> p[sloADBus].d _ force; --enable drivers state.iopAddrReg _ p[sloADBus].c; <> p[sloReady].l _ H; state.addrCycle _ FALSE; state.latchData _ TRUE; }; }; state.latchData => { p[sloADBus].d _ force; state.iopDataReg _ p[sloADBus].c; p[sloADBus].d _ none; --tri-state ENC drivers state.latchData _ FALSE; }; state.driveData => { p[sloADBus].d _ force; p[sloADBus].c _ state.iopDataReg; p[sloADBus].d _ none; --tri-state ENC drivers state.driveData _ FALSE; }; p[sloHold].l = L => { p[sloHlda].l _ L; p[sloReady].l _ L; }; ENDCASE => NULL; }; --end of eNetTask state.hardDiskTask => { <> }; --end of hardDiskTask state.serialCommTask => { <> }; --end of sccTask ENDCASE => NULL; }; IF SloClockLo[] THEN { <> }; }}}; --IOPSimple rs: Random.RandomStream _ Random.Create[]; END.