Trailing-Edge
-
PDP-10 Archives
-
7.01A_PCL20_KMCSRC_19830513
-
kmcser.mac
There are no other files named kmcser.mac in the archive.
TITLE KMCSER - Service for KMC controlled DZ11 communication lines - V003
SUBTTL S. A. Davidson 01-Nov-80/TL
XP VKMCSR,003
COMMENT @
Modifications to upgrade this code to TOPS-10 V 7.01A are
COPYRIGHT (C) 1983 DIGITAL EQUIPMENT CORPORATION, MAYNARD MASS.
THIS SOFTWARE IS FURNISHED UNDER LICENSE, AND MAY BE USED AND COPIED
ONLY ACCORDING TO THE TERMS OF SUCH LICENSE.
Also note:
This code seems to have been taken from Digital's D8KINT for 7.01.
As such, title to the original code seems unclear. TL/DEC 10-may-83
@
;***********************************************************************
;
; PROGRAM KMCSER
;
; PURPOSE:
; THIS ROUTINE IS THE TOPS-10 DRIVER FOR THE
; KMC11B DEVICE WITH 8 LINES AVAILABLE.
;
; INPUTS:
; MONITOR CALL PARAMETERS FROM UUOCON
; DATA IN KMC CSR'S
;
; OUTPUTS:
; DATA TO KMC CSR'S
; STATUS RETURN TO MONITOR CALLS
;
; INTERFACES:
; AS A TOPS-10 DRIVER, THIS ROUTINE IS CALLED
; BY AND RETURNS TO UUOCON.
; IT ALSO RESPONDS TO INTERRUPTS PROVIDED BY
; THE KMC11B.
;
; CPPS REFERENCE PARAGRAPH NUMBER: 3.2.2
;
; HISTORY:
; RELEASE NUMBER: 1(1)
; RELEASE DATE: MARCH 13, 1981
; PROGRAMMER: STU DAVIDSON
; ORGANIZATION: FREY FEDERAL SYSTEMS
;
; PROBLEMS:
;
;
;
;
;*************************************************************************
SEARCH F,S
SALL
$RELOC
$LOW ;define local data area first
DEFINE RETSKP,< JRST CPOPJ1## > ;SKIP RETURN MACRO
SUBTTL DMC SPECIFIC DDB DEFINITIONS
;prototype definition for DMC20 interrupt service entry and DDB - DMCDDB
.TYDMC==61 ;DEVICE TYPE CODE FOR DMC20
DMCTYP==61B27
PDVTIM=3400 ;DEVICE HUNG TIME CONSTANT
BFRSZE=^D<256/4>+1 ;DEFAULT BUFFER SIZE
kmcqln=10. ;length of message queue to KMC
DEFINE CHNMAC (Z) <
CHN'Z'CB##> ;END OF CHNMAC MACRO
DMCMOD==1_I+1_IB+1_D ;image, image binary, dump
; DEVICE DEPENDANT BITS IN LH(DEVIOS)
PCIACT==(1B1) ;INPUT ACTIVE
PCOACT==(1B2) ;OUTPUT ACTIVE
DVOACT==(1B3) ;DEVOP PENDING
ENTRY KMCINT,KMCDDB,KMCDDS
;DMC DDB BLOCK
KMCDDB::
dmcDDB::PHASE 0 ;THE FIRST DDB LOCATION
SIXBIT /dmc/ ;(0) DEVNAM
XWD PDVTIM,BFRSZE ;(1) DEVCHR
0 ;(2) DEVIOS
XWD 0,DMCDSP ;(3) DEVSER
XWD DVIN+DVOUT+DVLNG,DMCMOD ;(4) DEVMOD
0 ;(5) DEVLOG
0 ;(6) DEVBUF
XWD R,0 ;(7) DEVIAD
XWD R,0 ;(10) DEVOAD
0 ;(11) DEVSTS
XWD DEPLEN!DMCTYP,DEPEVM ;(12) DEVSTA
0 ;(13) DEVXTR
0 ;(14) DEVEVM
0 ;(15) DEVPSI
0 ;(16) DEVESE
0 ;(17) DEVHCW
0 ;(20) DEVJOB
DMCPTR:!0 ;INPUT DATA POINTER WORD
dmckmc:!KMC0CB ;link to owning KMC
DMCDV2:! 0 ;place to store sel2 for DEVOP.
DMCDV4:! 0 ;place to store sel4, sel6
KMCDDS::! ;length of DMC DDB
DEPHASE
SUBTTL KMC -- KMC block. One for each KMC that drives DZ's
KMCINT::
KMCAIN: 0 ;TRANSMIT INTERRUPT VECTOR ENTRY
EXCH T1,KMCAIN ;GET INTERRUPT PC
MOVEM T1,KMCCHL## ;PUT INTO -10 STYLE INTERRUPT HANDLER
EXCH T1,KMCAIN ;AND RESTORE T1
JSR KMCSAV## ;SAVE AC'S
JSP W,KMCIVA ;handle ready for input
KMCBIN: 0 ;RECEIVER INTERRUPT VECTOR ENTRY
EXCH T1,KMCBIN ;GET INTERRUPT PC
MOVEM T1,KMCCHL ;PUT INTO -10 STYLE INTERRUPT HANDLER
EXCH T1,KMCBIN ;RESTORE T1
JSR KMCSAV## ;SAVE AC'S
JSP W,KMCIVB ;Vector B interrupt
;TRADITIONALY INDEXED BY "W"
%%%OFF==0 ;INITIALIZE FOR "X" MACRO
KMCQLN==^D32 ;32 QUEUE ENTRIES IN TRANSACTION Q (64 WORDS)
MXNDUP==^D2 ;MAXIMUM NUMBER OF DUP-11'S ON THE KMC-11
KMC0CB::PHASE 0
KMCTBL:!EXP DMCDDB ;DDB table
block 7 ; ...
KMCCSR:!EXP KMC1BA ;XWD UBA #,ADDRESS OF KMC-11 CSR (KMC1BA)
KMCVEC:!EXP KMC1IV ;ADDRESS OF KMC-11 VECTOR (540 = KMC1IV)
KMCCDB:!CHNMAC \M.KMCC ;address of channel block
KMC1DZ:!EXP 0 ;-11 ADDRESS OF FIRST DZ11
KMCCPC:!EXP 0 ;PC OF THE LAST CALLER TO KMCERR.
KMCZER:! ;START ZERO-ING HERE ON A RESTART
KMCSTS:!EXP 0 ;STATUS.
KMCSRU==1B0 ;SAYS KMC-11 IS BELIEVED TO BE RUNNING
KMCACT:!EXP 0 ;COUNT OF VECTOR "A" INTERRUPTS
KMCBCT:!EXP 0 ;COUNT OF VECTOR "B" INTERRUPTS
KMCIQT:!EXP 0 ;INPUT QUEUE "TAKER"
KMCIQP:!EXP 0 ;INPUT QUEUE "PUTTER"
KMCINQ:!BLOCK 2*KMCQLN ;KMC-11 INPUT QUEUE. TWO WORD ENTRYS CONTAIN
; XWD 0,SEL2
; XWD SEL4,SEL6
KMCLEN:! ;LENGTH OF A KMC BLOCK
DEPHASE
SUBTTL DEFINITIONS -- KMC11
SEL0==0
BSEL1==1
KMCRUN==100000 ;RUN FLOP
KMCMCL==040000 ;MASTER CLEAR
KMCCWR==020000 ;CRAM WRITE
KMCSLU==010000 ;STEP LINE UNIT
KMCLUL==004000 ;LINE UNIT LOOP
KMCRMO==002000 ;ROM OUTPUT
KMCRMI==001000 ;ROM INPUT
KMCSUP==000400 ;STEP u-PROCESSOR
KMCRQI==000200 ;REQUEST INPUT
KMCIEO==000020 ;INTERRUPT ENABLE OUTPUT
KMCIEI==000001 ;INTERRUPT ENABLE INPUT
SEL2==2
BSEL3==3 ;CONTAINS LINE NUMBER
KM3CMS==170000 ;KMC command status
KM3IOD==004000 ;I/O direction (1 for out, 0 for in)
KM3FCN==003400 ;function code
F.DZS==0*400 ;DZ status
F.LNS==1*400 ;Line status
F.KIL==F.LNS!KM3IOD ;kill I/O (on close)
F.LPR==2*400 ;Line parameters
F.DRAM==3*400 ;read/write data ram
F.DATA==4*400 ;data i/o request
KMCRDO==000200 ;READY FOR OUTPUT
KMCRDI==000020 ;READY FOR INPUT
KM2LIN==000007 ;Line number
SEL4==4
BSEL5==5
;16 bit address for F.DATA (output)
;real byte count for F.DATA (input)
;DZ11 address for F.DZS
SEL6==6
BSEL7==7
KM6XBA==000014 ;extended addressing bits F.DATA (output)
;file status bits for F.DATA (input):
ddead==200 ;device dead
HDTERR==100 ;hard data error
TIMOUT==040 ;line time out
EOF==020 ;eof (ETX in block)
IODIR==010 ;I/O direction
LDEAD==004 ;line dead
STXETX==002 ;STX/ETX sequencing error
STXINB==001 ;STX in this block
;KMC11B IS 4K WORDS CRAM, 4K BYTES DRAM
CRAMSZ==10000 ;SIZE OF KMC11 CRAM
DRAMSZ==10000 ;SIZE OF KMC11 DRAM
;
;KMC11A IS 1K WORDS CRAM, 1KBYTES DRAM
;CRAMSZ==2000 ;SIZE OF KMC11A CRAM
;DRAMSZ==2000 ;SIZE OF KMC11A DRAM
SUBTTL KMC SERVICE DISPATCH TABLE
$HIGH
;KMC-11 DRIVER SERVICE DISPATCH TABLE
JRST KMCONL ;(-5)SEE IF THE KMC IS ON-LINE NOW
JRST KMCDVP ;(-4)KMC-11 DEVOP. UUO DISPATCH
JRST KMCOPN ;(-3)OPEN CALL, GET BUFFER SIZE FROM DDB
JRST KMCINI ;(-2)INITIALIZE KMC NETWORK
JRST KMCHNG ;(-1)HUNG DEVICE ERROR
DMCDSP::JRST KMCREL ;(0)RELEASE
JRST KMCCLS ;(1)CLOSE
JRST KMCOUT ;(2)OUTPUT
JRST KMCINP ;(3)INPUT
POPJ P, ;(4)ENTER
POPJ P, ;(5)LOOKUP
JRST KMCDOU ;(6)DUMP OUTPUT
JRST KMCDIN ;(7)DUMP INPUT
POPJ P, ;(10)USETO
POPJ P, ;(11)USETI
POPJ P, ;(12)GETF UUO
POPJ P, ;(13)RENAME UUO
PJRST KMCCLS ;(14)CLOSE INPUT
POPJ P, ;(15)UTPCLR
POPJ P, ;(16)MTAPE UUO
; Fix buffer size and EVM required on OPEN
KMCOPN: LDB T3,PIOMOD## ;see what mode we're to use
CAIE T3,D ;is it DUMP?
JRST BUFOPN ;no, must be a buffered mode
MOVEI T1,CRAMSZ/4+1 ;CRAM SIZE RETURNED AS BUFFER SIZE
POPJ P,
BUFOPN: MOVEI T1,^D256/4+1 ;DATA BUFFER SIZE
CAIE T3,I ;IMAGE IS REAL DATA TRANSFER
MOVEI T1,DRAMSZ/4+1 ;IB MODE READS DATA RAM
POPJ P,
SUBTTL Once only code
;KMCINI is called at ONCE time. It is responcible for initializing
;data structures. In particular, DDB's built at ONCE time must be
;adjusted to reflect unit numbers.
; At entry, F contains a DDB address.
KMCINI: MOVE T2,DEVNAM(F) ;Unit number on this KMC (in sixbit)
ANDI T2,7 ;get binary line number
DPB T2,PUNIT## ;Store as line number
move w,dmckmc(f) ;get pointer to KMC block
ADDI T2,KMCTBL(W) ;compute addr of back pointer
MOVEM F,(T2) ;Create link from KMC to DMC
JRST CPOPJ1 ;Skip return, get called for each DDB
SUBTTL CHECKS FOR KMC ON-LINE & HUNG
KMCONL: AOS (P) ;ADJUST FOR SKIP RETURN
POPJ P, ;RETURN
KMCHNG: PUSHJ P,SAVE1 ;we need P1
PUSHJ P,LOADW ;and our registers loaded
MOVEI T1,F.KIL ;tell KMC to stop
SETZ T2, ; SEL4,sel6
PUSHJ P,KMCQUE ;queue message to KMC
TRZ S,IOACT ;no longer I/O active
TRO S,IODERR!IODEND ;set error & EOF
JRST STOIOS##
SUBTTL DEVOP UUO INTERFACE - DISPATCH
;HERE ON A DISPATCH FROM UUOCON
; F=DDB
; T1=FUNCTION
;
;THE FOLLOWING ARE ERROR CODES WHICH CAN RESULT FOR THE KMC DEVOP UUO'S
;
;
;ERROR CODE TYPE UUO DESCRIPTION
;
; 1 GENERAL FUNCTION CODE = 0. SHOULD NEVER OCCUR AT
; DRIVER LEVEL SINCE UUOCON CHECKS FOR ZERO
; 2 GENERAL FUNCTION CODE NOT VALID FOR KMC-11 DRIVER
; 3 GENERAL CHECK OF THE KMC UBA ADDRESS FAILED
; 4 GENERAL TEST OF JOB ASSIGNED FAILED
;
;ERRORS
KE%ILF==ECOD1## ;ILLEGAL FUNCTION CODE
KE%ILK==ECOD2## ;ILLEGAL KMC NUMBER
KE%ALS==ECOD3## ;ARG LIST TOO SHORT
KE%IWR==ECOD4## ;ILLEGAL WHEN KMC-11 RUNNING
KE%ICA==ECOD5## ;ILLEGAL CRAM ADDRESS (READ OR WRITE)
KE%ILL==ECOD6## ;ILLEGAL LINE NUMBER
KE%KNR==ECOD7## ;KMC-11 NOT RUNNING (KDL TYPE OP'S)
KE%LNS==ECOD10## ;KDL LINE NOT STARTED
KE%LAS==ECOD11## ;KDL LINE ALREADY STARTED
KE%UNP==ECOD12## ;USER NOT PRIVLEDGED
KMCDVP: PUSHJ P,SAVE4## ;SAVE P1 THRU P4
MOVE P2,T1 ;make a more permanent copy
MOVSI T2,-KMCDVL ;GET TABLE LENGTH SETUP AOBJN PTR
KMCDV1: HLRZ T3,KMCDVT(T2) ;GET FUNCTION
HRRZ P3,KMCDVT(T2) ;GET THE DISPATCH ADDRESS
CAMN P2,T3 ;DO CODE MATCH?
JRST KMCDV2 ;YES, SO DISPATCH
AOBJN T2,KMCDV1 ;NO, GO LOOP
PJRST ECOD2## ;NO MATCH, GIVE ERROR RTN
KMCDV2: PUSHJ P,TSTJBN ;SEE IF USER OWNS DDB
PUSHJ P,CKPVBT ;TEST FOR [1,2] OR JACCT
PUSHJ P,SETBAS ;LOAD KMC BASE ADDRESS INTO P1
TRNN P2,3000 ;read/write type funct?
JRST (P3) ;no, just dispatch
HLRE T3,P4 ;yes, get actual aarg block len
CAIGE T3,4 ;need at least 4 words
JRST KE%ALS ; too short
JRST (P3) ;long enuf .... dispatch
KMCDVT: XWD 0,ECOD1## ;NO FUNCTION CODE SPECIFIED
XWD 1,KMCST ;Start the KMC
XWD 2,KMCHA ;Halt the KMC
XWD 1004,KMCPRR ;protocol read registers
XWD 1005,KMCBRR ;Blind read registers
XWD 2004,KMCPWR ;protocol write registers
XWD 2005,KMCBWR ;Blind write registers
KMCDVL==.-KMCDVT ;DISPATCH TABLE LENGTH
; KMCBRR - Blind read of KMC registers (debug only?)
KMCBRR: RDIO T2,SEL0(P1) ;read all registers
RDIO T1,SEL2(P1) ; ...
HRL T1,T2 ;merge sel0, sel2
PUSHJ P,PUTWD1## ;give to user
RDIO T2,SEL4(P1) ; ...
RDIO T1,SEL6(P1) ; ...
HRL T1,T2 ;merge sel4, sel6
PUSHJ P,PUTWD1## ;give to user
RETSKP
; KMCBWR - Blind write of KMC registers (Debug ONLY!!!)
KMCBWR: PUSHJ P,FTCHWD ;get user word
WRIO T1,SEL2(P1) ;write sel2
HLRZ T1,T1 ;get sel0
WRIO T1,SEL0(P1) ;and sel0
PUSHJ P,FTCHWD ;get next word
HLRZ T2,T1 ;get sel4 data
WRIO T2,SEL4(P1) ;write SEL4
WRIO T1,SEL6(P1) ;write SEL6
RETSKP
; KMCPWR, KMCPRR - Read/Write commands to the KMC.
;These are nearly the same, because the KMC indicates completion status
;for "set parameters" type commands.
KMCPRR:
KMCPWR: PUSHJ P,FTCHWD ;get next user word (0,,sel2)
MOVE P3,T1 ;save
TRNE P2,2000 ;is this a write DEVOP.?
TROA P3,KM3IOD ;set direction to out
TRZ P3,KM3IOD ;set for read
PUSHJ P,FTCHWD ;get [sel4,,sel6]
MOVE P4,T1 ;and save that!
TLO S,DVOACT ;mark DEVOP response pending
PUSHJ P,SETACT## ;set IO active
DMOVE T1,P3 ;get data to write
PUSHJ P,KMCQUE ;queue write registers request
PUSHJ P,WAIT1## ;wait for IO active to vanish!
TLZ T1,DVOACT ;no longer waiting for DEVOP.
MOVEM S,DEVIOS(F) ;store status
DMOVE T1,DMCDV2(F) ;get registers read
EXCTXU <DMOVEM T1,-1(M)> ;return data to users
RETSKP
; #1 -- START THE KMC-11. THIS FIRST STARTS THE KMC-11, AND THEN
; SETS UP THE INTERRUPT VECTORS. ONCE THE VECTORS ARE SET UP,
; IT SETS THE TWO KMC-11 INTERRUPT ENABLES, AND DECLARES THE KMC RUNNING.
KMCST: MOVEI T1,KMCRUN ;GET THE RUN BIT
TIOE T1,@KMCCSR(W) ;MAKE SURE THE KMC-11 ISN'T RUNNING ALREADY
PJRST KE%IWR ;IF IT IS, GIVE "ILLEGAL WHEN RUNNING" ERROR
WRIO T1,@KMCCSR(W) ;SET RUN NOW, WILL SET IEI & IEO SOON
; (MUST GIVE KMC TIME TO INIT)
MOVE T1,KMCVEC(W) ;GET THE ADDRESS OF THE VECTOR
LSH T1,-2 ;CONVERT BYTE OFFSET INTO WORD OFFSET
HRLI T2,(JSR) ;GET BODY OFF A "JSR" INSTRUCTION
HRRI T2,KMCIVA(W) ;GET ADDRESS OF VECTOR "A" INTERRUPT SERVICE
MOVEM T2,VECTB3##(T1) ;STORE ADDRESS OF ROUTINE TO FORCE JSR TO
HRRI T2,KMCIVB(W) ;GET ADDRESS OF "B" SERVICE ROUTINE
MOVEM T2,VECTB3##+1(T1);SET UP VECTOR "B" INTERRUPT SERVICE
MOVEI T1,KMCRUN!KMCIEI!KMCIEO ;START THE KMC-11 AND ENABLE INTS
WRIO T1,@KMCCSR(W) ;START THE KMC-11
MOVSI T1,(KMCSRU) ;GET AND SET THE "RUNNING"
IORB T1,KMCSTS(W) ; BIT SO IT AT LEAST LOOKS LIKE WE'RE UP.
RETSKP ;ALL DONE. GIVE THE USER A GOOD RETURN
; #2 -- HALT THE KMC-11. THIS DOES NOT DECLARE DUP-11 LINES DOWN SINCE
; SETTING THE RUN BIT WOULD, IN THEORY, ALLOW THE KMC-11 TO CONTINUE.
KMCHA: MOVEI T1,0 ;GET THE KMC-11 RUN BIT
WRIO T1,@KMCCSR(W) ;CLEAR THE RUN/MAINT BITS
MOVSI T1,(KMCSRU) ;GET THE "MICROCODE RUNNING" BIT
ANDCAM T1,KMCSTS(W) ; AND CLEAR THAT
RETSKP ;GIVE GOOD RETURN
; Read KMC-11 cram. KMC-11 must be halted.
KMCDIN: PUSHJ P,SAVE4 ;save the P's
PUSHJ P,LOADW ;setup W, check that KMC exists
MOVEI T1,KMCRUN ;GET THE RUN BIT
TIOE T1,SEL0(P1) ;SEE IF THE KMC-11 IS RUNNING
PJRST IMPERR ;IF IT IS RUNNING, GIVE AN ERROR
MOVEM S,DEVIOS(F) ;S is destroyed by COMCHK
PUSHJ P,COMCHK## ;get first IOWD, and buffer mapped
JUMPE T1,CPOPJ## ;no IOWD??
JUMPN S,ADRERR## ;address check??
HLRE P3,T1 ;isolate word count
ASH P3,1 ; *2 (cram words per 10 word)
HRLI T1,(POINT 18,,35) ;ILDB pointer to next word
SETZ P2, ;cram address
RDLOOP: MOVEI T2,KMCRMO ;GET THE "READ CRAM" BIT
WRIO T2,SEL0(P1) ;ENABLE THE KMC-11 FOR MAINT CRAM rd/wt
WRIO P2,SEL4(P1) ;STORE THE ADDRESS IN MAINT CRAM ADDR REG
RDIO T2,SEL6(P1) ;read the cram memory buffer register
XCT PX.SRC!PX.BYT,[IDPB T2,T1] ;GET THE VALUE TO WRITE
ADDI P2,1 ;step CRAM addr
AOJL P3,RDLOOP ;and loop.
POPJ P,
; Write KMC-11 cram. Just like read (almost).
KMCDOU: PUSHJ P,SAVE4## ;save registers
PUSHJ P,LOADW ;SET W,P1, CHECK FOR DEVICE EXISTS
PUSHJ P,KMCHA ;halt the KMC (in case it's running)
MOVEI T1,KMCRUN ;GET THE RUN BIT
TIOE T1,SEL0(P1) ;SEE IF THE KMC-11 IS RUNNING
PJRST IMPERR ;IF IT IS RUNNING, GIVE AN ERROR
MOVEM S,DEVIOS(F) ;S is destroyed by COMCHK
PUSHJ P,COMCHK## ;get first IOWD, and buffer mapped
JUMPE T1,CPOPJ## ;no IOWD??
JUMPN S,ADRERR## ;address check??
HLRE T3,T1 ;isolate word count
ASH T3,1 ; *2 (cram words per 10 word)
HRLI T1,(POINT 18,,35) ;ILDB pointer to next word
MOVE P3,T1 ;save byte pointer for verify
MOVE P4,T3 ; and word count
SETZ P2, ;cram address
LDLOOP: MOVEI T2,KMCRMO ;GET THE "READ CRAM" BIT
WRIO T2,SEL0(P1) ;ENABLE THE KMC-11 FOR MAINT CRAM rd/wt
WRIO P2,SEL4(P1) ;STORE THE ADDRESS IN MAINT CRAM ADDR REG
XCT PX.BYT!PX.SRC,[ILDB T2,T1] ;GET THE VALUE TO WRITE
WRIO T2,SEL6(P1) ;PUT IT IN THE CRAM MEMORY BUFFER REGISTER
ADDI P2,1 ;increment cram addr
MOVEI T2,KMCCWR ;GET THE CRAM WRITE BIT
BSIO T2,SEL0(P1) ;CLOCK THE DATA INTO THE CRAM
JFCL ;delay 1
BCIO T2,SEL0(P1) ;clear write cram toggle
AOJL T3,LDLOOP ;and loop.
; now verify the load
SETZ P2, ;cram address
VRLOOP: MOVEI T2,KMCRMO ;GET THE "READ CRAM" BIT
WRIO T2,SEL0(P1) ;ENABLE THE KMC-11 FOR MAINT CRAM rd/wt
WRIO P2,SEL4(P1) ;STORE THE ADDRESS IN MAINT CRAM ADDR REG
XCT PX.BYT!PX.SRC,[ILDB T2,P3] ;get the value to be verified
RDIO T3,SEL6(P1) ;read the cram memory buffer register
CAIE T3,(T2) ;does the word match?
JRST DEVERR ;device error
ADDI P2,1 ;increment cram addr
AOJL p4,VRLOOP ;and loop.
SETO T2, ;get a non-zero
WRIOB T2,SEL2(P1) ; and set as a flag that KMC not init'd
MOVEI T1,KMCMCL ;get the KMC master clear
WRIO T1,SEL0(P1) ;set run now, will set IEI & IEO soon
MOVEI T1,KMCRUN ;get the KMC run bit
WRIO T1,SEL0(P1) ;set run now, will set IEI & IEO soon
; (must give kmc time to init)
MOVE T1,KMCVEC(W) ;get the address of the vector
LSH T1,-2 ;convert byte offset into word offset
HRLI T2,(JSR) ;get body off a "JSR" instruction
HRRI T2,KMCAIN-KMC0CB(W) ;vector "A" interrupt service
MOVEM T2,VECTB3##(T1) ;store JSR to sevice routine
HRRI T2,KMCBIN-KMC0CB(W) ;GET ADDRESS OF "B" SERVICE ROUTINE
MOVEM T2,VECTB3##+1(T1);SET UP VECTOR "B" INTERRUPT SERVICE
MOVEI T1,KMCRUN!KMCIEI!KMCIEO ;START THE KMC-11 AND ENABLE INTS
RDIOB T2,SEL2(P1) ;KMC should have clear'd this by now
JUMPN T2,DEVERR ; declare device error if not!
WRIO T1,SEL0(P1) ;START THE KMC-11
POPJ P, ;done with loop ... exit
IMPERR: TRO S,IOIMPM ;set improper mode
PJRST STOIOS## ;store IOS and return to user
DEVERR: MOVEI S,IODERR ;device error
IORB S,DEVIOS(F) ;set error flag
POPJ P, ;and quit
;HERE TO GET A WORD FROM USERS ARGUMENT BLOCK
FTCHWD: PUSHJ P,GETWR1## ;GET USER ARGUMENT WORD
SKIPA
POPJ P, ;RETURN
POP P,(P) ;FETCH FAILED
PJRST ECOD10## ;EXIT
;HERE TO TEST DDB OWNERSHIP
TSTJBN: LDB T2,PJOBN## ;GET NODE ASSIGNED JOB NO.
CAMN J,T2 ;COMPARE WITH REQUESTING JOB
POPJ P, ;RETURN
POP P,(P) ;ADJUST STACK
PJRST ECOD4## ;JOB DOESN'T OWN DDB - ERROR
;HERE TO SETUP AND TEST KMC BASE ADDRESS
SETBAS: MOVE W,DMCKMC(F) ;GET KMC CONTROL BLOCK
MOVE P1,KMCCSR(W) ;LOAD P1 WITH DEVICE ADDR
MOVE T1,P1 ;T1 MUST HAVE ADDRESS
PUSHJ P,UBGOOD## ;GO CHECK UBA THERE
SKIPA ;BAD UBA,ADDRESS OR BUS
POPJ P, ;YES, RETURN
POP P,(P) ;ADJUST STACK
PJRST ECOD3## ;EXIT
;HERE TO CHECK FOR PRIVILEDGE USER
CKPVBT: popj p, ;%%%%for now, always OK.
PUSHJ P,PRVJ## ;GOTO CHECK ROUTINE
POPJ P, ;OK, GOOD RETURN
POP P,(P) ;NO - FORGET IT,BAD GUY!!!
PJRST ECOD5## ;EXIT
; Here to set W and P1 for I/O uuo calls
LOADW: MOVE W,DMCKMC(F) ;GET KMC CONTROL BLOCK
MOVE P1,KMCCSR(W) ;LOAD P1 WITH DEVICE ADDR
MOVE T1,P1 ;T1 MUST HAVE ADDRESS
PUSHJ P,UBGOOD## ;GO CHECK UBA THERE
SKIPA ;BAD UBA,ADDRESS OR BUS
POPJ P, ;YES, RETURN
POP P,(P) ;ADJUST STACK
TRO S,IODERR ;set device error
PJRST STOIOS## ;store IOS and return
SUBTTL OUT/OUTPUT KMC-11 UUO SERVICE
KMCOUT: PUSHJ P,SAVE4## ;SAVE P1 - P4
PUSHJ P,LOADW ;LOAD W, P1
TLO S,IO ;FLAG OUTPUT
PUSHJ P,KMSETO ;SETUP USER'S OUT BUFFER
PJRST SETACT## ;set I/O active and return
SUBTTL IN/INPUT KMC-11 UUO SERVICE
KMCINP: PUSHJ P,SAVE4## ;SAVE P1 - P4
PUSHJ P,LOADW ;LOAD W, P1
TLZ S,IO ;FLAG OUTPUT
PUSHJ P,KMSETI ;setup user's input buffer
PJRST SETACT## ;set I/O active and return
SUBTTL SETUP NEXT BUFFER ROUTINES
KMSETI: HRRZ T2,DEVIAD(F) ;GET INPUT BUFFER ADDRESS
CAIA
KMSETO: HRRZ T2,DEVOAD(F) ;GET OUTPUT BUFFER ADDRESS
SETZ P1, ;CLEAR P1
LDB T1,PIOMOD## ;get address-1 and correct
ADD T2,[IOWD ^D256/4,2 ; buffer size for MAPIO
0 ; and form IOWD
0 ;
IOWD DRAMSZ/4,2]-I(T1) ;
MOVE P3,KMCCDB(W) ;get Channel Data Block
LDB T1,PUNIT ;get line #
LSH T1,1 ;2 pages per DZ line
ADD T1,[KMCIMR##] ;compute correct first page
MOVEM T1,CHNIMR##(P3) ;store for MAPIO
PUSHJ P,MAPIO## ;go setup UBA registers
STOPCD CPOPJ,JOB,KGL ;+++MAPIO GOT LOST
LDB T1,PIOMOD## ;get IO mode
CAIE T1,I ;is it image?
SKIPA T1,[F.DRAM] ;IB mode - read DRAM
MOVEI T1,F.DATA ;normal data i/o
TLNE S,IO ;in or out?
TRO T1,KM3IOD ;set direction for output
HRLZ T2,CHNIEA##(P3) ;11 style virtual buffer addr
PUSHJ P,KMCQUE ;queue request to KMC
POPJ P, ;RETURN
SUBTTL CLOSE & RELEASE
KMCCLS:
KMCREL: PUSHJ P,SAVE1## ;we use P1 for KMC addr
PUSHJ P,LOADW ;load W, P1
TLZ S,DVOACT!IOEND ;no DEVOP pending!
MOVEI T1,F.KIL ;tell KMC to cancel
SETZ T2, ; sel4 = sel6 = 0
PUSHJ P,KMCQUE ;que rqst to KMC
PJRST CLRACT## ;return any EVM
SUBTTL INTERRUPTS -- INTERRUPT LEVEL INTERFACE TO THE KMC-11
Comment @
Each KMC-11 has two interrupt vector addresses.
"A" This interrupt is taken when RDYI (KMCRDI) comes up. In this
state the KMC-11 is ready for an input transaction. All
input transactions for the KMC-11 are queued in the KMC block.
This is necessary because the following situation would otherwise
cause a deadlock.
1) The KMC-11 sets RDYO and gives a BUFFER-OUT transaction.
2) At interrupt level, we want to do a BUFFER-IN.
3) If, in the meantime, the KMC-11 has set RDYO again,
we will not be able to get RDYI until we process another
output transaction.
The solution to this is to queue all input transactions. This does
mean that we have to take an interrupt on each transaction, but it
does circumvent the above problem.
"B" This interrupt is taken when RDYO (KMCRDO) comes up. In this
state the KMC-11 wants to perform an output transaction.
It is these output transactions that drive almost all of the
interrupt level KMC processing.
The vector instructions are set up to be JSR's to the
locations "KMCIVA", and "KMCIVB" in the KMC block for the
KMC-11. These locations contain the 5 or 6 instructions
necessary to save the AC's, load "W" with the address of the
particular KMC block, and dispatch to either of the two
interrupt routines "KMCIVA" or "KMCIVB".
End comment @
SUBTTL KMCIVA -- KMC-11 INTERRUPT VECTOR "A" PROCESSING.
;KMCIVA -- ROUTINE TO HANDLE KMC-11 INTERRUPT VECTOR "A" (INPUT)
;CALL MOVE W,[EXP KMC-BLOCK-ADDRESS]
; PUSHJ P,KMCIVA ;CALLED FROM KMCIVA IN THE KMC BLOCK
;RETURN POPJ P, ;TO DISMISS THE INTERRUPT.
;
;CLOBBERS MOST AC'S (WE SHOULD HAVE OUR OWN AC BLOCK ANYWAY)
;
;
KMCIVA::ADDI W,KMC0CB-KMCBIN ;FIX KMC POINTER
AOS KMCACT(W) ;COUNT THE INTERRUPT
MOVE U,KMCCSR(W) ;GET THE UNIBUS ADDRESS OF THE KMC-11
MOVEI T1,KMCRDI ;GET THE "RDYI" FLAG
TION T1,SEL2(U) ;MAKE SURE "RDYI" IS UP
PJSP T1,KMCERR ; IF IT'S NOT, THEN ITS AN ILLEGAL INTERRUPT
MOVE T3,KMCIQT(W) ;GET NUMBER OF NEXT QUEUED TRANSACTION
CAMN T3,KMCIQP(W) ;MAKE SURE THAT IT'S DIFFERENT NOT THE "PUTTER"
PJSP T1,KMCERR ; IF IT IS, THEN WE'RE GETTINT UNSOLICITED
; INTERRUPTS. DECLARE KMC ILL.
LSH T3,1 ;MAKE IT AN OFFSET INTO THE QUEUE
ADDI T3,KMCINQ(W) ;RELOCATE BY THE ADDRESS OF THE QUEUE
MOVE T1,0(T3) ;GET SEL2 DATA
MOVE T2,1(T3) ;GET SEL4, SEL6 DATA
AOS T3,KMCIQT(W) ;ADVANCE QUEUE TAKER
CAIL T3,KMCQLN ;IF ITS TIME TO WRAP AROUND, THEN
SETZB T3,KMCIQT(W) ; WRAP AROUND TO THE FIRST ENTRY
MOVEI T4,KMCRQI ;GET THE REQUEST INPUT INTERRUPT BIT
CAMN T3,KMCIQP(W) ;IF QUEUE EMPTY (PUTTER = TAKER) THEN
BCIO T4,SEL0(U) ; CLEAR RQI TO STOP THE INTERRUPTS
WRIO T2,SEL6(U) ;STORE TOP WORD
MOVSS T2,T2 ;GET SEL4 DATA
WRIO T2,SEL4(U) ; AND STORE THAT
TRZ T1,KMCRDI ;MAKE SURE RDYI CLEAR (SO KMC CAN RUN)
WRIO T1,SEL2(U) ;GIVE REST OF DATA TO KMC
POPJ P, ;ALL DONE
kmcerr: jfcl ;put bpt here, if you want
setz t1, ;stop the "bad" kmc
wrio t1,sel0(u) ; ...
popj p,
;KMCIVB -- Routine to handle KMC-11 interrupt vector "B" (output)
;Call: MOVE W,[EXP KMC-BLOCK-ADDRESS]
; PUSHJ P,KMCIVB ;called from KMCIVB in the KMC block
;Return:POPJ P, ;to dismiss the interrupt
;
;clobbers most AC's (we should have our own AC block anyways)
;
;
KMCIVB::AOS KMCBCT(W) ;Count the interrupt
MOVE U,KMCCSR(W) ;get the Unibus Address of the KMC
RDIO P1,SEL2(U) ;read status bits
TRNN P1,KMCRDO ;better want an output transaction
PJSP T1,KMCERR ;illegal interrupt. crash KMC
RDIO P2,SEL4(U) ;read SEL4 for later analysis
RDIO P3,SEL6(U) ;read error, status or what ever
PUSHJ P,SAVE3## ;make sure csrs are saved
MOVEI T1,KMCRDO ;get the RDYO bit
BCIO T1,SEL2(U) ;clear it to let the KMC continue
LDB F,[POINT 3,P1,35] ;get 3 bit line #.
ADD F,W ;get correct DDB
SKIPN F,KMCTBL(F) ;load DDB address
POPJ P, ;no DDB? - dismiss interrupt
HRL P3,P2 ;merge SEL4, SEL6
MOVEM P1,DMCDV2(F) ;store registers in DDB
MOVEM P3,DMCDV4(F) ; ...
PUSHJ P,IOSET## ;set up S, R, J from DDB
LDB J,PJOBN## ;set J to owning job #
PUSHJ P,SVEUF## ;GET THE PAGING "RIGHT" (??)
LDB T1,[POINT 3,P1,35-8] ;get function just completed
CAIE T1,F.DATA/400 ;buffer done?
CAIN T1,F.DRAM/400 ; (data or DRAM)
JRST BUFDON ;yes, go handle buffer done
TLNN S,DVOACT ;doing DEVOP.?
POPJ P, ;no, just return
PUSHJ P,SETIOD## ;yes, well it's done!
PJRST CLRACT## ;clear I/O active and exit
SUBTTL BUFDON - buffered IO done
BUFDON: ANDI P3,377-IODIR ;mask to relevent file status bits
LSH P3,^D9 ;shift to corresponding position for IOS
TRZ S,7700 ;clear device dependent bits in IOS
TRO S,(P3) ;merge new file status bits
MOVEM S,DEVIOS(F) ;save updated device status
PUSHJ P,SETIOD## ;a buffer is done...job may want to run
MOVE P1,KMCCSR(W) ;load P1 with csr addr
TLNN S,IO ;which direction?
JRST INPDON ;go handle input
; here on output done
PUSHJ P,ADVBFE## ;advance output buffers
JRST BUFSTP ;no more
TRNE S,760000 ;TEST FOR KMC ERRORS OR EOF
JRST BUFSTP ; END TRANSMISSION IF FOUND
PJRST KMSETO ;setup next output buffer
INPDON: HRRZ T1,DEVIAD(F) ;get current buffer header
EXCTXU <HRRZM P2,1(T1)>;store byte count
PUSHJ P,ADVBFF## ;advance buffers
JRST BUFSTP ;buffered IO stop
TRNE S,760000 ;TEST FOR KMC ERRORS OR EOF
JRST BUFSTP ; END TRANSMISSION IF FOUND
PJRST KMSETI ;set up next buffer
BUFSTP: TRNE S,760000 ;test for kmc errors or eof
TLO S,IOEND ;set for MONITOR
PJRST CLRACT##
SUBTTL KMCINP -- ROUTINE TO QUEUE TRANSACTIONS FOR THE KMC-11
;Called with:
; W := KMC pointer
; T1 := XWD 0,SEL2
; T2 := XWD SEL4,SEL6
;Returns
; CPOPJ KMC-11 not running
; CPOPJ1 Transaction described by T1 & T2 has been queued.
; RQI has been set to request an interrupt on vector "A".
; KMCIVA will then process the top transaction on the queue.
;
KMCQUE:
LDB T3,PUNIT## ;get line number
TRZ T1,KM2LIN!KMCRDO!KMCRDI ;clear forbidden bits
TRO T1,(T3) ;set line number
MOVE T3,KMCIQP(W) ;GET INDEX OF NEXT ENTRY IN THE QUEUE
LSH T3,1 ;MAKE IT AN OFFSET (ENTRYS ARE 2 WDS)
ADDI T3,KMCINQ(W) ;RELOCATE TO THE ADDRESS OF THE QUEUE
MOVEM T1,0(T3) ;STORE SEL2
MOVEM T2,1(T3) ;STORE XWD SEL4,SEL6
AOS T3,KMCIQP(W) ;ADVANCE THE "PUTTER"'S INDEX
CAIL T3,KMCQLN ;IF WE NEED TO WRAP AROUND, THEN
SETZB T3,KMCIQP(W) ; THEN WRAP TO THE FIRST ENTRY
CAMN T3,KMCIQT(W) ;IS THE QUEUE FULL (PUTTER = TAKER)
PJSP T1,KMCERR ; IF SO, KMC MUST BE DEAD. CRASH IT.
MOVEI T3,KMCRQI ;GET RQI AND SET IT IN BSEL0
BSIO T3,@KMCCSR(W) ; THIS WILL CAUSE A VECTOR "A" INTERRUPT
POPJ P, ;RETURN
XLIST ; **** LITERALS ****
LIT
LIST
KMCEND: END