%
*** *** *** *** *** *** *** *** *** Revision 1 *** *** *** *** *** *** *** *** *** *** ***
***********************************************************************************************
*** EDUTVFC1.mc: Exerciser for the User Terminal Variable Format Controller
and Large Format Display.
*** Purpose: This test exercise the User Terminal Variable Format Controller as well as
The Large Format (LF) display, the keyboard and the associated hardware
*** Minimum Hardware: The standard four CPU boards one 96K storage module and one UTVFC board
as well as an LF keyboard, an LF display and an associated power/interface unit
and one UTVFC I/O cable.
*** Run Time: Defined by the User. The test has passed when the user decides that the
appropriate patterns have been displayed. The user stops the test by bugging the
"ABORT" item on the Midas menu.
*** Written by: J. Katsiroumbas, September 24, 1978
*** Modified by: M. Spaur and J. Kellman, April 10, 1980
to drive the large format display and to standardize the microcode format and
install short looping capabilities.
************************************************************************************************

************************************************************************************************
* SubTest Descriptions
* SubTest 0: Initialize the I/O Control Block (IOCB) the Controller Status Block (CSB)
* SubTest 1: Shift out 20b controller addresses (CADDR) in decending order and input the
* Controller ID from register 0 of all controllers to locate the UTVFC.
* SubTest 2: Shift out 20b controller addresses in ascending order to all controllers
* except the UTVFC wich recieves an incrementing number from 0 to 17b.
* SubTest 3: Shift out Controller addresses of zero to all controllers except the UTVFC
* wich receives a CADDR = 5.
* SubTest 4: Start the Task 5 firmware driver and select the Next Test to run.
* SubTest 5: Increment the checkerboard pattern in the horizontal direction.
* SubTest 6: Increment the checkerboard pattern in the verticle direction.
* SubTest 7: Invert the checkerboard pattern.
* SubTest10: Simulate a mouse command to increment the checkerboard pattern horizontally
* for exercise purposes.
* SubTest11: Store the checkerboard pattern in the memory buffers.
* SubTest12: Send an alternating bar pattern to the memory buffers base on keyboard input
* and return to SubTest 7.
* SubTest13: Update the cursor position based on keyboard inputs and branch to the next
* SubTest base on keyboard inputs
************************************************************************************************

************************************************************************************************
* BreakPoints:
* BEGIN: Change the user-definable registers if you like, and start the test by bugging
* the "continue" item on the Midas menu.
* BOARD-NOT-FOUND: SubTest 1 did not find a controller with the proper ID number in
* register 0.
* BAD-ID: After the board was found, SubTest 2 was not able to assign all CADDR’s
* from 0 to 17b and receive the proper ID from register 0.
*
* Note that there is no Passed-EDUTVFC1-Test breakpoint because this test ends when the
* user bugs the "ABORT" item on the Midas menu. For the UTVFC module to pass this test
* the user must observe the appropriate patterns on the LF display screen.

************************************************************************************************

************************************************************************************************
* ShortLoop Logic Analyzer Sync Points and Control Store Addresses:
* BOARD-NOT-FOUND: Control Store Address 1443
* BAD-ID: Control Store Address 1443

************************************************************************************************
* Special Register Definitions:
* ShortLoop: At any breakpoint in the test
the register ShortLoop can be set equal to one. This will cause the current test
to loop forever. In the default case it is set to zero and no looping occurs.
* Exercise: Setting this register to a one will cause the microcode to exercise the UTVFC board
without user intervention. This feature can be used for a long run exercise of the user
interface. In the default case it is set to zero and no exercising occurs.
* NextTest: setting this register to a one will cause SubTest 5 to run first (checkerboard).
setting this register to a 2 will cause SubTest 6 (KeyTest) to run first. In the default
case it is set to 1 and the checkerboard test runs first.
************************************************************************************************
* Subroutine Definitions:

* ACCU: This subroutine runs in Task 5 and accumulates serial keyboard data sent back from the UTVFC
via the I/O Attention line. The data is accumulated in two R registers called
FCMSGU (most significant) and FCMSGL (least significant).
* CURSERW: This subroutine writes a checkerboard pattern in the Curser Image Ram.
* HEWRT: This subroutine runs at Task 5 and loads the Horizontal Control Ram of the UTVFC.
The starting location is given by the contents of the R register WR0. The number of locations
is given by the contents of the R register LINESTORUN. The data that is written into the
Horizontal Control Ram is that contents of the R register IOCB1.
* INITIALIZE: This subroutine runs in Task 5 and writes zero values in the entire Horizontal Control
Ram of the UTVFC.
* MSTORE: This subrouine runs in Task 0 and makes the following register assignments:
BASE = BASE10
BASE1 = BASE11
BASE2 = BASE12
BASE3 = BASE13
BASE4 = BASE14
BASE5 = BASE15
This subroutine then calls the PMPUT subroutine.
* NIBCLK: This subroutine generates Nibble Clock (NClk) pulses in the UTVFC hardware. The number of
NClk pulses generated is equal to the value of the R register CREG when the subroutine is
entered. This routine runs in Task 5, and is used with the FocreAARLoad feature of the
BufStart register on the UTVFC board to Load or increment the Activer Address Register
while loading the Horizontal Control Ram or the Cursor Image Ram.
* PMPUT: This subroutine runs in Task 0 and stores a variable number of words into the memory buffers
or the I/O control blocks.
PMPUT uses the BASE registers as follows:
BASE = Starting Memory Address (lower half)
BASE1 = Starting Memory Address (upper half)
BASE2 = Word Count (number of words to be stored)
BASE3 = The data word to be stored
BASE4 = A modifier, applied consecutively to every data word
BASE5 = Function definition:
0 means ADD the modifier to every data word
1 means XOR the modifier with every data word
* SHIFTOUT: This subroutine runs in Task 0 and shifts out bits 14, 15, 16 and 17 of the BASE register
as a controller address
* UTVRETURN: This subroutine runs in Task 5 and sets the AllowWU bit in the Control Register
to one to enable wake ups and the restarts (or notifies) the Task 0 microcode
at lable EN0.

************************************************************************************************

************************************************************************************************
%
* INITIALIZATION:

BUILTIN[INSRT,24];
INSRT[D0LANG];
NOMIDASINIT;
TITLE[FDEFS.MC];

**************** Macros and Set Values ****************

SET[FTASK,0];
* TASK ASSIGNMENTS
SET[RTASK,5];

MC[RTASK.1,LSHIFT[RTASK,14]];
* TASK SHIFTING
MC[FTASK.1,LSHIFT[FTASK,14]];

SET[F,1];
* PAGE ASSIGNMENTS
SET[F1,2];
SET[F2,3];
SET[F3,4];
SET[RPAGE,5];
SET[RPAGE1,6];

SET[F.1,LSHIFT[F,10]];
* PAGE SHIFTING
SET[RPAGE.1,LSHIFT[RPAGE,10]];
SET[RPAGE1.1,LSHIFT[RPAGE1,10]];
SET[RTASK.2,LSHIFT[RTASK,4]];


MC[RPAGE.2,LSHIFT[RPAGE,10]];
MC[F.2,LSHIFT[F,10]];

TITLE[F DEF FILE];
SET TASK[FTASK];

MC[RTASK#,RTASK];
MC[ID,RTASK.2];
MC[TESTS,3];
MC[CSB,100];
* Controller Status Block Address (Low 16 bits)

MC[MEMBUFU,0];
* Memory Buffer 0 address (upper half)
MC[MEMBUFL,2000];
* Memory Buffer 0 address (lower half)

MC[MYIDU,1000];
* Controller ID number (upper half)
MC[MYIDL,35];
* Controller ID number (lower half)

**************** R-Registers ****************

RV[REVISION,4,1];
* Current Revision
RV[SUBTEST,5,0];
* Current location of Task 0 microcode
RV[SHORTLOOP,6,0];
* For looping on errors in SubTest1, 2 or 3
RV[EXERCISE,7,0];
* This register controls the exercise feature
* Exercise = 0 disables the exercise feature.
* Exercise # 0 activates the exercise feature.
* In the default case the exercise feature is deactivated

RV[TESTRUN,40];
* Used in calculating the next test to run.
RV[NEXTTEST,41];
* Selects wich test will run first.
* Bit 16&17 = 10 the KeyBoard test (SubTest6) runs first
* Bit 16&17 # 10 the Checkerboard test (SubTest5) runs first
* In the default case (SubTest5) runs first

RV[KTIMER,42];
* Software Time out value for input loop of SubTest7
RV[DISPLAY,43];
* Used to select the number of displays to be used.

RV[SAVE1,45];
* A general purpose register
RV[SAVE3,47];
* A general purpose register

RV[WORDCOUNT,53];
* Counts the number of words per scan line.
RV[LINECOUNTER,52];
* Counts the number of horizontal scan lines per frame

RV[WR10,50];
* General purpose registers
RV[WR11,51];
RV[WR14,54];
RV[WR15,55];
RV[WR16,56];
RV[WR17,57];

RV[CADDR,60];
* Current controller address
RV[MYID,62];
* UTVFC controller ID hardwired in reg 0
RV[CONTROLLERID,63];
* Controller ID returned by reg 0 of addressed controller

RV[MESSU,66];
* Upper byte of Controller Status Block message word
RV[MESSL,67];
* Lower byte of Controller Status Block message word

RV[BASE,60];
* General purpose registers
RV[BASE1,61];
RV[BASE2,62];
RV[BASE3,63];
RV[BASE4,64];
RV[BASE5,65];
RV[BASE10,70];
RV[BASE11,71];
RV[BASE12,72];
RV[BASE13,73];
RV[BASE14,74];
RV[BASE15,75];
RV[BASE16,76];
RV[BASE17,77];

***********************************************************************************************
*** Main Routine

ON PAGE[F3];
SET TASK[FTASK];

*** SubTest 0
GO:
START:
SUBTEST←0C;
TESTRUN←TESTS; * TESTRUN HAS TESTS#S TO RUN
WR10←CSB;
T←WR10←(WR10)+(10C);* SETTING UP IOCB#0
WR11←0C;
BASE10←MEMBUFL; * BUFFER 0 ADDRESS
BASE11←MEMBUFU;
BASE12←10C;
BASE12←(BASE12)+(T);
BASE13←20000C;
TASK;
PSTORE4[WR10,BASE10,0];
BASE10←BASE10; * INTERLOCK
T←WR10←(WR10)+(10C);* SETTING UP IOCB#1
BASE10←(BASE10)+(100C); * BUFFER 1 ADDRESS
BASE12←(BASE12)-(10C);
TASK;
PSTORE4[WR10,BASE10,0];
BASE10←BASE10; * INTERLOCK
T←WR10←(WR10)+(10C);
WR11←0C;
BASE10←MEMBUFL;
BASE12←(BASE12)+(30C);* SETTING UP IOCB#2
T←(400C);
BASE10←(BASE10)+(T); * BUFFER 2 ADDRESS
BASE11←MEMBUFU;
BASE13←(200C);
TASK;
PSTORE4[WR10,BASE10,0];
BASE10←BASE10; * INTERLOCK
T←WR10←(WR10)+(10C);* SETTING UP IOCB#3
BASE10←(BASE10)-(100C); * BUFFER 3 ADDRESS
BASE12←(BASE12)+(10C);
BASE13←(20C);
TASK;
PSTORE4[WR10,BASE10,0];
BASE10←BASE10; * INTERLOCK
WR10←(WR10)+(10C);* SETTING UP IOCB#4
BASE10←(BASE10)-(100C); * BUFFER 4 ADDRESS
BASE12←(BASE12)+(10C);
BASE13←(20C);
TASK;
PSTORE4[WR10,BASE10,0];
BASE10←BASE10; * INTERLOCK
WR10←(WR10)+(10C);
T←(200C); * SETTING UP IOCB#5
BASE10←(BASE10)+(T); * BUFFER 2 ADDRESS
BASE12←CSB;
BASE12←(BASE12)+(30C);
BASE13←2000C;
TASK;
PSTORE4[WR10,BASE10,0];
BASE10←BASE10; * INTERLOCK
DISPLAY←0C; * SETTING UP CSB
T←WR10←CSB;
BASE10←10C; * IOCB 0 ADDRESS
T←BASE10←(BASE10)+T;
BASE12←T;
BASE12←(BASE12)+(10C);
T←DISPLAY;
BASE13←T;
TASK;
PSTORE4[WR10,BASE10,0];
BASE10←BASE10; * INTERLOCK
BASE10←30C; * SETTING UP CSB PART 2
T←300C;
TASK,BASE11←1400C;
BASE11←(BASE11)OR(T);
NEXTTEST←1C; * NEXTTEST HAS NEXT TEST# TO RUN
PSTORE2[WR10,BASE10,6];
WORDCOUNT←2C;* WORDCOUNT HAS WORD COUNTER
BEGIN:
BREAKPOINT;* Set the paramenters you like and
LOADPAGE[F2];* bug CONTINUE to start the test
GOTOP[CADD],DISPLAY←0C;

*** SubTest 1
ON PAGE[F2];

CADD:
NOP;* Resolves a branching conflict
CADD0:
NOP;* Resolves a branching conflict
CADD0A:
NOP;* Resolves a branching conflict
CADD0B:
NOP;* Resolves a branching conflict
CADD0C:
SUBTEST←1C;
BASE2←MYIDU;
T←MYIDL;
BASE2←(BASE2)+T;
BASE←20C;
CADD1:
BASE←(BASE)-1; * SHIFT OUT 17 TASK#’S
CALL[SHIFTOUT]; * CALL TO SHIFT OUT TASK#
LU←BASE;
GOTO[CADD1,ALU#0]; * GO GET ANOTHER TASK# TO TRY
BASE←20C;
CADD2:
BASE←(BASE)-1; * SHIFT OUT 17 TASK#’S
T←BASE;
CADDR←T;
T←LSH[BASE,4];
INPUT[BASE3];
BASE3←(BASE3)OR(1C);
T←BASE3;
CONTROLLERID←T;
T←BASE2;
MYID←T;
LU←(BASE3)XORT;
GOTO[CADD3,ALU=0],LU←BASE;
GOTO[CADD2,ALU#0]; * GO GET ANOTHER TASK# TO TRY
LU←SHORTLOOP;
GOTO[CADD,ALU#0];
BOARD-NOT-FOUND: BREAKPOINT;
* PROPER ID NOT RETURNED FROM ANY SLOT.
GOTO[CADD0];

*** SubTest 2
CADD3:
SUBTEST←2C;
T←BASE; * FOUND MY ID IN POSITION SAVED IN BASE16
BASE16←T;
BASE14←20C;
CADD4:
BASE14←(BASE14)-1; * BASE14=MY SOFT ID # FROM 17 TO 0
CADD5:
BASE15←20C;
CADD6:
T←BASE15←(BASE15)-1; * BASE15= CURRENT POSITION TO BE SHIFTED OUT
LU←(BASE16)XOR(T); * DOES CURRENT POSITION= MY POSITION
GOTO[CADD7,ALU#0],T←BASE14;
BASE←T,GOTO[CADD10];
CADD7:
BASE←T;
BASE←(BASE)XOR(17C);
CADD10:
CALL[SHIFTOUT];
LU←BASE15;
GOTO[CADD6,ALU#0]; * GO SHIFT ANOTHER TASK# OUT
T←LSH[BASE14,4]; * WE SHIFTED ALL 17 OUT NOW CHECK MY ID
INPUT[BASE3];
T←BASE14;
CADDR←T;
BASE3←(BASE3)OR(1C);
T←BASE3;
CONTROLLERID←T;
T←BASE2;
MYID←T;
LU←(BASE3)XORT;
GOTO[CADD10A,ALU#0],LU←BASE14;
GOTO[CADD4,ALU#0];
LU←SHORTLOOP;
GOTO[CADD0C,ALU#0];
GOTO[CADD25];
CADD10A: LU←SHORTLOOP;
GOTO[CADD0A,ALU#0];
BAD-ID:
BREAKPOINT;* Could not assign current CADDR to UTVFC and get back MYID
GOTO[CADD0B];

*** SubTest 3
CADD25:
SUBTEST←3C;
BASE15←20C;
CADD26:
T←BASE15←(BASE15)-1;* BASE15= CURRENT POSITION TO SHIFT OUT
LU←(BASE16)XOR(T); * DOES CURRENT POSITION= MY POSITION
GOTO[CADD27,ALU#0],T←RTASK#;
BASE←T,GOTO[CADD30];
CADD27:
BASE←0C;
CADD30:
CALL[SHIFTOUT];
LU←BASE15;
GOTO[CADD26,ALU#0]; * GO SHIFT ANOTHER TASK# OUT
LOADPAGE[F];
GOTOP[INIT];

****** Subroutine SHIFTOUT
SHIFTOUT: USECTASK;
T←GETRSPEC[143];
SAVE1←T;
BASE3←4C; * PUT TASK# INTO T AND SHIFT IT OUT
T←(BASE)XOR(17C);
BASE4←T;
SHIFTOUT1: GENSRCLOCK;
TASK,T←BASE4←RSH[BASE4,1];
NOP;
BASE3←(BASE3)-1;
GOTO[SHIFTOUT1,ALU#0];
APCTASK&APC←SAVE1;
RETURN; * QUIT WHEN YOU SHIFT FOUR TIMES

****** Subroutine PMPUT
PMPUT:
USECTASK;
T←GETRSPEC[143];
TASK,SAVE3←T;
T←BASE3;
WR14←T; * SET FIRST DATA TO MEMORY
LU←BASE5;
GOTO[PLOG,ALU#0];
T←BASE4;
WR14←(WR14)-T;
TASK;
NOP;
PM0$:
NOP;* DUMMY ENTRY
PM0:
BASE2←BASE2; * WORD COUNT <=0 WE ARE DONE
GOTO[PMOUT,ALU=0],FREEZERESULT;
GOTO[PMOUT$,ALU<0];
LU←BASE5;
GOTO[PLOG1,ALU#0];
T←BASE4;
TASK,T←WR14←(WR14)+T; * FIRST DATA WORD READY TO GO
T←(BASE4)+T;
WR15←T;
T←(BASE4)+T;
WR16←T;
T←(BASE4)+T;
WR17←T;
PCON:
T←RSH[BASE2,2]; * SET OF FOUR DATA, QUAD ALIGN AND ARITH MODIFIED
GOTO[PUT1,ALU=0]; * IF WORD COUNT LESS THAN 4 DO ONE PUT
T←LSH[BASE,16]; * IS MEMORY ADD QUAD ALINE IF NOT DO ONE PUT
GOTO[PUT4,ALU=0];
T←T;

PUT1:
PSTORE1[BASE,WR14,0]; * DATA TO MEMORY
TASK;
BASE←(BASE)+1; * UP COUNT MEMORY ADD
GOTO[PUT10,NOCARRY];
BASE1←(BASE1)+1; * CARRY ONE INTO UPPER ADDRESS
PUT10:
BASE2←(BASE2)-1; * DOWN COUNT WORD COUNT
GOTO[PM0];
PUT4:
PSTORE4[BASE,WR14,0]; * COUNT>=TO 4 ADDRESS IS QUAD, PUT 4 INTO MEMORY
TASK,T←(WR17);
WR14←T;
T←4C;
BASE2←(BASE2)-T; * DOWN COUNT WORD COUNT BY 4
BASE←(BASE)+T; * UP COUNT MEMORY ADDRESS BY 4
GOTO[PUT40,NOCARRY];
BASE1←(BASE1)+1; * CARRY 1 INTO UPPER ADDRESS
PUT40:
GOTO[PM0];
T←T;
PMOUT:
GOTO[PMOUT$];
PMOUT$:
APCTASK&APC←SAVE3;
RETURN;
PLOG:
T←BASE4;
WR14←(WR14)XORT,GOTO[PM0$];
PLOG1:
T←BASE4;
TASK,T←WR14←(WR14)XORT; * FIRST DATA WORD READY TO GO
T←(BASE4)XORT;
WR15←T;
T←(BASE4)XORT;
WR16←T;
T←(BASE4)XORT;
WR17←T;
GOTO[PCON];* SET OF FOUR DATA WORDS QUAD ALIGN & LOGICAL MODIFIED

************************************************************************************************

TITLE[F DISPLAY DIAG PROGRAM];
SET TASK[FTASK];
ON PAGE[F];

*** SubTest 4
INIT:
SUBTEST←4C;
BASE←RPAGE.2;
T←RTASK.1;
BASE←(BASE)OR(T);
APCTASK&APC←BASE;
RETURN; * NOTIFIY TASK TO SET ADDRESS
EN0:
LOADPAGE[F1];
GOTOP[TEST];


*** SubTest 13
SPIN:
SUBTEST←13C;* Read MESSU from Task 5 driver
GOTO[SPIN2];
SPIN1:
GOTO[SPIN2];
SPIN2:
WR10←CSB;
WR11←0C;
TASK,MESSU←0C;
PSTORE1[WR10,MESSU,4];
NOP;
SPIN3:
WR10←CSB;
WR11←0C;
NOP;
PFETCH2[WR10,MESSU,4];
TASK,PFETCH2[WR10,BASE10,6];
NOP;
KTIMER←(KTIMER)-1;* Soft Timmer: give the driver time to post MESSU
GOTO[SPIN4,ALU>=0],LU←LDF[MESSU,14,3];
GOTO[U+YR,ALU=0];
NOP;
U+XR:
LU←LDF[MESSU,13,1];* Update curser position X
GOTO[U-XR,ALU=0];
BASE11←(BASE11)+(1C), GOTO[U+YR];
U-XR:
BASE11←(BASE11)-(1C), GOTO[U+YR];
U+YR:
T←LDF[MESSU,10,3];* Update curser position Y
GOTO[UZR,ALU=0];
LU←LDF[MESSU,7,1];
GOTO[U-YR,ALU#0];
BASE10←(BASE10)+(1C), GOTO[UZR];
U-YR:
BASE10←(BASE10)-(1C), GOTO[UZR];
UZR:
PSTORE2[WR10,BASE10,6];
TASK;
NOP;
GOTO[EN1];
EN1:
LU←EXERCISE;
GOTO[EXERMOUSE,ALU#0];
LU←MESSU;
GOTO[SPIN3,ALU=0],WR10←7000C; * SEE IF ANYTHING TO DO
KTIMER←200C;
T←(MESSU)AND(7000C);
T←(WR10)XORT;
GOTO[INIT10,ALU=0],T←4C; * TIME TO CHANGE TEST MOUSE=1,2,3
T←(NEXTTEST)ANDT;
GOTO[INIT2,ALU=0]; * WE ARE IN THE KEYBOARD TEST IF ALU#0
T←(MESSL)AND(100000C);
GOTO[KEY1,ALU#0]; * DO SOMETHING ONLY IF KEY IS DOWN
GOTO[SPIN];
INIT2A:
NOP;
INIT2:
DISPATCH[MESSU,4,3];
DISP[MOUSE];

MOUSE:
GOTO[SPIN],AT[F.1,100];* MOUSE=0 GOTO SPIN
GOTO[INIT20],AT[F.1,101];* MOUSE=1 GOTO INIT20 INC WORD COUNT
GOTO[INIT30],AT[F.1,102];* MOUSE=2 GOTO INIT30 INC LINE COUNT
GOTO[SPIN],AT[F.1,103];* MOUSE=3 GOTO TEST
GOTO[INIT40],AT[F.1,104];* MOUSE=4 GOTO TEST
GOTO[SPIN],AT[F.1,105];* MOUSE=5 GOTO INIT21 DEC WORD COUNT
GOTO[SPIN],AT[F.1,106];* MOUSE=6 GOTO INIT31 DEC LINE COUNT
GOTO[SPIN],AT[F.1,107];* MOUSE=7 GOTO TEST

SPIN4:
GOTO[SPIN3];

*** SubTest 10
EXERMOUSE: SUBTEST←10C;
KTIMER←77777C;
EXERMOUSEB: T←(KTIMER)+(1C);
* Need a soft timer to slow this branch down
NOP;
KTIMER←T;
TASK;
LU←KTIMER;
GOTO[EXERMOUSEB,ALU#0];
MESSU←1000C;* will cause horizontal increment pattern
KTIMER←200C;
NOP;
EXERMOUSE1: NOP;
EXERMOUSE1A: GOTO[INIT2A];
* Go do it

*** SubTest 13 (continued)

KEY1:
LOADPAGE[F1];
GOTOP[KEY10];
INIT10:
LOADPAGE[F1];
GOTOP[TEST];

*** SubTest 5

INIT20:
SUBTEST←5C;
WORDCOUNT←(WORDCOUNT)+1; * INC WORD COUNTER
TASK;
NOP;
LU←(WORDCOUNT)-(77C);
GOTO[INIT21,ALU=0];
GOTO[MEM0];
INIT21:
WORDCOUNT←0C,GOTO[MEM0];


*** SubTest 6
INIT30:
SUBTEST←6C;
WR10←CSB;
TASK,WR10←(WR10)+(10C);
LINECOUNTER←(LINECOUNTER)+1; * INC LINE COUNTER
T←400C;
LU←(LINECOUNTER)-(T);
GOTO[INIT31,ALU=0],WR11←0C;
GOTO[INIT32],T←LINECOUNTER; * INC LINE COUNTER
INIT31:
T←0C;
LINECOUNTER←2000C;
NOP;
INIT32:
PSTORE1[WR10,LINECOUNTER,3];
TASK,PSTORE1[WR10,LINECOUNTER,13];
NOP;
LINECOUNTER←T,GOTO[SPIN];


*** SubTest 7
INIT40:
SUBTEST←7C;* FLIP BACK GROUND
WR10←CSB;
WR11←0C;
TASK;
PFETCH1[WR10,BASE17,2];
BASE17←(BASE17)XOR(140C);
PSTORE1[WR10,BASE17,2],GOTO[SPIN];


*** SubTest 11
MEM0:
SUBTEST←11C;
BASE10←MEMBUFL; * BUFFER 0 ADDRESS
TASK,BASE11←MEMBUFU;
T←WORDCOUNT;
BASE12←T; * # OF WORD TO SWAP DATA
GOTO[SPIN2,ALU=0],BASE13←0C; * ZERO CASE DO NOTHING
BASE14←0C;
TASK,BASE15←0C;
T←(BASE15)-1;
BASE16←T; * ALTERNATING DATA
T←100C;
WR10←MEMBUFL; * BUFFER SIZE
WR10←(WR10)+(T),GOTO[MEP0]; * BUFFER SIZE
MEM00:
BASE10←MEMBUFL; * BUFFER 1 ADDRESS
WR10←MEMBUFL;
TASK,T←200C;
WR10←(WR10)+(T); * BUFFER SIZE
BASE11←MEMBUFU;
BASE10←(BASE10)+(100C); * BUFFER 1 ADDRESS
BASE16←0C;
T←(BASE16)-1;
BASE13←T,GOTO[MEP1];
MEM01:
T←WR10←CSB;
BASE10←10C; * IOCB 0 ADDRESS
TASK,T←BASE10←(BASE10)+T;
BASE11←0C;
WR11←0C;
NOP;
PSTORE2[WR10,BASE10,0],GOTO[SPIN2];* SETTING UP CSB
MEP0:
T←T;
CALL[MSTORE];
T←WR10;
T←(BASE)-T;
GOTO[MEM00,ALU>=0],T←BASE;
BASE10←T;
T←BASE13;
BASE17←T;
T←BASE16;
BASE13←T;
T←BASE17;
BASE16←T,GOTO[MEP0];
MEP1:
T←T;
CALL[MSTORE];
T←WR10;
T←(BASE)-T;
GOTO[MEM01,ALU>=0],T←BASE;
BASE10←T;
T←BASE13;
BASE17←T;
T←BASE16;
BASE13←T;
T←BASE17;
BASE16←T,GOTO[MEP1];


*** Subroutine MSTORE
MSTORE:
USECTASK;
T←GETRSPEC[143]; * SAVE CALL RETURN
SAVE1←T;
T←BASE10;* LOW ADD
BASE←T;
T←BASE11;* HIGH ADD
TASK,BASE1←T;
T←BASE12;* WORD COUNT
BASE2←T;
T←BASE13;* DATA TO BE STORED
BASE3←T;
T←BASE14;* MODIFIER TO DATA
BASE4←T;
T←BASE15;* ARITH OR LOGICAL MOD
LOADPAGE[F2];
CALLP[PMPUT],BASE5←T; * CALL THE PUTTER
APCTASK&APC←SAVE1; * RESTORE THE CALL RETURN
RETURN;

*** Entry Points to SubTests 0, 4, 11 and 12 THESE ARE ENTRY POINTS FOR TASK SWITCHING
GOTO[EN0],AT[F.1,0]; * Try TEST again
GOTO[MEM0],AT[F.1,40]; * Pattern Test Entry
LOADPAGE[F1],AT[F.1,41];* Key Test Entry
GOTOP[KEY];
LOADPAGE[F3],AT[F.1,377];* Restart the test
GOTOP[START];

*** SubTest 12
ON PAGE[F1];
KEY:
SUBTEST←12C;
BASE10←MEMBUFL;* BUFFER 0 ADDRESS
T←(200C);
BASE10←(BASE10)+(T);* BUFFER 0 ADDRESS
TASK,BASE11←MEMBUFU;
BASE12←60C; * # OF WORD TO SWAP DATA
BASE13←0C; * STARTING DATA
BASE14←0C;
BASE14←(BASE14)-1; * ALTERNATING DATA
LOADPAGE[F];
CALLP[MSTORE],BASE15←1C;* LOGICAL MOD
T←BASE;
TASK,BASE10←T;
BASE12←230C;* FINISH BUFFER#0=P,BUFFER#1=0 AND BUFFER#2=0

LOADPAGE[F];
CALLP[MSTORE],BASE14←0C;
T←T;* BUFFER 0= TO PROMPT DATA, - - - - ECT 20 BITS
KEY10:
T←MESSU;
WR10←T; * BIT DATA WORD
WR11←17C; * # OF BITS
BASE10←MEMBUFL;* BUFFER 0 ADDRESS
T←(300C);
T←BASE10←(BASE10)+(T); * BUFFER 0 ADDRESS
BASE←T; * FIRST WORD = TO ZERO
BASE12←2C; * COUNT OF WORDS TO STORE
BASE13←0C; * FIRST WORD = TO ZERO
TASK,BASE11←MEMBUFU;
BASE14←0C;
BASE15←1C;
BASE17←1C;
T←BASE17←LSH[BASE17,17];
KEY2:
T←(WR10)ANDT;
GOTO[KEY3,ALU=0];
T←(BASE13)-1;
BASE14←T; * SECOND WORD = TO 177777
KEY3:
T←BASE;
LOADPAGE[F];
CALLP[MSTORE],BASE10←T;
BASE14←0C;
TASK,WR10←LSH[WR10,1]; * SHIFT FOR NEXT DATA BIT
T←BASE17;
WR11←(WR11)-1; * DEC COUNT
GOTO[KEY2,ALU>=0];
T←MESSL;
WR10←T; * BIT DATA WORD
WR11←7C; * # OF BITS
KEY4:
T←BASE17;
T←(WR10)ANDT;
GOTO[KEY5,ALU=0];
T←(BASE13)-1;
BASE14←T; * SECOND WORD = TO 177777
KEY5:
T←BASE;
LOADPAGE[F];
CALLP[MSTORE],BASE10←T;
BASE14←0C;
TASK,WR10←LSH[WR10,1]; * SHIFT FOR NEXT DATA BIT
NOP;
WR11←(WR11)-1; * DEC COUNT
GOTO[KEY4,ALU>=0];
T←BASE;
BASE10←T;
LOADPAGE[F];
CALLP[MSTORE],BASE12←30C;
T←WR10←CSB;
BASE10←30C; * IOCB 0 ADDRESS
BASE10←(BASE10)+T;
BASE11←0C;
WR11←0C;
NOP;
PSTORE2[WR10,BASE10,0];* SETTING UP CSB
LOADPAGE[F];
GOTOP[SPIN2];


*** SubTest 4 (continued)
TEST:
SUBTEST←4C;
LU←NEXTTEST;
GOTO[TEST5,ALU=0];
LU←TESTRUN;
GOTO[TEST6,ALU=0];
TEST1:
T←1C;
WR10←0C;
TEST2:
LU←(NEXTTEST)ANDT;
GOTO[TEST3,ALU#0];
WR11←T;
TASK;
T←LSH[WR11,1];
WR10←(WR10)+1,GOTO[TEST2];
TEST3:
LU←(TESTRUN)ANDT;
GOTO[TEST4,ALU=0];
NEXTTEST←LSH[NEXTTEST,1];
T←40C;
WR10←(WR10)+T;
T←F.2;
TASK,WR10←(WR10)OR(T);
T←FTASK.1;
WR10←(WR10)OR(T);
APCTASK&APC←WR10;
RETURN;
TEST4:
NEXTTEST←LSH[NEXTTEST,1],GOTO[TEST];
TEST5:
NEXTTEST←1C,GOTO[TEST];
TEST6:
LOADPAGE[F];
GOTOP[EN0];

************************************************************************************************
*** This is the Task 5 firmware. It Initializes the UTVFC, loads the data buffers and generates
*** the Verticle sync pulse. It also accumulates the serial Keyboard data.

TITLE[ TASK FIRMWARE];
SET TASK[RTASK];
SET[RTASK.2,LSHIFT[RTASK,4]];

**************** Macros and Set Values ****************

SET[CLKCR,0];
* Control Register number
SET[CLKSTART,1];
* Buffer Starting Address Register number
SET[HORZLOAD,2];
* Horizontal Control Ram Register number
SET[CLKIAR,3];
* Inactive Address Register number
SET[CLKCUR0CR,4];
* Curser 0 Control Register number
SET[CLKCUR1CR,5];
* Curser 1 Control Register number
SET[CUR0WE,6];
* Curser 0 Meomory Register number
SET[CUR1WE,7];
* Curser 1 Meomory Register number

MC[HECOUNT,400];
* The number of Horizontal Ram locations
MC[LINESU,400];
* Number of scan lines per frame (upper byte)
MC[LINESL,256];
* Number of scan lines per frame (lower byte)
MC[VST,22];
* Verticle Sync Pulse width (in scan lines)
MC[UTVCSB,100];
* Controller Status Block Address (lower half)

**************** R-Registers ****************

RV[IOCB,20];
* IOCB word #0 (low half of Memory Buffer Address)
RV[IOCB1,21];
* IOCB word #1 (high half of Memory Buffer Address)
RV[BUFP,20];
* IOCB word #0 (low half of Memory Buffer Address)
RV[BUFP1,21];
* IOCB word #1 (high half of Memory Buffer Address)
RV[NIOCB,22];
* IOCB word #2 (short pointer to next IOCB)
RV[LINESTORUN,23];
* IOCB word #3 (number of Lines in this Buffer)

RV[WR0,24];
* Memory addressing register (low half)
RV[WR1,25];
* Memory addressing register (high half)

RV[CREG,26];
* UTVFC control word register
RV[DEVICE,27];
* Used to keep track of terminals
RV[LINECOUNT,30];
* Used to count horizontal scan lines

RV[FCMSGU,32];
* Used to Accumulate serial back channel data (upper half)
RV[FCMSGL,33];
* Used to Accumulate serial back channel data (lower half)

RV[CURC,31];
* Curser control word
RV[CUREG,34];
* Curser position Y
RV[CUREG1,35];
* Curser position X

RV[STP,36];
* Used for branch selection
RV[TEMP,37];
* A general purpose register

***********************************************************************************************
*** Driver Routine

ON PAGE[RPAGE1];

ENTRY:
TASK;
ENTRY1:
NOP;
ENTRY2:
DISPATCH[STP,15,3];
DISP[DISP0];

DISP0:
GOTO[VS0L],IOCB←UTVCSB,AT[RPAGE1.1,100];
GOTO[VS0T16L],LU←(LINECOUNT)-(VST),AT[RPAGE1.1,101];
GOTO[VS16L],CREG←(CREG)AND(367C),AT[RPAGE1.1,102];
GOTO[VS17L],T←(DEVICE) OR (4C), AT[RPAGE1.1,103];
GOTO[VS0D], IOFETCH20[IOCB,ADD[RTASK.2,10],0], AT[RPAGE1.1,104];
GOTO[EXIT], IOFETCH20[IOCB,ADD[RTASK.2,11],0], AT[RPAGE1.1,105];
GOTO[EXIT], IOFETCH20[IOCB,ADD[RTASK.2,12],0], AT[RPAGE1.1,106];
GOTO[EXIT], IOFETCH20[IOCB,ADD[RTASK.2,13],0], AT[RPAGE1.1,107];

VS0L:
IOCB1←0C;
TASK,CURC←2000C;
PFETCH4[IOCB,WR0,0];* GET POINTER TO IOCB
WR0←WR0;
STP←1C;
PFETCH4[WR0,IOCB,0];* GET IOCB
LU←LDF[FCMSGL,10,1];
GOTO[VS0L1,ALU=0]; * SEE IF WE POSTED THE MSG
FCMSGU←0C;
VS0L1:
CREG←(CREG)XOR(4C);
CREG←(CREG)OR(32C);
WR0←UTVCSB;
CALL[ACCU],LINECOUNT←0C;
PSTORE1[WR0,CREG,2];
OUTPUT[CREG,CLKCR];
PFETCH2[WR0,CUREG,6];
GOTO[EXIT],LINESTORUN←(LINESTORUN)-1;
VS0T16L: GOTO[VS0T16L1,ALU#0];
STP←2C;
VS0T16L1: LU←LDF[FCMSGL,10,1];
GOTO[VS0T16L2,ALU=0]; * SEE IF WE POSTED THE MSG
FCMSGU←0C;
VS0T16L2: NOP;
CALL[ACCU],OUTPUT[CREG,CLKCR];
GOTO[EXIT],LINESTORUN←(LINESTORUN)-1;
VS16L:
LU←LDF[FCMSGL,10,1];
GOTO[VS16L1,ALU=0]; * SEE IF WE POSTED THE MSG
FCMSGU←0C;
VS16L1:
STP←3C;
CALL[ACCU],OUTPUT[CREG,CLKCR];
GOTO[EXIT],LINESTORUN←(LINESTORUN)-1;
VS17L:
STP←T;
CREG←(CREG) AND (347C);
OUTPUT[CREG,CLKCR], GOTO[ENTRY2];
VS0D:
IOCB←(IOCB)+(20C);
T←CUREG;
LU←(LINECOUNT)-(T);
GOTO[UTV0CURSER,ALU>=0],T←37C;
GOTO[UTV0NOCURSER],TEMP←40C;
VS0D1:
IOFETCH20[IOCB,ADD[RTASK.2,10],0];
LU←LDF[FCMSGL,10,1];
GOTO[VS0D2,ALU=0]; * SEE IF WE POSTED THE MSG
FCMSGU←0C;
VS0D2:
IOCB←(IOCB)+(20C);
CALL[ACCU],IOFETCH20[IOCB,ADD[RTASK.2,10],0];
IOCB←(IOCB)+(20C);
IOFETCH20[IOCB,ADD[RTASK.2,10],0];
IOCB←(IOCB)-(60C);
GOTO[EXIT],LINESTORUN←(LINESTORUN)-1;
UTV0CURSER: LU←(LDF[CURC,0,5])-(T);
GOTO[UTV0NOCURSER,ALU=0],TEMP←40C;
T←CURC;
TEMP←T;
T←CUREG1;
TEMP←(TEMP)OR(T);
OUTPUT[TEMP,CLKCUR0CR];
CURC←(CURC)+(4000C),GOTO[VS0D1];
UTV0NOCURSER: OUTPUT[TEMP,CLKCUR0CR],GOTO[VS0D1];

*** Subroutine ACCU
ACCU:
T←100000C,GOTO[ACCU2,IOATTEN];
T←0C;
ACCU2:
LU←LDF[FCMSGU,17,1];
GOTO[ACCU0,ALU=0];
ACCU1:
FCMSGL←RSH[FCMSGL,1];
FCMSGL←(FCMSGL)ORT,RETURN;* MERGE BIT
ACCU0:
FCMSGU←RSH[FCMSGU,1];
FCMSGU←(FCMSGU)ORT; * MERGE BIT
RETURN,FCMSGL←100000C;

EXIT:
GOTO[NEXT,ALU=0],T←LINESU;
EXIT1:
TEMP←LINESL;
T←TEMP←(TEMP)OR(T);
LU←(LINECOUNT)-(T);
GOTO[EXIT4,ALU>=0];
EXIT2:
LU←LDF[FCMSGU,17,1];
GOTO[EXIT5,ALU=0],LINECOUNT←(LINECOUNT)+1;
LU←LDF[FCMSGU,0,1];
GOTO[EXIT3,ALU=0], LU←LDF[FCMSGL,10,1];
GOTO[EXIT6,ALU=0];
NOP;
EXIT3:
FCMSGL←(FCMSGL) OR (200C);
PSTORE2[WR0,FCMSGU,4];
EXIT5:
GOTO[ENTRY],IOSTROBE;
EXIT6:
GOTO[ENTRY],IOSTROBE;
EXIT4:
STP←0C,GOTO[EXIT2];
NEXT:
PFETCH4[NIOCB,IOCB,0];
T←LINESU,GOTO[EXIT1];

RUNEN0:
CALL[INITIALIZE],AT[RPAGE.1,0];
NOP;
CALL[CURSERW];
NOP;
CALL[INITIALIZE];
WR0←0C;*ADDRESS
LINESTORUN←12C;
CALL[HEWRT],IOCB1←0C;
LINESTORUN←123C;
CALL[HEWRT],IOCB1←4C;
LINESTORUN←10C;
CALL[HEWRT],IOCB1←0C;
LINESTORUN←1C;
CALL[HEWRT],IOCB1←2C;
LINESTORUN←103C;
CALL[HEWRT],IOCB1←0C;
LINESTORUN←1C;
CALL[HEWRT],IOCB1←1C;
LINESTORUN←124C;
CALL[HEWRT],IOCB1←0C;
LINESTORUN←1C;
CALL[HEWRT],IOCB1←10C;
LINESTORUN←1C;
CALL[HEWRT],IOCB1←0C;
LINECOUNT←0C;
CURC←2000C; * CURC=CURSER COUNT
FCMSGL←0C;
STP←0C; * STATEPOINTER
FCMSGU←0C; * FCMSGU&FCMSGL= MSG
WR0←0C;
OUTPUT[WR0,CLKSTART];
OUTPUT[WR0,CLKIAR];
WR0←(WR0)OR(140000C);
OUTPUT[WR0,CLKSTART]; * SET DB POINTER TO 0 (HEX)
CALL[UTVRETURN]; * UPASSMSGL=SAVE LAST MSG
LOADPAGE[RPAGE1];
GOTOP[ENTRY2];

*** Subroutine UTVRETURN
UTVRETURN: WR1←2C;
OUTPUT[WR1,CLKCR];* WR1 REG = ENABLE OSC(WAKEUP IS SET)
T←F.2;
WR1←FTASK.1;
WR1←(WR1)OR(T);
APCTASK&APC←WR1;
RETURN;

*** Subroutine NIBCLK
NIBCLK:
USECTASK;
T←GETRSPEC[143];
FCMSGU←T;
CREG←LSH[CREG,2];
NIBCLK1: DEVICE←(DEVICE)OR(200C);
OUTPUT[DEVICE,CLKCR];
CREG←(CREG)-1;
GOTO[NIBCLK1,ALU#0];
APCTASK&APC←FCMSGU;
RETURN;

*** Subroutine HEWRT
HEWRT:
USECTASK;
T←GETRSPEC[143];
CURC←T;
WR1←0C;
OUTPUT[WR1,CLKSTART];
CALL[NIBCLK],CREG←2C;* 2 NIBCLK
WR1←(WR1)OR(140000C);
OUTPUT[WR1,CLKSTART];
WR1←0C;
HEWRT1:
T←WR0;
LU←(WR1)XOR(T);
GOTO[HEWRT3,ALU#0];
OUTPUT[IOCB1,HORZLOAD];
LINESTORUN←(LINESTORUN)-1;
GOTO[HEWRT2,ALU=0],WR0←(WR0)+1;
NOP;
HEWRT3:
WR1←(WR1)+1;
CALL[NIBCLK],CREG←1C;* 1 NIBCLK
GOTO[HEWRT1];
HEWRT2:
APCTASK&APC←CURC;
RETURN;

*** Subroutine INITIALIZE
INITIALIZE: USECTASK;
T←GETRSPEC[143];
LINECOUNT←T;
DEVICE←0C;
OUTPUT[DEVICE,CLKCR];
CREG←1C;
CALL[NIBCLK];* CLEAR SWITCH IF SET
IOCB1←0C; * PATTERN=0
LINESTORUN←HECOUNT; * COUNT
CALL[HEWRT],WR0←0C;* CLEAR ALL HEVENTS CONTROL SET
IOCB1←7C; * PATTERN=SWITCH,HS,ML
LINESTORUN←1C; * COUNT
CALL[HEWRT],WR0←0C; * ADDRESS
IOCB1←0C; * PATTERN=0
LINESTORUN←1C; * COUNT
CALL[HEWRT],WR0←0C; * ADDRESS
APCTASK&APC←LINECOUNT;* CONTROL PHASE S/B LOW
RETURN;


*** Subroutine CERSERW
CURSERW: USECTASK;
T←GETRSPEC[143];
LINECOUNT←T;
WR0←0C;* ADDRESS
LINESTORUN←400C;* COUNT
CALL[HEWRT],IOCB1←14C;
WR0←15C;
IOCB1←2000C;
IOCB←374C;
T←1400C;
IOCB←(IOCB)OR(T);
CURSERW1: T←IOCB;
LINESTORUN←T;
CURSERW2: T←LINESTORUN;
NIOCB←T;
T←IOCB1;
NIOCB←(NIOCB)OR(T);
OUTPUT[NIOCB,CLKCUR0CR];
OUTPUT[NIOCB,CLKCUR1CR];
CALL[NIBCLK],CREG←1C;* 1 NIBCLK
OUTPUT[WR0,CUR0WE];
OUTPUT[WR0,CUR1WE];
LINESTORUN←(LINESTORUN)-(4C);
LU←LINESTORUN;
GOTO[CURSERW2,ALU>=0];
IOCB1←(IOCB1)+(4000C);
CURSERW3: WR0←(WR0)XOR(17C);
T←LDF[IOCB1,0,5];
GOTO[CURSERW1,ALU#0];
APCTASK&APC←LINECOUNT;
RETURN;

END;