;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