TERMINAL DRIVER INTERFACE UNDER VMS

by Alex Wong
Automated Systems Pty Ltd
DECUS Seminar, Singapore, March 1986

  1. INTRODUCTION

    Most VMS application programs perform terminal i/o through high level language statements such as READ or WRITE which compile into system calls to the terminal driver. For applications that need to manipulate read timeouts, character echo, line speed, etc this is inadequate in terms of performance and control. However, the terminal driver can be accessed directly through QIO system calls. This paper covers the background of the driver and how to interface to it.

  2. UNIBUS HARDWARE ARCHITECTURE

    The VAX is designed with a "memory mapped" I/O interface for all of its UNIBUS peripheral devices. This means a device communicate with the processor through CSR (Control and Status Register) and data registers which are mapped as addresses in the portion of the physical address space called the UNIBUS address space. The contents of these addresses can then be manipulated by various common instructions eg. MOVW, CLRW, BISW, etc. This is unlike some systems eg. IBM which has special I/O and channel control instructions for addressing and data transfer on its channels.

  3. READING AND WRITING DEVICE REGISTERS

    Each I/O controller or device directly attached to the UNIBUS has a set of CSR and data registers which are addressable as memory locations in the UNIBUS address space. The device driver can read or write data to the registers as though they are locations in memory. Most hardware controllers have DIP switches which allow the CSR and vector offsets to be set to various parts of the UNIBUS address space. The UNIBUS adapter performs the mapping of physical addresses to UNIBUS addresses that correspond to device registers.

  4. UNIBUS ADDRESS SPACE

    The UNIBUS address space consists of 256 Kbytes of memory (18-bit address) of which 8 Kbytes are reserved for device control registers. The UNIBUS adapter translates the 18-bit addresses into actual (32-bit) physical addresses by using mapping registers. It is this translation that allows the O/S, I/O drivers and UNIBUS devices to access the same physical address space. Listed below are the start of the UNIBUS address space for some of the VAX processors:
         VAX 780        20100000 (hex)
         VAX 750        FC0000
         VAX 730        FC0000
    
  5. DEVICE CSR AND VECTORS

    The Control and Status Register of a device enables the driver to perform I/O and return status information on the outcome of the operation. Vectors are offsets into a table of interrupt service routines used by the processor. To produce a list of known device CSR and vector on the system, invoke SYSGEN as follows:
    $ RUN SYS$SYSTEM:SYSGEN
    SYSGEN> SHOW /CONFIG
    
         System CSR and Vectors on 14-FEB-1986 11:35:50.24
    
    Name:DQA Units:1 Nexus:3 (UBA) CSR:775606 Vector1:250 Vector2:000 
    Name:MSA Units:1 Nexus:3 (UBA) CSR:772520 Vector1:224 Vector2:000
    Name:XGA Units:1 Nexus:3 (UBA) CSR:760344 Vector1:300 Vector2:304
    Name:TXA Units:8 Nexus:3 (UBA) CSR:760354 Vector1:320 Vector2:324
    
    The physical memory address of the CSR can be found by adding the CSR to the start of the UNIBUS address space eg. for a VAX 730, DMF32 terminal controller CSR is 760354(oct), vectors are 320 and 324(oct). The physical memory address of the CSR register is:

    FC0000 + 760354(oct) = FFE0EC

    The terminal driver for DMF32, YCDRIVER, obtain the device's status and activate the device by reading and writing to location FFE0EC. Terminal device drivers require 1 vector to handle character transmit interrupts and 1 vector to handle character receive interrupts. The vectors listed by SYSGEN on a VAX 730 are actually offsets into the second page of the System Control Block (SCB). The SCB is a VMS data structure that contains all the interrupt service routine addresses and is filled in by SYSGEN at AUTOCONFIG time. The second SCB page on a VAX 730 is used for direct-vectored UNIBUS device interrupts.

    When a character receive interrupt occurs, the processor will add the receive vector offset(320) to the SCBB register and 200(hex) to obtain the SCB vector. The SCB vector contains an address which points to the Interrupt Transfer Vector in another data structure called Channel Request Block(CRB). This vector contains instruction to save registers R0-R5 and jump to the character receive entry point in YCDRIVER. The transmit vector(324) works in a similar manner when a transmit interrupt occurs.

  6. TERMINAL DEVICE DRIVER

    The terminal driver was rewritten in VMS 3.0 using the class and port strategy. The terminal class driver (TTDRIVER) contains FDT routines and device dependent routines. The port drivers like YCDRIVER and DZDRIVER contain interrupt and controller-specific routines for DMF32 and DZ11 boards. Both class and port driver images can be separately loaded, thus enabling users to write custom-designed device drivers and test them out.

    When the system is booted, SYSBOOT reads TTDRIVER into nonpaged pool. Later, AUTOCONFIG in SYSGEN determines the port drivers to be loaded in for each controllers. These drivers then initializes the various Unit Control Block (UCB) fields.

  7. QIO REQUEST PROCESSING

    All terminal I/O requests are handled by the QIO system service which interfaces with the terminal driver. A QIO request issued from the host is processed in the following manner:

    1. A channel number is assigned to his process for a particular terminal device. This number is actually an offset into a data structure in P1 space called Channel Control Block. The CCB contains a pointer to the device UCB.

    2. The QIO system service performs device-independent validation of the request, check for sufficient process quota and allocates an Interrupt Request Packet (IRP).

    3. The IRP is initialized with data concerning the i/o request and then passed to class driver TTDRIVER. The class drivers's FDT routines validate device-dependent QIO parameters (P1-P6).

    4. A fork process is created and the class driver activates device by calling port driver routines to set the bits in the device CSR. If it is a DMA request, the transmit buffer register is filled with address of user buffer and char count register initialized to number of bytes to transfer.

    5. The driver waits until device requests an interrupt. The interrupt service routine is selected through the device vectors.

    6. The port driver reads CSR to check transfer status and pass it it back to the class driver.

    7. The class driver and VAX/VMS performs I/O post-processing and return status to QIO system service. Control returns to program.

  8. APPLICATION PROGRAM INTERFACE

    Programs can be written to interface directly with the driver through QIO system calls instead of high-level i/o statements eg. READ or WRITE. The main advantages are faster operations and complete control over the terminal and its characteristics. The disadvantages are program becomes terminal-dependent and more complex to write. A QIO statement requires the following parameters, some of which are optional:

    Event flag, channel number, function code, I/O status block, AST address, AST parameter, P1-P6 parameters

    The following examples are written in FORTRAN and MACRO.

  9. CHANNEL ASSIGNMENT

    Before any QIO can be issued, a channel to the device (eg. TXA3: or SYS$INPUT) must be assigned to the calling process.
        INTEGER SYS$ASSIGN,STATUS
        INTEGER*2 TTCHAN
    
        STATUS=SYS$ASSIGN('SYS$INPUT',TTCHAN,,)
        IF (.NOT.STATUS) CALL LIB$STOP(%VAL(STATUS))
    
  10. READ QIO

    To accept input from the terminal, issue a read QIO which specifies the function required and an input buffer:
         INCLUDE '($IODEF)'
         INTEGER STATUS,FUNC,SYS$QIOW
         BYTE BUFFER(10)
         
         FUNC=IO$_READVBLK.OR.IO$M_NOECHO
         STATUS=SYS$QIOW(,%VAL(TTCHAN),%VAL(FUNC),,,,BUFFER,%VAL(10),,,,)
    
    The IO$_READVBLK is known as a function code and IO$M_NOECHO is the function modifier code. A read QIO is normally terminated by a terminator char, buffer full or device timeout. ASCII chars 0-1F(hex) normally terminate the read. To terminate a read specifically by TAB (9 hex), code this:
        INTEGER MASK(2)
        
        MASK(1)=0
        MASK(2)='00000200'X                ! 9th bit position
        FUNC=IO$_READVBLK.OR.IO$M_NOFILTR
        STATUS=SYS$QIOW(,%VAL(TTCHAN),%VAL(FUNC),,,,BUFFER,%VAL(10),,MASK,,)
    
  11. WRITE QIO

    Write operations display the contents of a user buffer on the associated terminal. The example below uses the common function code IO$_WRITEVBLK.
        CHARACTER LINE*20
        
        LINE='HELLO WORLD'
        FUNC=IO$_WRITEVBLK
        STATUS=SYS$QIOW(,%VAL(TTCHAN),%VAL(FUNC),,,,%REF(LINE),%VAL(11),,,,)
    
    To specify carriage control to the write QIO, use the P4 parameter. For example, to output "CRLF CRLF printline CR" :
        INTEGER CCTL
        
        CCTL='8D020000'X
        STATUS=SYS$QIOW(,%VAL(TTCHAN),%VAL(FUNC),,,,%REF(LINE),%VAL(11),,%VAL(CCTL),,)
    
  12. SET PASTHRU MODE

    Normally, all terminal input is preprocessed by the terminal driver for special control characters such as CTRL/Y, CTRL/T, etc. To force the driver to pass everything to the program, the terminal must be set to PASTHRU mode using either DCL or program control.
             $TT2DEF
        TTC: .BLKL     3
        
             $QIOW_S   CHAN=TTCHAN,FUNC=#IO$_SENSEMODE,P1=TTC,P2=#12
             BISL2     #TT2$M_PASTHRU,TTC+8
             $QIOW_S   CHAN=TTCHAN,FUNC=#IO$_SETMODE,P1=TTC,P2=#12
    
    Terminal with PASTHRU will still honour XON-XOFF characters if TTSYNC is set.

  13. SET LINE SPEED

    Line speed can be set by DCL commands or program control. What the manual on terminal drivers did not mention is that to set the speed by program of a device other than your own terminal, AUTOBAUD must also be turned off. The QIO does not return any error status at all, it simply does not change the speed.
         $QIOW_S   CHAN=TTCHAN,FUNC=#IO$_SENSECHAR,P1=TTC,P2=#12
         BICL2     #TT2$M_AUTOBAUD,TTC+8
         $QIOW_S   CHAN=TTCHAN,FUNC=#IO$_SETCHAR,-
                   P1=TTC,P2=#12,P3=#TT$C_BAUD_1200
    
    Changing the characteristics of your own terminal eg. speed, echo, PASTHRU, etc does not require privilege. LOG_IO or PHY_IO is required, using the function code IO$_SETCHAR, if other devices are to be modified.

  14. SUMMARY

    The developers of the VAX architecture and VMS have designed a well-structured, highly flexible approach to device control. Users have the ability to directly control terminals through low-level QIO calls and improve i/o performance, but at the risk of the application being machine-dependent. To obtain the best of both worlds, these calls should be isolated into subroutine libraries for easy porting in future.

  15. REFERENCE