Trailing-Edge
-
PDP-10 Archives
-
BB-P363B-SM_1985
-
mcb/drivers/cr.m11
There are no other files named cr.m11 in the archive.
.enabl lc
.title CR CR11 LLC and Driver
.ident "X02070"
; COPYRIGHT (c) 1980, 1981, 1982
; DIGITAL EQUIPMENT CORPORATION
; Maynard, Massachusetts
;
; This software is furnished under a license and may be used
; and copied only in accordance with the terms of such license
; and with the inclusion of the above copyright notice. This
; software or any other copies thereof may not be provided or
; otherwise made available to any other person. No title to
; and ownership of the software is hereby transferred.
;
; The information in this software is subject to change
; without notice and should not be construed as a commitment
; by DIGITAL EQUIPMENT CORPORATION.
;
; DIGITAL assumes no responsibility for the use or reliability
; of its software on equipment which is not supplied by
; DIGITAL.
;
;
;
; This crock was originally foisted upon the unsuspecting
; world in June, 1978 by R. South who was preoccupied
; by travels through the legendary dungeon of Mordatz Idu.
;
; X01010 thru X01170 omitted because following update constituted
; such a major change that previous audit trail
; was rendered meaningless - or at best useless.
;
; X02000 10-June-81 Buren Hoffman
; Extensive modifications to correspond to MCB V3.0,
; and a major facelift to aid maintainability.
;
; X02010 12-June-81 Buren Hoffman
; Fixed old calls to $CCBGT and $CCBRT to use new
; $CBBGT and $CBBRT.
;
; X02020 Added NOOP dispatches for Power-Failure and Initialization
; entries in the Timer Dispatch table.
;
; X02030 1-July-81
; General update to fix numerous bugs found via desk checking.
;
; X02040 8-July-81 Buren Hoffman
; Call TIMPIN on initialization
;
; X02050 16-July-81 Buren Hoffman
; General upgrade to include fixes incorporated into LE.
;
; x02060 10-sept-81 Ron Platukis
; -fix bugs in interrupt and synch level code.
;
; x02070 2-december-81 Ron Platukis
; reduce small buffer size from 80. to 60. bytes.
.sbttl Macro Calls & Dispatch Tables
.mcall NURDF$,CCBDF$,SYNDF$,SCDF$
.mcall PHD$B,DSP$,DSP$B,DSP$E,PUSH$S,POP$S,MAP$,SMAP$,DAT$,END$
NURDF$
CCBDF$
SYNDF$
SCDF$
;+
; Identify us to mcb
;+
PHD$B CR
PHD$D CRMCB
PHD$E
.psect $PLIT$,D,RO
;+
; Dispatch Tables
;-
CRMCB: DSP$B
DSP$ ; Asynchronous trap
DSP$ FC.XME ; Xmit enable
DSP$ FC.RCE ; Receive enable
DSP$ FC.KIL ; Kill
DSP$ FC.CTL,CRCTL ; Control (start / stop)
DSP$ FC.TIM,CRTIM ; Timeout (clock)
DSP$ FC.XCP,CRDONE ; Xmit complete (resource ret)
DSP$ FC.RCP,CRDSP ; Receive complete (arriving data)
DSP$ FC.KCP ; Kill complete
DSP$ FC.CCP ; Control complete
DSP$E
;+
; Control Dispatch
;-
CRCTL: CALLR @1$(R3)
1$: DSP$B
DSP$
DSP$ FM.STR,DVOPEN ; Start device
DSP$ FM.STP,DVCLOS ; Stop device
DSP$E
;+
; Timer Dispatch
;-
CRTIM: CALLR @1$(R3)
1$: DSP$B
DSP$ FM.STM ;Short timer
DSP$ FM.LTM,CLOCK ;Long timer
DSP$ FM.PWF,NOOP ;Power failure
DSP$ FM.PIN,TIMPIN ;Initialization
DSP$E
.sbttl Data Base
;+
; CR Data Base Offsets and Values
;-
DAT$ DSR
C.TIMC: .blkb 1 ; TIMER BYTE
C.NRD: .blkb 1 ; NRD'S PIX
C.CSR: CSR$W ; ONE WORD CSR POINTER
DTXTSZ= 16. ; DATA/FEATURES PROCESS CONTEXT ALLOCATED
C.DTXT: .blkw DTXTSZ ; CONTEXT BLOCK FOR DA/FEATURES PROCESS
C.DTXL: .blkb 1 ; NO. WORDS ON STACK AT SLEEP TIME
.even
C.DFSP: .blkw 1 ; STACK ORIGIN
C.SYN: SYN$X ; SYNCH BLOCK
C.RST: .blkw 1 ; CR11 STATUS READ AT INTERRUPT
C.COLC: .blkb 1 ; PHYSICAL COLUMN COUNT
C.HUNG: .blkb 1 ; DEVICE HUNG TIMER
C.PUBP: .blkw 2 ; BUFFER PTR DOUBLEWORD
C.SGHD: .blkw 1 ; CURRENT SEGMENT HEADER ADDRESS
C.LDAT: .blkw 1 ; LAST DATA ITEM READ
C.PUBS: .blkw 1 ; BUFFER INPUT COUNTER
C.NRDA: .blkw 1 ; BEG OF NURD MESSAGE(ADDRESS)
C.DDMQ: LST$D ; CCB'S QUEUED FOR INPUT
C.ASTS: .blkw 1 ; ACTION STATUS BIT MAP
CA.CLO== 1 ; CLOSED
CA.PAU = 2 ; PAUSED
CA.ADN = 4 ; ABORT WHEN DONE WITH DDM QUEUE
CA.ABO = 10 ; ABORTING
CA.ABE = 20 ; CLEAR ABORT ON EOF (ELSE ON CLEAR)
CA.EOF = 40 ; CURRENT MESSAGE HAS EOF
CA.HOP = 100 ; HOPPER CHECK - EMPTY INPUT OR FULL OUTPUT
CA.MOT = 200 ; MOTION CHECK - PICK, STACK, OR MOTION ERROR
CA.TER = 400 ; TIMING ERROR - DATA OVERRUN CONDITION
CA.ERR= CA.HOP!CA.MOT!CA.TER ; SUMMARY - HARD ERROR
CA.OFL = 1000 ; READER OFFLINE
CA.IVP = 2000 ; INVALID PUNCH - MULTIPUNCH
CA.TMO = 4000 ; DEVICE TIME OUT
CA.syn = 10000 ; synch request in progress flag
CA.XOF = 100000 ; READER XOF'D
C.CDCT: .blkw 1 ; PHYSICAL CARD COUNT
; MISCELLANEOUS ITEMS
C.IOCN: .blkw 1 ; OUTSTANDING IO COUNT
C.IOWT: .blkw 1 ; CLOSE WAIT FLAG = CLOSE CCB
; CONTROL MESSAGE PROCESSING DATA BASE
C.CMSQ: LST$D ; CONTROL MESSAGE QUEUE
C.RECO: .blkb 1 ; CONTROL MESSAGE RESOURCE ERROR FLAG
C.RATT: .blkb 1 ; PENDING ATTENTION MESSAGE FLAG - REASON CODE
C.CAPP: .blkb 1 ; PENDING CAPABILITIES MESSAGE FLAG
C.STRT: .blkb 1 ; PENDING READ START
; DATA & FEATURES PROCESSING DATA BASE
C.DLCQ: LST$D ; CCB'S QUEUED INTO DLC
C.MFLG: .blkb 1 ; CURRENT NURD MESSAGE FLAGS
C.CAPN: .blkb 1 ; CURRENT INDEX INTO CAPABILITIES LIST
C.NFSP: .blkb 1 ; NO. FEATURE SPECS IN CURRENT MSG
.even
C.DMAD: .blkw 2 ; DATA MSG ADDRESS DOUBLEWORD (PTR)
C.DMBS: .blkw 1 ; DATA MSG BUFFER SIZE
C.DMSQ: .blkb 2 ; LAST GOOD, CURRENT DATA SEQ NUMBERS
C.PBRC: .blkb 1 ; TEMP BYTE
.even
C.MSGQ: LST$D ; OUTGOING MSG QUEUE
C.MSGA: .blkw 2 ; CURRENT MSG BUFFER ADDRESS DOUBLEWORD
C.MSGS: .blkw 1 ; CURRENT MSG BUFFER SIZE
; FEATURES
; LP11 COMMON FEATURE LIST
C.CFET: .blkb 1 ; NUMBER OF COMMON FEATURES
.blkb 1 ; FEATURE FE.DAT SUPPORTED
.blkb 1 ; FEATURE FE.SER NOT SUPPORTED
.blkb 1 ; FEATURE FE.LCR NOT SUPPORTED
.blkb 1 ; FEATURE FE.FWD NOT SUPPORTED
.blkb 1 ; FEATURE FE.EOF SUPPORTED
.blkb 1 ; FEATURE FE.DVT NOT SUPPORTED
.blkb 1 ; FEATURE FE.TRN NOT SUPPORTED
.blkb 1 ; FEATURE FE.FNM NOT SUPPORTED
.blkb 1 ; FEATURE FE.DWD SUPPORTED
CCFETL== .-C.CFET-1
C.DFET: .blkb 1 ; NUMBER OF DEVICE SPECIFIC FEATURES
.blkb 1 ; FEATURE 129 NOT DEFINED
.blkb 1 ; FEATURE CD.CWD SUPPORTED
CDFETL== .-C.DFET-1
; FEATURE BLOCKS
F.FSB = 0 ; (BM)FEATURES STATUS BYTE
FB.CL0 = 0 ; CLASS 0 FEATURE => <BIT> FORM
FB.CL1== 1 ; CLASS 1 FEATURE => <CNT><...> FORM
FB.WRD = 2 ; FEATURE IS A WORD AND
; F.FCV IS A DATABASE OFFSET TO IT
FB.STR = 4 ; FEATURE IS A STRING
; F.FCV IS THE LENGTH
; CURRENT VALUE BEGINS AT F.FCV+1
; STANDARD VALUE(IF ANY) BEGINS AT F.FCV+1+(F.FCV)
FB.STE = 10 ; STANDARD VALUE EXISTS
FB.SST = 20 ; STANDARD IS SET
FB.CP = 40 ; CHANGE PENDING
FB.CA = 100 ; CHANGE ALLOWED
F.FCV = 1 ; FEATURE CURRENT VALUE BYTE
F.FSV = 2 ; FEATURE STANDARD VALUE BYTE
; DATA MODE
CR.DAT::.blkb 1
CRDATS== FB.CL1!FB.CA!FB.SST!FB.STE ; INITIAL STATUS OF LE.DOF LE.DAT
.blkb 1 ; ASCII
.blkb 1 ; ASCII IS STD
; EOF RECOGNITION
CR.EOF::.blkb 1
CREOFS== FB.CL1!FB.CA ; INITIAL STATUS OF CR.EOF
.blkb 1
; DEVICE WIDTH
CR.DWD::.blkb 1
.blkb 1 ; STD WIDTH
; DEVICE SPECIFIC FEATURES
; CARD WIDTH
CR.CWD::.blkb 1
CRCWDS== FB.CL1!FB.CA!FB.STE!FB.SST ; INITIAL STATUS OF CR.CWD
.blkb 1
.blkb 1
END$
.psect $CODE$,I,RO
.sbttl Start / Stop Device (FC.CTL)
;+
; Initialize unit
; R4 CCB
; R5 Database address
;-
DVOPEN: PUSH$S R4 ; START DEVICE
MOVB C.PIX(R4),C.NRD(R5) ; SAVE NRD'S PIX
BIT #CA.CLO,C.ASTS(R5) ; CLOSED?
BEQ 11$ ; NO, THEN HOW CAN IT BE OPENED?
CLR @C.CSR(R5) ; BE VERY PESSIMISTIC
MOV #CA.PAU,C.ASTS(R5) ; INIT THE ACTION STATUS WORD
CLR C.PUBP+2(R5) ; FLUSH CURRENT READ BUFFER
CLRB C.DTXL(R5) ; Clear saved context indicator
CLR C.DMAD(R5) ; FLUSH SOURCE BUF IN USE
CLR C.DMAD+2(R5)
CLR C.DMBS(R5)
CLR C.MSGA(R5) ; INIT CURRENT OUT MSG
CLR C.MSGA+2(R5)
CLR C.MSGS(R5)
CLR C.IOCN(R5) ; INIT OUTSTANDING IO COUNT
CLR C.IOWT(R5) ; INIT CLOSE WAIT FLAG
CLRB C.COLC(R5) ; INIT COLUMN COUNT
CLRB C.HUNG(R5) ; INIT HUNG DEVICE TIMER
CLRB C.RECO(R5) ; INIT CONTROL RESOURCE ERROR FLAG
CLRB C.RATT(R5) ; INIT PENDING ATTENTION MSG FLAG
CLRB C.CAPP(R5) ; INIT PENDING CAPABILITIES MSG FLAG
CLRB C.STRT(R5) ; INIT PENDING READ FLAG
CLR C.CDCT(R5) ; INIT CARD COUNTER
; Set all features with standards to std
MOV #C.CFET,R0 ; COMMON FEATURES
CALL 100$ ; DOO ALL
MOV #C.DFET,R0 ; DEVICE SPECIFIC FEATURES
CALL 100$ ; ALL OF THEM TOO
MOV #S.SSUC,R3 ; RETURN SUCCESS
INCB (R5) ; START THE TIMER
CALL $LTMEN ; ...
BR 20$
10$: BIS #CA.CLO,C.ASTS(R5) ; NOTE REMAINING CLOSED
11$: MOV #S.ERBO,R3 ; FAILED TO OPEN
20$: POP$S R4 ; RESTORE POINTER FOR COMMAND CCB
BR CTLXIT
; Feature setting routine
100$: ADD R5,R0 ; R0/FEATURE LIST OFFSET
CLR R1
BISB (R0)+,R1 ; GET NO. OF FEATURES
110$: CLR R3
BISB (R0)+,R3 ; GET ADDRESS OF FEATURE BLOCK
BEQ 120$ ; EMPTY SLOT
ADD R5,R3
CALL SETSTD ; SET IT TO STD
120$: SOB R1,110$
NOOP: RETURN
;+
; Stop Unit
;
; R5 Database Address
;-
DVCLOS: CALL $CRSTP ; STOP DEVICE
CLRB (R5) ; STOP THE CLOCK
BIS #CA.CLO,C.ASTS(R5) ; MARK AS CLOSED
CALL Q$PURG ; FLUSH THE QUEUES
PUSH$S R4 ; SAVE COMMAND CCB POINTER
10$: DEQ$ C.CMSQ,20$ ; FLUSH ANY OUTSTANDING CONTROL MSGS
MOVB #FC.RCE,C.FNC(R4)
CALL $SCHED
BR 10$
20$: POP$S R4 ; RESTORE COMMAND CCB POINTER
MOV R4,C.IOWT(R5) ; SET THE CLOSE WAIT FLAG
; COMPLETE CLOSE ONLY WHEN ALL CCB'S RETURNED
STOPWT: TST C.IOCN(R5)
BEQ 10$
INCB (R5)
RETURN
10$: CLRB (R5) ; FLUSH THE TIMER FCNS
MOV C.IOWT(R5),R4 ; GET THE CLOSE CCB BACK
CLR C.IOWT(R5) ; CLEAN UP BEHIND OURSELVES
MOV #S.SSUC,R3 ; CLOSE NEVER FAILS
CTLXIT: MOV R3,C.STS(R4)
MOVB #FC.CCP,C.FNC(R4)
CALLR $SCHED
.sbttl Timer handler (FC.TIM)
;+
; R5 Database address
;-
CLOCK: TST C.IOWT(R5) ; CHECK FOR CLOSE-WAIT
BEQ 5$
CALLR STOPWT ; PREEMPTS ALL ELSE
5$: TSTB C.RECO(R5) ; CHECK CONTROL RESOURCE ERROR
BEQ 10$
CLRB C.RECO(R5) ; YES - FLUSH THE FLAG
CALL MSGFIN ; RESTART THE PROCESS
10$: TSTB C.DTXL(R5) ; Check timesleep
BEQ 20$ ; Nope
CALL ZZ$WAK ; Restart process - will return here
20$: BIT #CA.ERR!CA.OFL,C.ASTS(R5) ; CHECK DEVICE PROBLEMS
BEQ 30$ ; NOT BECAUSE OF DEVICE ERROR
BIT #RDROFL,@C.CSR(R5) ; DEVICE ERROR WAS REASON
BNE 30$ ; NOT YET RESTORED TO ONLINE
CALL SN$ALR ; CURE HS BEEN EFFECTED, NOTIFY USER
BCS 30$ ; COULDN'T SEND ONE, COME BACK LATER
BIC #CA.ERR!CA.OFL,C.ASTS(R5) ; FLUSH ERROR BUT LEAVE CA.PAU
; USER MUST RESUME
30$: TSTB C.STRT(R5) ; CHECK PENDING READ START
BEQ 40$
CALL $CRSTR ; START THE READER
40$: TSTB C.HUNG(R5) ; CHECK HUNG TIMER
BEQ 50$ ; NOT SET
DECB C.HUNG(R5) ; COUNT THE TOCK
BNE 50$ ; STILL OK
BIS #CA.TMO,C.ASTS(R5) ; DEVICE IS COMATOSE
TSTB C.RATT(R5) ; CHECK PENDING ATTENTION MSG
BNE 55$ ; YES - DON'T GENERATE ANOTHER
MOVB #N.ASTC,C.RATT(R5) ; SET PENDING ATTENTION FLAG
50$: TSTB C.RATT(R5) ; CHECK PENDING ATTENTION MSG
BEQ 60$
55$: CALL SN$ATT ; TRY TO SEND ONE
60$: TSTB C.CAPP(R5) ; CHECK PENDING CAPABILITIES MSG
BEQ 70$
CALL SN$CAP ; TRY TO SEND ONE
70$: INCB (R5) ; RESET THE CLOCK FOR THE NEXT TOCK
RETURN
.sbttl Resource return
;+
; Resource return
;-
CRDONE: DEC C.IOCN(R5) ; COUNT THE RETURNED RESOURCE
BGE 10$
CLR C.IOCN(R5) ; BLEW IT SOMEWHERE
10$: TST C.PRM2(R4) ; Discern buffer type
BEQ 20$ ; Small data buffer
CALLR $RDBRT ; Deallocate RDB and return
20$: MOV #60.,R1 ; Set buffer length
CALLR $CBBRT ; Release CCB and buffer
.sbttl Message Received (FC.RCP)
;+
; Dispatch according to the type of nurd message received.
;
; Inputs: R4 - Points to the first, or only CCB in chain
; R5 - Points to CR database
;
; Outputs: Dispatches to message handler, or returns an
; error if the type is illegal or out of range.
; The called routine is responsible for queuing
; messages to be returned to the higher level.
;
; Msg format: <msgtype><msgflgs><msgtxt.....>
;-
CRDSP: BIT #CA.CLO,C.ASTS(R5) ; DEVICE CLOSED?
BNE 60$ ; YES, HENCE INACCESSIBLE
MAP$ C.BUF(R4) ; GET MAPPING
MOV C.BUF+2(R4),R0 ; POINT TO CCB DATA BUFFER
MOVB (R0),R1 ; GET NURD MESSAGE TYPE
BIC #^C<NM.TYP>,R1 ; ISOLATE JUST MESSAGE TYPE
CMP R1,#NRDOTR ; TYPE OUT OF RANGE?
BLO 30$ ; NO, OKAY TO DISPATCH
MOV #NRDOTR,R1 ; YES, SPECIFY ILLEGAL NURD HANDLER
30$: ASL R1 ; GET WORD OFFSET
CALLR @40$(R1) ; DISPATCH TO MESSAGE PROCESSOR
40$: .word 50$ ; 0 - DATA MESSAGE
.word 50$ ; 1 - ATTENTION (ILLEGAL IF REC'D)
.word MSGDAT ; 2 - FEATURES MESSAGE
.word MSGCTL ; 3 - CONTROL MESSAGE
NRDOTR = <.-40$>/2
.word 50$ ; N - ILLEGAL NURD TYPE SPEC
50$: MOV #S.EIDM,C.STS(R4)
BR 70$
60$: MOV #S.EABO,C.STS(R4)
70$: MOVB #FC.RCE,C.FNC(R4)
CALLR $SCHED
;+
; Queue incoming NURD Control and Features Messages
;
; R4 CCB
; R5 Database address
;-
MSGDAT: BIT #CA.ABO,C.ASTS(R5) ; CHECK FOR ABORT STATE
BEQ MSGQUE ; OK TO PROCEED
MOV #S.EABO,C.STS(R4) ; DROP DATA ON THE FLOOR
MOVB #FC.RCE,C.FNC(R4)
CALLR $SCHED
MSGQUE: ENQ$ C.DLCQ ; QUEUE THE PACKET
CMP R4,C.DLCQ(R5) ; WAS QUEUE EMPTY ?
BNE 60$ ; NO, ROUTINES OF INTEREST ARE WORKING
TSTB C.DTXL(R5) ; Maybe waiting for packet ?
BNE 60$ ; Could be
30$: MOV SP,C.DFSP(R5) ; SET THE STACK ORIGIN FOR THIS PROCESS
CALL RD$BYT ; EXTRACT MSG TYPE
MOV R0,R1
CALL RD$BYT ; EXTRACT MSG FLAGS
MOV R0,C.MFLG(R5)
CMPB #NM.CTL,R1 ; DISTINGUISH CONTROL AND FEATURES
BNE 40$ ; FEATURES
CALL CTLSYN ; NON-INTERRUPT CONTROL
BR 50$
40$: CALL FTRSYN ; FEATURES
50$: MOV C.DLCQ(R5),R4 ; GET NEXT MSG
BNE 30$ ; MORE
60$: RETURN ; EXIT
;+
; NURD Control Message Handler
;
; R0 Buffer ptr: ->nurd msg type
; R4 CCB
; R5 Database address
; KISAR6 Mapped to buffer
;
; Control msg format: <seq no.><command><result>
;-
.enabl lsb
MSGCTL: CMPB C.MOD(R4),#S$INT ; CHECK FOR INTERRUPT MSG
BEQ 5$ ; THEY ARE PROCESSED NOW
CALLR MSGQUE ; OTHERS ARE SYNCH'D WITH DATA STREAM
5$: ENQ$ C.CMSQ ; Queue CCB til resources are checked
CMP #N.CCMD+1,C.CNT(R4) ; CHECK TO SEE IF ENOUGH SENT
BGT 100$ ; NOT EVEN 4 LOUSY BYTES!
MOVB N.CCMD(R0),R1 ; GET CONTROL COMMAND BYTE
BLE 100$ ; SKIP OUT ON ILLEGAL CODE
CMP #CTLOTR,R1 ; CHECK RANGE OF COMMAND
BLOS 100$ ; OUT OF RANGE, SKIP OUT
ASL R1 ; IN RANGE, GET AS WORD OFFSET
CLR R0 ; INITIALIZE CODE
CALL @CTLDSP(R1) ; EXECUTE DETAILED CONTROL ROUTINE
CMP R0,#-1 ; ANY MESSAGE TO DO ?
BEQ 6$ ; NO
; Here when finished, or when performing a retry to get a resource
MSGFIN: CALL BF$SDB ; GET A RESPONSE BUFFER
BCC 10$ ; Ok
INCB C.RECO(R5) ; Control resource error flag
6$: RETURN
10$: BCS 100$ ; OOPS
PUSH$S R4 ; SAVE THE RESPONSE CCB
DEQ$ C.CMSQ ; GET THE MSG CCB BACK
MAP$ C.BUF(R4) ; R0/RESULT
MOV C.BUF+2(R4),R1
MOVB N.CCMD(R1),R2 ; R2/COMMAND
MOVB N.CSEQ(R1),R1 ; R1/SEQ NO. OF CONTROL MSG
CLR C.STS(R4) ; ACK THE CONTROL MESSAGE
MOVB #FC.RCE,C.FNC(R4) ; ...
CALL $SCHED ; ...
POP$S R4 ; GET THE RESPONSE CCB BACK
MAP$ C.BUF(R4) ; MAP TO THE BUFFER
MOV C.BUF+2(R4),R3 ; GET BUF PTR
MOVB #NM.CTL,(R3)+ ; FORMAT A NURD CONTROL MSG
CLRB (R3)+ ; NO MSG FLAGS
MOVB R1,(R3)+ ; SEQ NO.
MOVB R2,(R3)+ ; COMMAND
MOVB R0,(R3) ; RESULT
MOV #N.CRES+1,C.CNT(R4) ; SET THE BUFFER COUNT
INC C.IOCN(R5) ; COUNT THE I/O
CALLR $SCHED
; Illegal function
100$: DEQ$ C.CMSQ ; GET THE CCB BACK
BIS #CA.ADN,C.ASTS(R5) ; PAUSE AND COMPLAIN
MOV #S.ERBO,C.STS(R4) ; REJECT(?) THIS ONE
MOVB #FC.RCE,C.FNC(R4) ; ACK THE MESSAGE
MOV #-1,R0 ; SET FLAG CODE
CALLR $SCHED
; THE DISPATCH TABLE
CTLDSP: .word 100$ ; 0 - CODE ZERO IS RESERVED
.word CTLABE ; 1 - ABORT TO END OF FILE
.word CTLABT ; 2 - ABORT ALL
.word CTLABC ; 3 - ABORT CLEAR
.word CTLSTS ; 4 - STATUS REQUESTED, SEND ATTENTION
.word CTLDMP ; 5 - DUMP OUTPUT BUFFERS
.word CTLPAU ; 6 - PAUSE
.word CTLRSM ; 7 - RESUME FROM ERROR OR PAUSE
.word 100$ ; 8 - UNDEFINED
.word CTLCPB ; 9 - SEND CAPABILITIES MESSAGE
CTLOTR = <. - CTLDSP>/2
.dsabl lsb
;+
; Non-interrupt control message processing
;-
CTLSYN: CALL RD$BYT ; GET SEQ NO.
MOVB R0,C.DMSQ(R5) ; SAVE IT FOR RESPONSE
CALL RD$BYT ; GET COMMAND
MOV R0,R1
BLE 50$ ; SKIP OUT ON ILLEGAL CODE
CMP #CTLOTR,R1 ; CHECK RANGE OF COMMAND
BLOS 50$ ; OUT OF RANGE, SKIP OUT
PUSH$S R1 ; SAVE COMMAND CODE FOR RESPONSE
ASL R1 ; IN RANGE, GET AS WORD OFFSET
CLR R0 ; INITIALIZE FLAG
CALL @CTLDSP(R1) ; EXECUTE DETAILED CONTROL ROUTINE
POP$S R1 ; GET COMMAND CODE BACK
CMP R0,#-1 ; ANY MESSAGE STILL TO DO ?
BEQ 60$ ; NO
PUSH$S R0 ; SAVE RESPONSE CODE
CALL RD$DQX ; ACK THE MSG
MOV #NM.CTL,R0 ; CONSTRUCT A CONTROL MSG
CALL MS$BYT ; CONTROL CODE
CLR R0
CALL MS$BYT ; NULL MSG FLAGS
MOVB C.DMSQ(R5),R0
CALL MS$BYT ; SEQ NO. OF ORIGINAL COMMAND
MOV R1,R0
CALL MS$BYT ; COMMAND
POP$S R0
CALL MS$BYT ; RESPONSE CODE
DEQ$ C.MSGQ ; GET MESSAGE OFF QUEUE
SUB C.MSGS(R5),C.CNT(R4) ; CALCULATE MESSAGE SIZE
CLR C.MSGS(R5) ; COVER OUR TRACKS
INC C.IOCN(R5) ; COUNT THIS I/O
CALL $SCHED ; SEND IT OFF
TSTB C.RATT(R5) ; CHECK FOR OTHER MESSAGES TO GOE OUT
BEQ 20$ ; NO ATTENTION MSGS
CALL SN$ATT ; PENDING ATTENTION MSG
20$: TSTB C.CAPP(R5) ; TRY CAPABILITIES MSG
BEQ 60$
CALLR SN$CAP ; PENDING CAPABILITIES MSG
50$: BIS #CA.ADN,C.ASTS(R5) ; PAUSE AND COMPLAIN
CALL RD$DQX ; ACK THE MSG AND WAIT FOR DEATH
60$: RETURN
;+
; Clear abort status
;-
CTLABC: BIT #CA.ABE!CA.ABO,C.ASTS(R5) ; ABORT SET?
BEQ 10$ ; NO
BIC #CA.ABE!CA.ABO,C.ASTS(R5) ; CLEAR ABORTING
RETURN
10$: MOV #NR.ACN,R0 ; NOT IN ABORT STATE
RETURN
;+
; Abort to end of file
;-
CTLABE: BIS #CA.ABE,C.ASTS(R5) ; SET THE FLAG FOR READER
RETURN
;+
; Abort until clear received
;-
CTLABT: CALL $CRSTP ; FLUSH THE DEVICE
BIS #CA.ABO,C.ASTS(R5) ; NOTE ABORTING
MOV C.DDMQ(R5),R1 ; CHECK ALL QUEUES TO SEE IF
BIS C.DLCQ(R5),R1 ; ANYTHING HAPPENING
BIS C.MSGQ(R5),R1
BISB C.DTXL(R5),R1 ; CHECK SUSPENDED PROCESSES
BNE 10$ ; NR.ABS
MOV #NR.NAB,R0 ; NOTHING TO ABORT
10$: CALLR Q$PURG ; CLEAR THE WORLD
;+
; Request capabilities message
;-
CTLCPB: INCB C.CAPP(R5) ; SET CAPABILITIES PENDING FLAG
RETURN
;+
; Dump output buffers
;-
CTLDMP: TSTB C.RATT(R5) ; PENDING ATTENTION?
BNE 10$ ; YES
TSTB C.CAPP(R5) ; PENDING CAPABILITIES?
BNE 10$ ; YES
MOV #NR.NOB,R0 ; NOTHING TO DUMP
10$: RETURN
;+
; Pause input
;-
CTLPAU: BIT #CA.PAU!CA.ADN,C.ASTS(R5) ; ALREADY PAUSED/PAUSING?
BNE 20$ ; YES
10$: BIS #CA.PAU,C.ASTS(R5) ; PAUSE NO MATTER WHAT
RETURN
20$: MOV #NR.PAU,R0 ; ALREADY PAUSED
RETURN
;+
; Resume input
;-
CTLRSM: BIT #CA.PAU!CA.ADN!CA.TMO,C.ASTS(R5); CHECK PAUSEDNESS
BEQ 20$ ; NOTHING HUNG
BIT #CA.EOF,C.ASTS(R5) ; EOF ?
BEQ 10$
CLR C.CDCT(R5) ; IF SO, CLEAR CARD COUNT FOR NEW FILE
10$: BIC #CA.PAU!CA.ADN!CA.TMO!CA.ERR!CA.EOF!CA.ABO!CA.ABE,C.ASTS(R5)
CALL $CRSTR ; TURN ON DEVICE AGAIN
BR 30$
20$: MOV #NR.NPS,R0 ; NOT PAUSED
30$: RETURN
;+
; Status request
;-
CTLSTS: TSTB C.RATT(R5) ; CHECK ATTENTION ALREADY PENDING
BNE 10$ ; DON'T MUNGE ORIGNAL REASON
MOVB #N.ARQS,C.RATT(R5) ; SET ATTENTION PENDING FLAG
10$: RETURN
;+
; NURD Features message handlers
;
; Feature msg format:
; <seq no.><no. feature specs><...feature specs...>
;
; Feature spec format:
; <feature id><feature flags><class><response>[<feature data>]
;
; Feature data format:
; <cnt><...data...>
;
; NOTE: Incoming message has only one feature spec.
;
; Buffer has been set up and nurd type and flags bytes
; (1st & 2nd bytes) have been extracted.
;
; R4 CCB AT TOP OF C.DLCQ
; R5 Database address
; KISAR6 Mapped to data buffer
;-
.enabl LSB
FTRSYN: MOV #NM.FTR,R0 ; BEGIN A REPLY
CALL MS$BYT ; INSERT NURD MSG TYPE
CLR R0
CALL MS$BYT ; INSERT MSG FLAGS
CALL RD$BYT ; GET SEQ NO.
MOVB R0,C.DMSQ(R5)
CALL MS$BYT ; SEND IT BACK
CALL RD$BYT ; GET NO. FEATURE SPECS
CLR R0 ; BUT IGNORE IT
MOVB R0,C.NFSP(R5) ; SAVE IT FOR SOMTHING
CALL MS$BYT ; STUFF IT IN REPLY
CALL RD$BYT ; GET FEATURE ID
MOV R0,R2
CALL RD$BYT ; GET FEATURE FLAGS
MOV R0,R1
CALL RD$BYT ; GET CLASS
SWAB R1
BIS R0,R1 ; R1/FLAGS,,CLASS
CALL RD$BYT ; READ THE RESPONSE FIELD AND IGNORE IT
CLRB C.CAPN(R5) ; INIT INDEX INTO CAPABILITIES LIST
CMPB #FE.ALL,R2 ; CHECK FOR ALLNESS
BNE 30$ ; SINGLE FEATURE
CLR R2 ; INIT COMMON FID'S
MOVB C.CFET(R5),C.CAPN(R5) ; GET COUNT OF COMMON ENTRIES
BIT #NF.CMD*400,R1 ; ALL FEATURES - CHECK READ/SET
BEQ 10$ ; READ - CONTINUE
CMPB #FC.SST,R1 ; SET - CHECK SET TO STD
BNE FERERR ; NO - ILLEGAL COMBINATION
10$: INCB R2 ; ADVANCE THRU LIST
BMI 15$ ; GRUBBLING THRU DEVICE FEATURES
CMPB R2,C.CAPN(R5) ; CHECK RANGE
BLOS 20$ ; OK
MOVB C.DFET(R5),C.CAPN(R5) ; INIT FOR DEVICE SPECFIC FEATURES
MOV #201,R2
15$: MOV R2,R0 ; DEVICE FEATURE - HACK OFF SIGN
BIC #^C177,R0
CMPB R0,C.CAPN(R5) ; CHECK RANGE
BHI 70$ ; DONE
20$: CALL FTRFND ; LOOK IT UP
BCC 40$ ; SUPPORTED FEATURE
BR 10$ ; TRY NEXT ONE
30$: CALL FTRFND ; LOOK UP FEATURE
BCS FERUSF ; UNSUPPORTED FEATURE
; AT THIS POINT:
; R1 Feature msg flags word(hi) + class(lo)
; R2 Feature id (byte)
; R3 Points to the feature status byte
; R5 Database address
; C.DMSQ Seq no.
; C.NFSP No. specs
40$: BITB #FB.CP,(R3) ; CHECK FOR CHANGE PENDING
BNE FERCPN ; CAN'T READ OR SET IF SO
BIT #NF.CMD*400,R1 ; FEATURE READ OR FEATURE SET?
BEQ FTRSHO ; READ - GO PROCESS FEATURE READ
CALLR FTRSET ; SET - GO PROCESS IN FEATURE SET
FTRCON: TSTB C.CAPN(R5) ; CHECK FOR ALLNESS
BNE 10$ ; YES
70$: MOV C.MSGQ(R5),R4 ; GET BEG OF MSG
MAP$ C.BUF(R4)
MOV C.BUF+2(R4),R0 ; GET THE PTR
MOVB C.NFSP(R5),N.NSPC(R0) ; SET IN THE FINAL SPEC COUNT
CALL RD$DQX ; RETURN ORIGNAL MSG TO NRD
DEQ$ C.MSGQ ; GET MESSAGE OFF QUEUE
SUB C.MSGS(R5),C.CNT(R4) ; CALCULATE MESSAGE SIZE
CLR C.MSGS(R5) ; COVER OUR TRACKS
INC C.IOCN(R5) ; COUNT THIS I/O
CALLR $SCHED ; SEND IT OFF
FERUSF: PUSH$S #FR.USF
BR 200$
FERBCL: PUSH$S #FR.BCL
BR 200$
FERNST: PUSH$S #FR.NST
BR 200$
FERERR: PUSH$S #FR.ERR
BR 200$
FERCPN: PUSH$S #FR.CPN
BR 200$
FERNEB: PUSH$S #FR.NEB
BR 200$
FERDNP: PUSH$S #FR.DNP
200$: MOV R2,R0 ; INSERT <FID><FLAGS><CLASS><ERROR>
CALL MS$BYT ; INSERT FID
MOV R1,R0
SWAB R0
CALL MS$BYT ; INSERT FLAGS
MOV R1,R0
CALL MS$BYT ; INSERT CLASS
POP$S R0 ; GET ERROR CODE
CALL MS$BYT ; INSERT RESP
INCB C.NFSP(R5) ; COUNT THE SPEC
BR FTRCON
.dsabl lsb
;+
; Features Read
;
;R1 Feature msg flags word(hi) + class(lo)
;R2 Feature id (byte)
;R3 Points to the feature status byte
;R5 Database address
;
; Reply has been formatted thru <no. specs>
; insert in msg:
; <fid><flgs><class><resp><data>
;-
FTRSHO: MOV R2,R0
CALL MS$BYT ; INSERT FID
MOV R1,R0 ; GET READ/SET BIT
SWAB R0
BIC #^C<NF.CMD>,R0 ; NOW ISOLATED
BITB #FB.SST,(R3) ; FEATURE SET TO STD?
BEQ 10$ ; NO
BIS #NF.STD,R0 ; SET TO STD
10$: CALL MS$BYT ; INSERT FLAGS
CLRB R1 ; SET FEATURE CLASS IN R1 (LO)
BITB #FB.CL1,(R3) ; CHECK CLASS 1
BEQ 20$ ; TIS CLASS 0
BISB #FC.CL1,R1 ; SET CLASS 1
20$: MOV R1,R0
CALL MS$BYT ; INSERT CLASS
CLR R0
CALL MS$BYT ; RESP - NO ERRORS
TSTB R1 ; CHECK CLASS FOR LENGTH OF DATA
BEQ 30$ ; 1 BIT
BITB #FB.WRD!FB.STR,(R3) ; MORE THAN 1 BYTE ?
BNE 60$ ; YES
INC R0 ; COUNT = 1
CALL MS$BYT ; INSERT COUNT
30$: MOVB 1(R3),R0 ; COPY FEATURE TABLE DATA ENTRY
40$: CALL MS$BYT ; INSERT DATA
50$: INCB C.NFSP(R5) ; COUNT THE SPEC
BR FTRCON ; CONTINUE FEATURE HACKING
; MULTIPLE BYTE VALUE
60$: BITB #FB.STR,(R3) ; DELINEATE WORD(SPECIAL) AND LONGER STRINGS
BNE 70$ ; STRING
; WORD VALUE - F.FCV = DATABASE OFFSET TO WORD
MOV #2,R0 ; 2 BYTE VALUE
CALL MS$BYT ; INSERT CNT
CLR R0
BISB F.FCV(R3),R0
ADD R5,R0
MOV (R0),R0 ; YES, READ SETTING FROM THE DATABASE
CALL MS$BYT ; INSERT LO BYTE
SWAB R0
BR 40$ ; INSERT HI BYTE
; STRING - F.FCV HAS THE LENGTH, CURRENT VALUE BEGINS AT F.FCV+1
70$: INC R3 ; THIS DEPENDS ON F.FCV=1
MOVB (R3)+,R0 ; GET THE LENGTH
CALL MS$BYT ; INSERT IN MSG
MOV R0,R4 ; SAVE IT
80$: MOVB (R3)+,R0 ; INSERT THE STRING IN MSG
CALL MS$BYT
DECB R4 ; COUNT THE BYTE
BNE 80$
BR 50$
;+
; Features set
;
; R1 Feature msg flags word(hi) + class(lo)
; R2 Feature id (byte)
; R3 Points to the feature status byte
; R5 Database address
;
; Reply has been formatted thru <no. specs=1>
;-
FTRSET: CMPB #FC.SST,R1 ; CHECK STDNESS
BEQ 40$ ; STD RESULT
BITB #FB.CA,(R3) ; REAL SET - CHECK IF SETABLE
BEQ FERERR ; NO
MOVB (R3),R0 ; FEATURE IS SETTABE
XOR R1,R0 ; CHECK CLASS SPEC
BIC #^C<FB.CL1>,R0 ; R0/ <CLASS SPEC'D>.NOT.EQUIV. <FEATURE CLASS>
BNE FERBCL ; RESULT SHOULD BE 0
CMPB #FC.CL1,R1 ; CHECK DATA CLASS
BNE 10$ ; CLASS 0
CALL RD$BYT ; CLASS 1 - FEATURE DEPENDENT DATA
; CHECK EXPLICITLY FOR ALL > 1
BITB #FB.WRD!FB.STR,(R3) ; CHECK MULTIPLE BYTE DATA
BNE 30$ ; GO DO IT
; ONLY ONE BYTE FEATURES LEFT
CMPB #1,R0 ; SEE IF IT IS
BNE FERERR ; LOSER
; YES - GO SET THE FEATURE
10$: CALL RD$BYT ; CLASS 0 OR CLASS 1(1 BYTE) - GET THE BYTE
MOVB R0,1(R3) ; SET FEATURE CURRENT VALUE
12$: BICB #FB.SST,(R3) ; NOT SET TO STD
BR FTRSHO ; NOW READ THE FEATURE
; MULTIPLE BYTE VALUES
30$: BITB #FB.STR,(R3) ; DELINEATE WORD(SPECIAL) AND LONGER STRINGS
BNE 35$ ; STRING VALUE
CMPB #2,R0 ; 2 BYTE LENGTH
BNE 36$ ; SCREWED IT UP
CALL RD$BYT ; GET THE PAGE LIMIT
MOVB R0,C.PBRC(R5) ; HIDE THE LO PART
CALL RD$BYT ; GET THE HI PART
SWAB R0
BISB C.PBRC(R5),R0 ; R0/NEW WORD VALUE
MOV R0,-(SP)
CLR R0
BISB F.FCV(R3),R0
ADD R5,R0
MOV (SP)+,(R0) ; SET THE NEW VALUE IN WORD
BR 12$
; STRING - F.FCV HAS THE LENGTH, CURRENT VALUE BEGINS AT F.FCV+1
35$: PUSH$S R3 ; SAVE THE FEATURE BLOCK PTR
INC R3 ; THIS DEPENDS ON F.FCV=1
CMPB R0,(R3)+ ; CHECK THE LENGTH
BEQ 37$ ; OK
POP$S R3 ; LENGTH ERROR - BACK PTR UP TO BEG OF BLOCK
36$: CALLR FERERR ; AND REPORT THE ERROR
37$: PUSH$S R1 ; SAVE THE VARIABLES
MOV R0,R1 ; R1/COUNT,R3/PTR TO BEG OF CURRENT VALUE
38$: CALL RD$BYT ; XFER THE NEW VALUE TO THE CURRENT VALUE
MOVB R0,(R3)+ ; STUFF THE BYTE
SOB R1,38$ ; AND COUNT IT
POP$S <R1,R3>
CALLR FTRSHO ; NOW READ THE FEATURE
40$: CALL SETSTD ; SET FEATURE TO STD
BCC 45$
CALLR FERNST ; NO STD TO SET
45$: CALLR FTRCON ; DON'T READ IT
;+
; Set feature to its standard value
;
; R3 Ptr to feature block in database
; R5 Database address
;-
SETSTD: BITB #FB.STE,(R3) ; SEE IF IT HAS ONE
BNE 10$ ; YES
SEC ; NO STD TO SET
RETURN
10$: BITB #FB.WRD!FB.STR,(R3) ; CHECK MULTIPLE BYTE VALUES
BNE 20$ ; YES
MOVB F.FSV(R3),F.FCV(R3) ; SET CURRENT VALUE = STD VALUE
BISB #FB.SST,(R3) ; MARK FEATURE AS SET TO STD
BR 50$
; MULTIPLE BYTE VALUE
20$: BITB #FB.STR,(R3) ; DELINEATE WORD AND LONGER STRINGS
BNE 40$ ; STRING
PUSH$S R5 ; WORD VALUE
CLR -(SP)
MOVB F.FCV(R3),(SP)
ADD (SP)+,R5 ; R5 /PTR TO CURRENT VALUE
MOVB F.FSV(R3),(R5)+ ; XFER LO BYTE
MOVB F.FSV+1(R3),(R5) ; XFER HI BYTE
POP$S R5
BR 50$
; STRING - F.FCV HAS THE LENGTH, CURRENT VALUE BEGINS AT F.FCV+1
; STD VALUE BEGINS AT F.FCV+1+(F.FCV)
40$: PUSH$S <R0,R1,R3>
INC R3 ; DEPENDS ON F.FCV=1
CLR R0
BISB (R3)+,R0 ; GET THE COUNT
MOV R0,R1
ADD R3,R1 ; R0/COUNT
; R1/SOURCE ADDRESS
; R3/DESTINATION ADDRESS
45$: MOVB (R1)+,(R3)+ ; XFER THE STD VALUE
SOB R0,45$ ; COUNT IT
POP$S <R3,R1,R0>
50$: CLC
RETURN
;+
; FTRFND looks for a feature with fid in r2 and returns ptr
; to feature block in r3 if successful normal carry flag
; condition for success or failure
;-
FTRFND: MOV #C.CFET,R3 ; TRY COMMON FEATURE 1ST
PUSH$S R2 ; SAVE FID CAUSE IT WILL BE MANGLED
TSTB R2 ; CHECK IF DEVICE SPECIFIC FTR
BPL 10$ ; COMMON, SKIP
MOV #C.DFET,R3 ; DEVICE SPECIFIC, GET POINTER
BIC #177600,R2 ; TRUNCATE TO JUST OFFSET ABOVE 128
10$: BEQ 20$ ; ZERO IS AN ILLEGAL FEATURE CODE
ADD R5,R3 ; R3 -> FEATURE LIST IN DATABASE
CMP R2,(R3) ; CHECK ON ID RANGE
BHIS 20$ ; SKIP IF OUT OF RANGE
; R3 IS POINTING TO THE BASE OF THE
; FEATURES LIST, WHICH HOLDS HIGHEST
; STORED FEATURE CODE
ADD R2,R3 ; ADD THE FID TO POINT TO ADDRESS
; OF FEATURE BLOCK
MOVB (R3),R3 ; ENTRY IS DB OFFSET TO FEATURE BLOCK
BEQ 20$ ; UNSUPPORTED FEATURE
BIC #^C377,R3 ; FLUSH SIGN EXTENSION
ADD R5,R3 ; R3 -> FEATURE BLOCK
POP$S R2
CLC
RETURN
20$: POP$S R2 ; UNSUPPORTED FEATURE
SEC
RETURN
.sbttl Support Routines
;+
; The following pages, up to start of interrupt handler code,
; contain the various support routines needed in CR.
;
; The routines are arranged in alphabetical order.
;-
;+
; Get a small data buffer
;-
BF$SDB: PUSH$S R1 ; SAVE R1
MOV #60.,R1 ; BUFFER SIZE WANTED
CALL $CBBGT ; GET A MESSAGE BUFFER
BCS 10$ ; LOSE
MOV R1,C.CNT(R4) ; SET SIZE
CLR C.PRM2(R4) ; IDENTIFY AS A MESSAGE BUFFER
MOVB #S$PEOM,C.PRM1+1(R4) ; INIT AS A WHOLE MSG
MOVB #FC.XME,C.FNC(R4) ; INIT FUNCTION AND MOD
MOVB #S$SND,C.MOD(R4) ; ...
MOVB C.NRD(R5),C.PIX(R4) ; SET NRD'S PIX
10$: POP$S R1 ; RESTORE R1
RETURN
;+
; NURD message builder
;
; R0 Byte to put into buffer
; R5 Database address
;-
MS$BYT: DEC C.MSGS(R5) ; COUNT IT
BLT 20$ ; BUFFER ALREADY FULL
MAP$ C.MSGA(R5) ; MAP TO BUFFER
MOVB R0,@C.MSGA+2(R5) ; INSERT CHAR
INC C.MSGA+2(R5) ; ADVANCE PTR
RETURN
20$: CLR C.MSGS(R5) ; RESET THE COUNT
25$: PUSH$S R4
CALL BF$SDB ; GET A BUFFER
BCS 30$ ; OOPS
CLR C.STS(R4) ; INIT THE STATUS
MOV C.BUF(R4),C.MSGA(R5) ; MAKE IT THE CURRENT BUFFER
MOV C.BUF+2(R4),C.MSGA+2(R5)
MOV C.CNT(R4),C.MSGS(R5)
ENQ$ C.MSGQ ; ADD IT TO END OF LIST
POP$S R4
BR MS$BYT ; NOW STUFF THE CHAR
30$: POP$S R4
CALL ZZ$SLP ; ZZZzzz
BR 25$
;+
; Purge the queues
;
; Abort all from <DDMQ>, <DLCQ>, and <MSGQ> (in that order).
;-
Q$PURG: PUSH$S <R0,R1,R3,R4> ; SAVE CURRENT CCB, DATABASE ADDR, ETC
CALL $CRSTP ; Stop the reader
10$: DEQ$ C.DDMQ,20$ ; RETURN CURRENT READ BUFFERS TO POOL
CALL $RDBRT ; ...
BR 10$
20$: DEQ$ C.DLCQ,30$ ; ABORT ANY MSGS WAITING TO BE DONE
MOV #S.EABO,C.STS(R4)
MOVB #FC.RCE,C.FNC(R4)
CALL $SCHED
BR 20$
30$: DEQ$ C.MSGQ,40$ ; FLUSH ANYTHING GOING OUT
MOV #60.,R1
CALL $CBBRT ; ...
BR 30$
40$: CLRB C.DTXL(R5) ; Clear any suspended processing
CLR C.PUBP+2(R5) ; NO CURRENT READ BUFFER
CLR C.DMAD+2(R5) ; NO CURRENT SOURCE BUFFER
CLR C.DMAD(R5)
CLR C.DMBS(R5) ; MAY HAVE BEEN A MESSAGE IN PROGRESS
CLR C.MSGS(R5) ; ...
POP$S <R4,R3,R1,R0> ; DONE
RETURN
.sbttl Get and Put Data Bytes
;+
; USED BY "DATA" AND BY "FTRSYN".
; A FTRSYN MSG IS SHUFFLED THRU DDM (AS AN EMPTY BUFFER) SO THAT
; IT IS RETURNED IN THE SAME SEQUENCE RELATIVE TO DATA THAT IT
; WAS RECEIVED.
;-
RD$BYT: DEC C.DMBS(R5) ; DECREMENT COUNTER
BLT 5$ ; BUFFER EMPTIED ALREADY
MAP$ C.DMAD(R5) ; MAP IF NEED BE
CLR R0
BISB @C.DMAD+2(R5),R0 ; GET BYTE FROM PHYSICAL BUFFER
INC C.DMAD+2(R5) ; INCREMENT POINTER
RETURN
5$: TST C.DMAD+2(R5) ; IS A BUFFER IN PROCESS?
BEQ 10$ ; NO BUF IN USE
MOV C.DLCQ(R5),R4 ; CHECK FOR MSG CONTINUITY
BITB #S$PEOM,C.PRM1+1(R4)
BEQ 9$
BIS #CA.ADN,C.ASTS(R5) ; PAUSE AND COMPLAIN
9$: CALL RD$DQX ; EMPTIED BUF ON TOP
BIT #S$PEOM,R0 ; CHECK STATUS OF MSG DEQUEUED
BEQ 10$
MOV C.DFSP(R5),SP ; GET THE STACK ORIGIN BACK SO CAN QUIT
RETURN ; EXIT
10$: MOV C.DLCQ(R5),R4 ; IS THERE A QUEUED ENTRY?
BNE 15$ ; YES, SET UP POINTER AND COUNTER
CALL ZZ$SLP ; Wait til next segment arrives
BR 10$
15$: MOV C.BUF(R4),C.DMAD(R5) ; GET ADDRESS DOUBLEWORD AS PTR
MOV C.BUF+2(R4),C.DMAD+2(R5)
MOV C.CNT(R4),C.DMBS(R5) ; GET BUFFER COUNT AS SIZE COUNTER
BR RD$BYT ; TRY AGAIN
;+
; Dequeue and return a source buffer to NRD
;-
RD$DQX: CLR C.DMAD+2(R5) ; INDICATE "NO BUFFER IN USE"
CLR C.DMBS(R5)
DEQ$ C.DLCQ ; DEQUEUE MSG JUST DONE
PUSH$S C.STS(R4) ; SAVE MSG STAUS
CLR C.STS(R4) ; AND ACK IT
MOVB #FC.RCE,C.FNC(R4) ; ...
CALL $SCHED
POP$S R0
RETURN
;+
; Send alert message
;-
SN$ALR: CALL BF$SDB ; GET A MESSAGE BUFFER
BCS 10$ ; COULDN'T
MOV C.BUF+2(R4),R1 ; GET BUFFER PTR
MOVB #NM.ALR,(R1)+ ; BUILD ALERT MSG IN SINGLE WORD
CLRB (R1)+ ; CLEAR NURD MSG FLGS
MOV #2,C.CNT(R4)
MOVb #S$SNI,C.MOD(R4) ; ALERT IS AN INTERRUPT MSG
INC C.IOCN(R5)
CALLR $SCHED
10$: RETURN
;+
; Send attention message
;
; Allocate an sdb and build an attention message.
; Reason code is in C.RATT.
;
; format: <1><0><last seq #><rsn code><flags: 1-3 bytes><card count: 2 bytes>
;-
SN$ATT: PUSH$S <R0,R1,R2,R3,R4> ; PRESERVE THE REGISTERS
MOVB C.RATT(R5),R2 ; GET EXCUSE CODE FOR ATTENTION MSG
BEQ 110$ ; NO ATTENTION IS PENDING, LEAVE
; BUILD AND SEND AN ATTENTION MESSAGE
CALL BF$SDB ; GET A MESSAGE BUFFER
BCS 110$ ; FAILED, EXIT - WE'LL BE BACK
MOV C.BUF+2(R4),R1 ; GET POINTER TO START OF BUFFER
MOVB #NM.ATT,(R1)+ ; LOAD MSG TYPE TO BUFFER
CLRB (R1)+ ; CLEAR NURD MSG FLGS
MOVB C.CDCT(R5),(R1)+ ; STORE LAST GOOD SEQ NUMBER IN ATTENTION
MOVB R2,(R1)+ ; LOAD ATTENTION CODE
; BUILD FLAGS FIELD
CLR R2 ; CLEAR FLAGS ACCUMULATOR
MOV C.ASTS(R5),R0 ; GET DEVICE STATUS
BIT #CA.ADN!CA.MOT!CA.TER,R0 ; FATAL ERRORS ?
BEQ 10$
BIS #NA.FAT,R2 ; SOME FATAL ERROR - USUALLY USER'S
10$: BIT #CA.OFL,R0 ; READER OFFLINE ?
BEQ 11$ ; NO
BIS #NA.OFL,R2 ; YES, NOTE OFFLINE
11$: BIT #CA.PAU,R0 ; PAUSED?
BEQ 12$ ; NO
BIS #NA.PAU,R2 ; YES
12$: BIT #CA.HOP,R0 ; HOPPER EMPTY ?
BEQ 20$
BIS #NA.OMD,R2 ; MAYBE - SETS NA.OUF ALSO
20$: BIS #200,R2 ; TENTATIVELY SET EXTEND FLAG
MOVB R2,(R1)+ ; THAT'S IT FOR BYTE 1 FLAGS
CLR R2 ; CLEAR FOR BYTE 2 FLAGS
BIT #CA.HOP,R0 ; OUTPUT HOPPER FULL ?
BEQ 21$
BIS #NA.OUF,R2 ; MAYBE
21$: BIT #CA.TMO,R0 ; HUNG?
BEQ 22$ ; NO
BIS #NA.DTO,R2 ; YES
22$: BIT #CA.MOT,R0 ; PICK FAILURE ?
BEQ 30$
BIS #NA.PF,R2 ; MAYBE
30$: BIS #200,R2 ; TENTATIVELY SET EXTEND FLAG
MOVB R2,(R1)+ ; THAT'S IT FOR BYTE 2
CLR R2 ; CLEAR FOR BYTE 3 FLAGS
BIT #CA.IVP,R0 ; INVALID PUNCH ?
BEQ 40$
BIS #NA.IVP,R2 ; YES
40$: MOVB R2,(R1) ; THAT'S IT FOR BYTE 3 FLAGS
BNE 50$ ; 3 BYTE FEILD
BICB #200,-(R1) ; NOT MORE THAN 2 BYTES
BNE 50$ ; 2 BYTER
BICB #200,-(R1) ; ONLY 1 BYTE
50$: INC R1 ; ADVANCE R1 TO NEXT AVAILABLE BYTE
MOV C.CDCT(R5),R3 ; GET CARD COUNT ACCUMULATOR
MOVB R3,(R1)+ ; STORE LOW BYTE OF COUNT
SWAB R3 ; GET HIGH BYTE
MOVB R3,(R1)+ ; STORE IT TOO
SUB C.BUF+2(R4),R1 ; COMPUTE MSG SIZE
MOV R1,C.CNT(R4) ; STUFF IT INTO CCB
INC C.IOCN(R5)
CALL $SCHED
CLRB C.RATT(R5) ; CLEAR PENDING REQUEST FOR ATTENTION
110$: POP$S <R4,R3,R2,R1,R0> ; RESTORE REGS
RETURN ; EXIT SEND ATTENTION
;+
; Send capabilities message
;
; message format: <no. features><...fid's...>
;-
SN$CAP: CALL BF$SDB ; GET A MSG BUFFER
BCS 100$
MOV C.BUF+2(R4),R3 ; GET BUFFER ADDRESS
; FORMAT A NURD MESSAGE
MOVB #NM.CAP,(R3)+ ; NURD MSG TYPE = CAPABILITIES
CLRB (R3)+ ; NO FLAGS
PUSH$S R3 ; SAVE PTR TO CNT
CLRB (R3)+ ; INIT CNT
MOV #3,C.CNT(R4) ; SET BUFFER CNT = BYTES INSERTED
PUSH$S R5 ; SAVE THE DATABASE PTR
ADD #C.CFET,R5 ; GET R5 -> COMMON FEATURES LIST
CLR R1 ; INIT THE FID
10$: CLR R0 ; GET LENGTH OF FEATURE LIST
BISB (R5)+,R0
BEQ 31$ ; NO FEATURES!!
20$: INC R1 ; ADVANCE THE FID
TSTB (R5)+ ; CHECK FOR SUPPORT OF IT
BEQ 30$ ; NOPE
MOVB R1,(R3)+ ; YES - STORE FID IN MSG
INC C.CNT(R4) ; COUNT IT
30$: SOB R0,20$
31$: TSTB R1 ; CHECK WHICH FEATURE LIST
BMI 40$ ; DEVICE SPECIFIC - DONE
MOV #200,R1 ; INIT FID FOR DEVICE SPECIFIC FEATURES
BR 10$ ; PROCESS THAT LIST
40$: POP$S R5 ; GET THE DATABASE PTR BACK
MOV C.CNT(R4),R0 ; GET THE BUFFER CNT
SUB #3,R0 ; CALC NO. FEATURES FOUND
MOVB R0,@(SP)+ ; STORE CNT IN CNT BYTE OF MSG
INC C.IOCN(R5)
CALL $SCHED
CLRB C.CAPP(R5) ; FLUSH THE FLAG
100$: RETURN
;+
; Data / Features hiber function
; Called by process to wait for a clock tick.
;-
ZZ$SLP: MOV R0,C.DTXT(R5) ; STORE THE REGISTERS 1ST
MOV #C.DTXT+2,R0
ADD R5,R0 ; R0 -> R1 SLOT
MOV R1,(R0)+
MOV R2,(R0)+
MOV R3,(R0)+
MOV R4,(R0)+
CLRB C.DTXL(R5) ; INIT THE COUNT
10$: CMPB #DTXTSZ-5,C.DTXL(R5) ; CHECK INCIPIENT OVERFLOW
BHI 20$
BPT ; PROGRAM BUG
20$: MOV (SP)+,(R0)+ ; XFER NEXT STACK WORD
INCB C.DTXL(R5) ; COUNT IT
CMP C.DFSP(R5),SP ; CHECK ORIGIN
BNE 10$ ; MORE
RETURN ; DONE
;+
; Clock has ticked.
;-
ZZ$WAK: MOV SP,C.DFSP(R5) ; Set the new stack origin
CLR R0 ; Get the number of
BISB C.DTXL(R5),R0 ; words to return to stack
ASL R0 ; as word offset
ADD #C.DTXT+12,R0 ; This is where they are at
ADD R5,R0 ; R0 -> 1st word to return to stack
10$: MOV -(R0),-(SP) ; Xfer the stack contents
DECB C.DTXL(R5) ; Count them
BNE 10$
MOV -(R0),R4 ; Restore the registers
MOV -(R0),R3
MOV -(R0),R2
MOV -(R0),R1
MOV -(R0),R0
RETURN ; RETURN TO ORIGINAL CALLER OF ZZ$SLP
.sbttl Interrupt Service
;+
; Configuration stuff
;-
CRHNG = 5 ; HUNG DEVICE TIME CONSTANT
RDAHD = 5 ; C.IOCN LIMIT WHEN CA.XOF SET
;+
; CR11 Hardware device register definitions
;-
CRS = 0 ; CARD READER STATUS REGISTER
READ = 1 ; (W) FEED A CARD TO THE READ STATION
EJECT = 2 ; (R/W) INHIBIT COLUMN DONE & TIMERR
INTENB = 100 ; (R/W) INTERRUPT ENABLE
; (ERROR,CARD DONE,COLUMN DONE,
; OFFLINE OR ONLINE TRANSITION)
COLDN = 200 ; (R:I) COLUMN DONE - DATA READY
RDROFL = 400 ; (R) READER IS OFFLINE
BUSY = 1000 ; (R) READER BUSY
RDRONL = 2000 ; (R:I) READER TRANSITION TO ONLINE
TIMERR = 4000 ; (R) TIMING ERROR - SERVICE TOO SLOW
MOCHK = 10000 ; (R) MOTION CHECK -FORCES OFFLINE
; (FEED ERROR,MOTION ERROR,STACK FAIL)
HOCHK = 20000 ; (R) HOPPER CHECK - INPUT EMPTY/OUTPUT FULL
; FORCES OFFLINE
CARDN = 40000 ; (R:I) CARD DONE
ERROR = 100000 ; (R:I) SUMMARY ERROR BIT
; SET BY: TRANSITION TO OFFLINE
; TIMING ERROR AT CARD DONE TIME
CRB1 = CRS+2 ; IMAGE DATA REGISTER
; BIT 11 = ZONE 12
; BIT 10 = ZONE 11
; BIT 9 = ZONE 0
; BITS 8-0 = ROWS 1-9
CRB2 = CRB1+2 ; COMPRESSED DATA REGISTER
; BIT 7 = ZONE 12
; BIT 6 = ZONE 11
; BIT 5 = ZONE 0
; BIT 4 = ROW 9
; BIT 3 = ROW 8
; BITS 2-0 = ROWS 1-7 ENCODED(SINGLE PUNCH)
; MULTIPUNCH IN 1-7 OR'S
;+
; Start reader
;-
$CRSTR: BIT #CA.PAU!CA.EOF,C.ASTS(R5) ; START THE CARD READER
BNE 6$ ; CAN'T YET
CMP #RDAHD,C.IOCN(R5) ; YES - CHECK READ AHEAD LIMIT
BLE 6$ ; STOP READING
5$: TST C.DDMQ(R5) ; CHECK FOR BUFFERS
BNE 10$ ; YES - CAN PROCEED
CALL $RDBGT ; GET A BUFFER
BCC 7$ ; OK
6$: MOVB #1,C.STRT(R5) ; SET PENDING READ
RETURN ; WAIT TIL ANOTHER TIME
7$: MOVB #S$PEOM,C.PRM1+1(R4)
MOV #-1,C.PRM2(R4) ; Identify as an RDB
MOV .RDBSZ,C.CNT(R4) ; Set size
MOVB #FC.XME,C.FNC(R4)
MOVB #S$SND,C.MOD(R4)
MOVB C.NRD(R5),C.PIX(R4)
ENQ$ C.DDMQ ; Queue it
10$: CLR C.PUBP+2(R5) ; INIT THINGS TO CAUSE COLD STARTUP
CLRB C.STRT(R5) ; FLUSH THE PENDING READ
CLRB C.COLC(R5) ; CLEAR COLUMN COUNT FOR CLEAN START
BIC #CA.ERR!CA.OFL!CA.TMO!CA.IVP,C.ASTS(R5)
; FLUSH CONDITIONS OF LAST CARD
$CRGO: MOVB #CRHNG,C.HUNG(R5) ; SET THE HUNG TIMER
MOV #INTENB!READ,@C.CSR(R5) ; GOOSE IT
RETURN
$CRSTP: CLR @C.CSR(R5) ; STOP THE INTERRUPTS
CLRB C.HUNG(R5) ; AND FLUSH THE HUNG TIMER
CLRB C.STRT(R5) ; FLUSH ANY PENDING READS
RETURN
;+
; Interrupt service routine
;
; R5 Database address
;
; NURD msg format: <0><msg flags><seq><data flags><seg cnt><...segs...>
;
; Segment format: <cnt><...cnt data items> or <200!cnt><data item>
; EOR segment: <0>
;-
$CRINT::
CLRB C.HUNG(R5) ; Make sure hung timer is off
SMAP$S
PUSH$S <R0,R1,R2,R3>
MOV C.CSR(R5),R3 ; R3/CSR ADR
MOV (R3)+,C.RST(R5) ; READ THE STATUS
BLE 25$
BIT #COLDN,C.RST(R5) ; CHECK COLUMN DONE
BNE 20$
CALLR CRDEND ; MUST BE CARD DONE
; COLUMN DONE - READ DATA
20$: DECB C.COLC(R5) ; COUNT THE COLUMN
BNE 30$
25$: CALLR INTERR ; READING BEYOND DEVICE WIDTH
30$: MOV (R3)+,R0 ; R0/IMAGE DATA
TSTB CR.EOF+F.FCV(R5) ; CHECK EOF?
BEQ 50$ ; NOT INTERESTED
BIT #CA.EOF,C.ASTS(R5) ; EOF ALREADY ENCOUNTERED ?
BEQ 40$ ; NO
JMP 190$ ; YES, SKIP JUNK
40$: CMP #EOFASC,R0 ; CHECK FOR EOF PUNCH
BNE 50$
TST C.PUBP+2(R5) ; CHECK COLUMN 1
BNE 50$
BIS #CA.EOF!CA.PAU,C.ASTS(R5) ; SET EOF AND PAUSE
CLR -(SP) ; PUT A FAKE DATA MODE INDICATOR ON
BR 100$ ; STACK FOR LATER CODE TO CLEAN OFF
50$: MOVB CR.DAT+F.FCV(R5),R4 ; CHECK DATA MODE
SUB #DM.CLI,R4 ; CREATE 3 STATE FLAG FOR LATER USE
MOV R4,-(SP) ; TOP OF STACK = DATA MODE FLAG:
; < 0 => ASCII MODE
; = 0 => COLUMN IMAGE MODE
; > 0 => AUGMENTED COLUMN IMAGE MODE
BEQ 100$ ; IMAGE
MOV (R3)+,R1 ; R1/CODED DATA
MOV R1,R2
BIC #^C7,R2
ASL R2 ; MAKE WORD OFFSET
BIC #7,R1
ASR R1
ASR R1 ; R1/Z<12,11,0,9,8>*2, R2/<Z1-Z7 CODE>*2
TST (SP) ; CHECK DATA MODE
BGE 80$ ; AUGMENTED COLUMN IMAGE MODE
; ASCII MODE
ROR R0 ; CHECK FOR MULTIPUNCH
CLC
RORB R0 ; LO R0/0+Z1-Z7
BICB ZTAB(R2),R0 ; FLUSH SINGLE ZONE
BNE 60$ ; NONZERO => MULTIPUNCH
MOV ZONTAB(R1),R1 ; GET TABLET
BNE 70$ ; ZONES OK
; ILLEGAL ZONE COMBINATION
60$: MOV #ERRCHR,R0 ; ILLEGAL CHARACTER
BIS #CA.IVP,C.ASTS(R5) ; SET INVALID PUNCH FLAG
BR 100$
70$: ASR R2 ; GET BYTE OFFSET BACK
ADD R2,R1 ; R1/TABLET ENTRY
CLR R0 ; MAKE FULL WORD DATA ITEM
BISB (R1),R0 ; R0/TRANSLATED CHARACTER
BR 100$
; AUGMENTED COLUMN IMAGE
80$: MOV R0,R4 ; CHECK ERRORS
ROR R4
CLC
RORB R4 ; LO R4/0+Z1-Z7
BICB ZTAB(R2),R4 ; FLUSH ZONE BIT
BEQ 90$ ; ZERO => SINGLE PUNCH
BIS #100000,R0 ; MULTIPUNCH
BIS #CA.IVP,C.ASTS(R5) ; SET INVALID PUNCH FLAG
90$: SWAB R0 ; STUFF Z1-Z7 CODE IN UPPER HALF
BISB ZTAB+1(R2),R0
SWAB R0
; WE NOW HAVE THE DECODED CHARACTER
; COLUMN IMAGE
100$: MAP$ C.PUBP(R5) ; MAP THE BUFFER
MOV C.PUBP+2(R5),R3 ; R3/CURRENT BUFFER PTR
BEQ 110$ ; 1ST COLUMN
MOV C.SGHD(R5),R2 ; GET SEGMENT HEAD ADR
BEQ 120$ ; NONE IN PROGRESS
TSTB (R2)
BPL 130$ ; CHECK FOR COMPRESSION
; COMPRESSED SEGMENT
CMP R0,C.LDAT(R5) ; CHECK CONTINUITY
BNE 120$ ; END OF SEQUENCE
INCB (R2) ; COUNT ANOTHER - ASSUME 127 COL LIMIT HERE
BR 180$
; NEW CARD, SO SET UP THE BUFFER
110$: MOV C.DDMQ(R5),R3 ; 1ST COLUMN - SET UP PTRS
MOV C.BUF+2(R3),C.PUBP+2(R5); BUFFER ADDRESS
MOV C.BUF(R3),C.PUBP(R5) ; BUFFER VIRTUAL ADDRESS
MAP$ C.BUF(R3)
MOV C.PUBP+2(R5),R3 ; GET R3/BUFFER ADDRESS
MOV R3,C.NRDA(R5) ; SAVE BEG OF NURD MSG
MOVB CR.DWD+F.FCV(R5),C.COLC(R5) ; SET COLUMN COUNTER
; FORMAT A NURD MESSAGE
MOVB #NM.DAT,(R3)+ ; MSGTYPE = DATA
CLRB (R3)+ ; NO MSG FLAGS
INCB C.CDCT(R5) ; COUNT THE CARD
MOVB C.CDCT(R5),(R3)+ ; INSERT SEQ NO. = LO CARD COUNT
CLRB (R3)+ ; INIT DATA FLAGS
CLRB (R3)+ ; INIT SEGMENT COUNT
CLR C.SGHD(R5) ; FLUSH C.SGHD
CLR C.LDAT(R5) ; FLUSH C.LDAT
MOV #N.DDAT,C.PUBS(R5) ; SET BUFFER COUNT TO MSG OVERHEAD
120$: MOV R3,R2 ; BEGIN NEW SEGMENT
CLRB (R3)+ ; INIT NEW SEGMENT HEADER
INC C.PUBS(R5) ; COUNT SEG HEAD IN BUFFER
MOV R2,C.SGHD(R5) ; SAVE NEW HDR ADR
MOV C.NRDA(R5),R4 ; GET MSG BEG
INCB N.DSGC(R4) ; INCREMENT TOTAL SEGMENT COUNT
BIT #CA.EOF,C.ASTS(R5) ; DID WE GET EOF CHARACTER ?
BEQ 160$ ; NO
BR 170$ ; YES, LEAVE
130$: CMP R0,C.LDAT(R5) ; SEE IF NEW COMPR SEQ
BNE 160$ ; NO - JUST BUFFER THE COL
TST (SP) ; REMOVE DATA ITEM FROM BUFFER
BLT 140$
DEC R3 ; WORD
DEC C.PUBS(R5) ; REM FROM BUFFER
140$: DEC R3 ; BYTE
DEC C.PUBS(R5) ; REM FROM BUFFER
DECB (R2) ; REMOVE PREVIOUS DATA ITEM FROM LAST SEG
BEQ 150$ ; REMOVED WHOLE SEGMENT
MOV R3,R2 ; BEGIN NEW SEGMENT
MOV R2,C.SGHD(R5) ; SAVE NEW HDR ADR
MOV C.NRDA(R5),R4
INCB N.DSGC(R4) ; INCREMENT TOTAL SEGMENT COUNT
INC C.PUBS(R5) ; COUNT NEW SEG HEAD IN BUFFER
150$: MOV R2,R3 ; SET BUFFER PTR BACK TO SEG HEAD
MOVB #ND.CMP+1,(R3)+ ; NEW SEGMENT - INIT AS A COMPRESSED SEG
160$: MOV R0,C.LDAT(R5) ; SAVE NEW DATA ITEM IN C.LDAT
MOVB R0,(R3)+ ; INSERT NEW DATA ITEM(LO) IN BUFFER
INC C.PUBS(R5) ; COUNT IT IN BUFFER
INCB (R2) ; COUNT IT IN SEGMENT
TST (SP) ; CHECK DATA MODE => DATA LENGTH
BLT 170$ ; ASCII - 1 BYTE
SWAB R0 ; OTHERWISE - 2 BYTES
MOVB R0,(R3)+ ; INSERT NEW DATA ITEM(HI) IN BUFFER
INC C.PUBS(R5) ; COUNT IT IN BUFFER
; BUT NOT IN SEGMENT
170$: MOV R3,C.PUBP+2(R5) ; SAVE UPDATED BUFFER PTR
180$: TST (SP)+ ; FLUSH DATA MODE FLAG
190$: BIT #CARDN,C.RST(R5)
BNE CRDEND ; CARD FINISHED ALSO
MOVB #CRHNG,C.HUNG(R5) ; EXIT - SET TIMER
POP$S <R3,R2,R1,R0>
MAP$S
RETURN
INTERR: MOV C.RST(R5),R1 ; ERROR-INTERRUPT ENTRY POINT
MOV #CA.PAU,R0 ; DETECT INDIVIDUAL ERRORS
BIT #HOCHK,R1
BEQ 11$
BIS #CA.HOP,R0 ; HOPPER CHECK
11$: BIT #MOCHK,R1
BEQ 12$
BIS #CA.MOT,R0 ; MOTION CHECK
12$: BIT #TIMERR,R1
BEQ 13$
BIS #CA.TER,R0 ; TIMING ERROR
13$: BIT #RDROFL,R1
BEQ 14$
BIS #CA.OFL,R0 ; READER OFFLINE
14$: BIS R0,C.ASTS(R5) ; MARK ERROR => PAUSE ALSO
TST C.PUBP+2(R5) ; CHECK FOR EXISTING BUFFER
BEQ CRDEND ; NO CARD TO MARK ERRORS
MAP$ C.PUBP(R5) ; MAP TO THE BUFFER
MOV C.NRDA(R5),R1 ; AND GET PTR TO PLACE IN BUFFER
BISB #ND.IER,N.DFLG(R1) ; SET ERROR STATUS FLAG IN NURD MSG
; CALLR CRDEND ; FALL INTO CRDEND
; CARD DONE
CRDEND:
CLR @C.CSR(R5) ; STOP THE READER
POP$S <R3,R2,R1,R0> ; RESTORE INTERRUPT LEVEL REGISTERS
MAP$S
bit #ca.syn,c.asts(r5) ; synch requested in progress
beq 3$ ; no so do synch request
return
3$: bis #ca.syn,c.asts(r5) ; set requesting synch
MOV R5,R4 ; Calculate synch block
ADD #C.SYN,R4 ; address
MOV #5$,S.DSP(R4) ; Set resumption address
CALLR $SYNCH ; Go
; Here at synch level
5$:
bic #ca.syn,c.asts(r5) ; clear synch request flag
MAP$ C.PUBP(R5)
MOV C.PUBP+2(R5),R3 ; GET THE BUFFER PTR
BEQ 20$ ; NULL CARD
CLRB (R3) ; INSERT EOR = NULL SGMENT
MOV C.PUBS(R5),R1 ; GET THE BUFFER CNT
INC R1 ; COUNT THE EOR IN THE BUFFER
MOV C.NRDA(R5),R4 ; GET THE MSG PTR
INCB N.DSGC(R4) ; COUNT THE EOR IN MSG SEGMENT CNT
DEQ$ C.DDMQ
MOV R1,C.CNT(R4) ; STUFF FINAL BUFFER CNT IN CCB
BIT #CA.EOF,C.ASTS(R5) ; CHECK FOR EOF
BEQ 10$
MOV C.NRDA(R5),R1 ; INSERT EOF IN MSG
BISB #ND.EOF,N.DFLG(R1)
10$: BIT #CA.ABE,C.ASTS(R5) ; CHECK ABORTS
BEQ 14$
MAP$ C.BUF(R4) ; ABORTING
MOV C.BUF+2(R4),R0
BITB #ND.EOF,N.DFLG(R0) ; CHECK THIS CARD FOR EOF
BNE 12$ ; YES!
CALL $RDBRT ; No, return the buffer
BR 20$
12$: BIC #CA.ABE,C.ASTS(R5) ; ABORT CONDITION FULFILLED
14$: INC C.IOCN(R5) ; COUNT THE BUFFER
MOVB #FC.XME,C.FNC(R4)
CALL $SCHED
20$: BIT #CA.PAU!CA.ADN!CA.EOF,C.ASTS(R5) ; DO WE NEED TO PAUSE ?
BEQ 30$ ; NO
TSTB C.RATT(R5) ; PAUSING, ATTN ALREADY PENDING ?
BNE 25$ ; YES, DON'T OVERWRITE CODE
MOVB #N.ASTC,C.RATT(R5) ; SET THE CODE
CALL SN$ATT ; INSTIGATE THE ATTN MESSAGE
25$: RETURN ; GET ON OUT
30$: CALLR $CRSTR ; START NEXT CARD
.sbttl Hollerith - ASCII Conversion Tables
; CONVERSION IS ZONE ORIENTED
; ZONE LABELS ARE CONSTRUCTED BY APPENDING TO "ZON"
; THE OCTAL CODE FOR CARD ZONES(ROWS)
; ZONE 12 = 20
; ZONE 11 = 10
; ZONE 0 = 4
; ZONE 9 = 2
; ZONE 8 = 1
ZON0: ;NO ZONE PUNCHES
.byte 40 ;NO ROW PUNCHES
.byte '1 ;ROW 1
.byte '2 ;ROW 2
.byte '3 ;ROW 3
.byte '4 ;ROW 4
.byte '5 ;ROW 5
.byte '6 ;ROW 6
.byte '7 ;ROW 7
ZON20: ;ZONE 12
.byte '& ;NO ROW PUNCHES
.byte 'A ;ROW 1
.byte 'B ;ROW 2
.byte 'C ;ROW 3
.byte 'D ;ROW 4
.byte 'E ;ROW 5
.byte 'F ;ROW 6
.byte 'G ;ROW 7
ZON10: ;ZONE 11
.byte '- ;NO ROW PUNCHES
.byte 'J ;ROW 1
.byte 'K ;ROW 2
.byte 'L ;ROW 3
.byte 'M ;ROW 4
.byte 'N ;ROW 5
.byte 'O ;ROW 6
.byte 'P ;ROW 7
ZON4: ;ZONE 0
.byte '0 ;NO ROW PUNCHES
.byte '/ ;ROW 1
.byte 'S ;ROW 2
.byte 'T ;ROW 3
.byte 'U ;ROW 4
.byte 'V ;ROW 5
.byte 'W ;ROW 6
.byte 'X ;ROW 7
ZON1: ;ZONE 8
.byte '8 ;NO ROW PUNCHES
.byte 140 ;ROW 1
.byte ': ;ROW 2
.byte '# ;ROW 3
.byte '@ ;ROW 4
.byte '' ;ROW 5
.byte '= ;ROW 6
.byte '" ;ROW 7
ZON2: ;ZONE 9
.byte '9 ;NO ROW PUNCHES
.byte ERRCHR ;ROW 1
.byte SYN ;ROW 2
.byte ERRCHR ;ROW 3
.byte ERRCHR ;ROW 4
.byte ERRCHR ;ROW 5
.byte ERRCHR ;ROW 6
.byte EOT ;ROW 7
ZON30: ;ZONE 12-11
.byte 174 ;NO ROW PUNCHES
.byte 'J ;ROW 1
.byte 'K ;ROW 2
.byte 'L ;ROW 3
.byte 'M ;ROW 4
.byte 'N ;ROW 5
.byte 'O ;ROW 6
.byte 'P ;ROW 7
ZON24: ;ZONE 12-0
.byte 173 ;NO ROW PUNCHES
.byte 'A ;ROW 1
.byte 'B ;ROW 2
.byte 'C ;ROW 3
.byte 'D ;ROW 4
.byte 'E ;ROW 5
.byte 'F ;ROW 6
.byte 'G ;ROW 7
ZON21: ;ZONE 12-8
.byte 'H ;NO ROW PUNCHES
.byte ERRCHR ;ROW 1
.byte '[ ;ROW 2
.byte '. ;ROW 3
.byte '< ;ROW 4
.byte '( ;ROW 5
.byte '+ ;ROW 6
.byte '! ;ROW 7
ZON22: ;ZONE 12-9
.byte 'I ;NO ROW PUNCHES
.byte SOH ;ROW 1
.byte STX ;ROW 2
.byte ETX ;ROW 3
.byte ERRCHR ;ROW 4
.byte HT ;ROW 5
.byte ERRCHR ;ROW 6
.byte DEL ;ROW 7
ZON14: ;ZONE 11-0
.byte 175 ;NO ROW PUNCHES
.byte 176 ;ROW 1
.byte 'S ;ROW 2
.byte 'T ;ROW 3
.byte 'U ;ROW 4
.byte 'V ;ROW 5
.byte 'W ;ROW 6
.byte 'X ;ROW 7
ZON11: ;ZONE 11-8
.byte 'Q ;NO ROW PUNCHES
.byte ERRCHR ;ROW 1
.byte '] ;ROW 2
.byte '$ ;ROW 3
.byte '* ;ROW 4
.byte ') ;ROW 5
.byte '; ;ROW 6
.byte '^ ;ROW 7
ZON12: ;ZONE 11-9
.byte 'R ;NO ROW PUNCHES
.byte DC1 ;ROW 1
.byte DC2 ;ROW 2
.byte DC3 ;ROW 3
.byte ERRCHR ;ROW 4
.byte ERRCHR ;ROW 5
.byte BS ;ROW 6
.byte ERRCHR ;ROW 7
ZON5: ;ZONE 0-8
.byte 'Y ;NO ROW PUNCHES
.byte ERRCHR ;ROW 1
.byte '\ ;ROW 2
.byte ', ;ROW 3
.byte '% ;ROW 4
.byte '_ ;ROW 5
.byte '> ;ROW 6
.byte '? ;ROW 7
ZON6: ;ZONE 0-9
.byte 'Z ;NO ROW PUNCHES
.byte ERRCHR ;ROW 1
.byte ERRCHR ;ROW 2
.byte ERRCHR ;ROW 3
.byte ERRCHR ;ROW 4
.byte LF ;ROW 5
.byte ETB ;ROW 6
.byte ESC ;ROW 7
ZON3: ;ZONE 9-8
.byte ERRCHR ;NO ROW PUNCHES
.byte ERRCHR ;ROW 1
.byte ERRCHR ;ROW 2
.byte ERRCHR ;ROW 3
.byte DC4 ;ROW 4
.byte NAK ;ROW 5
.byte ERRCHR ;ROW 6
.byte SUB ;ROW 7
ZON23: ;ZONE 12-9-8
.byte ERRCHR ;NO ROW PUNCHES
.byte ERRCHR ;ROW 1
.byte ERRCHR ;ROW 2
.byte VT ;ROW 3
.byte FF ;ROW 4
.byte CR ;ROW 5
.byte SO ;ROW 6
.byte SI ;ROW 7
ZON13: ;ZONE 11-9-8
.byte CAN ;NO ROW PUNCHES
.byte EM ;ROW 1
.byte ERRCHR ;ROW 2
.byte ERRCHR ;ROW 3
.byte FS ;ROW 4
.byte GS ;ROW 5
.byte RS ;ROW 6
.byte US ;ROW 7
ZON7: ;ZONE 0-9-8
.byte ERRCHR ;NO ROW PUNCHES
.byte ERRCHR ;ROW 1
.byte ERRCHR ;ROW 2
.byte ERRCHR ;ROW 3
.byte ERRCHR ;ROW 4
.byte ENQ ;ROW 5
.byte ACK ;ROW 6
.byte BEL ;ROW 7
ZON25: ;ZONE 12-0-8
.byte 'H ;NO ROW PUNCHES
.byte ERRCHR ;ROW 1
.byte ERRCHR ;ROW 2
.byte ERRCHR ;ROW 3
.byte ERRCHR ;ROW 4
.byte ERRCHR ;ROW 5
.byte ERRCHR ;ROW 6
.byte ERRCHR ;ROW 7
ZON26: ;ZONE 12-0-9
.byte 'I ;NO ROW PUNCHES
.byte ERRCHR ;ROW 1
.byte ERRCHR ;ROW 2
.byte ERRCHR ;ROW 3
.byte ERRCHR ;ROW 4
.byte ERRCHR ;ROW 5
.byte ERRCHR ;ROW 6
.byte ERRCHR ;ROW 7
ZON31: ;ZONE 12-11-8
.byte 'Q ;NO ROW PUNCHES
.byte ERRCHR ;ROW 1
.byte ERRCHR ;ROW 2
.byte ERRCHR ;ROW 3
.byte ERRCHR ;ROW 4
.byte ERRCHR ;ROW 5
.byte ERRCHR ;ROW 6
.byte ERRCHR ;ROW 7
ZON32: ;ZONE 12-11-9
.byte 'R ;NO ROW PUNCHES
.byte ERRCHR ;ROW 1
.byte ERRCHR ;ROW 2
.byte ERRCHR ;ROW 3
.byte ERRCHR ;ROW 4
.byte ERRCHR ;ROW 5
.byte ERRCHR ;ROW 6
.byte ERRCHR ;ROW 7
ZON15: ;ZONE 11-0-8
.byte 'Y ;NO ROW PUNCHES
.byte ERRCHR ;ROW 1
.byte ERRCHR ;ROW 2
.byte ERRCHR ;ROW 3
.byte ERRCHR ;ROW 4
.byte ERRCHR ;ROW 5
.byte ERRCHR ;ROW 6
.byte ERRCHR ;ROW 7
ZON16: ;ZONE 11-0-9
.byte 'Z ;NO ROW PUNCHES
.byte ERRCHR ;ROW 1
.byte ERRCHR ;ROW 2
.byte ERRCHR ;ROW 3
.byte ERRCHR ;ROW 4
.byte ERRCHR ;ROW 5
.byte ERRCHR ;ROW 6
.byte ERRCHR ;ROW 7
ZON33: ;ZONE 12-11-9-8
.byte ERRCHR ;NO ROW PUNCHES
.byte DLE ;ROW 1
.byte ERRCHR ;ROW 2
.byte ERRCHR ;ROW 3
.byte ERRCHR ;ROW 4
.byte ERRCHR ;ROW 5
.byte ERRCHR ;ROW 6
.byte ERRCHR ;ROW 7
ZON27: ;ZONE 12-0-9-8
.byte ERRCHR ;NO ROW PUNCHES
.byte NUL ;ROW 1
.byte ERRCHR ;ROW 2
.byte ERRCHR ;ROW 3
.byte ERRCHR ;ROW 4
.byte ERRCHR ;ROW 5
.byte ERRCHR ;ROW 6
.byte ERRCHR ;ROW 7
; ZONE INDEX TABLE
.even
ZONTAB:
$$=0
.rept 32.
.irp Z,<$$>
.if df, ZON'Z
.word ZON'Z
.iff
.word 0
.endc
.endm
$$=$$+1
.endr
; ZTAB IS INDEXED BY Z1-Z7 CODE FOR PUNCH BIT.
; LO BYTE IS ZONE PUNCH MASK, HI BYTE IS ZONE CODE SHIFTED FOR AUG COL
ZTAB: .byte 0,0 ; NO PUNCHES
.byte 100,1*20 ; ZONE 1
.byte 40,2*20 ; ZONE 2
.byte 20,3*20 ; ZONE 3
.byte 10,4*20 ; ZONE 4
.byte 4,5*20 ; ZONE 5
.byte 2,6*20 ; ZONE 6
.byte 1,7*20 ; ZONE 7
.even
.end