; MesaSlotMc.mu - Microcode for Slot, TriCon to be used with the Mesa System

; A note on February 18, 1982
; This code works on both Stinger and the DLP. It runs the 64K slot card and 8K slot card.

; last modified by GWilliams February 18, 1982 1:16 PM
; Changed some register assignments, and added one register, to avoid a smashed InitReturn.

; last modified by GWilliams February 5, 1982 3:52 PM
; Took out all debugging communication

; last modified by GWilliams November 13, 1981 4:37 PM
; changed calculation of # of zero’s to write into buffer@ InitZero

; last modified by GWilliams November 11, 1981 10:57 AM
; Changed to store the servo count in a separate word. Before it had only 13 bits.
; For now, this version of the microcode is incompatible with BCPL Press.
; Had to add FLAGS register & change the code somewhat

; last modified by GWilliams September 8, 1981 11:29 AM
; This SLOT microcode now uses bank 1 of the S registers because of conflict with MESA.
;This code runs ok with the BCPL Press

; last modified by GWilliams August 18, 1981 2:14 PM
; -- no longer assemble TriConmc.mu, instead, assemble TriConDriver.mu in order to get
; XMesaoverflow stuff into the ram. Also patched out the LOC1 predef because I now
; have it predefed in TriconDriver.mu

; last modified by Butterfield, October 8, 1980 4:55 PM
; - added invert bit - 10/6
; - changed SUB to InitBuffers - 10/3
; - predefined LOC1 - 7/22/80

;MICROCODE FOR SLOT 3100 CONTROLLER February 29, 1976
;
; This stuff uses task 1; BLV 177775 (bit 14)
; (disk uses 3,15; BLV 77767 (bits 0, 12))
; Auto-Boot feature means start emulator in RAM BLV 177776
; "and" all these together to get 77764

;Put in packed RAM format with BLV as version:
;
PackMu SlotMc.Mb SlotMc.Br 77764
;

;
;;;%0, 1777, 1, LOC1;
Slot start THIS IS NOW DEF’D IN TriconDriver.mu
$LREG
$R40;
#TriconDriver.Mu;
--I changed this from TriConMc.mu on August 18, 1981 2:14 PM

; Location 720 points to a control block:
;
;0
blank bit 14; COM bit 2
;
COM: BeamOn=0, Status=1, Reset=2, Print=3
;1
BlowUp bit-- for factor of 2 increase in each direction
;
LastPage bit-- marks this command as the last page
;
invert bit-- inverts the page
;
moreBlank bit 13 -- used to be bitsPerLine
;

;2 bottomMargin word
-- # bits at bottom margin: divides by 8
;3
scanLineWc word-- # words in scan line /2
;4
leftMargin word-- # bits at left of portrait page
;5
scansPerPage word-- total number of scan lines of data
;6
bufferPtr word-- pointer to first buffer -- must be even
;
buffers are linked by next=current!-1
;7
scanLineWcInc-- how far (in words) to advance within buffer to find
;
next scan line -- must be even
;10
scansPerBuf word-- number of scan lines in each buffer
;11 bitsPerLine word
-- for servoing the scan motor
;12
currentBuff word-- points to current buffer
;13
currentLine-- counts up to scansPerPage
;14
status:
;
blank bit 9
;
Wait bit-- 0 true
;
PaperJam bit-- 0 true
;
AddPaper bit-- 0 true
;
SelectB bit
;
Ready bit
;
LineSync bit
;
PageSync bit-- 0 true

;So processing of buffer pointed to by b is:
;
currentBuff=b
;
for i=0 to scansPerBuff-1 do
;
Send data starting at b+i*scanLineWcInc for scanLineWc*2 words
;
b=b!-1


; REGISTER DEFINITIONS FOR SLOT
; SLOT DEVICE DEFINITIONS

;F1’s
$SLOTSTOP
$L16016, 00000, 000000; non-data
$SLOTBEAM
$L16017, 00000, 000000; non-data

;F2’s
$SLOTBLOCK
$L24010, 00000, 000000; non-data
$SLOTDATA
$L26011, 00000, 124000; non-data
$SLOTADDR
$L26012, 00000, 124000; destination
$SLOTSERVO
$L26013, 00000, 124000; destination
$SLOTPRINT
$L24014, 00000, 000000; non-data
$SLOTRESET
$L24015, 00000, 000000; non-data
$SLOTDISABLE
$L24016, 00000, 000000; non-data
$SLOTSTATUS
$L24017, 00000, 000000; non-data

$DCBADDR$R41;
Normally points to currentLine entry
$PBM
$R42;Bottom margin
$PDWC
$R43;scanLineWc (in double words)
$LM
$R44;Left margin
$MSL
$R45;scansPerPage
$PBBA
$R46;Current print buffer address
$PBSLI
$R47;scanLineWcInc
$PBL
$R50;Scan lines/buffer
$InitOnesPairs $R51; How many pairs of ones to init the buffers with
$CSA
$R53;CURRENT SCAN ADDRESS
$CRC
$R54;FIRST SERVO COUNT THEN CURRENT RING COUNT
$CLA
$R55;CURRENT LAST ADDRESS
$CSBA
$R52;CURRENT SCAN BASE ADDRESS
;$InitReturn $R52; Init return BUS byte with sign bit for which buffer
$InitReturn $R62; Init return BUS byte with sign bit for which buffer
$Command $R56;
$InitPairs $R56; InitBuffers’ pair counter
$InitCount $R63;
Used to cause the two buffers of the SLOT to be initialized
;$FLAGS $R57
$FLAGS $R61

;
Constants known elsewhere by other names:
$600
$600;
$12
$12;

; PREDEFINITIONS

!3,4,BEAMON,SLOTSTAT,RESETSLOT,PRINT;
!1,2,Invert,InitBuffers;
!1,2,LOC1+1,CKPAGE;
!1,2,STARTPG,PAGESYNC;
!1,2,MARWAIT,MARDONE;
!1,2,STOPPRINT,KEEPPRINT;
!1,2,MOREWORDS,LASTWORDS;
!1,2,InvertNextWord,NEXTWORD;
!1,2,InvertMoreWords,InvertLastWords;
!1,2,BUFFEROK,RESETBUFFER;
!1,2,NEXTLINE,LINESDONE;
!1,2,InitZeroLoop,InitBufferDone;
!1,2,InitDone,InitSecond;
!1,2,PAGEWAIT,PAGEDONE;
!1,2,RET0,RET1;
!1,2,InitOnes,InitZero;


; THE CODE

LOC1:

;new code added to use bank 1 of the S registers. This is because Mesa hogs the bank
;zero registers.

SRB←2;SRB is loaded from BUS[12-14]

T←600;TASK STARTS HERE AFTER SIO
LOC1+1:
L←100+T,TASK;
DCBADDR←L;MANUFACTURE #720
;
T←20;
MAR←L←DCBADDR+T;GET CONTENTS OF DCB FROM @(720)
NOP;
L←MD,TASK;
DCBADDR←L;
;
MAR←DCBADDR;
T←3;
L←MD AND T;MASK COMMAND TO 2 BITS
T←MD;
Command←L,L←T,TASK;GET COMMAND
FLAGS←L;GET FLAGS
;
MAR←T←DCBADDR;CLEAR COMMAND
L←2+T;
DCBADDR←L,TASK;
MD←0;
;
MAR←T←DCBADDR;@(#720)+2
L←2+T;
DCBADDR←L;
T←MD;GET PRINT BOTTOM MARGN
L←MD;GET PRINT DBL WORD CNT
PDWC←L;
L←177777-T,TASK;
PBM←L;
;
T←2;
L←PDWC-T,TASK;
PDWC←L;
;
MAR←T←DCBADDR;@(#720)+4
L←2+T;
DCBADDR←L;
L←MD;GET LEFT MARGIN (BITS)
T←MD;GET TOTAL SCAN LINES
LM←L,L←T,TASK;
MSL←L;
;
MAR←T←DCBADDR;@(#720)+6
L←2+T;
DCBADDR←L;
L←MD;GET ADDR TO PRINT BUFF
T←MD;GET WORDS PER SCAN LINE
PBBA←L,L←T,TASK;
PBSLI←L;
;
MAR←DCBADDR;@(#720)+10
L←DCBADDR+1;
DCBADDR←L;
L←MD, TASK;GET SCAN LINES PER BUFF
PBL←L;

MAR←T←DCBADDR;@(#720)+11
L←2+T;
DCBADDR←L;
L←MD, TASK;;Get CRC (servo count for scan motor)
;
PBL←L;L←T,TASK;
CRC ← L;--later to become the Current Ring Count

;
T←DCBADDR;@(#720)+10
;
L←3+T, TASK;;we want DCBADDR to point to currentLine so as to permit
;
DCBADDR←L;either +1 or -1 to get to status and currentBuf easily.

SINK←Command,BUS;BRANCH ON COMMAND TO:
T← FLAGS, :BEAMON;OR SLOTSTAT OR RESETSLOT OR PRINT
;
(T← FLAGS is for PRINT - reduces time between TASKs)
;
;
BEAMON:
SLOTSERVO←CRC;
SLOTBEAM,:SLOTSTAT;
;
RESETSLOT: SLOTRESET;
SLOTSTOP,:SLOTSTAT;STOP PRINTING
;
SLOTSTAT: MAR←DCBADDR+1,SLOTDISABLE;
RETURN STATUS
L←377,SLOTSTATUS;
TASK;SLOTRESET,TASK;
MD←LREG,:LOC1;MC STOPS HERE UNTILL NEW SIO
;

PRINT:
L← 20000 ANDT; T has FLAGS, Test the Invert bit
SLOTBEAM, SH=0;
InitOnesPairs← L, SLOTPRINT, TASK, :Invert; [Invert, InitBuffers]
Invert:
NOP;

;NB THAT THE FOLLOWING 2 LINES COULD CAUSE A PROBLEM WHEN SCAN LINES ARE > 32K. AT THAT
;POINT, TRYING TO AD 177577 WILL CAUSE HAVOC. AN ALTERNATE WAY TO HANDLE THIS IS TO
;DO THE DIVISION BY 32 BY SHIFTING, THEN SUBTRACTING 4 FROM InitOnesPairs
; -Implemented above comment November 13, 1981 3:47 PM

;
T← CRC;
;
L← 177577 +T+1; i.e. T← CRC - 128(changed sink to L rather than T)
;
L← 17777 ANDT; Just bitsPerLine - 128--don’t need now that CRC = 16 bits
L←CRC;###
MTEMP← L RSH 1; divide by 32, truncating
L← MTEMP, TASK;
InitOnesPairs← L;
L← InitOnesPairs;
MTEMP← L RSH 1;
L← MTEMP;
MTEMP← L RSH 1;
L← MTEMP, TASK;
InitOnesPairs← L;
L← InitOnesPairs;
MTEMP← L RSH 1;
L← MTEMP;
MTEMP← L RSH 1;the T←0 is to get it to L
L← MTEMP, TASK;
InitOnesPairs← L;now have BitsPerLine/32

T←4;Subtract 128 bits worth from InitOnesPairs###
L←InitOnesPairs-T;i.e., InitOnesPairs-4###
InitOnesPairs←L;###
L←0, TASK, :InitBuffers; (L← 0)###
;
RET0:
SLOTSERVO←CRC;
;
PAGESYNC: T←13,SLOTBLOCK;
MAR←DCBADDR-T; WAIT FOR PAGE SYNC & MARGIN
T←ONE;
L←ONE AND T,SLOTSTATUS;
SINK←MD,BUS=0;TEST FOR NO NEW COMMAND
T←600,:LOC1+1;IFSO GOTO CKPAGE
;
CKPAGE:
SH=0,TASK;CHECK PAGE NOT STARTED
:STARTPG;IFSO GOTO PAGESYNC
;
STARTPG: NOP;
MARWAIT: L←LM-1,SLOTBLOCK;
WAIT FOR MARGIN
NOP;
LM←L,TASK,SH<0;TEST FOR MARGIN SENT
:MARWAIT;IFSO GOTO MARDONE
;
MARDONE: T←40000;
ISSUE STOPPRINT IF REQUIRED
L←FLAGS AND T;
L←PBBA,SH=0;TEST FOR NOT LAST PAGE
CSBA←L,:STOPPRINT;IFSO GOTO KEEPPRINT
;
ALSO INITIALIZE CURRENT SCAN BASE ADDRESS
;
STOPPRINT: SLOTSTOP,:KEEPPRINT;
STOP PRINTING
KEEPPRINT: L←PBL,TASK;
CRC←L;INITIALIZE CURRENT RING COUNT
;
NEXTLINE: SLOTADDR←PBM;
RESET LEFT MARGIN
L←CSBA;RESET CURRENT SCAN ADDRESS
CSA←L;
T←PDWC;RESET LAST ADDRESS
L←PDWC+T;
CLA←L;
T←CLA;
L←CSA+T,TASK;
CLA←L;
SINK← InitOnesPairs, BUS=0, TASK; Check if we’re inverting
:InvertNextWord; [InvertNextWord, NEXTWORD]
;
; MAIN WORD TRANSFER LOOP
;
NEXTWORD: MAR←T←CSA; **SLOT HDWARE REQUIRES 3 INS. AFTER MAR←
L←CLA-T;
L←2+T,SH<0;TEST FOR WORDS SENT
CSA←L,:MOREWORDS;IFSO GOTO LASTWORDS
;
MOREWORDS: SLOTDATA←MD,TASK;
SINK←MD,:NEXTWORD
;
; Inverting Word Transfer Loop
;
InvertNextWord:
MAR← T← CSA; **SLOT HDWARE REQUIRES 3 INS. AFTER MAR←
; I take the previous comment to mean that the clock cannot stop
; for the two cycles following the SLOTDATA - Butterfield - 10/6
L← CLA -T;
L← 2 +T, SH<0;TEST FOR WORDS SENT
CSA← L, :InvertMoreWords; [InvertMoreWords, InvertLastWords]
;
InvertMoreWords:
T← MD;
L← MD;
L← 0 -T-1, MTEMP← L;
T← MTEMP;
L← 0 -T-1, MTEMP← L;
SLOTDATA← MTEMP, TASK;
SINK← LREG, :InvertNextWord;
;
InvertLastWords:
T← MD;
L← MD;
L← 0 -T-1, MTEMP← L;
T← MTEMP;
L← 0 -T-1, MTEMP← L;
SLOTDATA← MTEMP, TASK;
SINK← LREG, :FinishScanLine;
;
;
LASTWORDS: SLOTDATA←MD,TASK;
SINK←MD;
;
;
; FINISH SCANLINE
;
FinishScanLine:
T←PBSLI;INC CURRENT SCAN BASE ADDR
L←CSBA+T;
CSBA←L;
L←CRC-1;
CRC←L,SH=0,TASK;CHECK FOR BUFFER COMPLETED
:BUFFEROK,SLOTBLOCK; IFSO GOTO RESETBUFFER
;
RESETBUFFER: MAR←PBBA-1;
GET POINTER FOR NEXT BUFF ADDR
L←PBL;AND GET FIRST BUFFER ADDR
CRC←L;
L←MD;
MAR←DCBADDR-1;
PBBA←L;
CSBA←L;
MD←PBBA;
;
BUFFEROK:L←MSL-1;
MSL←L,TASK,SH=0;TEST FOR LAST SCAN LINE OF PAGE
:NEXTLINE;IFSO GOTO LINESDONE
;
LINESDONE: L←ONE,:InitBuffers,TASK;
ZERO BOTH BUFFERS
;
RET1:
NOP;
PAGEWAIT: T←ONE,SLOTBLOCK;
L←ONE AND T,SLOTSTATUS;
SH=0,TASK;TEST FOR END OF PAGE
:PAGEWAIT;IFSO GOTO PAGEDONE
;
PAGEDONE: :SLOTSTAT;


;
; Subroutine to initialize the buffers. Returns to RET0 or RET1
;
;there is a TASK just before we get here, so store L away
InitBuffers:
InitReturn← L; Save return index
InitCount ← L; Later manipulations simply require this be non-negative at start.
InitSecond:
SLOTADDR← 177777; Start at the beginning
SLOTDATA← 0; with 64 zero bits
SINK← 0;
SLOTDATA← 0;
SINK← 0;
L← InitOnesPairs, TASK; Now for InitOnesPairs pair of ones
InitPairs← L;
InitOnesLoop:
L← InitPairs -1, BUS=0, TASK;
InitPairs← L, :InitOnes; [InitOnes, InitZero]
InitOnes:
L← 177777; see if using L helps put in the ones
SLOTDATA← LREG;
SINK← LREG, :InitOnesLoop;

InitZero:

T ← InitOnesPairs +1;
;
L← 377 -T-1, TASK; i.e. 253 - InitOnesPairs
L← 3777 -T-1, TASK; i.e. 2045 - InitOnesPairs (for 64K Slot Card)
InitPairs← L; (this can get squeezed out if necessary)
InitZeroLoop:
SLOTDATA← 0;
SINK← 0;
L← InitPairs -1, BUS=0, TASK;
InitPairs← L, :InitZeroLoop; [InitZeroLoop, InitBufferDone]
InitBufferDone:
T← 100000, SLOTBLOCK;
L← InitCount XORT;
InitCount← L, SH<0, TASK; Test for last buffer
:InitDone; [InitDone, InitSecond]
InitDone:
SINK← InitReturn, BUS, TASK;
:RET0; [RET0, RET1]