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, 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<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];
};
EnableUninitializedReads:
PUBLIC
PROC [b:
BOOL] ~ {
gEnableUninitializedReads ← b;
};
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];
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.