// DLSDriverInit.bcpl -- Alto DLS Driver initiailization // This code may be thrown away after use // Last modified April 25, 1982 4:49 PM by Taft // Last modified October 20, 1983 1:31 PM by Diebert get "DLSDriver.decl" external [ // outgoing procedures InitializeDLS; CreateDCLM // incoming procedures -- DLSDriver DLSInput7; DLSOutput7; DLSResetInput; DLSResetOutput; DLSOutputTI UpdateCarrierOn; SetDLSLineSpeed TurnOnDLS; TurnOffDLS; DLSInputInterrupt; DLSOutputInterrupt; DLSErrorInterrupt; DLSUserFinishProc; DLSSwatContextProc; DLSInputEmpty; DLSOutputFull // incoming procedures -- OS and packages InitRingBuffer; InitializeInterrupt; SetBlock; Zero; Dvec; Allocate; CallSwat; SysErr; Noop // outgoing statics lbTable; dlsInputOverflows; dlsErrorInterrupts; dlsOnVector; dlsSavedUserFinish; dlsSavedSwatContext; baseIGCB; inputRBCB; outputRBCB; parityTable // incoming statics lvUserFinishProc; lvSwatContextProc; ] static [ @baseIGCB // Base of input group control blocks iLCBTable // Table of pointers to input LCBs oLCBTable // Table of pointers to output LCBs @inputRBCB // Input ring buffer control block @outputRBCB // Output ring buffer control block inputRB // Input ring buffer outputRB // Output ring buffer dlsTimerQueue // Timer queue table dlsOnVector = 0 // Argument for DLSON instruction @lbTable = 0 // Table of pointers to line blocks dlsInputOverflows = 0 // Line input buffer overflow count dlsErrorInterrupts = 0 // DLS error interrupt count dlsSavedUserFinish // Places to save old contents dlsSavedSwatContext // of special os dispatches parityTable // Table of Ascii chars with even parity ] // --------------------------------------------------------------------------- let InitializeDLS(zone, lct) be // --------------------------------------------------------------------------- // zone is where to get space from. // lct is a Line Configuration Table of length numLines. [ TurnOffDLS() // Make sure DLS is off SetBlock(dlsOutBase, 1, numLines) // Set output lines marking let firstTime = dlsOnVector eq 0 // True only on first call if firstTime then // Allocate storage only once [ // Storage that need not be aligned in any special way iLCBTable = Allocate(zone, numLines) // Input LCB table oLCBTable = Allocate(zone, numLines) // Output LCB table lbTable = Allocate(zone, numLines) // Line data block table dlsTimerQueue = Allocate(zone, 256) // Timer queue for microcode inputRB = Allocate(zone, lenDLSIRB) // Input ring buffer outputRB = Allocate(zone, lenDLSORB) // Output ring buffer // IGCBs must start on #20-word boundary baseIGCB = (Allocate(zone, numLines+#17)+#17)𫙠 // DLBs must be aligned so that the ILCBs and OLCBs // contained within them are on even word boundaries. // CLBs need not be aligned. let unusedLB = Allocate(zone, lenLBH) for line = 0 to numLines-1 do [ let lb = nil switchon lct>>LCT↑line.lineType into [ case ltControl: case ltDialler: [ lb = Allocate(zone, lenCLB) endcase ] case ltUnused: [ lb = unusedLB endcase ] default: [ // Data line lb = Allocate(zone, lenDLB+1) let lcb = lv lb>>DLB.iLCB.link if (lcb&1) ne 0 then lb = lb+1 Zero(lb, lenDLB) iLCBTable!line = lv lb>>DLB.iLCB.line oLCBTable!line = lv lb>>DLB.oLCB.line endcase ] ] lbTable!line = lb lb>>LBH.line = line lb>>LBH.lineType = lct>>LCT↑line.lineType lb>>LBH.otherLine = lct>>LCT↑line.otherLine ] // RBCBs and DLSOnVector must be aligned on even words // Nestle them into the space wasted in the IGCBs inputRBCB = baseIGCB+#10+1 // +1 since RBCB pointers are to outputRBCB = baseIGCB+#14+1 // second word of block dlsOnVector = baseIGCB+#30 ] // InitializeDLS (cont'd) Zero(dlsTimerQueue, 256) // Initialize the timer queue // Initialize the microcode ring buffers inputRBCB!-1 = inputRB // Reset input pointer inputRBCB!1 = inputRB // Reset output pointer inputRBCB!0 = inputRB+lenDLSIRB-1 // Set limit pointer @inputRBCB!0 = inputRB // Make last word point to first outputRBCB!-1 = outputRB // Reset input pointer outputRBCB!1 = outputRB // Reset output pointer outputRBCB!0 = outputRB+lenDLSORB-1 // Set limit pointer @outputRBCB!0 = outputRB // Make last word point to first // Initialize the vector for DLSON dlsOnVector!0 = iLCBTable dlsOnVector!1 = baseIGCB dlsOnVector!2 = inputRBCB dlsOnVector!3 = outputRBCB dlsOnVector!4 = dlsTimerQueue // Initialize the input group control blocks for line = 0 to numLines-1 by 16 do [ let lcb = baseIGCB+line lcb>>IGCB.link = 0 lcb>>IGCB.type = typeIGCB lcb>>IGCB.line = line // First line number in group lcb>>IGCB.idle = 0 // All lines not being sampled lcb>>IGCB.interval = defaultSampleInterval lcb>>IGCB.active = 0 // All lines turned off dlsTimerQueue!(line/16) = lcb+1 // Spread IGCBs along queue ] // Initialize DLS interrupts if firstTime then // Do this stuff only once [ InitializeInterrupt(Allocate(zone, 30), 30, inputIntMask, DLSInputInterrupt) InitializeInterrupt(Allocate(zone, 30), 30, outputIntMask, DLSOutputInterrupt) InitializeInterrupt(Allocate(zone, 30), 30, errorIntMask, DLSErrorInterrupt) // Set dispatches for eventual cleanup dlsSavedUserFinish = @lvUserFinishProc @lvUserFinishProc = DLSUserFinishProc dlsSavedSwatContext = @lvSwatContextProc @lvSwatContextProc = DLSSwatContextProc // Initialize table for parity computation parityTable = Allocate(zone, 128) for char = 0 to 127 do [ parityTable!char = char for j = 0 to 6 do if ((char rshift j)&1) ne 0 then parityTable!char = parityTable!char xor #200 ] ] // InitializeDLS (cont'd) // Initialize the line blocks for line = 0 to numLines-1 do [ let lb = lbTable!line let mask = 100000B rshift (line) switchon lb>>LBH.lineType into [ case ltControl: case ltDialler: // Control line [ lb>>CLB.lastState = -1 // Force an update the first time // Raise DTR if dataset control, drop control signal if dialler dlsOutBase!line = lb>>LBH.lineType eq ltDialler endcase ] case ltUnused: // Unused line or speed status line endcase default: // Data line [ // Initialize stream dispatches lb>>DLB.gets = DLSInput7 lb>>DLB.reset = DLSResetInput lb>>DLB.endof = DLSInputEmpty lb>>DLB.error = Noop lb>>DLB.puts = DLSOutputTI // Undefined entries to SysErr lb>>DLB.close = SysErr lb>>DLB.putback = SysErr lb>>DLB.stateof = SysErr // Initialize status and ring buffers lb>>DLB.statusA = 0 lb>>DLB.statusB = 0 lb>>DLB.position = 0 lb>>DLB.outActive = false lb>>DLB.timeout = -1 InitRingBuffer(lv lb>>DLB.iRBD, lv lb>>DLB.iBuf, lenIRB) InitRingBuffer(lv lb>>DLB.oRBD, lv lb>>DLB.oBuf, lenORB) // Initialize input line control block lb>>DLB.iLCB.link = 0 lb>>DLB.iLCB.type = typeILCB lb>>DLB.iLCB.line = line lb>>DLB.iLCB.char = 0 lb>>DLB.iLCB.sdMode = 0 // Not speed determination mode lb>>DLB.iLCB.bitsPerChar = 2 // 8 bits per char lb>>DLB.iLCB.sdLink = 0 // Initialize output line control block lb>>DLB.oLCB.link = 0 // Clear link lb>>DLB.oLCB.type = typeOLCB lb>>DLB.oLCB.line = line lb>>DLB.oLCB.char = 0 // Set sample intervals, bitsPerChar, puts routine SetDLSLineSpeed(lb, defaultBaud) // Enable sampling of this line in the GCB let lcb = baseIGCB + (line𫙠) lcb>>IGCB.idle = lcb>>IGCB.idle % mask lcb>>IGCB.active = lcb>>IGCB.active % mask endcase ] ] ] // Get current control state of lines, then turn on DLS microcode UpdateCarrierOn(Noop) TurnOnDLS() ] // --------------------------------------------------------------------------- and CreateDCLM(zone, lineVec) = valof // --------------------------------------------------------------------------- // Creates and returns a Dialler Control Line Map. // lineVec is a vector of six dialler control line numbers, which must // be mentioned in the order CRQ/PND, DPR/ACR, DSS/NB1, NB2, NB4, NB8. [ for i = 0 to 5 do if (lbTable!(lineVec!i))>>LBH.lineType ne ltDialler then CallSwat() let dclm = Allocate(zone, lenDCLM) dclm>>DCLM.inUse = 0 dclm>>DCLM.lineCRQ = lineVec!0 dclm>>DCLM.lineDPR = lineVec!1 dclm>>DCLM.lineNB↑0 = lineVec!2 dclm>>DCLM.lineNB↑1 = lineVec!3 dclm>>DCLM.lineNB↑2 = lineVec!4 dclm>>DCLM.lineNB↑3 = lineVec!5 dclm>>DCLM.diallerType = lineVec!6 resultis dclm ]