; 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:
;
;0blank bit 14; COM bit 2
;COM: BeamOn=0, Status=1, Reset=2, Print=3
;1BlowUp 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
;3scanLineWc word-- # words in scan line /2
;4leftMargin word-- # bits at left of portrait page
;5scansPerPage word-- total number of scan lines of data
;6bufferPtr word-- pointer to first buffer -- must be even
;buffers are linked by next=current!-1
;7scanLineWcInc-- how far (in words) to advance within buffer to find
;next scan line -- must be even
;10scansPerBuf word-- number of scan lines in each buffer
;11 bitsPerLine word-- for servoing the scan motor
;12currentBuff word-- points to current buffer
;13currentLine-- counts up to scansPerPage
;14status:
; 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]