;modifications for MESA:
;
remove #altoconsts23.mu
;
external file must predefine MRT correctly!!!!
;
remove halftoning stuff
;
remove bcpl interface stuff
;
change R register allocation

;On each MRT, decrement the ScanWait counter
;
when =0, do a scanner start pulse, and reset counter to ITTIME
;
(if counter=0 on entry, just do a reset)
;
;
If the scanner is running, also check for input words, and smash
;
them into ScanBuffer

;REGISTERS USED BY NOVA EMULATOR
$AC0
$R3; ac’s are backwards because the hardware supplies
; the complement address when addressing from ir
$AC1
$R2;
$AC2
$R1;
$AC3
$R0;
$NWW
$R4;
$SAD
$R5;
$PC
$R6;
$XREG
$R7;
$MTEMP
$R25;
$LastL
$R40; not a real S register, but rather L gated to the bus
$ScanWait $R14;
$ScanBuffer
$R13;watch out!! this is used with the ethernet
$ScanData
$R11;watch out!! this is used with the ethernet
$StoreCount
$R12;watch out!! this is CLOCKTEMP

;available constants: 177024,25,26,34,40,42
$177024
$177024;
$177026
$177026;
;$Outport
$177016
;$SafeLoc
$177023
;$StepLoc
$177020
$420$420;417 is StepState
$ScanCBHead$736;and 737 is Startcommand
$ScanTime
$526;
$10000
$10000;
$4000
$4000;
$400
$400;
$StatusDONE$177777;
$StatusDATALATE
$177776;

;Clock (in refresh task) R11,R37
;Ethernet R12,R13
;Display controller: R20-R30
;Disk Controller: R31-R34

;Available: R5
;--------------------------------------------------------------------
; MRT: do start pulses off MRT task, for constant timing
;--------------------------------------------------------------------
;MEMORY REFRESH TASK AND MOUSE HANDLER

!17,20,TX0,TX6,TX3,TX2,TX8,TX5,TX1,TX7,TX4,,,,,,,;
!1,2,DOTIMER,NOTIMER;
!1,2,NOTIMERINT,TIMERINT;
!1,2,DOCUR,NOCUR;
!1,2,SHOWC,WAITC;
!1,2,SPCHK,NOSPCHK;

!1,2,NOCLK,CLOCK;
!1,1,MRTLAST;
!1,2,CNOTLAST,CLAST;
$CLOCKTEMP$R11;
$REFZERO $7774; REFRESH ZERO
$REFIIMSK $7777; REFRESH MASK
$R37
$R37;
$CURX
$R20;
$CURDATA
$R21;
$YPOS
$R27;

;* * * A T T E N T I O N * * *
;There are two versions of the Memory refresh code:
;
AltoIIMRT4K.mu for refreshing 4K chips
;
AltoIIMRT16K.mufor refreshing 16K chips

;first time initialization
MRT:
MAR ← ScanTime;
L←0;
ScanBuffer←L;
StoreCount←L;
L←MD;
MAR ← 420-1; initialize StepState
ScanWait←L;
MD ← StoreCount;

;On each MRT, decrement the ScanWait counter
;
when =0, do a scanner start pulse, and reset counter to ITTIME
;
(if counter=0 on entry, just do a reset)
;
;
If the scanner is running, also check for input words, and smash
;
them into ScanBuffer

!1,2,ScannerOn,ScannerOff;
!1,2,checkInput,startScan;
!1,2,haveHead,noHead;
!1,2,haveCurrent,noCurrent;
!1,2,doMouse,doWord;
MRTloop: L←ScanWait-1,BUS=0;
1
MAR←
ScanTime,:ScannerOn; !1,2,ScannerOn,ScannerOff2
ScannerOn: NOP,SH=0;
3
ScanWait←L,:checkInput;
!1,2,checkInput,startScan;4

;unless StoreCount is 0, read bytes and decrement StoreCount

;between MAR←StepLoc and L←MD you need:
;
5 NOPs if running at -11 volts
;
6 NOPs if running at -10 volts
!1,2,doCount,noCount;
!1,2,oddByte,evenByte;
!1,2,read1,done1;
!1,2,doMouse1,doWord1;
!1,2,haveBuffer1,noBuffer1;
!1,2,read2,done2;
!1,2,doMouse2,doWord2;
!1,2,read3,done3;
!1,2,doMouse3,doWord3;
!1,2,haveBuffer3,noBuffer3;
!1,2,doMouse4,done4;
!1,2,StoreCountZero,noCountMouse;

checkInput: T ← StoreCount,BUS=0;
5
T ← StoreCount,:doCount;!1,2,doCount,noCount;6
doCount: MAR←177024-1;
SafeLoc;7
L ← ONE AND T;BUSODD doesn’t work for MRT8
T ← 377,SH=0;9
L ← MD,:oddByte;!1,2,oddByte,evenByte;10

;on even: must reset MAR to enable flop to toggle for step
evenByte: L ← MD AND T,SH<0,
TASK;11
ScanData ← L LCY 8,:doMouse;!1,2,doMouse,doWord;12
doWord:
MAR←T←20;13
MAR←177000+T;StepLoc;must allow 6 cycles before reading from XBus14
L ← StoreCount - 1;15
StoreCount ← L,SH=0,TASK;16
NOP,:read1;!1,2,read1,done1;17

read1: MAR←177024-1;
in case TASK was taken18
NOP;19
T←377;20
L←MD;21
oddByte: T ← MD.T,SH<0;
22
T ← ScanData OR T,:doMouse1;!1,2,doMouse1,doWord1;23
doWord1:
MAR←ScanBuffer+1,BUS=0;24
L←ALLONES XOR T,:haveBuffer1; !1,2,haveBuffer1,noBuffer1;25
haveBuffer1:
ScanData←L,TASK;2x
MD ← ScanData;2x
MAR←T←20;2x
MAR←177000+T;StepLoc;must allow 5 cycles before reading from XBus2x
L ← StoreCount - 1;3x
StoreCount ← L,SH=0;3x
L←ScanBuffer+1,:read2;!1,2,read2,done2;3x
noBuffer1:
MAR←T←20;2x
MAR←177000+T;StepLoc;must allow 5 cycles before reading from XBus2x
L ← StoreCount - 1;3x
StoreCount ← L,SH=0;3x
L←0,:read2;!1,2,read2,done2;3x

read2: MAR←177024-1;
in case TASK was taken;3x
ScanBuffer←L;3x
T←377;3x
L←MD;3x
L ← MD AND T,SH<0;3x
ScanData ← L LCY 8,:doMouse2;!1,2,doMouse2,doWord2;3x
doWord2:
MAR←T←20;3x
MAR←177000+T;StepLoc;must allow 5 cycles before reading from XBus40
L ← StoreCount - 1;4x
StoreCount ← L,SH=0,TASK;4x
NOP,:read3;!1,2,read3,done3;43

read3: MAR←177024-1;
in case TASK was taken;4x
NOP;4x
T←377;4x
L←MD;4x
T ← MD.T,SH<0;4x
T ← ScanData OR T,:doMouse3;!1,2,doMouse3,doWord3;4x
doWord3:
MAR←ScanBuffer+1,BUS=0;5x
L←ALLONES XOR T,:haveBuffer3; !1,2,haveBuffer3,noBuffer3;5x
haveBuffer3:
ScanData←L,TASK;5x
MD ← ScanData;5x
MAR←T←20;5x
MAR←177000+T;StepLoc;must allow 5 cycles before reading from XBus5x
L ← StoreCount - 1;5x
StoreCount ← L;5x
L←ScanBuffer+1,SH=0,TASK;
ScanBuffer←L,:doMouse4;!1,2,doMouse4,done4;
noBuffer3:
MAR←T←20;5x
MAR←177000+T;StepLoc;must allow 5 cycles before reading from XBus5x
L ← StoreCount - 1;5x
StoreCount ← L,SH=0,TASK;
NOP,:doMouse4;!1,2,doMouse4,done4;

;make ScanBuffer non-zero (in case of no buffer)
done1: L←ALLONES,:done;
18
done2: L←ALLONES,:done;
33
done3: L←ALLONES,:done;
44
done4: L←ALLONES,:done;
59
done: ScanBuffer←L,:noMouse;
60

;come here when storecount is exhausted
;if ScanBuffer = 0 then NOP (wait for next START time to examine CBHead)
;
otherwise, mark current head "DONE", dequeue, and do next command
;
(adjacent reads allow windowing, and stepper wants to go before next START)

;need to do something if requested read was odd number of bytes
noCount: SINK←ScanBuffer,BUS=0;
7
MAR←ScanCBHead,:StoreCountZero;!1,2,StoreCountZero,noCountMouse;8
StoreCountZero:
NOP;9
NOP;1x
;T←MD+1,BUS=0;1x
;!1,2,ScanCBHeadOK,ScanCBHead0;
driver may have zeroed ScanCBHead
;
MAR←0+T+1,:ScanCBHeadOK;!1,2,ScanCBHeadOK,ScanCBHead0;Done stamp1x
;ScanCBHeadOK:
L←T;1x
;
MTEMP←L;1x
;
MD←StatusDONE;15
;
MAR←MTEMP-1;Unlink1x
L←MD+1,BUS=0;1x
!1,2,ScanCBHeadOK,ScanCBHead0;
driver may have zeroed ScanCBHead
ScanBuffer←L,:ScanCBHeadOK;
ScanCBHead0: NOP,:noCurrent;

ScanCBHeadOK:
MAR ← ScanBuffer + 1;
NOP;
TASK;
MD ← StatusDONE;

MAR ← ScanBuffer - 1;
NOP;
NOP;1x
L←MD;1x

MAR←ScanCBHead;2x
;NOP;21
;
MTEMP←L,TASK;2x
MTEMP←L,L←0;5x
ScanBuffer←L,TASK;
MD←MTEMP,:noCurrent;23

startScan:L←MD;
5
;quick like a bunny pulse start, then (whew!) you can TASK
MAR←ScanCBHead+1;
StartCommand6
T ← 10;
get ready for faking 1770167
ScanWait←L;
8
L←MD;
9

MAR←177026-T;
Outport;10
T←200;
11
ScanData←L;
12
MD←ScanData,L←ScanData OR T;<0><START><SkipCount>;
START=713
T←10;
1x

MAR←177026-T;
Outport;1x
MTEMP ← L,TASK;
<1><START><SkipCount>;16-17
MD←MTEMP;
1x

T ← 10;
19
MAR← 177026-T;
Outport;2x
NOP;
2x
SINK←ScanBuffer,BUS=0;
22
MD←ScanData,:haveCurrent;
!1,2,haveCurrent,noCurrent;23

;there is a current scan buffer: mark it DataLate, clear CB queue
haveCurrent: MAR ← ScanCBHead;
22
NOP;23
NOP;24
L←MD+1,BUS=0,TASK;25
!1,2,HeadOK,Head0;
driver may have zeroed ScanCBHead
ScanBuffer ← L,: HeadOK;!1,2,HeadOK,Head0;2x

HeadOK:
MAR ← ScanBuffer;2x
NOP;28
TASK;29
MD ← StoreCount;30

MAR ← ScanBuffer + 1;31
NOP;32
TASK;3x
MD ← StatusDATALATE;3x

Head0:
L←0;3x
MAR ← ScanCBHead;3x
ScanBuffer ← L;3x
StoreCount ← L;3x
MD ← ScanBuffer,:doMouse;39

;check for available input buffer
noCurrent: MAR←ScanCBHead;
24
L←0;
25
StoreCount←L;
2x
L←MD,BUS=0;
2x
ScanBuffer←L,:haveHead;
!1,2,haveHead,noHead;2x

;ScanCB structure:
;
link
;
command (Read,Delay,Forward,Back)
;
status/count (negative = status, pos=count)
;
buffer

!3,4,CommandREAD,CommandDELAY,CommandFORWARD,CommandBACK;
haveHead:
MAR←L←ScanBuffer+1;29
ScanBuffer←L;3x
T ← 10;3x
SINK←MD,BUS;3x
L ← 177026-T,:CommandREAD;3x

!1,2,realBuffer,dummyBuffer;
CommandREAD: MAR ← L ← ScanBuffer+1;
34
ScanBuffer ← L;35
NOP;36
L←MD;3x
MAR ← ScanBuffer + 1;3x
StoreCount ← L;doesn’t work for odd scan counts3x
NOP;40
L ← MD-1,BUS=0,TASK;4x
ScanBuffer ← L,:realBuffer;42
dummyBuffer: L←0;
43
ScanBuffer←L,:noMouse;44

;DELAY: wait until next start pulse (just throw command away)
CommandDELAY: NOP,:dequeueCB;
35

$521
$521;
$523
$523;
;
MOTORCTL=5
;<00000000><ENABLE><MOTORCTL><xxxx>

;0101xxxx = disabled = 120 (521 available)
CommandBACK:
MAR ← 420-1;
MTEMP←L;set up to be Outport=177016
SINK ← MD,BUS;
MAR←MTEMP,:bstep0;Outport;34
;sequence is: 1,0,2,3
bstep0:L←523-1,:stepDone;#522
bstep1:L←521-1,:stepDone;#520
bstep2:L←523,:stepDone;#523
bstep3:L←521,:stepDone;#521

CommandFORWARD:
MAR ← 420-1;
MTEMP←L;set up to be Outport=177016
SINK ← MD,BUS;
MAR←MTEMP,:fstep0;Outport;34
;sequence is: 3,2,0,1
fstep0:L←521,:stepDone;#521
fstep1:L←523,:stepDone;#523
fstep2:L←521-1,:stepDone;#520
fstep3:L←523-1,:stepDone;#522

stepDone: ScanData←L;
MD←ScanData;<0><MOTORCTL><StepState>

T←200;
MAR←MTEMP;
L←ScanData OR T;
ScanData←L;
MD ← ScanData;<1><MOTORCTL><StepState>

MAR←MTEMP;
L←ScanData XOR T;
ScanData←L;
MD ← ScanData;<0><MOTORCTL><StepState>

MAR ← 420-1;store updated value
TASK;
MD←ScanData,:dequeueCB;

;take CB off queue, mark DONE, store ScanData into Outport
dequeueCB: MAR ← ScanBuffer + 1;
43
NOP;44
TASK;4x
MD ← StatusDONE;4x

MAR ← ScanBuffer - 1;4x
NOP;4x
NOP;49
L ← MD;--link50

MAR ← ScanCBHead;5x
MTEMP←L,L←0;5x
ScanBuffer←L,TASK;5x
MD←MTEMP,:noMouse;59

ScannerOff: NOP;
3
;NOP;
4
L←MD;
5
ScanWait←L,:doMouse;
6

realBuffer: MAR← R37,:MRTA;
43
noHead: MAR← R37,:doMousex;
29
doMouse1: MAR← R37,:doMousex;
24
doMouse2: MAR← R37,:doMousex;
39
doMouse3: MAR← R37,:MRTA;
50
doMouse4: MAR← R37,:MRTA;
doMouse5: MAR← R37,:MRTA;
59
noCountMouse: MAR← R37,:doMousex;
9

;special code for long MRT cycles: don’t update mouse
noMouse: MAR←R37,:MRTA;
63

doMouse:MAR← R37;
**FIRST REFRESH CYCLE**40
doMousex:
SINK← MOUSE, BUS;MOUSE DATA IS ANDED WITH 17B
MRTA:
L← T← -2, :TX0;DISPATCH ON MOUSE CHANGE42,64
TX0:
L← R37 AND NOT T, T← R37;INCREMENT CLOCK65
T← 3+T+1, SH=0;IE. T← T +4. IS INTV TIMER ON?66
L←REFIIMSK AND T,:DOTIMER;[DOTIMER,NOTIMER]ZERO HIGH 4 BITS67
NOTIMER: R37← L;
STORE UPDATED CLOCK68(better have timer off)
NOTIMERINT: T← 2;
NO STATE AT THIS POINT IN PUBLIC REGS69
MAR← R37 XOR T,T← R37;**SECOND REFRESH CYCLE**70
L← REFZERO AND T;ONLY THE CLOKCK BITS, PLEASE71
SH=0, TASK;TEST FOR CLOCK OVERFLOW72
:NOCLK;[NOCLK,CLOCK]73
NOCLK:
T ← 200;81
MAR← R37 XOR T;**THIRD FEFRESH CYCLE**82
L← CURX, BLOCK;CLEARS WAKEUP REQUEST FF8x
T← 2 OR T, SH=0;NEED TO CHECK CURSOR?8x
MAR← R37 XOR T, :DOCUR;**FOURTH REFRESH CYCLE**85
NOCUR:
CURDATA← L, TASK;86
MRTLAST:CURDATA← L, :MRTloop;
END OF MAIN LOOP90

DOTIMER:R37← L;
STORE UPDATED CLOCK
L←0;
if we ever get here, swat break at 0
PC←L;
MAR← EIALOC;INTERVAL TIMER/EIA INTERFACE
L← 2 AND T;
SH=0, L← T← REFZERO.T;***V3 CHANGE (USED TO BE BIAS)
CURDATA←L, :SPCHK;CURDATA← CURRENT TIME WITHOUT CONTROL BITS

SPCHK:
SINK← MD, BUS=0, TASK;CHECK FOR EIA LINE SPACING
SPIA:
:NOTIMERINT, CLOCKTEMP← L;

NOSPCHK:L←MD;
CHECK FOR TIME = NOW
MAR←TRAPDISP-1;CONTAINS TIME AT WHICH INTERRUPT SHOULD HAPPEN
MTEMP←L;IF INTERRUPT IS CAUSED,
L← MD-T;LINE STATE WILL BE STORED
SH=0, TASK, L←MTEMP, :SPIA;

TIMERINT:MAR← ITQUAN;
STORE THE THING IN CLOCKTEMP AT ITQUAN
L← CURDATA;
R37← L;
T←NWW;AND CAUSE AN INTERRUPT ON THE CHANNELS
MD←CLOCKTEMP;SPECIFIED BY ITQUAN+1
L←MD OR T, TASK;
NWW←L,:NOTIMERINT;



CLOCK:
MAR← CLOCKLOC;R37 OVERFLOWED. UPDATE CLOCK74
NOP;75-76
L← MD+1;7x
MAR← CLOCKLOC;7x
MTEMP← L, TASK;79
MD← MTEMP, :NOCLK;80


DOCUR:
L← T← YPOS;CHECK FOR VISIBLE CURSOR ON THIS SCAN86
SH < 0, L← 20-T-1; ***x13 change: the constant 20 was 1787
SH<0, L← 2+T, :SHOWC;88

WAITC:
YPOS← L, L← 0, TASK, :MRTLAST;89
SHOWC:
MAR← CLOCKLOC+T+1, :CNOTLAST;89

CNOTLAST:
T← CURX, :CURF;90
CLAST:
T← 0;90
CURF:
YPOS← L, L← T;91
CURX← L;92
L← MD, TASK;93
CURDATA← L, :MRTloop;



;AFTER THIS DISPATCH, T WILL CONTAIN XCHANGE, L WILL CONTAIN YCHANGE-1

TX1:
L← T← ONE +T, :M00;Y=0, X=143
TX2:
L← T← ALLONES, :M00;Y=0, X=-143
TX3:
L← T← 0, :M00;Y=1, X= 043
TX4:
L← T← ONE AND T, :M00;Y=1, X=143
TX5:
L← T← ALLONES XOR T, :M00;Y=1, X=-143
TX6:
T← 0, :M00;Y= -1, X=043
TX7:
T← ONE, :M00;Y= -1, X=143
TX8:
T← ALLONES, :M00;Y= -1, X= -143

;old code using CLOCKTEMP
;M00:
MAR← MOUSELOC;START THE FETCH OF THE COORDINATES44
;
MTEMP← L;YCHANGE -145-46
;
L← MD+ T;X+ XCHANGE47
;
T← MD;Y48
;
T← MTEMP+ T+1;Y+ (YCHANGE-1) + 149
;
MTEMP← L, L← T;50
;
MAR← MOUSELOC;NOW RESTORE THE UPDATED COORDINATES51
;
CLOCKTEMP← L;52-53
;
MD← MTEMP, TASK;54
;
MD← CLOCKTEMP, :MRTA;55


;new code without CLOCKTEMP
M00:
MAR← MOUSELOC;START THE FETCH OF THE COORDINATES44
MTEMP← L;YCHANGE -145-46
L← MD+ T;X+ XCHANGE47
T← MD;Y48
MAR←MOUSELOC;
49
T← MTEMP+ T+1;Y+ (YCHANGE-1) + 150
MTEMP← L, L← T;51
MD←MTEMP;
52
MAR← MOUSELOC+1;NOW RESTORE THE UPDATED COORDINATES53
MTEMP← L,TASK;54-55
MD← MTEMP, :MRTA;56