RAMArray.rose
Last Edited by: Barth, March 14, 1985 8:22:56 pm PST
Imports BitOps, IO, Rope, RoseRun, RoseTypes, SwitchTypes;
Library Transistors;
Open SwitchTypes;
CEDAR
Drive: TYPE = REF DriveRep;
DriveRep: TYPE = RECORD [
drives: PACKED SEQUENCE length: DriveTagType OF DriveLevel];
RAMArrayIORef: TYPE = REF RAMArrayIORec;
RAMArrayIORec: TYPE = MACHINE DEPENDENT RECORD [
Vdd: SwitchVal,
Gnd: SwitchVal,
values: SEQUENCE COMPUTED CARDINAL OF SwitchVal];
BitCell: TYPE = RECORD [
state: Level,
nstate: Level];
;
RAMArray:
LAMBDA [
rows, columns: |NAT|,
pullUpStrength: |Strength ← driveWeak|,
pullDownStrength: |Strength ← drive|]
RETURN CELLTYPE NameMaker
strengthName: ARRAY Strength OF ROPE ← ["n", "cW", "c", "cS", "dW", "d", "dS", "i"];
name ← Rope.Cat[IO.PutFR["RAMArray%g%g", IO.int[rows], IO.int[columns]], strengthName[pullUpStrength], strengthName[pullDownStrength]]
PortsProc
ports ← NEW [PortsRep[2+rows+(2*columns)]];
ports[0] ← [0, 1, "Vdd", bitType, TRUE, FALSE];
ports[1] ← [1, 1, "Gnd", bitType, TRUE, FALSE];
FOR row: NAT IN [0..rows) DO
ports[2+row] ← [2+row, 1, IO.PutFR["Word%g", IO.int[row]], bitType, TRUE, FALSE];
ENDLOOP;
FOR column: NAT IN [0..columns) DO
ports[2+rows+(2*column)] ← [2+rows+(2*column), 1, IO.PutFR["Bit%g", IO.int[column]], bitType, TRUE, TRUE];
ports[2+rows+(2*column)+1] ← [2+rows+(2*column)+1, 1, IO.PutFR["nBit%g", IO.int[column]], bitType, TRUE, TRUE];
ENDLOOP;
IF pullUpStrength >= pullDownStrength THEN ERROR;
IOAux RefType RAMArrayIORef
IOAux InitialValue |NEW [RAMArrayIORec[2+rows+(2*columns)]]|
DriveAux RefType Drive
DriveAux InitialValue |NEW [DriveRep[2+rows+(2*columns)]]|
State
Invariant: oneActive AND multipleActive = FALSE
oneActive: BOOL,
multipleActive: BOOL,
activeRow: CARDINAL,
memory: PACKED SEQUENCE COMPUTED CARDINAL OF BitCell
Initializer
state: RAMArrayStateRef ← NEW [RAMArrayStateRec[rows*columns]];
cell.realCellStuff.state ← state;
FOR i:CARDINAL IN [0..rows*columns) DO
state.memory[i] ← [X, X];
ENDLOOP;
state.oneActive ← FALSE;
state.multipleActive ← TRUE;
ValsChanged
UpdateState: PROC [bitline: SwitchVal, nstate: Level, oldState: Level] RETURNS [perturb: BOOL ← FALSE, newState: Level] = {
newState ← oldState;
SELECT nstate FROM
H => IF pullDownStrength<bitline.s[u] OR bitline.val=L THEN newState ← bitline.val ELSE perturb ← TRUE;
L => IF pullUpStrength<bitline.s[d] OR bitline.val=H THEN newState ← bitline.val ELSE perturb ← TRUE;
X => IF (pullUpStrength<bitline.s[d] AND pullDownStrength<bitline.s[u]) OR bitline.val=X THEN newState ← bitline.val ELSE perturb ← TRUE;
ENDCASE => ERROR;
};
ZapRow: PROC [row:CARDINAL] = {
FOR memIndex:CARDINAL IN [(row*columns)..((row+1)*columns)) DO
memory[memIndex].state ← X;
memory[memIndex].nstate ← X;
ENDLOOP;
};
IF Vdd.val#H OR Gnd.val#L THEN ERROR;
oneActive ← multipleActive ← FALSE;
FOR row:CARDINAL IN [0..rows) DO
IF values[row].val=H OR values[row].val=X THEN {
IF oneActive THEN {
multipleActive ← TRUE;
ZapRow[row];
}
ELSE {
oneActive ← TRUE;
activeRow ← row;
};
};
ENDLOOP;
IF multipleActive THEN {
valueIndex: CARDINAL ← rows;
portIndex: CARDINAL ← valueIndex+2;
oneActive ← FALSE;
ZapRow[activeRow];
FOR col:CARDINAL IN [0..columns) DO
IF values[valueIndex].val # X THEN RoseRun.PerturbPort[cell, portIndex];
IF values[valueIndex+1].val # X THEN RoseRun.PerturbPort[cell, portIndex+1];
valueIndex ← valueIndex+2;
portIndex ← portIndex+2;
ENDLOOP;
};
IF oneActive THEN {
memIndex: CARDINAL ← activeRow*columns;
valueIndex: CARDINAL ← rows;
portIndex: CARDINAL ← valueIndex+2;
perturbBit, perturbnBit: BOOL;
FOR col:CARDINAL IN [0..columns) DO
oldState: Level ← memory[memIndex].state;
[perturbBit, memory[memIndex].state] ← UpdateState[values[valueIndex], memory[memIndex].nstate, memory[memIndex].state];
[perturbnBit, memory[memIndex].nstate] ← UpdateState[values[valueIndex+1], oldState, memory[memIndex].nstate];
IF perturbBit THEN RoseRun.PerturbPort[cell, portIndex];
IF perturbnBit THEN RoseRun.PerturbPort[cell, portIndex+1];
memIndex ← memIndex+1;
valueIndex ← valueIndex+2;
portIndex ← portIndex+2;
ENDLOOP;
};
PropQ
IF multipleActive THEN {
valueIndex: CARDINAL ← rows;
FOR col:CARDINAL IN [0..columns) DO
values[valueIndex].s[q] ← input;
values[valueIndex+1].s[q] ← input;
valueIndex ← valueIndex+2;
ENDLOOP;
};
IF oneActive THEN {
memIndex: CARDINAL ← activeRow*columns;
valueIndex: CARDINAL ← rows;
maxpupd: Strength ← MAX[pullUpStrength, pullDownStrength];
FOR col:CARDINAL IN [0..columns) DO
cell: BitCell ← memory[memIndex];
values[valueIndex].s[q] ← MAX[values[valueIndex].s[q], IF cell.nstate=H OR cell.nstate=X THEN maxpupd ELSE pullUpStrength];
values[valueIndex+1].s[q] ← MAX[values[valueIndex+1].s[q], IF cell.state=H OR cell.state=X THEN maxpupd ELSE pullUpStrength];
memIndex ← memIndex+1;
valueIndex ← valueIndex+2;
ENDLOOP;
};
PropUD
IF multipleActive THEN {
valueIndex: CARDINAL ← rows;
FOR col:CARDINAL IN [0..columns) DO
values[valueIndex].s[u] ← input;
values[valueIndex].s[d] ← input;
values[valueIndex+1].s[u] ← input;
values[valueIndex+1].s[d] ← input;
valueIndex ← valueIndex+2;
ENDLOOP;
};
IF oneActive THEN {
memIndex: CARDINAL ← activeRow*columns;
valueIndex: CARDINAL ← rows;
maxpupd: Strength ← MAX[pullUpStrength, pullDownStrength];
FOR col:CARDINAL IN [0..columns) DO
cell: BitCell ← memory[memIndex];
pu: Strength ← IF cell.state=X OR cell.nstate=X THEN pullDownStrength ELSE pullUpStrength;
values[valueIndex].s[u] ← MAX[values[valueIndex].s[u], pu];
values[valueIndex].s[d] ← MAX[values[valueIndex].s[d], IF cell.nstate=H OR cell.nstate=X THEN pullDownStrength ELSE none];
values[valueIndex+1].s[u] ← MAX[values[valueIndex+1].s[u], pu];
values[valueIndex+1].s[d] ← MAX[values[valueIndex+1].s[d], IF cell.state=H OR cell.state=X THEN pullDownStrength ELSE none];
memIndex ← memIndex+1;
valueIndex ← valueIndex+2;
ENDLOOP;
};
Test Primitive StateToo
high: SwitchTypes.SwitchVal ← [[driveStrong, driveStrong, none], H, 0];
low: SwitchTypes.SwitchVal ← [[driveStrong, none, driveStrong], L, 0];
tristate: SwitchTypes.SwitchVal ← [[none, none, none], X, 0];
select0: NAT = 0;
bit0: NAT = rows;
Access: PROC [write: BOOL, row: NAT, data: LONG CARDINAL] = {
SetColumnLines: PROC [value: SwitchTypes.SwitchVal] = {
valueIndex: CARDINAL ← bit0;
FOR col:CARDINAL IN [0..columns) DO
values[valueIndex] ← value;
values[valueIndex+1] ← value;
valueIndex ← valueIndex+2;
ENDLOOP;
};
d: BitOps.BitDWord ← BitOps.ILID[data, BitOps.BitDWordZero, 32, 0, 32];
precharge
SetColumnLines[high];
[] ← RoseRun.Eval[handle];
SetColumnLines[tristate];
[] ← RoseRun.Eval[handle];
enable select line
values[row] ← high;
if write then enable write drivers
IF write THEN {
valueIndex: CARDINAL ← bit0;
FOR col:CARDINAL IN [0..columns) DO
IF BitOps.EBFD[d, columns, col] THEN {
values[valueIndex] ← high;
values[valueIndex+1] ← low;
} ELSE {
values[valueIndex] ← low;
values[valueIndex+1] ← high;
};
valueIndex ← valueIndex+2;
ENDLOOP;
};
[] ← RoseRun.Eval[handle];
if read then check data
IF NOT write THEN {
valueIndex: CARDINAL ← bit0;
FOR col:CARDINAL IN [0..columns) DO
bitOfData: BOOL ← BitOps.EBFD[d, columns, col];
IF (bitOfData AND (values[valueIndex].val # H OR values[valueIndex+1].val # L)) OR (NOT bitOfData AND (values[valueIndex].val # L OR values[valueIndex+1].val # H)) THEN RoseTypes.Stop["Read failed", $FailedAssertion];
valueIndex ← valueIndex+2;
ENDLOOP;
};
disable select line
values[row] ← low;
if write then disable write drivers
IF write THEN SetColumnLines[tristate];
[] ← RoseRun.Eval[handle];
};
Vdd ← high;
Gnd ← low;
IF rows<2 OR columns>32 THEN RoseTypes.Stop["Too many columns in RAM for this test procedure", $FailedAssertion];
FOR row:CARDINAL IN [0..rows) DO
values[row] ← [[input, none, input], L, 0];
ENDLOOP;
[] ← RoseRun.Eval[handle];
FOR row:CARDINAL IN [0..rows) DO
IF values[row] # [[input, none, input], L, 0] THEN RoseTypes.Stop["select lines are crazy", $FailedAssertion];
ENDLOOP;
Access[write: TRUE, row: 0, data: 0];
Access[write: TRUE, row: 1, data: LAST[LONG CARDINAL]];
Access[write: FALSE, row: 0, data: 0];
Access[write: FALSE, row: 1, data: LAST[LONG CARDINAL]];
values[select0] ← high;
values[select0+1] ← high;
[] ← RoseRun.Eval[handle];
{
valueIndex: CARDINAL ← bit0;
FOR col:CARDINAL IN [0..columns) DO
IF values[valueIndex].val # X OR values[valueIndex+1].val # X THEN RoseTypes.Stop["data line is incorrect for multiple rows", $FailedAssertion];
valueIndex ← valueIndex+2;
ENDLOOP;
FOR row:CARDINAL IN [0..2) DO
FOR col:CARDINAL IN [0..columns) DO
memIndex: NAT ← row*columns+col;
IF memory[memIndex].state # X OR memory[memIndex].nstate # X THEN RoseTypes.Stop["state bit is incorrect for multiple rows", $FailedAssertion];
ENDLOOP;
ENDLOOP;
};
ENDCELLTYPE