%
****************************************************************************************
*** EDtimex.mc : Timer Exerciser microcode *** Revision 1.1 ***
*** Purpose : This test exercises timers 0 - 15d.
It replaces the page 16d portion of standard KERNEL.
*** Minimum Hardware : Standard 4 CPU boards.
*** Approximate Run Time : 6d seconds.
*** Written by : C. Thacker, Feb. 25, 1979
*** Modified by : K. Mayekawa, Feb. 28, 1980
*** Standardize title page and code format.
*** Modified by : C. Thacker, May 3, 1980
Standardized assembly with timex.cm, fixed for new d0lang.
****************************************************************************************


****************************************************************************************
*SubTest Description:
* SubTest 0: Timer Initilization (Task 14)
Clears the timers and sets up the refresh timer.

* SubTest 1: Timer Wakeup routine (Task 14)
Timer wakeups come here.
If the timer 15d expires, memory is refreshed and a new value
is added to the timer, then Mouse halt is checked.
If any of the timers 0-14d expires, it is restarted and timeout
counter for that timer is set to TimeOut.

* SubTest 2: Check Timeout routine (Task 0)
Loads the timers 0-14d, sets a timeout value for these timers
to TimeOut, then checks for timeouts.

****************************************************************************************
*BreakPoints:
* Fail : The timer was not restarted (timeout register was not set
to TimeOut) when it expired.
* Passed-EDtimex-Test: Passed all tests, and all passes.
* WrongSlotExpired : Wrong timer slot expired. Timer slots should expire from
14d to 0 sequentially.

*Note: The program also breaks at MouseHalt.

****************************************************************************************
*BreakPoint Logic Analyzer Sync Points:
* There is no short looping capability for this exerciser.

****************************************************************************************
*Loading and Reading Timers:
* Timers are loaded from the ALUA bus by functions LOADTIMER and ADDTOTIMER.
* Also they can be read as an external R source(TIMER).
* When loading or adding to timers, bits are divided as follows:
* Bits 0 - 3 : new state (loaded by both LOADTIMER and ADDTOTIMER)
* Bits 4 - 11 : new data to be loaded (by LOADTIMER) or new data to be added
* to the current data (by ADDTOTIMER)
* Bits 12 - 15 : slot number to be loaded

****************************************************************************************
*Special Reg. Definition:

* RM[20b] - RM[36b]: contains timeout values for each slot.
set to TimeOut(=40b) when timers are started initially.

Each time through the BigLoop, these timeouts are decremented.
If one of the timeouts becomes zero, a breakpoint occurs.
The maintenance panel is also incremented, so if you kill the
breakpoint at FAIL, you will see if any errors occur by noting
a nonzero panel.

Whenever a timer expires normally, it is restarted and its associated
timeout register is set to TimeOut. Thus, we should never see a zero
value in any of the timeout registers.

* InnerCount: incremented each time through the BigLoop, i.e. each time
TimeOuts for all slots 0 through 14d are decremented by one.

* MaxInnerCount: contains the maximum value for InnerCount.
When InnerCount=MaxInnerCount, the program completes one
pass, resets InnerCount, and goes back to the start of the
program if PassCount<MaxPass.

****************************************************************************************
*Subroutine Description:
* StartTimer: loads the timer whose slot is in Tslot0 and sets RM[Tslot0 + 20b]
to TimeOut(=40b).
It sets the state of the timer to 5 (Simple Timer).
Value loaded is (112d - (slot# x 4)), loading timer 14d
with the smallest value and timer 0 with the largest value.
Thus the timers should expire from slot 14d through 0 sequentially.

Slot number State loaded Value loaded TimeOut
(decimal) (decimal) stored at

14 5 56 RM[36b]
13 5 60 RM[35b]
12 5 64 RM[34b]
11 5 68 RM[33b]
10 5 72 RM[32b]
9 5 76 RM[31b]
8 5 80 RM[30b]
7 5 84 RM[27b]
6 5 88 RM[26b]
5 5 92 RM[25b]
4 5 96 RM[24b]
3 5 100 RM[23b]
2 5 104 RM[22b]
1 5 108 RM[21b]
0 5 112 RM[20b]

****************************************************************************************
%

****************************************************************************************
*INITIALIZATION:

TITLE[Timer Exerciser];

Set[TTask,16];
Set[TimerPage,2];

Set[TimerInitLoc,add[lshift[TimerPage,10],20]];
MC[TimerInitlocL,and[TimerInitLoc,377]];
MC[TimerInitLocH,add[160000,and[TimerInitLoc,177400]]]; *Notify to task 16, location TimerInitLoc
Set[TimerTable,add[lshift[TimerPage,10],100]];

MC[TimerValue,53400];
*State 5, Value 112d
MC[TimeOut,40];

********** R-Registers: **********
* Task 0 Registers
SETTASK[0];

RV[SubTest, 60];
RV[Rlink0, 61];
*subroutine return link
RV[Revision, 62, 1];
*Revision 1
RV[Run-Time, 63, 6];
*Run-Time is 6d seconds
RV[PassCount, 64, 0];
RV[MaxPass, 65, 5000];
RV[InnerCount, 66];
RV[MaxInnerCount, 67, 100];
RV[Tslot0, 70];
*slot number for timers
RV[Temp, 71];
RV[Temp1, 72];

* Task 14 Registers
SETTASK[TTask];

RV[Tslot,40];
RV[ExpectedSlot,41];
*slot number which should expire next
RV[TimerTemp,42];
*temporary register
RV[RTimer,43];
*constant for memory refresh timer
RV[REFR,44];
*refresh address

****************************************************************************************
*** MAIN routine:

*SubTest 0 (Timer Initialization)

SETTASK[TTask];
ONPAGE[TimerPage];

InitTimers: TimerTemp ← (100000C), AT[TimerInitLoc];

ClrTimers: LOADTIMER[TimerTemp];
*clear out all Timers
NOP;
*Timers can be loaded only once
NOP;
*every 7 microinstructions
NOP;
NOP;
TimerTemp ← (TimerTemp) + 1, ResetMemErrs;
*clear any pending memory errors
LU ← (TimerTemp) AND (17C);
*there are 16d timers
REFR ← (0C), DBLGOTO[InitDone, ClrTimers, ALU=0];

InitDone: LU ← TIMER;
*clear all wakeups
RTimer ← (50000C);
*set up the Refresh timer
RTimer ← (RTimer) OR (257C);
*simple timer, value 10d, slot 15d
LOADTIMER[RTimer];
ExpectedSlot ← 16c;
*insist that the timers expire in order
CALL[TimerRet];
*returns to task 0

*SubTest 1 (Timer Wakeup routine)

TimerWakeup: DISPATCH[TIMER,14,4];
*Timer wakeups come here
DISP[Timers];
*initialize base register

*Timer dispatch table for task 14 (Timers are read in complemented form.)
Timers: REFRESH[REFR], GOTO[RefreshNext], AT[TimerTable,00]; *slot 15d(used as a refresh timer)
Tslot ←T ← 16c, GOTO[RestartTimer], AT[TimerTable,01]; *slot 14d
Tslot ←T ← 15c, GOTO[RestartTimer], AT[TimerTable,02]; *slot 13d
Tslot ←T ← 14c, GOTO[RestartTimer], AT[TimerTable,03]; *slot 12d
Tslot ←T ← 13c, GOTO[RestartTimer], AT[TimerTable,04]; *slot 11d
Tslot ←T ← 12c, GOTO[RestartTimer], AT[TimerTable,05]; *slot 10d
Tslot ←T ← 11c, GOTO[RestartTimer], AT[TimerTable,06]; *slot 9d
Tslot ←T ← 10c, GOTO[RestartTimer], AT[TimerTable,07]; *slot 8d
Tslot ←T ← 7c, GOTO[RestartTimer], AT[TimerTable,10]; *slot 7d
Tslot ←T ← 6c, GOTO[RestartTimer], AT[TimerTable,11]; *slot 6d
Tslot ←T ← 5c, GOTO[RestartTimer], AT[TimerTable,12]; *slot 5d
Tslot ←T ← 4c, GOTO[RestartTimer], AT[TimerTable,13]; *slot 4d
Tslot ←T ← 3c, GOTO[RestartTimer], AT[TimerTable,14]; *slot 3d
Tslot ←T ← 2c, GOTO[RestartTimer], AT[TimerTable,15]; *slot 2d
Tslot ←T ← 1c, GOTO[RestartTimer], AT[TimerTable,16]; *slot 1d
Tslot ←T ← 0c, GOTO[RestartTimer], AT[TimerTable,17]; *slot 0d



*Refresh has been started.
RefreshNext: ADDTOTIMER[RTimer];
*load the refresh timer

*Check for Mouse halt
CheckMouse: T ← 10000C;*check for mouse halt
LU ← (PRINTER) AND (T);
DBLGOTO[MouseHalt,TimerRet,ALU#0];
TimerRet: RETURN;
*for task switching

*Mouse halt, Midas breakpoint
MouseHalt: GOTO[.], SETFAULT;
*timers cannot be restarted.

RestartTimer: LU ← (ExpectedSlot) - (T);
*insist that the slots expire in order 14..0
SKIP[ALU=0];
WrongSlotExpired: BREAKPOINT;
ExpectedSlot ← (ExpectedSlot)-1;
SKIP[ALU>=0];
*reset expectedslot if negative
ExpectedSlot ← 16c;
T ← (Tslot) OR (TimerValue);
TimerTemp ← T;
ADDTOTIMER[TimerTemp];

*Set RM[20b + Tslot] to TimeOut - if this register ever becomes zero,
*the main program will restart the timer and cause an error.
Tslot ← (Tslot) + (20c);
*Array of count words is in RM[20b]-RM[36b]
T←STKP;
Tslot ← T, STKP ← Tslot;
Tslot ← (Tslot) XOR (377C);
STACK ← TimeOut;
STKP ← Tslot, RETURN;
*restore stackpointer

*SubTest 2 (Check Timeout routine)

SETTASK[0];
ONPAGE[1];

start:
go: SubTest ← 2C;
InnerCount ← 0C;
*reset InnerCount
CLEARMPANEL, CALL[SwitchTo14];
*Notify timer initialization stuff

*come back here after timer initialization
SetTimers: SubTest ← 2C;
Tslot0 ← T ← (16C), GOTO[StartTLoop];

*switch to Task 14, InitTimers
SwitchTo14: SubTest ← 0C;
Tslot0 ← TimerInitlocL;
Tslot0 ← (Tslot0) OR (TimerInitLocH);
APC&APCTask ← TSlot0;
RETURN;

StartTLoop: CALL[StartTimer];
*start timer, set count to TimeOut
Tslot0 ← T ← (Tslot0)-1;
GOTO[BigLoop, ALU<0];
GOTO[StartTLoop];

BigLoop: Tslot0 ← T ← (16C);
MainLoop: Temp ← T;
NOP;
*make the loop longer
Temp ← (Temp) + (20c);
SubTest ← 1C, TASK;
CheckTimeout: SubTest ← 2C;
STKP ← Temp;
STACK ← (STACK) - (1C), GOTO[NoFail,R>=0];
*slot Tslot0 got restarted in time

Fail: BREAKPOINT,INCMPANEL;
GOTO[go];

NoFail: Tslot0 ← T ← (Tslot0) - (1C);
GOTO[MainLoop, ALU>=0];
InnerCount ← T ← (InnerCount) + (1C);
*increment InnerCount
LU ← (MaxInnerCount) - (T);
GOTO[OnePassFinished, ALU=0];
*finished one pass ?
GOTO[BigLoop];

OnePassFinished: PassCount ← T ← (PassCount) + (1C);
*increment PassCount
LU ← (MaxPass) - (T);
GOTO[Passed-EDtimex-Test, ALU=0];
*finished all passes ?
GOTO[go];

Passed-EDtimex-Test: PassCount ← 0C, GOTO[go], BREAKPOINT;

********** SUBROUTINE: StartTimer **********
*
* to load the timer whose slot is in Tslot0 and
* to set RM[Tslot0 + 20b] to TimeOut

StartTimer: USECTASK;
T ← APC&APCTASK;
Rlink0 ← T;

T ← Tslot0;
*Tslot0 has the slot number
Temp ← T;
Temp ← (Temp) OR (TimerValue);
T ← lsh[Tslot0,6];
Temp ← (Temp) - (T);
*subtract (slot number x 4) from TimerValue
LoadTimer[Temp];
T ← Tslot0;
Temp ←T;
Temp ← (Temp) + (20c);
STKP ← Temp;
*set count to TimeOut
STACK ← TimeOut;
Temp ← T;
*restore the slot number

APC&APCTASK ← Rlink0;
RETURN;



END;