ENCTest: RosemaryUser.TestProc
= {
junkAddr: CARDINAL ← 0;
iopAddrReg: CARDINAL ← 0;
iopDataReg: CARDINAL ← 0;
CycleClock:
PROC [n:
NAT ← 1] = {
--always returns low
THROUGH [0..n)
DO
p[Clock].d ← drive;
p[Clock].l ← L;
Eval[];
p[Clock].d ← drive;
p[Clock].l ← H;
Eval[! Ports.CheckError => RESUME];
ENDLOOP;
p[Clock].d ← drive;
p[Clock].l ← L;
Eval[];
};
ClkLevel: TYPE = {hi, lo};
SetClock:
PROC [cl: ClkLevel] = {
p[Clock].d ← drive;
p[Clock].l ← SELECT TRUE FROM cl=hi=> H, ENDCASE=> L;
Eval[! Ports.CheckError => RESUME];
};
Assert:
PROC [signal:
NAT, strength: Ports.Drive ← drive, cycles:
NAT] = {
THROUGH [0..cycles)
DO
p[signal].d ← strength;
p[signal].l ← H;
SetClock[lo]; --calls Eval
p[signal].d ← strength;
p[signal].l ← H;
SetClock[hi];
ENDLOOP;
p[signal].d ← strength;
p[signal].l ← H;
SetClock[lo];
};
ResetENC:
PROC = {
Assumes clock is low on entry.
SetClock[hi];
Assert[signal: Reset, strength: drive, cycles: 4];
SetClock[hi];
p[Reset].l ← L;
SetClock[lo]; --deassert it
SetClock[hi];
CycleClock[10];
};
WriteIOP:
PROC [] = {
NoteState["Interrupt from Ethernet"];
Assert[signal: SerialDataReceived, strength: force, cycles: 1]; --returns low
ENC requests SloBus
NoteState["ENC sent interrupt to IOP"];
p[SerialDataReceived].l ← L; --expected (only in test mode)
SetClock[hi];
SetClock[lo];
p[IntrptReq].l ← H; --expected
SetClock[hi];
SetClock[lo];
p[HoldReq].l ← H; --expected
Simulate IOP busy; burn some cycles before granting SloBus
NoteState["SloBus busy (1 cycles)"];
SetClock[hi];
SetClock[lo];
NoteState["Grant SloBus"];
p[HoldAck].l ← H;
Write transfer starts here
Tri-state IOP drivers
p[ADBus].d ← none;
NoteState["IOP is addressed"];
SetClock[hi];
SetClock[lo];
p[ADBus].d ← expect;
iopAddrReg ← p[ADBus].c ← 60000;
NoteState["IOP busy (2 cycles)"];
SetClock[hi];
SetClock[lo];
SetClock[hi];
SetClock[lo];
p[Ready].l ← H;
SetClock[hi];
SetClock[lo]; --t1
p[ADBus].d ← none; --tri-state IOP drivers
ENC writes valid data out
SetClock[hi];
SetClock[lo]; --t2
NoteState["Data available from ENC"];
p[ADBus].d ← expect;
iopDataReg ← p[ADBus].c ← 4000;
p[ADBus].d ← none; --tri-state ENC drivers
SetClock[hi];
SetClock[lo]; --t3
SetClock[hi];
SetClock[lo]; --t4
Finalize DMA transfer
NoteState["Releasing SloBus"];
SetClock[hi];
SetClock[lo];
p[HoldReq].l ← L; --expected
SetClock[hi];
p[HoldAck].l ← L;
p[Ready].l ← L;
SetClock[lo];
}; --WriteIOP
ReadIOP:
PROC = {
NoteState["Interrupt Ethernet controller"];
Assert[signal: ChanAttn, strength: force, cycles: 1]; --returns low
ENC acknowledges & requests SloBus
NoteState["Request SloBus"];
SetClock[hi];
SetClock[lo];
Both of these lines deasserted by ENC
p[ChanAttn].l ← L; --expected
p[IntrptReq].l ← L; --expected
SetClock[hi];
SetClock[lo];
p[HoldReq].l ← H;
--expected
Simulate IOP busy; burn some cycles before granting SloBus
NoteState["SloBus Busy (2 cycles)"];
SetClock[hi];
CycleClock[1];
SetClock[hi];
NoteState["Grant SloBus"];
p[HoldAck].l ← H;
SetClock[lo];
Read transfer starts here
NoteState["Generate address"];
SetClock[hi];
Tri-state IOP drivers
p[ADBus].d ← none;
SetClock[lo];
Address is available
p[ADBus].d ← expect;
iopAddrReg ← p[ADBus].c ← 60000;
p[ADBus].d ← none; --tri-state
SetClock[hi];
SetClock[lo]; --t1
NoteState["Address ready"];
IOP drivers enabled
SetClock[hi];
p[ADBus].d ← force;
SetClock[lo]; --t2
NoteState["IOP data drivers enabled"];
Force wait-state insertions
NoteState["SloBus Busy (3 cycles) => ENC Wait States"];
SetClock[hi];
CycleClock[2]; --t3
SetClock[hi];
IOP puts valid data out
NoteState["Data available"];
p[ADBus].c ← iopDataReg;
p[Ready].l ← H;
SetClock[lo];
ENC samples data
NoteState["Data sampled"];
SetClock[hi];
SetClock[lo]; --t4
Finalize DMA transfer
p[HoldReq].l ← L; --expect
SetClock[hi];
p[HoldAck].l ← L;
p[Ready].l ← L; -- drop this line too
SetClock[lo];
}; -- ReadIOP
-- Initialization --
p[Vdd].l ← H;
p[Reset].l ← L;
p[ChanAttn].l ← L;
p[IntrptReq].l ← L;
p[HoldReq].l ← L;
p[HoldAck].l ← L;
p[Ready].l ← L;
p[Clock].l ← L;
p[ADBus].c ← junkAddr;
--Test commences here
IMPORTANT: Ensure that asynchBehaviour is disabled in ENetMaxModeSimple
NoteState["... START "];
CycleClock[2];
SetClock[hi];
WriteIOP[]; --returns low
SetClock[hi];
ReadIOP[]; --returns low
SetClock[hi];
NoteState["Initiate reset cycling"];
ResetENC[];
}; --ENCTest
Vdd, Gnd, Reset, ChanAttn, IntrptReq, HoldReq, HoldAck, Ready, SerialDataReceived, Clock, ADBus: NAT;
testeeName: Core.ROPE = "Ethernet Controller";
InitPorts:
PROC [public: Core.Wire] = {
Vdd ← Ports.PortIndex[wire: public, name: "Vdd"];
Gnd ← Ports.PortIndex[wire: public, name: "Gnd"];
Reset ← Ports.PortIndex[wire: public, name: "RESET"];
ChanAttn ← Ports.PortIndex[wire: public, name: "CA"];
IntrptReq ← Ports.PortIndex[wire: public, name: "INT"];
HoldReq ← Ports.PortIndex[wire: public, name: "HOLD"];
HoldAck ← Ports.PortIndex[wire: public, name: "HLDA"];
Ready ← Ports.PortIndex[wire: public, name: "READY"];
SerialDataReceived ← Ports.PortIndex[wire: public, name: "RxD"];
Clock ← Ports.PortIndex[wire: public, name: "CLK"];
ADBus ← Ports.PortIndex[wire: public, name: "ADBus"];
IOP Outputs
Ports.InitTesterDrive[wire: public[Reset], initDrive: drive];
Ports.InitTesterDrive[wire: public[HoldAck], initDrive: drive];
Ports.InitTesterDrive[wire: public[Ready], initDrive: drive];
Ports.InitTesterDrive[wire: public[Clock], initDrive: drive];
IOP BiDirectional
Ports.InitTesterDrive[wire: public[ChanAttn], initDrive: force];
Ports.InitTesterDrive[wire: public[SerialDataReceived], initDrive: force]; --fake test wire
Ports.InitTesterDrive[wire: public[ADBus], initDrive: force];
IOP Inputs
Ports.InitTesterDrive[wire: public[IntrptReq], initDrive: expect];
Ports.InitTesterDrive[wire: public[HoldReq], initDrive: expect];
};