-- Copyright (C) 1984 by Xerox Corporation. All rights reserved.
-- DESDicentra.mesa, HGM, 12-Jan-84 22:47:54
DIRECTORY
Environment USING [Byte],
Inline USING [DBITXOR],
DicentraInputOutput USING [Input, IOAddress, Output, ReadHole, WriteHole],
DESFace USING [Block, Blocks, Direction, IV, Key, Mode, parityTable],
MultibusAddresses USING [desByte, desWord];
DESDicentra: MONITOR IMPORTS Inline, DicentraInputOutput EXPORTS DESFace SHARES DESFace =
BEGIN
<<
Unless you check the status bits, you have to wait "long enough" in several places.
I can't find these restrictions anyplace in the spec sheet.
There is a hint of some on pg 11 for the direct control mode.
The ones I know about are:
6 clocks after any command or set mode.
Note that the hardware does this automaticaly if you use byte accesses.
18 clocks (maybe more) for a data block to trickle through the chip.
6 clocks after writing a block before writing another block.
6 clocks after reading a block before reading the next block (assuming there is one).
This code pipelines things by writing the second block before reading the first.
Except for the 1 block case, that seems to provide the required delay.
If you tweak this code, or the microcode, and it stops working,
consider inserting some delays.
>>
BadParity: ERROR = CODE;
NotImplemented: ERROR = CODE;
desChip: DicentraInputOutput.IOAddress = MultibusAddresses.desByte;
desWord: DicentraInputOutput.IOAddress = MultibusAddresses.desWord;
Register: TYPE = MACHINE DEPENDENT {
data(0), command(1), mode(3)};
DESMP: PROCEDURE [where: Register, byte: Environment.Byte] = INLINE
BEGIN
DicentraInputOutput.Output[byte, desChip+LOOPHOLE[where, CARDINAL]];
END;
DESWriteBlock: PROCEDURE [p: LONG POINTER TO DESFace.Block] = INLINE
BEGIN
DicentraInputOutput.WriteHole[
from: p,
to: desWord+LOOPHOLE[Register[data]],
words: SIZE[DESFace.Block]];
END;
DESReadBlock: PROCEDURE [p: LONG POINTER TO DESFace.Block] = INLINE
BEGIN
DicentraInputOutput.ReadHole[
to: p,
from: desWord+LOOPHOLE[Register[data]],
words: SIZE[DESFace.Block]];
END;
ResetTheChip: PROCEDURE =
BEGIN
DESMP[command, 00H];
END;
LoadIV: PROCEDURE [ivP: LONG POINTER TO DESFace.IV, direction: DESFace.Direction] =
BEGIN
iv: LONG POINTER TO DESFace.Block = LOOPHOLE[ivP];
DESMP[command, IF direction = encrypt THEN 85H ELSE 84H];
DESWriteBlock[iv];
END;
LoadKey: PROCEDURE [keyP: LONG POINTER TO DESFace.Key, direction: DESFace.Direction] =
BEGIN
key: LONG POINTER TO DESFace.Block = LOOPHOLE[keyP];
FOR i: CARDINAL IN [0..7] DO
IF keyP[i].p # DESFace.parityTable[keyP[i].b] THEN ERROR BadParity;
ENDLOOP;
DESMP[command, IF direction = encrypt THEN 11H ELSE 12H];
DESWriteBlock[key];
END;
SetMode: PROCEDURE [mode: DESFace.Mode, direction: DESFace.Direction] =
BEGIN
byte: Environment.Byte;
SELECT direction FROM
encrypt => byte ← 18H;
decrypt => byte ← 08H;
ENDCASE => ERROR;
SELECT mode FROM
ecb => NULL;
cbc => byte ← byte + 2;
cbcCheck => byte ← byte + 2;
ENDCASE => ERROR;
DESMP[mode, byte];
END;
Crunch: PROCEDURE [from, to: DESFace.Blocks, nBlks: CARDINAL] =
BEGIN
DESMP[command, 0C0H]; -- Start
IF nBlks = 0 THEN RETURN;
DicentraInputOutput.WriteHole[
from: @from[0],
to: desWord+LOOPHOLE[Register[data]],
words: SIZE[DESFace.Block]];
from ← from + SIZE[DESFace.Block];
nBlks ← nBlks - 1;
IF nBlks = 0 THEN
BEGIN -- Read Status so hardware provides the delay
status: CARDINAL = 1;
[] ← DicentraInputOutput.Input[desChip+status];
[] ← DicentraInputOutput.Input[desChip+status];
[] ← DicentraInputOutput.Input[desChip+status];
END;
UNTIL nBlks < 4 DO -- Unroll the loop a bit
DicentraInputOutput.WriteHole[
from: @from[0],
to: desWord+LOOPHOLE[Register[data]],
words: SIZE[DESFace.Block]];
DicentraInputOutput.ReadHole[
to: @to[0],
from: desWord+LOOPHOLE[Register[data]],
words: SIZE[DESFace.Block]];
DicentraInputOutput.WriteHole[
from: @from[1],
to: desWord+LOOPHOLE[Register[data]],
words: SIZE[DESFace.Block]];
DicentraInputOutput.ReadHole[
to: @to[1],
from: desWord+LOOPHOLE[Register[data]],
words: SIZE[DESFace.Block]];
DicentraInputOutput.WriteHole[
from: @from[2],
to: desWord+LOOPHOLE[Register[data]],
words: SIZE[DESFace.Block]];
DicentraInputOutput.ReadHole[
to: @to[2],
from: desWord+LOOPHOLE[Register[data]],
words: SIZE[DESFace.Block]];
DicentraInputOutput.WriteHole[
from: @from[3],
to: desWord+LOOPHOLE[Register[data]],
words: SIZE[DESFace.Block]];
DicentraInputOutput.ReadHole[
to: @to[3],
from: desWord+LOOPHOLE[Register[data]],
words: SIZE[DESFace.Block]];
from ← from + 4*SIZE[DESFace.Block];
to ← to + 4*SIZE[DESFace.Block];
nBlks ← nBlks - 4;
ENDLOOP;
UNTIL nBlks = 0 DO
DicentraInputOutput.WriteHole[
from: @from[0],
to: desWord+LOOPHOLE[Register[data]],
words: SIZE[DESFace.Block]];
DicentraInputOutput.ReadHole[
to: @to[0],
from: desWord+LOOPHOLE[Register[data]],
words: SIZE[DESFace.Block]];
from ← from + SIZE[DESFace.Block];
to ← to + SIZE[DESFace.Block];
nBlks ← nBlks - 1;
ENDLOOP;
DicentraInputOutput.ReadHole[
to: @to[0],
from: desWord+LOOPHOLE[Register[data]],
words: SIZE[DESFace.Block]];
END;
CryptData: PUBLIC ENTRY PROCEDURE [
keyP: POINTER TO DESFace.Key, nBlks: CARDINAL, from, to: DESFace.Blocks,
direction: DESFace.Direction, mode: DESFace.Mode,
seedP: LONG POINTER TO DESFace.IV ← NIL] =
BEGIN ENABLE UNWIND => NULL;
IF mode = checksum THEN ERROR NotImplemented;
IF mode = cbcCheck AND direction = encrypt AND nBlks > 0 THEN
BEGIN
last: LONG POINTER TO DESFace.Block = @from[nBlks - 1];
FOR blk: CARDINAL IN [0..nBlks - 1) DO
XOR64[last, @from[blk], last]; ENDLOOP;
END;
ResetTheChip[];
SetMode[mode, direction];
LoadKey[keyP, direction];
IF mode = cbc OR mode = cbcCheck THEN LoadIV[seedP, direction];
Crunch[from, to, nBlks];
IF mode = cbcCheck AND direction = decrypt AND nBlks > 0 THEN
BEGIN
last: LONG POINTER TO DESFace.Block = @to[nBlks - 1];
FOR blk: CARDINAL IN [0..nBlks - 1) DO
XOR64[last, @to[blk], last]; ENDLOOP;
END
END;
Words4: TYPE = MACHINE DEPENDENT RECORD [a, b: LONG CARDINAL];
XOR64: PROCEDURE [a, b, out: LONG POINTER] = INLINE
BEGIN OPEN
aLP: LOOPHOLE[a, LONG POINTER TO Words4],
bLP: LOOPHOLE[b, LONG POINTER TO Words4],
outP: LOOPHOLE[out, LONG POINTER TO Words4];
outP.a ← Inline.DBITXOR[aLP.a, bLP.a];
outP.b ← Inline.DBITXOR[aLP.b, bLP.b];
END;
END.