<> <> <> <> DIRECTORY Basics, BitOps, CardTab, Core, CoreClasses, CoreCreate, CoreFlat, CoreProperties, DRam, IO, Ports, Rope, Rosemary, RosemaryUser; DRamImpl: CEDAR PROGRAM IMPORTS Basics, BitOps, CardTab, CoreClasses, CoreCreate, CoreFlat, CoreProperties, IO, Ports, Rosemary, RosemaryUser EXPORTS DRam ~ BEGIN nRAS, nCAS, nWE, Add, Data, Vdd, Gnd: NAT _ LAST[NAT]; ROPE: TYPE = Core.ROPE; Port: TYPE = Ports.Port; AddressBits: TYPE = DRam.AddressBits; AddressBit: TYPE = DRam.AddressBit; Address: TYPE = DRam.Address; DataBits: TYPE = DRam.DataBits; DataBit: TYPE = DRam.DataBit; Quad: TYPE = BitOps.BitQWord; Size: TYPE = REF SizeRec; SizeRec: TYPE = RECORD[ addressBits: AddressBits, dataBits: DataBits ]; State: TYPE = { PowerUp, Idle, InternalRefreshStart, InternalRefresh, InternalRefreshDoneRAS, InternalRefreshDoneCAS, AccessOrExternalRefresh, RamRead, RamWrite, NibbleAccess, AccessDone }; Handle: TYPE = REF HandleRec; HandleRec: TYPE = RECORD [ rowAddress: CARDINAL, columnAddress: CARDINAL, addressBits: AddressBits, dataBits: DataBits, state: State, master: CARDINAL, storage: CardTab.Ref _ NIL ]; bitsPerNibble: CARDINAL = 4; DRamError: SIGNAL [msg: Rope.ROPE] = CODE; gEnableUninitializedReads: BOOL _ FALSE; InitPortIndicies: PROC [ct: Core.CellType] = { [nRAS, nCAS, nWE, Add, Data, Vdd, Gnd] _ Ports.PortIndexes[ct.public, "nRAS", "nCAS", "nWE", "Add", "Data", "Vdd", "Gnd"]; }; Create: PUBLIC PROC [a: AddressBits, d: DataBits] RETURNS [ct: Core.CellType] = { size: Size _ NEW[SizeRec]; size.addressBits _ a; size.dataBits _ d; ct _ CoreClasses.CreateUnspecified[ public: CoreCreate.WireList[LIST["nRAS", "nCAS", "nWE", CoreCreate.Seq["Add", a], CoreCreate.Seq["Data", d], "Vdd", "Gnd"], "DRam", NIL], name: dRamName ]; [] _ Rosemary.BindCellType[cellType: ct, roseClassName: dRamName]; [] _ Ports.InitPorts[ct, b, none, "nRAS", "nCAS", "nWE"]; [] _ Ports.InitPorts[ct, c, none, "Add"]; [] _ Ports.InitPorts[ct, c, none, "Data"]; CoreProperties.PutCellTypeProp[ct, $size, size] }; SingleBitError: PUBLIC PROC [state: REF, a: Address, d: DataBit] ~ { found: BOOL; val: REF; data: CARDINAL; h: Handle _ NARROW[state]; mask: WORD _ Basics.BITSHIFT[1, h.dataBits-d-1]; IF h.dataBits> size: Size _ NARROW[CoreProperties.InheritCellTypeProp[cellType, $size]]; h: Handle _ NEW[HandleRec]; bits: INT _ BitOps.TwoToThe[2*size.addressBits]; InitPortIndicies[cellType]; h.addressBits _ size.addressBits; h.dataBits _ size.dataBits; h.state _ PowerUp; h.storage _ CardTab.Create[]; stateAny _ h; }; DRamSimple: Rosemary.EvalProc = { <<--PROC [p: Ports.Port, stateAny: REF ANY]-->> h: Handle _ NARROW[stateAny]; ctl: RECORD [r, c: BOOL] _ [p[nRAS].b, p[nCAS].b]; IF ~clockEval THEN SELECT h.state FROM PowerUp => SELECT ctl FROM [TRUE, TRUE] => h.state _ Idle; ENDCASE => NULL; Idle => SELECT ctl FROM [TRUE, TRUE] => NULL; [TRUE, FALSE] => h.state _ InternalRefreshStart; [FALSE, TRUE] => { h.rowAddress _ p[Add].c; h.state _ AccessOrExternalRefresh; }; ENDCASE => ERROR; InternalRefreshStart => SELECT ctl FROM [TRUE, FALSE] => NULL; [FALSE, FALSE] => h.state _ InternalRefresh; ENDCASE => ERROR; InternalRefresh => SELECT ctl FROM [TRUE, TRUE] => h.state _ Idle; [TRUE, FALSE] => h.state _ InternalRefreshDoneRAS; [FALSE, TRUE] => h.state _ InternalRefreshDoneCAS; [FALSE, FALSE] => NULL; ENDCASE => ERROR; InternalRefreshDoneRAS => SELECT ctl FROM [TRUE, TRUE] => h.state _ Idle; [TRUE, FALSE] => h.state _ InternalRefreshDoneRAS; ENDCASE => ERROR; InternalRefreshDoneCAS => SELECT ctl FROM [TRUE, TRUE] => h.state _ Idle; [FALSE, TRUE] => h.state _ InternalRefreshDoneCAS; ENDCASE => ERROR; AccessOrExternalRefresh => SELECT ctl FROM [TRUE, TRUE] => h.state _ Idle; [FALSE, TRUE] => h.state _ AccessOrExternalRefresh; [FALSE, FALSE] => { a: LONG CARDINAL; h.columnAddress _ p[Add].c; a _ ConstructAddress[h.rowAddress, h.columnAddress, h.addressBits]; IF ~p[nWE].b THEN { BusToMaster[h, p]; h.state _ RamWrite; } ELSE { StorageToBus[h, p, a]; p[Data].d _ drive; h.state _ RamRead; }; }; ENDCASE => ERROR; RamRead => SELECT ctl FROM [TRUE, TRUE] => {p[Data].d _ none; h.state _ Idle}; [TRUE, FALSE] => {p[Data].d _ none; h.state _ AccessDone}; [FALSE, TRUE] => {p[Data].d _ none; h.state _ NibbleAccess}; [FALSE, FALSE] => NULL; ENDCASE => ERROR; RamWrite => SELECT ctl FROM [TRUE, TRUE] => { a: LONG CARDINAL _ ConstructAddress[h.rowAddress, h.columnAddress, h.addressBits]; p[Data].d _ none; MasterToStorage[h, p, a]; h.state _ Idle }; [TRUE, FALSE] => {p[Data].d _ none; h.state _ AccessDone}; [FALSE, TRUE] => { a: LONG CARDINAL _ ConstructAddress[h.rowAddress, h.columnAddress, h.addressBits]; p[Data].d _ none; MasterToStorage[h, p, a]; h.state _ NibbleAccess }; [FALSE, FALSE] => { BusToMaster[h, p]; }; ENDCASE => ERROR; NibbleAccess => SELECT ctl FROM [TRUE, TRUE] => h.state _ Idle; [FALSE, TRUE] => h.state _ NibbleAccess; [FALSE, FALSE] => { a: LONG CARDINAL; bits: CARDINAL _ Basics.BITSHIFT[Basics.BITAND[1, h.columnAddress], 1] + Basics.BITAND[1, h.rowAddress] + 1; h.rowAddress _ Basics.BITAND[0fffeh, h.rowAddress] + Basics.BITAND[1, bits]; bits _ Basics.BITSHIFT[bits, -1]; h.columnAddress _ Basics.BITAND[0fffeh, h.columnAddress] + Basics.BITAND[1, bits]; a _ ConstructAddress[h.rowAddress, h.columnAddress, h.addressBits]; IF ~p[nWE].b THEN { BusToMaster[h, p]; h.state _ RamWrite; } ELSE { StorageToBus[h, p, a]; p[Data].d _ drive; h.state _ RamRead; }; }; ENDCASE => ERROR; AccessDone => SELECT ctl FROM [TRUE, TRUE] => h.state _ Idle; [FALSE, TRUE] => NULL; ENDCASE => ERROR; ENDCASE => ERROR; }; StorageToBus: PROC [h: Handle, p: Port, a: LONG CARDINAL] ~ { found: BOOL; val: REF; [found, val] _ CardTab.Fetch[h.storage, a]; IF found THEN p[Data].c _ NARROW[val, REF CARDINAL]^ ELSE { IF NOT gEnableUninitializedReads THEN SIGNAL DRamError [IO.PutFR["Uninitialized location %g", IO.card[a]]]; p[Data].c _ 0 }; }; BusToMaster: PROC [h: Handle, p: Port] ~ { h.master _ p[Data].c; }; MasterToStorage: PROC [h: Handle, p: Port, a: LONG CARDINAL] ~ { [] _ CardTab.Store[h.storage, a, NEW[CARDINAL _ h.master]]; }; PrintStorage: PROC [s: IO.STREAM, h: Handle] ~ { PrintIt: CardTab.EachPairAction ~ { IO.PutF[s, "Add: %x, Data: %x\n", IO.card[key], IO.card[NARROW[val, REF CARDINAL]^]]; RETURN[FALSE]; }; [] _ CardTab.Pairs[h.storage, PrintIt]; }; Init: PROC [ct: Core.CellType] = { InitPortIndicies[ct]; [] _ Ports.InitTesterDrive[wire: ct.public[nRAS], initDrive: force]; [] _ Ports.InitTesterDrive[wire: ct.public[nCAS], initDrive: force]; [] _ Ports.InitTesterDrive[wire: ct.public[nWE], initDrive: force]; [] _ Ports.InitTesterDrive[wire: ct.public[Add], initDrive: force]; [] _ Ports.InitTesterDrive[wire: ct.public[Data], initDrive: none]; [] _ Rosemary.SetFixedWire[ct.public[Vdd], H]; [] _ Rosemary.SetFixedWire[ct.public[Gnd], L]; [] _ RosemaryUser.TestProcedureViewer[name: "DRam Tester", cellType: ct, testButtons: LIST["TestDRam"], displayWires: RosemaryUser.DisplayPortLeafWires[ct], cutSet: CoreFlat.CreateCutSet[cellTypes: LIST["DRam"]]]; }; ExtractAddresses: PROC [add: LONG CARDINAL, addressBits: CARDINAL] RETURNS [rowAdd, colAdd: CARDINAL] ~ { rowAdd _ BitOps.ECFD[add, 0, addressBits, 2*addressBits]; colAdd _ BitOps.ECFD[add, addressBits, addressBits, 2*addressBits]; }; ConstructAddress: PROC [rowAdd, colAdd, addressBits: CARDINAL] RETURNS [add: LONG CARDINAL] ~ { add _ BitOps.ICID[rowAdd, 0, 0, addressBits, 2*addressBits]; add _ BitOps.ICID[colAdd, add, addressBits, addressBits, 2*addressBits]; }; TestDRam: RosemaryUser.TestProc = { --PROC [cellType: Core.CellType, p: Ports.Port, Eval: PROC]-- Reset: PROC ~ { p[Data].d _ none; p[nRAS].b _ TRUE; p[nCAS].b _ TRUE; Eval[]; }; Read: PROC [address: LONG CARDINAL, expectedData: CARDINAL] ~ { rowAdd, colAdd: CARDINAL; [rowAdd, colAdd] _ ExtractAddresses[address, addressBits]; p[Add].c _ rowAdd; p[nRAS].b _ FALSE; Eval[]; p[Add].c _ colAdd; p[nWE].b _ TRUE; p[nCAS].b _ FALSE; p[Data].c _ expectedData; p[Data].d _ expect; Eval[]; p[Data].d _ none; p[nRAS].b _ TRUE; p[nCAS].b _ TRUE; Eval[]; }; Write: PROC [address: LONG CARDINAL, data: CARDINAL] ~ { rowAdd, colAdd: CARDINAL; [rowAdd, colAdd] _ ExtractAddresses[address, addressBits]; p[Data].d _ none; p[Add].c _ rowAdd; p[nRAS].b _ FALSE; Eval[]; p[Add].c _ colAdd; p[nWE].b _ FALSE; p[nCAS].b _ FALSE; p[Data].c _ data; p[Data].d _ force; Eval[]; p[Data].d _ none; p[nRAS].b _ TRUE; p[nCAS].b _ TRUE; p[nWE].b _ TRUE; Eval[]; }; ReadNibble: PROC [address: LONG CARDINAL, expected: Quad] ~ { rowAdd, colAdd: CARDINAL; [rowAdd, colAdd] _ ExtractAddresses[address, addressBits]; p[Add].c _ rowAdd; p[nRAS].b _ FALSE; Eval[]; p[Add].c _ colAdd; p[nWE].b _ TRUE; p[Data].d _ expect; FOR i: NAT IN [0..bitsPerNibble) DO p[nCAS].b _ FALSE; p[Data].c _ expected[i]; Eval[]; p[nCAS].b _ TRUE; IF i=bitsPerNibble-1 THEN { p[nRAS].b _ TRUE; p[Data].d _ none; }; Eval[]; ENDLOOP; }; WriteNibble: PROC [address: LONG CARDINAL, data: Quad] ~ { rowAdd, colAdd: CARDINAL; [rowAdd, colAdd] _ ExtractAddresses[address, addressBits]; p[Data].d _ none; p[Add].c _ rowAdd; p[nRAS].b _ FALSE; Eval[]; p[Add].c _ colAdd; p[nWE].b _ FALSE; p[Data].d _ force; FOR i: NAT IN [0..bitsPerNibble) DO p[nCAS].b _ FALSE; p[Data].c _ data[i]; Eval[]; p[nCAS].b _ TRUE; IF i=bitsPerNibble-1 THEN { p[nRAS].b _ TRUE; p[Data].d _ none; p[nWE].b _ TRUE; }; Eval[]; ENDLOOP; }; addressBits: AddressBits _ NARROW[CoreProperties.InheritCellTypeProp[cellType, $size], Size].addressBits; InitPortIndicies[cellType]; Reset[]; Write[0, 0]; Write[1, 1]; Write[2, 2]; Write[3, 3]; WriteNibble[4, [4, 5, 6, 7]]; Read[0, 0]; Read[1, 1]; Read[2, 2]; Read[3, 3]; ReadNibble[4, [4, 5, 6, 7]]; }; dRamName: ROPE = Rosemary.Register[roseClassName: "DRam", init: DRamInit, evalSimple: DRamSimple]; RosemaryUser.RegisterTestProc["TestDRam", TestDRam]; END.