DRamImpl.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Gasbarro August 7, 1986 10:28:32 am PDT
Last Edited by: Gasbarro May 13, 1987 9:14:07 am PDT
DIRECTORY
Basics, BitOps, CardTab, Core, CoreClasses, CoreCreate, CoreFlat, CoreProperties, DRam, IO, Ports, 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: NATLAST[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;
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<d+1 THEN ERROR;
[found, val] ← CardTab.Fetch[h.storage, a];
IF ~found THEN ERROR; --address doesn't exist
data ← NARROW[val, REF CARDINAL]^;
[] ← CardTab.Store[h.storage, a, NEW[CARDINAL ← Basics.BITXOR[data, mask]]];
};
DoubleBitError: PUBLIC PROC [state: REF, a: Address, d0, d1: DataBit] ~ {
SingleBitError[state, a, d0];
SingleBitError[state, a, d1];
};
DRamInit: Rosemary.InitProc = {
--PROC [cellType: Core.CellType, p: Ports.Port] RETURNS [stateAny: REF ANY ← NIL]--
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];
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 ERROR; --this word was read before being written
p[Data].c ← NARROW[val, REF CARDINAL]^;
};
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.