 IDENT LEDIT VERSION D
* LEDIT - SMALL, RECORD ORIENTED TEXT EDITOR - OCT 2008 - V1D
*         ADAPTED TO RUN UNDER DOM.
*
* LEDIT WAS WRITTEN TO RUN WITH ONE OF THE STANDARD P800 MONITORS, WHICH
* PROVIDED THE IO. THIS VERSION IS CHANGED IN SUCH A WAY THAT IT CAN RUN AS
* A STAND ALONE PROGRAM, TO BE A TEST FOR THE P860 SIMULATOR AND ALL ITS
* SUPPORTED PERIPHERALS.
*
* THE FOLLOWING PERIPHERALS ARE SUPPORTED:
* - TTY (KEYBOARD/PRINTER)          EDITOR CONTROL, RECORD INPUT/PRINT
* - PTR (PAPER TAPE READER)         RECORD INPUT
* - CRD (CARD READER)               RECORD INPUT
* - PTP (PAPER TAPE PUNCH)          RECORD OUTPUT
* - LPT (LINE PRINTER)              PRINTING
*
* TTY,PTR AND PTP ARE CONNECTED TO THE PROGRAMMED IO CHANNEL; THE CARD READER
* AND LINE PRINTER ARE CONNECTED TO A MULTIPLEX CHANNEL.
*
* THE SIMULATED CARD READER USES 16 BITS TO STORE CHARACTER CODES. FOR THE 
* REAL CARD READER THE CHARACTERS ARE CODED IN 12 BIT HOLLERITH, WHICH CODES
* ARE STORED IN THE LOWEST 12 BIT OF THE 2 BYTE CHARACTERS OF THE SIMULATED
* READER. THE UTILITY '2CDR.PL' CONVERTS A TEXT FILE TO CARD FILE FORMAT
* (WITH A .CRD EXTENSION). THIS UTILITY EITHER CONVERTS ASCII CHARACTER CODES
* TO 2 BYTE 12-BIT HOLLERITH CHARACTER CODES OR TO 2 BYTE 8-BIT ASCII CODE.
* SO FOR BOTH TYPES OF CONVERSION, THE SIMULATED CARD READER HAS TO HANDLE
* 16 BIT FOR EACH CHARACTER; FOR THE 2ND TYPE HOWEVER THE CONVERSION IS
* EASIER. BECAUSE THE SIMULATED CARDREADER IS CONNECTED VIA A MULTIPLEX
* CHANNEL, ITS NEEDS WORD TRANSFER TO MOVE THE CHARACTERS FROM THE CARDREADER
* CONTROL UNIT TO MEMORY. THIS PROGRAM USES THE 2ND TYPE OF CARD CHARACTER
* CODES, SO DOES NOT NEED THE HOLLERITH=>ASCII CONVERSION (THIS BECAUSE
* THE MAIN GOAL OF THE CARD READER SUPPORT IN THIS PROGRAM IS TO TEST THE
* MULTIPLEX WORD INPUT LOGIC).
*
****************************************************************************
* PHILIPS P800 16 BIT COMPUTER SOFTWARE.
* THE PROGRAM IS CREATED BY: THEO ENGEL (THEO.ENGEL@HETNET.NL)
****************************************************************************
*
* USAGE
* =====
* THE FOLLOWING COMMANDS ARE SUPPORTED BY MEANS OF THE TTY:
* (WHEN # IS PRINTED ON THE TTY, A COMMAND IS EXPECTED; WHEN A . (DOT) IS
* PRINTED ON THE TTY, A RECORD NUMBER IS EXPECTED).
* 1) R[A|P|C] <LN>
*    INPUT RECORDS, STARTING AT RECORD <LN> (LINE NUMBER), WHERE 'A' MEANS
*    READING FROM THE TTY, 'P' READING FROM PTR AND 'C' READING FROM THE
*    PUNCHED CARD READER. READING STOPS WHEN THE 1ST TWO CHARACTERS OF A READ 
*    RECORD CONTAIN THE CHARACTER COMBINATION :E (WHICH ARE THE 1ST TWO 
*    CHARACTERS OF AN :EOS (END OF SEGMENT) OR :EOF (END OF FILE) SIGN. 
*    TAB EXPANSION IS SUPPORTED FOR TTY AND PTR INPUT RECORDS ('\' IS THE TAB
*    CHARACTER). MAXIMUM (EXPANDED) INPUT RECORD LENGTH IS 130 CHARACTERS.
* 2) P[A|U|P| ] <LNS> <LNE>
*    OUTPUT RECORDS, STARTING WITH RECORD NUMBER <LNS> AND ENDING WITH
*    RECORD NUMBER <LNE>, WHERE 'A' MEANS THAT THE OUTPUT IS PRINTED ON THE TTY,
*    'U' THAT OUTPUT IS PUNCHED ON THE PAPER TAPE PUNCHER, 'P' THAT OUTPUT IS
*    PRINTED ON THE LINE PRINTER, AND ' ' (SPACE) THAT OUTPUT IS ALSO PRINTED
*    ON THE LINE PRINTER BUT WITHOUT LINE NUMBERS. PUNCHED OUTPUT CAN BE READ 
*    FOR INSTANCE BY THE ASSEMBLER.
* 3) / <LN>
*    DELETE RECORD WITH RECORD NUMBER <LN>
* 4) = <LN>
*    REPLACE RECORD WITH RECORD NUMBER <LN>
* 5) < <LN>
*    INSERT RECORD BEFORE RECORD NUMBER <LN>
* 5) ? <LN>
*    PRINT SINGLE RECORD WITH RECORD NUMBER <LN> ON CONSOLE (TTY)
* 7) T[A|F|X|<OTHER>]
*    SET TABS: 'A' FOR RECORDS FORMATTED FOR THE ASSEMBLER, 'F' FOR RECORDS 
*    FORMATTED FOR THE FORTRAN COMPILER, 'X' FOR SOME TEXT FORMAT. ANY OTHER 
*    CHARACTER REMOVES ANY TAB SETTING.
* 8) #
*    PACKS THE TEXT BUFFER; WHEN RECORDS ARE DELETED, ALL RECORDS GET A 
*    CONSECUTIVE RECORD NUMBER.
* 9) $[Y|E]
*    THE $ CONFIRMED WITH A 'Y' DELETES ALL RECORDS FROM THE TEXT BUFFER AND
*    REINITIALIZES THE EDITOR TO RECEIVE NEW RECORDS.
*    THE $ CONFIRMED WITH A 'E' STOPS THE EDITOR.
*
* SOME COMMANDS CAN BE REPEATED BY TYPING A '.' (DOT) WHEN A NEXT COMMAND IS 
* EXPECTED. THE PREVIOUS COMMAND IS EXECUTED THEN, WHILE THE LINE NUMBER IS
* INCREMENTED WITH 1. THESE COMMANDS ARE: /, =, <, ? (THE REPEAT COMMAND
* ITSELF CAN ALSO BE REPEATED).
*
 EJECT
 RF TEXT TO START ADDRESS
* GENERATION DATA
* MAXIMUM CORE = 16K WORDS!; MAXIMUM NUMBER OF RECORDS IS 1000 [0..999]
HCOR EQU /7FFE 16K
MAXL EQU 500 500 RECORDS DEFAULT [0..499]
*
TX1TAB DATA /030A TEXT TAB'S: 10,20,50
 DATA /1432
ASMTAB DATA /0308 ASSEMBLER TAB'S: 8,20,41
 DATA /1429
FORTAB DATA /0107 FORTRAN TAB'S: 7
NOTAB EQU 0 NO TAB SETTING
* DEFAULT TAB SETTING: EITHER NOTAB, ASMTAB, FORTAB, OTHER
DEFTAB EQU ASMTAB
*
TOPCOR EQU HCOR-2
MAXL2 EQU MAXL+MAXL NUMBER OF RECORDS * 2
LTABM EQU TOPCOR-MAXL2
LTAB EQU LTABM+2 RECORD POINTER TABLE
CHAD EQU A9 CHARACTER ADDRESS
RENU EQU A10 LINE NUMBER
NULL EQU A11 0
WA EQU A12 WRITE CHAR TO TTY
RA EQU A13 READ CHAR FROM TTY
LST EQU A14 LINKSTACK POINTER
 EJECT
* -- COMMAND TABLE
N EQU 18 NUMBER OF COMMANDS * 2
NN EQU -N NUMBER OF COMMANDS * 2 NEGATIVE
*
CTAB DATA '$ ' KILL
 DATA 'R ' READ
 DATA 'P ' WRITE
 DATA '/ ' DELETE
 DATA '= ' REPLACE
 DATA '? ' CONSOLE
 DATA 'T ' TABS
 DATA /3C00 < INSERT
 DATA '# ' PACK 
*
JTAB DATA KILL
 DATA READ
 DATA WRITE
 DATA DELETE
 DATA REPLAC
 DATA CONS
 DATA TAB
 DATA INSERT
 DATA PACK
 EJECT
* -- INIT
TEXT INH
 MLK 14
 RES 7 LINKSTACK
LSTK RES 1
 DATA BCOR A9-CHAD (CHARACTER ADDRESS IN TEXT BUFFER)
 DATA 0 A10-RENU (LINE NUMBER = POINTER INTO LINE TABLE)
 DATA 0 A11-NULL 
 DATA WASR A12-WRITE CHARACTER TO TELETYPE
 DATA RASR A13-READ CHARACTER FROM TELETYPE
 DATA LSTK A14-LINKSTACKPOINTER
 RF INIBUF INIT BUFFER
*
* -- COMMAND LOOP
CI CF LST,NLCR
 LDK A6,0
 ST A6,LPRFLG RESET LINEPRINTER FLAG
 LDK A6,'#'
 CFR LST,WA WASR: SHOW PROMPT
 CFR LST,RA RASR => COMMAND INTO A6
 CCK A6,'. ' REPEAT ?
 RF(0) REPEAT YES
 ST A6,LAST SAVE COMMAND FOR REPEAT
 LDKL A1,NN COMMAND COUNTER
NEXT CC A6,CTAB+N,A1 COMPARE COMMAND WITH TABLE
 ABI(0) JTAB+N,A1 JUMP OVER TABLE
 ADK A1,2 CHECK NEXT COMMAND
 RB(0) CI NO VALID COMMAND FOUND
 RB NEXT
 EJECT
* -- INITIALIZE MEMORY
*
KILL LDK A6,'?'
 CFR LST,WA WASR
 CFR LST,RA RASR
 CCK A6,'Y '
 RF(0) INIBUF KILL !
 CCK A6,'E ' EXIT ?
 RB(4) CI NO
* EXIT
 ENB
 LKM\\EXIT TO MONITOR
 DATA 3
 HLT
*
* -- KILL
* -- INITIALIZE THE TEXT BUFFER
INIBUF LDKL A1,BCOR BUFFER START
 LDR CHAD,A1 INIT CHAD
KL STR NULL,A1 STORE NULL
 ADK A1,2
 CWK A1,TOPCOR
 RB(5) KL
 RB CI
 EJECT
* -- REPEAT LAST COMMAND: VALID FOR CONSOLE PRINT, DELETE, INSERT AND REPLACE
*
REPEAT ADKL RENU,2 NEXT LINE
 CWK RENU,MAXL2 CHECK NEW RENU
 RB(6) CI
 LDKL A1,0
LAST EQU *-2 LAST COMMAND
 CCK A1,'/ ' DELETE ?
 RF(0) DELETE+4
 CCK A1,/3C00 INSERT ?
 RF(0) INSERT+4
 CCK A1,'= ' REPLACE ?
 RF(0) REPLAC+4
 CCK A1,'? ' CONSOLE ?
 ABL(0) CONS+4
 RB CI
 EJECT
* -- DELETE RECORD
*
DELETE CF LST,LRENU READ LINENUMBER TO RENU (A10)
 ST NULL,LTAB,RENU CLEAR RECORD POINTER
 RB CI
*
* -- INSERT RECORD
*
INSERT CF LST,LRENU  READ LINENUMBER TO RENU (A10)
 MLK 3
 DATA TOPCOR
 DATA TOPCOR-2
 DATA LTAB
 ADR A3,RENU RECORD POINTER INTO RECORD TABLE
IL CWR A1,A3 
 RF(0) REPLAC+4 INPUT RECORD
 LDR* A4,A2 SHIFT RECORDS ABOVE NEW ONE
 STR A4,A1
 SUK A1,2
 SUK A2,2
 RB IL
*
* -- PACK
*
PACK LDKL A1,LTAB TABLE POINTER
PL LDR* A2,A1 TABLE ENTRY ZERO?
 RF(0) PC ZERO ENTRY FOUND; A1=POINTER
PT ADK A1,2
 CWK A1,TOPCOR
 RB(5) PL CHECK NEXT TABLE ENTRY
 RB CI END OF TABLE
* ZERO TABLE ENTRY; LOOK FOR A NON ZERO ONE
PC LDR A3,A1
 LDR* A2,A3
 RF(4) PNZ NON ZERO ENTRY FOUND; A3=PONTER
 ADK A3,2
 CWK A3,TOPCOR
 RB(5) PC+2
CIT RB CI NO NONZERO TABLE ENTRY
* NON ZERO TABLE ENTRY FOUND (A3=POINTER) AFTER A ZERO ENTRY; CHANGE
PNZ STR A2,A1 NONZERO ENTRY; STORE CONTENT IN ZERO ENTRY
 LDK A2,0 
 STR A2,A3 MAKE FOUND NONZERO ENTRY ZERO
 RB PT
 EJECT
*
* -- READ RECORDS UNTIL :E[OS|OF]
*
READ CFR LST,RA RASR
 CCK A6,'A '
 RF(0) TEL FROM TELETYPE
 CCK A6,'P '
 RF(0) PTAP FROM PAPERTAPE (PTR)
 CCK A6,'C '
 RF(0) CARD FROM CARD READER (CRD)
 RB CI
*
* -- PAPERTAPE
*
PTAP LDKL A1,RHSR PAPERTAPE READ
 ST A1,BYTEIN SET INPUT ROUTINE SWITCH
 CF LST,LRENU READ LINE NUMBER
 CF LST,NLCR
RIL CF LST,RLINE READ RECORD
 LD A1,ISTAT STATUS ?
 RB(4) CIT :EOF, :EOS, ERROR (OR END OF TAPE)
 ADKL RENU,2 RENU=RENU+2, NEXT LINE
 CWK RENU,MAXL2
 RB(6) CIT >=
 RB RIL
*
* -- CONSOLE
*
TEL LDKL A1,RASR CONSOLE READ
 RB PTAP+4
*
* -- CARD READER
*
CARD LDKL A1,RCRD READ FROM CARD READER
 RB PTAP+4
 EJECT
* -- REPLACE
*
REPLAC CF LST,LRENU READ LINE NUMBER
 CF LST,NLCR
 LDK A6,' '
 CFR LST,WA WASR
 CFR LST,WA WASR 
 CFR LST,WA WASR 
 CFR LST,WA WASR
* PRINT 4 BLANKS
 LDKL A1,RASR TELETYPE READ
 ST A1,BYTEIN SET INPUT ROUTINE SWITCH
 CF LST,RLINE READ LINE
CIT1 RB CIT
*
* -- CHANGE TAB SETTING
TAB CFR LST,RA RASR
 CCK A6,'A '
 RF(0) TA
 CCK A6,'F '
 RF(0) TF
 CCK A6,'X '
 RF(0) T1
 LDK A1,NOTAB
TS ST A1,TABTAB
 RB CIT
*
* ASSEMBLER TAB'S
TA LDKL A1,ASMTAB
 RB TS
* FORTRAN TAB'S
TF LDKL A1,FORTAB
 RB TS
* TEXT TAB'S
T1 LDKL A1,TX1TAB
 RB TS
 EJECT
* -- WRITE/PRINT RECORDS FROM <LNS> TO <LNE>
*
WRITE CFR LST,RA RASR READ DESTINATION CHARACTER
 ST A6,SA6 AND SAVE : A,U,P,..
 CF LST,LRENU START LINE NUMBER <LNS>
 CF LST,DEC END LINE NUMBER <LNE>
 LDKL A6,0 OUTPUT DEVICE: A,U,P,..
SA6 EQU *-2
END EQU *-2
 ST A1,END SAVE END LINE NUMBER <LNE>
 CCK A6,'U ' TEST DESTINATION
 RF(0) PUNCH PUNCH PAPERTAPE ON PTP
 CCK A6,'A '
 RF(0) LIST LIST ON TTY
 CCK A6,'P '
 RF(0) PRINT LIST ON LPT
 CCK A6,'  '
 RF(0) PRINTX LIST ON LPT WITHOUT LINENUMBERS
 RB CIT
*
* -- LIST ON LINEPRINTER
PRINT CF LST,SLP SELECT LINE PRINTER OUTPUT AND START ON NEW PAGE
PRL LDKL A5,BUFO+2 RESET BUFFER POINTER
 CF LST,PRENU RENU TO PRINT BUFFER
 CF LST,PLINE RECORD TO PRINT BUFFER
 CW RENU,END RENU <LNE> ?
 RB(6) CIT1 >=
 ADKL RENU,2 RENU=RENU+2
 RB PRL
*
* -- OUTPUT SINGLE RECORD ON CONSOLE
CONS CF LST,LRENU  READ LINENUMBER TO RENU (A10)
 ST NULL,END END = 0
*
* -- LIST ON CONSOLE
LIST CF LST,NLCR
 LDKL A1,WASR SELECT CONSOLE OUTPUT
 ST A1,BYTOUT
 RB PRL
*
* -- PUNCH (NO LINENUMBERS)
PUNCH LDKL A1,PHSP SELECT PTP OUTPUT
 ST A1,BYTOUT
 CF LST,LDTR PUNCH LEADER
PUL LDKL A5,BUFO+2
 CF LST,PLINE RECORD TO PUNCH BUFFER
 ADKL RENU,2 RENU=RENU+2
 CW RENU,END RENU <LNE> ?
 RB(5) PUL
 CF LST,LDTR PUNCH TRAILER
 RB CIT1
*
* -- PRINT ON LINEPRINTER WITHOUT LINENUMBERS
PRINTX CF LST,SLP SELECT LINE PRINTER OUTPUT AND START ON NEW PAGE
PRLX LDKL A5,BUFO+2 RESET BUFFER POINTER
 CF LST,PLINE RECORD TO PRINT BUFFER
 ADKL RENU,2 RENU=RENU+2
 CW RENU,END RENU <LNE> ?
 RB(5) PRLX
 RB CIT1
 EJECT
*************************************************************************
* BASIC IO SUBROUTINES (PROGRAMMED CHANNEL)                             *
*************************************************************************
* ASSIGNMENTS
ASR EQU /10 DEV ADDR
HSR\EQU\/20\DEV ADDR
HSP\EQU\/30\DEV ADDR
S\EQU\1\START
H\EQU\0\HALT
*
* WASR--OUTPUT ASCII FROM A6 TO TELETYPE
*       STATUS TO A7
*
WASR\LDK\A7,0\SELECT OUTPUT MODE
\CIO\A7,S,ASR
\RB(4)\*-2
\OTR\A6,0,ASR\OUTPUT CHAR
\RB(4)\*-2
\CIO\A7,H,ASR\STOP
\SST\A7,ASR
\RB(4)\*-2
\RTN\LST
*
* RASR--INPUT ASCII TO A6 FROM TELETYPE
*       STATUS TO A7
*
RASR\LDK\A7,1\SELECT INPUT MODE
\CIO\A7,S,ASR
\RB(4)\*-2
\INR\A6,0,ASR\INPUT CHAR
\RB(4)\*-2
\ANK\A6,/7F\MASK 7 BITS
\CIO\A7,H,ASR\STOP
\SST\A7,ASR
\RB(4)\*-2
\CCK\A6,/0D20
\RF(4)\*+6
\LDK\A6,/0A\REPLACE CR BY LF
\CFR\LST,WA\AND PRINT THE LF
\RTN\LST
*
* NLCR--PRINT NLCR ON TELETYPE
*
NLCR\LDKL\A6,/0D0A\NLCR
\CFR\LST,WA WASR
\ECR\A6,A6
\CFR\LST,WA WASR
\RTN\LST
*
* RHSR--READ OCTAD TO A6 FROM PTR
*       STATUS TO A7
*
RHSR\CIO\A7,S,HSR
\RB(4)\*-2
TI\SST\A7,HSR
\RF(4)\IN\NOT ACCEPTED
\RTN\LST\ACCEPTED:END OF TAPE OR ERROR
IN\INR\A6,0,HSR\INPUT CHAR
\RB(4)\TI
\CIO\A7,H,HSR\STOP
\SST\A7,HSR
\RB(4)\*-2
\RTN\LST
*
* LDTR--PUNCH LEADER/TRAILER ON PTP
*       RETURN: A5,A6=0 A7=STATUS
*
LDTR\LDK\A5,/7F
\LDK\A6,0
\CF\LST,PHSP
\SUK\A5,1
\RB(4)\*-6
\RTN\LST
*
* PHSP--PUNCH OCTAD FROM A6 ON PTP
*       STATUS TO A7
*
PHSP\CIO\A7,S,HSP
\RB(4)\*-2
\OTR\A6,0,HSP\PUNCH
\RB(4)\*-2
\CIO\A7,H,HSP\STOP
\SST\A7,HSP
\RB(4)\*-2
\RTN\LST
\EJECT
*************************************************************************
* BUFFERS + IO ROUTINES FOR BUFFER IO                                   *
*************************************************************************
LPRFLG DATA 0 1 IF PRINT OUTPUT ON LINE PRINTER
BUFA EQU *
BUFO DATA /2020 TEXT OUTPUT BUFFER
BUFI RES 67 TEXT INPUT BUFFER
*
* INPUT CB
ICB DATA BUFI POINTER TO INPUT BUFFER
 DATA 130 MAX REQUESTED RECORD LENGTH
ELI DATA 0 EFFECTIVE RECORD LENGTH
ISTAT DATA 0 RESULTING STATUS
TABTAB DATA DEFTAB DEFAULT TAB SETTING
*
* OUTPUT CB
OCB DATA BUFO OUTPUT BUFFER
RLO DATA 0 REQUESTED RECORD LENGTH
 DATA 0 EFFECTIVE RECORD LENGTH
 DATA 0 STATUS
*
 EJECT
* RLINE -- READ A RECORD AND STORE INTO MEMORY
* SLINE -- STORE A RECORD FROM INPUT BUFFER INTO MEMORY
RLINE CF LST,IREC INPUT RECORD
 LD A2,ELI EFFECTIVE LENGTH
*
* INPUT READY; STORE RECORD INTO MEMORY
SLINE LDK A1,0 CHAR COUNT
 ST CHAD,LTAB,RENU STORE CHAD(A9) AS START OF LINE IN TABLE AT RENU(A10)
 SCR A2,CHAD STORE EFFECTIVE LENGTH OVER CHARACTER ADDRESS (CHAD=A9)
 ADKL CHAD,1
SL CWR A1,A2 END OF RECORD?
 RF(4) *+4
RT RTN LST
 LC A3,BUFI,A1 CHAR FROM BUFFER
 SCR A3,CHAD STORE OVER CHAD(A9)
 CWK CHAD,LTAB-20 END OF MEMORY?
 RF(6) VOL => YES
 ADKL CHAD,1 INCR CHARACTER ADDRESS
 ADK A1,1 INCR CHAR COUNT
 RB SL
* END OF MEMORY
VOL LDK A6,'!'
 CFR LST,WA WASR
 CFR LST,WA WASR
 CFR LST,WA WASR
 ST NULL,LTAB,RENU STORE NULL(A11) IN TABLE FOR RENU(A10)
 ADKL LST,4 ABNORMAL RETURN FROM SUBR
 ABL CI TO COMMAND INPUT
 EJECT
* PLINE -- RECORD TO OUTPUT BUFFER AND OUTPUT
* RENU(A10) = POINTER TO RECORD
* A5 = CHAR POINTER INTO BUFFER
PLINE LD A4,LTAB,RENU POINTER TO RECORD
 RF(5) RPL EMPTY RECORD
 LCR A3,A4 LENGTH
 ANK A3,/FF
 RF(5) RPL
PLL ADK A4,1
 LCR A1,A4 CHAR FROM MEMORY
 SCR A1,A5 INTO BUFFER
 ADK A5,1 INCR OUTPUT BUFFER POINTER
 SUK A3,1 DECR LENGTH; READY?
 RB(1) PLL
*
WLINE SUKL A5,BUFO REQUESTED LENGHT
 ST A5,RLO SET REQUESTED LENGTH
 LD A1,LPRFLG OUTPUT ON LINEPRINTER ?
 RF(0) XXX NO
* FORM FEED IF 1ST TWO CHARS OF LINE ARE '$F'
* REMAINING PART OF THAT LINE IS IGNORED
 LD A1,BUFO+2
 CWK A1,'$F'
 RF(4) PR
 CF LST,SLP DO A FORM FEED
 RTN LST
PR CF LST,LPREC LINEPRINTER
 RTN LST
XXX CF LST,OREC TELETYPE/PUNCHER
RPL RTN LST
*
* SLP--SET LINEPRINTER AND SKIP TO A NEW PAGE
SLP LDK A1,1
 ST A1,LPRFLG SET PRINTING ON LINEPRINTER
 LDKL A1,/0D0C TOP OF FORM
 ST A1,BUFO SET  CONTROL BYTES IN OUTPUT BUFFER
 LDK A1,2
 ST A1,RLO SET REQUESTED LENGTH
 CF LST,LPREC PRINT
 LDKL A1,'  '
 ST A1,BUFO RESET CONTROL BYTES
 RTN LST
 EJECT
* PRENU -- RECORD NUMBER TO OUTPUT BUFFER
* A5 IS POINTER INTO BUFFER
*
PRENU LDR A4,RENU GET RENU(A10)
 LDK A3,0 DIVIDE INDEX
*
CLL LDK A6,0 DIGIT=0
CL LDR A1,A4
 SU A1,DEEL,A3
 RF(2) PCYF
 ADK A6,1 DIGIT=DIGIT+1
 LDR A4,A1
 RB CL
*
PCYF ADK A6,/30 ASCII
 SCR A6,A5
 ADK A5,1
 ADK A3,2
 CWK A3,6
 RB(2) CLL
 LDK A6,/20 SPACE
 SCR A6,A5
 ADK A5,1
 RTN LST
*
DEEL DATA 200 LINE NUMBERS ARE REPRESENTED * 2
 DATA 20
 DATA 2
 EJECT
* DEC -- READ DECIMAL FROM CONSOLE INTO A1
*
DEC LDK A6,'.'
 CFR LST,WA WASR
 LDK A1,0 NUM=0
*
DLC CFR LST,RA RASR
 SUK A6,/30
 RF(2) UIT
 CWK A6,9
 RF(1) UIT
 LDR A5,A1
 SLA A5,2 *4
 ADR A5,A1 *5
 SLA A5,1 *10
 ADR A5,A6 + DEC
 LDR A1,A5 NUM
 RB DLC
*
UIT CWK A1,MAXL
 RF(1) *+6
 SLA A1,1 *2 (ALL NUMBERS * 2)
 RTN LST
 LDK A6,'?'
 RB DEC+2
*
* LRENU -- LINE NUMBER TO RENU
*
LRENU CF LST,DEC
 LDR RENU,A1
 RTN LST
 EJECT
********************************************************************
* RECORD IO, REPLACING MONITOR IO                                  *
********************************************************************
* IREC -- READ RECORD
* HACK TO PROVIDE SOME OF THE MONITOR STANDARD READ FUNCTION FOR TTY AND PTR
* RECORDS END BY FINDING A  <LF> OR HAVING READ THE REQUESTED LENGTH
* CONTROL CHARACTERS <CR> AND <LF> ARE NOT PUT IN THE RECORD BUFFER NOR
* INCLUDED IN THE EFFECTIVE RECORD LENGTH.
* ICB (INPUT CONTROL BLOCK) PROVIDES INPUT PARAMETERS
*
IREC ML 2,ICB A1=BUFFER ADDRESS A2=REQ LENGHT
 LDK A3,0 CHAR COUNT = 0
IB CF LST,RASR READ BYTE TO A6
BYTEIN EQU *-2 CHAR INPUT ROUTINE
 LDR A7,A7
 RF(4) IEND ERROR OR EOT
 LDR A6,A6
 RB(0) IB SKIP NULLS
 CCK A6,/0A20 LINE FEED ?
 RF(0) EOL END OF LINE
 CCK A6,/0D20 CR ?
 RB(0) IB SKIP CR'S
 CCK A6,/5C20 TAB?
 RF(0) CKCTAB
STORE SCR A6,A1 STORE CHAR INTO BUFFER
 ADK A1,1 INCR BUFFER POINTER
 ADK A3,1 INCR CHAR COUNT
 CWR A3,A2 CHAR COUNT NE REQ LENGTH?
 RB(4) IB
EOL LD* A1,ICB 1ST 2 CHARS
 CWK A1,':E'
 RF(4) IEND
 LDK A7,1 :EOF/:EOS
IEND ST A3,ELI EFFECTIVE LENGTH
 ST A7,ISTAT STATUS
 RTN LST
* CHECK TAB SETTINGS AND EXPAND TABS
CKCTAB LD A4,TABTAB
 RB(0) STORE NO TAB SETTING
 LCR A5,A4 NUMBER OF TABS
 ADK A4,1 1ST TAB
 ST A4,PTRTAB
 ANK A5,/FF NUMBER OF TABS
 ST A5,NTABS
 LDK A5,0
NT LC* A4,PTRTAB GET TAB POSITION
 ANK A4,/FF
 SUK A4,1
 CWR A3,A4 COMPARE CHAR POSITION AND TAB POSITION
 RF(2) SETTAB <
 IM PTRTAB
 ADK A5,1
 CW A5,NTABS
 RB(2) NT
 RB STORE
* EXPAND
SETTAB LDK A6,/20 BLANK
NB SCR A6,A1 INTO BUFFER
 ADK A1,1 INCR BUFFER POINTER
 ADK A3,1 INCR CHAR COUNT
 CWR A3,A2 CHAR COUNT EQ REQ LENGTH?
 RB(0) IEND YES
 CWR A3,A4 CHAR POSITION AT TAB POSITION?
 RB(2) NB NO; PUT NEXT BLANK
 RB IB YES, AT TAB POSITION; EXPANSION READY
PTRTAB DATA 0 POINTER TO TABS (STARTING WITH TAB1)
NTABS DATA 0 NUMBER OF TABS
 EJECT
* INPUT A CONVERTED CHARACTER FROM A PUNCHED CARD TO A6; A7 IS STATUS
RCRD MS 2,SRC SAVE A1,A2
 LD A7,CBPTR BUFFER CHARACTER POINTER
 RF(4) GETN GET NEXT CHARACTER
* PTR = 0 => NO CARD => READ CARD
* INPUT A PUNCHED CARD FROM THE CARD READER
CR EQU /06 DEVICE ADDRESS = CHANNEL ADDRESS
RCR EQU CR+CR CHANNEL EXTERNAL REGISTER
 TST A1,CR BUSY?
 RB(4) *-2
 LDK A1,80 LENGTH TO READ IN WORDS
 ORKL A1,/8000 INPUT MODE WORDS
 LDKL A2,BCARD CARD IMAGE BUFFER ADDRESS
 WER A1,RCR LOAD 1ST CHANNEL REGISTER
 WER A2,RCR+1 AND THE 2ND WITH THE BUFFER ADDRESS
 CIO A1,S,CR START IO
 RB(4) *-2
*
 SST A7,CR
 RB(4) *-2 READY?
 LDR A7,A7 STATUS?
 RF(0) *+4
 RF EXRCRD NONZERO; NO CARD?
* LENGTH?
 RER A1,RCR
 ANK A1,/FF
 RF(0) *+4 RECORD INPUT OK; REMOVE TRAILING BLANKS
\HLT\\NO 80 WORDS READ => ERROR
* CARD IMAGE IN BUFFER
* REMOVE TRAILING BLANKS
 LDK A1,158 START COMPARING LAST CHARACTER FOR A BLANK
RTB LD A2,BCARD,A1
 SUK A2,/20 BLANK ?
 RF(4) SRL NON BLANK
 SUK A1,2
 RF(0) SRL EMPTY RECORD
 RB RTB CHECK NEXT
SRL ADK A1,2
 ST A1,RLEN SAVE ACTUAL RECORD LENGTH TO CHECK FOR
* 
* GET NEXT CHARACTER ROUTINE
GETN LD A7,CBPTR CHAR POINTER
 CW A7,RLEN END OF RECORD?
 RF(4) GN
 LDK A6,/0A LF, INDICATION BUFFER END
 LDK A7,0 RESET POINTER TO INDICATE A NEXT CARD READ
 RF GN1
GN LD A6,BCARD,A7 GET CHARACTER
 ADK A7,2 INCR POINTER
GN1 ST A7,CBPTR SAVE POINTER
 LDK A7,0 STATUS OK
EXRCRD MLK 2 RESTORE A1,A2
SRC DATA 0 SAVED A1,A2
 DATA 0
 RTN LST
*
CBPTR DATA 0 CURRENT CHAR POINTER INTO CARD BUFFER
RLEN DATA 0 RECORD LENGTH IN CHARS (TRAILING BLANKS REMOVED)
BCARD RES 80 CARD INPUT BUFFER
 EJECT
* OREC -- OUTPUT RECORD (TELETYPE AND PUNCH)
* HACK TO PROVIDE (PART OF) THE MONITOR STANDARD WRITE FUNCTION:
* 1ST 2 BYTES CONTROL THE CARRIAGE AND ARE IGNORED FOR TTY AND PTP AND.
* AT RECORD END, CR LF ARE INSERTED AFTER THE BUFFER 
* OCB (OUTPUT CONTROL BLOCK) PROVIDES THE OUTPUT PARAMETERS
*
OREC ML 2,OCB A1=BUFFER ADDRESS A2=REQUESTED LENGTH
 LDK A3,/0D PUT CRLF AT THE END  OF THE BUFFER
 LDR A4,A1 BUFFER ADDRESS
 ADR A4,A2 + REQ. LENGTH
 SCR A3,A4
 LDK A3,/0A
 ADK A4,1
 SCR A3,A4
*
 ADK A1,2 SKIP 1ST 2 BYTES (CONTROL CHARS)
 LDK A3,0 MOVED CHAR COUNT = 0
OB LCR A6,A1
 CF LST,WASR
BYTOUT EQU *-2 OUTPUT ROUTINE
CO ADK A1,1 INCR BUFFER POINTER
 ADK A3,1 INCR CHAR COUNT
 CWR A3,A2 CHAR COUNT NE REQ LENGTH?
 RB(2) OB <
 RTN LST
 EJECT
* LPREC -- OUTPUT RECORD (LINEPRINTER)
* HACK TO PROVIDE (PART OF) THE MONITOR STANDARD/BASIC WRITE FUNCTION
* 1ST 2 BYTES IN BUFFER CONTROL THE CARRIAGE (SKIP AFTER PRINT IS ASSUMED).
* REQUESTED LENGTH INCLUDE THE 2 CONTROL BYTES.
* LINEPRINTER WITH ITS CONTROL UNIT IS CONNECTED TO A MULTIPLEX CHANNEL.
* OCB (OUTPUT CONTROL BLOCK) PROVIDES THE OUTPUT PARAMETERS: BUFFER ADDRESS
* AND THE REQUESTED LENGTH (IN CHARACTERS) TO PRINT.
*
LP EQU /07 DEVICE ADDRESS = CHANNEL ADDRESS
RLP EQU LP+LP CHANNEL EXTERNAL REGISTER
*
LPREC TST A1,LP BUSY?
 RB(4) *-2
 ML 2,OCB A1=BUFFER ADDRESS A2=REQUESTED LENGTH
* CHECK CONTROL CHARS; <SPACE><SPACE> (WHICH IS THE STANDARD FOR SKIPPING
* A SINGLE LINE) IS REPLACED BY /0D0A. NO OTHER STANDARD WRITE SKIPPING IS 
* SUPPORTED BY THIS DRIVER. WHEN REQUIRED, HARDWARE RECOGNIZED CONTROL MUST 
* BE INSERTED IN THE 1ST 2 BYTE POSITIONS OF THE BUFFER, AND THE DRIVER
* OPERATES AS BASIC WRITE: 
* - 0D0A SKIPS A SINGLE LINE
* - 0A0A SKIPS 2 LINES
* - 0D0C SKIPS TO TOP OF PAGE
*
 LDR* A3,A1
 CWK A3,/2020
 RF(4) MS
 LDKL A3,/0D0A
 STR A3,A1
* SET MULTIPLEX WORDS (A2 IS LENGTH, A1 IS BUFFER)
MS ORKL A2,/4000 FUNCTION IS CHARACTER OUTPUT
 WER A2,RLP LOAD THE 1ST CHANNEL REGISTER
 WER A1,RLP+1 AND THE 2ND WITH THE BUFFER ADDRESS
 CIO A1,S,LP ACTIVATE
 RB(4) *-2
 SST A7,LP WAIT FOR READY
 RB(4) *-2
 LDR A7,A7
 RF(0) *+6
\HLT\\LINE PRINTER NOT OPERATING PROPERLY
 RB LPREC RETRY
 RTN LST
*
BCOR EQU * START OF POOL
*
 END TEXT
:EOS
:EOF

