INSERT[D0LANG]; :TITLE[Kernel]; % Modified 1 May 1980 by ERF. Bum 11b mi on page 17, 2b mi on page 16, place timer task code on 16 to limit required IMReserve, add At for exit from rsr overlay, beautify, reduce overlay IMReserve. 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[17,101,11]; *space for Midas overlays (7500-7517) IMReserve[17,113,5]; 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); *Notify Task 0, address 6400 KNotify: APCTask&APC ← RTMP, GoTo[MidasRestart]; 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); APCTask&APC ← 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 H4 parity 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); APCTask&APC ← RTMP, GoTo[p15ret]; *Set TPC[16] to TimerTask and return to task 17, address 7400. RTMP ← 177400C, Call[KNotify], At[7010]; *The simple timer task assumes slot 17 expired, since all others were cleared. *At's are used on these so that KernelOccupied does not have to reserve the *initialization mi that are on page 16b. TimerTask: Refresh[REFR], At[7011]; LU ← Timer, At[7005]; *read timer to clear the wakeup *Build simple timer constant, value 11d, slot 17b RTMP ← 50000C, At[7006]; RTMP ← (RTMP) or (277C), At[7007]; AddToTimer[RTMP], At[7012]; CheckStop: T ← 10000C, At[7013]; LU ← (Printer) and T, At[7014]; REFR ← (REFR) + (20C), Skip[ALU#0], At[7001]; Return, At[7002]; *Midas recognizes a mouse halt as a task 16 breakpoint that was not set by *the user. It continues from (absolute) MidasStop+1 MidasStop: LU ← T, GoTo[MidasStop], SetFault, At[7003]; MidasRestart: Return, At[7004]; *Page Zero stuff *Emulator buffer refill code is on page 0 LoadPageExternal[0], GoToExternal[377], At[0]; T ← APCTask&APC, At[1]; *Fault entry. Save APC first, then the other volatile regs. RXAPC ← T, At[100]; *T ← (CTask&NCIA) xnor (170000C), At[101]; is better here T ← CTask&NCIA, At[101]; RXCTASK ← T, At[102]; T ← (SStkP&NStkP) xor (377C), At[103]; *(stkp is read complemented) RXSTK ← 20C, At[104]; *Set StkP to 20 in case stack ovf was pending StkP ← RXSTK, RXSTK ← T, NoRegILockOK, At[106]; T ← (ALUResult&SALUF) xnor (0C), At[107]; *(both read complemented) RXALU ← T, At[110]; T ← Page&Par&Boot, 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]; APCTask&APC ← RTMP, At[115]; Return, At[116]; *Go overlay sends 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; *Can't have Call here RWSTAT ← RecvByte, Call[Recv]; *Get Count (byte) RCNT ← T; WriteMILoop: RWSTAT ← RecvWord, Call[Recv]; *Get Data 0 (word) RW0 ← T, Call[RecvW]; *Get Data 1 (word) RW1 ← T, Call[RecvB]; *Get Data 2 (byte) LU ← RW0; *T has data 2 APCTask&APC ← RADDR; WriteCS0&2; LU ← RW1, At[CMDisp,12]; *force writecs to have JA.7 = 0 APCTask&APC ← RADDR; WriteCS1; RCNT ← (RCNT) - 1, At[CMDisp,14]; *force writecs to have JA.7 = 0 RADDR ← (RADDR) + 1, GoTo[WriteMILoop,ALU#0]; GoTo[NextCom]; *Read a single R register. Midas will use an overlay to read RM 0 and RM 17, *to avoid generating stack overflow. ReadR: RWSTAT ← RecvByte, Call[Recv], At[CMDisp,4]; *Get Address StkP ← RDATA; T ← Stack; *d0rsr overlay exits here ReadRX: RDATA ← T, At[7406]; 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, Call[RecvW]; *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 RecvB: RWSTAT ← RecvByte, Skip, At[7410]; RecvW: RWSTAT ← RecvWord, At[7411]; Recv: RDATA ← Zero, At[7464]; *location 7464 is known to overlays RW: Refresh[REFR]; *Refresh the memory RTMP ← 30C; RTMP ← (RTMP) - 1, GoTo[.,R>=0]; REFR ← (REFR) + (20C); *Get Printer data, insisting that it yield the same data three times. T ← Printer; RTMP ← T; LU ← (Printer) - T; LU ← (Printer) - T, Skip[ALU=0]; GoTo[RW]; T ← LdF[RTMP,0,2], Skip[ALU=0]; *Get strobe/ack bits GoTo[RW]; 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, NoRegILockOK; *restore RTMP Dispatch[RWSTAT,13,2]; *dispatch on state bits of rwstat LU ← (RWSTAT) and (4C), Disp[ReadStrobeOff]; *setup byte/word ReadStrobeOff: *Get Another byte if word set UseCTask, GoTo[ReadMore,ALU#0], At[RWDisp,0]; 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[Kernel];