INSERT[D0LANG];
NOMIDASINIT;
TITLE[kernel];

%
Modified October 3, 1979 by CT. Made bit 3 the ’Midas present’ bit in FFAULT
Modified August 1, 1979 by CT. put one-time initialization on page 15
Modified July 26, 1979 by CT. Added resetmemerrs at DoOverlay
Modified June 28, 1979 by CT.

This kernel consists of three parts:
1) A section that occupies part of pages 0 and 17, runs at task 17, and handles
all communication with Midas with the exception of Mouse halt testing
(which is done by a timer). This section refreshes the memory frequently
without using a timer.

2) A section that occupies part of page 16, runs at task 16, and handles
kernel initialization, normal memory refresh and Mouse halt testing while a program is running.

3) An initialization section on page 15 that can be wiped out at will.

The idea is that if you have a simple program, you can use the page 16 and 17 parts of
this kernel, and you will get minimal memory refresh and mouse halt testing.
If you need something more complex, you overwrite the stuff on page 16,
but in this case you must supply the code for mouse halt testing.
%
SETTASK[17];

RV[REFR,77];
*memory refresh address

*The following registers hold the volatile state of the processor on a fault:
RV[RXALU,76];
*ALU result and SALUF
RV[RXAPC,75];
*APCTask&APC
RV[RXCTASK,74];
*CTASK.NCIA
RV[RXPPB,73];
*Page,Parity,BootReason
RV[RXSTK,72];
*Stackpointer

RV[RTMP,71];
*temporary

*The following registers are used for D0-Midas communication (RTMP is also used):
RV[RWSTAT,70];
*status register
RV[RDATA,67];
*holds data

*FFault determines how faults will be treated when programs are running. If it is
*zero, all faults will be reported to Midas. If FFault is nonzero, the kernel will
*send control through location 120 when a fault occurs and PARITY # 0 (faults with
*PARITY = 0 are breakpoints).
RV[FFAULT,66];

*Registers between 360 and 365 are used by the Midas overlays. The following
*registers, used by WriteMI, are also in this range.
RV[RADDR,65];
RV[RCNT,64];
RV[RW0,63];
RV[RW1,62];



*Constants for Recv and Send
MC[RecvByte,12];
MC[RecvWord,16];
MC[SendByte,21];
MC[SendWord,25];

IMRESERVE[,7501,11];
*space for Midas overlays (7500-7527)
IMRESERVE[,7513,15];

SET[CMDisp,7420];
*8-way dispatch on Midas command
SET[RWDisp, 7440];
*4-way dispatch on state bits of RWStat


*After loading kernel.mb, Midas starts it at 7000
Start:
RTMP ← 6000c, AT[7000];
RTMP ← (RTMP) + (400C),goto[KNotify];*Notify Task 0, address 6400
KNotify:
APC&APCTASK ← RTMP;
Kn1:
RETURN;

SETTASK[0];
*R definitions
RV[R0,0];
RV[R1,1];
RV[R2,2];
RV[R3,3];
RV[R4,4];
RV[R5,5];
RV[R6,6];
RV[R7,7];
RV[R10,10];
RV[R11,11];
RV[R12,12];
RV[R13,13];
RV[R14,14];
RV[R15,15];
RV[R16,16];
RV[R17,17];


*Clear R0-R17 to avoid R parity errors later
R1 ← 0c, AT[6400];
R2 ← 0c;
R3 ← 0c;
R4 ← 0c;
R5 ← 0c;
R6 ← 0c;
R7 ← 0c;
R10 ← 0c;
R11 ← 0c;
R12 ← 0c;
R13 ← 0c;
R14 ← 0c;
R15 ← 0c;
R16 ← 0c;
R17 ← 0c;
*Clear R20-R377 using Stkp
R0 ← 20c;
RClear:
Stkp ← R0;
Stack ← 0c;
lu ← (R0) xor (377c);
R0 ← (R0) + 1, goto[RClear,ALU#0];
R0 ← 5c;*Notify task 17, location 6405
R0 ← (R0) + (176400c);
APC&APCTASK ← R0;
p15ret:
return;

SETTASK[17];

RTMP ← (400C), AT[6405];*set Printer idle, don’t drive bus
Printer ← RTMP;

RTMP ← (100000C);
ClrTimers:
LOADTIMER[RTMP];*Clear out all Timers
RESETMEMERRS;*Clear any pending memory errors
*NOTE: FFAULT[2] DISABLES H4PARITY ERRORS IN THE NORMAL (non-diagnostic) FAULT HANDLER
FFAULT ← 30000c;*Initialize so that Midas takes faults, indicate midas is present
RTMP ← (RTMP) + 1;
LU ← (RTMP) AND (17C);*there are 16d timers
REFR ← (0C), DBLGOTO[InitDone, ClrTimers, ALU=0];
InitDone:
LU ← TIMER;*Set up the Refresh timer
RTMP ← (50000C);
RTMP ← (RTMP) OR (277C);*simple timer,value 11d,slot 17b
LoadTimer[RTMP];

*Notify task 16, address 7010 to set up timer task
RTMP ← (167000C);
RTMP ← (RTMP) OR (10C);
APC&APCTask ← RTMP, goto[p15ret];

Call[TimerInitDone], AT[7010]; *Set TPC[16] to TimerTask

*The simple timer task assumes slot 17 expired, since all others were cleared.
TimerTask:
Refresh[REFR];
lu ← Timer;*read timer to clear the wakeup
REFR ← (REFR) + (20c);
RTMP ← (50000C);*build timer constant
RTMP ← (RTMP) OR (277C);*simple timer,value 11d,slot 17b
AddToTimer[RTMP];
CheckStop:
T ← Printer;
RTMP ← T;
LU ← (RTMP) AND (10000C) ;
GOTO[MidasStop,ALU#0] ;
TimerRet:
RETURN;
MidasStop:
LU ← T, goto[MidasStop],SetFault, AT[7003]; *Midas recognizes a mouse halt as
*a task 16 breakpoint that was not set by the user. It continues from (absolute) MidasStop+1
MidasRestart:
return, AT[7004];

*return to task 17, address 7400
TimerInitDone:
RTMP ← (177400C), goto[KNotify];


*Page Zero stuff
*We put the instruction for BufferRefill here..
x377x:
gotop[x377x], at[377];*dummy instruction
loadpage[0], goto[x377x], at[0]; *Emulator buffer refill code is on page 0
T ← APCTASK&APC, AT[1];*Fault entry. Save APC first, then the other volatile regs.
RXAPC ← T, AT[100];
T ← GETRSPEC[147], AT[101];*ctask, ncia
RXCTASK ← T, AT[102];
T ← (GETRSPEC[103]) xor (377c), AT[103];*sstkp, stkp (stkp is read complemented)
RXSTK ← T, AT[104];
RTMP ← 20c, AT[105]; *Set stkp to 20 in case there was a stack overflow pending
Stkp ← RTMP, AT[106];
T ← (GETRSPEC[107]) xnor (0c), AT[107];*aluresult, saluf (both read complemented)
RXALU ← T, AT[110];
T ← GETRSPEC[157], LOADPAGE[0], AT[111]; *page, parity, bootreason
RXPPB ← T, RESETERRORS, AT[112];
*Notify Task 17, address 7505 (breakpoint communication)
RTMP ← (177400C), AT[113];
RTMP ← (RTMP) OR (105C), AT[114];
APC&APCTASK ← RTMP, AT[115];
RETURN, AT[116];
*The go overlay will send control to UserFault (120) if PARITY # 0 and FFAULT<0
UserFault:
loadpage[17], at[120]; *User may overwrite these instructions if desired
gotop[MidasFault], at[117];


*The following is the page 17 portion of the kernel. We get here
*after setting up the timer task.
RDATA ← 40000C, AT[7400];*send #100 to Midas
RWSTAT ← SendByte, CALL[Send];

NextCom:
RWSTAT ← RecvByte, CALL[Recv], AT[7404];
Dispatch[RDATA,15,3];
DISP[DoOverlay];

DoOverlay:
ResetMemErrs, GOTO[OverlayArea], AT[CMDisp,0]; *Midas overlay
OverlayArea:
return, AT[7500];*placeholder for overlay
MidasFault:
return, AT[7512];*placeholder for fault in Midas go overlay

WriteMI:

RWSTAT ← RecvWord, CALL[Recv], AT[CMDisp,2];*Write Control Store
RADDR ← T;
RWSTAT ← RecvByte, CALL[Recv];*Get Count (byte)
RCNT ← T;
WriteMILoop:
NOP;
RWSTAT ← RecvWord, CALL[Recv];*Get Data 0 (word)
RW0 ← T;
RWSTAT ← RecvWord, CALL[Recv];*Get Data 1 (word)
RW1 ← T;
RWSTAT ← RecvByte, CALL[Recv];*Get Data 2 (byte)
LU ← RW0;*T has data 2
APC&APCTASK ← RADDR;
WRITECS0&2;
LU ← RW1, AT[CMDisp,12]; *force writecs to have JA.7 = 0
APC&APCTASK ← RADDR;
WRITECS1;
RADDR ← (RADDR) + 1, AT[CMDisp,14]; *force writecs to have JA.7 = 0
RCNT ← (RCNT) -1;
GOTO[WriteMILoop, ALU#0];
GOTO[NextCom];

*Read a single R register. Midas will use an overlay to read RM 0 and RM 10 - RM 17,
*to avoid generating stack overflow.
ReadR:
RWSTAT ← RecvByte, CALL[Recv], AT[CMDisp,4];*Get Address
STKP ← RDATA;
nop;
T ← STACK;
RDATA ← T;
RWStat ← SendWord, Call[Send];
GOTO[NextCom];

*Write a single R register. Midas will use an overlay to write RM 0 and RM 10 - RM 17,
*to avoid generating stack overflow.
WriteR:
RWSTAT ← RecvByte, CALL[Recv], AT[CMDisp,6];*Get Address
STKP ← RDATA;
RWSTAT ← RecvWord, CALL[Recv];*Get (word) data
STACK ← T, GOTO[NextCom];


*SUBROUTINES Send and Receive communicate with Midas.

Send:
T ← rsh[RDATA,10], AT[7460];*get msbyte (location 7460 is known to overlays)
RTMP ← T, goto[RPRT];*will get WrStrb on
Recv:
RDATA ← Zero, AT[7464];*location 7464 is known to overlays
RW:
Refresh[REFR];*Refresh the memory
RTMP ← 30c;
Dlyloop:
RTMP ← (RTMP) -1, goto[Dlyloop,R>=0];
REFR ← (REFR) + (20C);
T ← Printer; *Get Printer data
RTMP ← T;
T ← Printer; *Insist that the printer yield the same data three times.
LU ← (RTMP)-(T);
T← Printer, Goto[.+2,ALU=0];
Goto[RW];
LU ← (RTMP)-(T);
Goto[.+2,ALU=0];
Goto[RW];
T ← LDF[RTMP,0,2]; *Get strobe/ack bits
LU ← (LDF[RWSTAT,16,2]) xor (T);*Compare to desired bits
T ← RTMP, GOTO[RW,ALU#0];*if reached, clear all bits
RTMP ← 400C;
Printer ← RTMP, RTMP ← T;*restore RTMP
Dispatch[RWSTAT,13,2];*dispatch on state bits of rwstat
LU ← (RWSTAT) AND (4C), DISP[ReadStrobeOff];*setup byte/word

ReadStrobeOff:
USECTASK, GOTO[ReadMore, ALU#0], AT[RWDisp,0];*Get Another byte if word set
T ← RDATA, RETURN;
ReadMore:
RWSTAT ← RecvByte, GOTO[RW];*Go get another byte

ReadStrobeOn:
T ← RHMask[RTMP], AT[RWDisp,1];*Get Data Byte
RDATA ← (LSH[RDATA,10]) OR (T);*Merge Byte
RWSTAT ← (RWSTAT) AND (4C);*State←0, Look for RDStrb off, retain byte/word
RTMP ← (100400C);*Set RdAck
RPRT:
Printer ← RTMP, GOTO[RW];


*Here on Write Ack On - state ← 3
RWSTAT ← (RWSTAT) XOR (11C), GOTO[RW], AT[RWDisp,2];

*Here on Write Ack Off
RDATA ← LSH[RDATA,10], goto[SendMore, ALU#0], AT[RWDisp,3];
lu ← Zero, goto[ReadStrobeOff]; *must do non-tasking return
SendMore:
RWSTAT ← SendByte, goto[Send];


END;