Retrocomputing

ACIA module for Motorola 6850

The ACIA module is responsible for communication with serial (RS-232) devices.

         nam ACIA
         ttl Interrupt-Driven Acia driver

* Copyright 1982 by Microware Systems Corporation
* Reproduced Under License

* This source code is the proprietary confidential property of
* Microware Systems Corporation, and is provided to licensee
* solely  for documentation and educational purposes. Reproduction,
* publication, or distribution in any form to any party other than
* the licensee is strictly prohibited!

         use  defsfile

***************
* Edition History

*  #   date    Comments
* -- -------- ----------------------------------------------------
*  3 83/02/11  Add X-ON/X-OFF generation code
*  4 83/03/10  Getstat Ready returns (B)=bytecount

Edition  equ  4          Current Edition

***************
* Interrupt-driven Acia Device Driver

INPSIZ   set  80         input  buffer size (<=256)
OUTSIZ   set  140        output buffer size (<=256)

IRQReq   set  %10000000  Interrupt Request
PARITY   set  %01000000  parity  error bit
OVERUN   set  %00100000  overrun error bit
FRAME    set  %00010000  framing error bit
NOTCTS   set  %00001000  not clear to send
DCDLST   set  %00000100  data carrier lost

IRQIN    equ  %10000000  input IRQ enable
IRQOUT   equ  %00100000  output IRQ enable

INPERR   set  PARITY+OVERUN+FRAME+NOTCTS+DCDLST

**********
* Static storage offsets
*
         org  V.SCF      room for scf variables
INXTI    rmb  1          input  buffer next-in  ptr
INXTO    rmb  1          input  buffer next-out ptr
INCNT    rmb  1          input char count
ONXTI    rmb  1          output buffer next-in  ptr
ONXTO    rmb  1          output buffer next-out ptr
HALTED   rmb  1          output IRQ's disabled when non-zero
INHALT   rmb  1          input halted
INPBUF   rmb  INPSIZ     input  buffer
OUTBUF   rmb  OUTSIZ     output buffer
ACIMEM   equ  .          Total static storage requirement

* HALTED state conditions
H.XOFF   equ  1          V.XOFF char has been received; awaiting V.XON
H.EMPTY  equ  2          Output buffer is empty

***************
* Module Header
         mod  ACIEND,ACINAM,DRIVR+OBJCT,REENT+1,ACIENT,ACIMEM
         fcb  UPDAT.
ACINAM   fcs  "ACIA"

         fcb  Edition    Current Revision

ACIENT   lbra INIT
         lbra READ
         lbra WRITE
         lbra GETSTA
         lbra PUTSTA
         lbra TRMNAT

ACMASK   fcb  0          no flip bits
         fcb  IRQReq     Irq polling mask
         fcb  10         (higher) priority

         ttl INTERRUPT-DRIVEN Acia device routines
         pag
***************
* Init
*   Initialize (Terminal) Acia
*
INIT     ldx  V.PORT,U   I/o port address
         ldb  #$03       master reset signal
         stb  0,X        reset acia
         ldb  #H.EMPTY
         stb  HALTED,U   output IRQ's disabled; buffer empty
         lda  M$OPT,Y    option byte count
INIT05   cmpa #PD.PAR-PD.OPT acia control value given?
         blo  INIT10     ..no; default $15
         ldb  PD.PAR-PD.OPT+M$DTYP,Y
         bne  INIT20
INIT10   ldb  #$15       default acia control
INIT20   stb  V.TYPE,U   save device type
         stb  0,X        init acia
         lda  1,X
         lda  1,X        remove any interrupts
         tst  0,X        interrupt gone?
         bmi  ErrNtRdy   ..No; abort
         clra
         clrb
         std  INXTI,U    Initialize buffer ptrs
         std  ONXTI,U
         sta  INHALT,U   flag input not halted
         sta  INCNT,U    clear in char count
         ldd  V.PORT,U
         leax ACMASK,PCR
         leay ACIRQ,PCR  address of interrupt service routine
         OS9  F$IRQ      Add to IRQ polling table
         bcs  INIT9      Error - return it
         ldx  V.PORT,U
         ldb  V.TYPE,U
         orb  #IRQIN     enable acia input interrupts
         stb  0,X        initialize acia for input interrupts
         clrb
INIT9    rts

***************
* Read
*   return One Byte of input from the Acia
*
* Passed: (Y)=Path Descriptor
*         (U)=Static Storage address
* returns: (A)=input Byte (carry clear)
*     or   CC=Set, B=Error code if error
*
READ00   bsr  ACSLEP
READ     lda  INHALT,U   is input halted?
         ble  Read.a     branch if not
         ldb  INCNT,U    get input character count
         cmpb #10        less than 10 chars in buffer?
         bhi  Read.a     branch if not
         ldb  V.XON,U    get X-ON char
         orb  #Sign      set sign bit
         stb  INHALT,U   flag input resume
         ldb  V.TYPE,U   get control value
         orb  #IRQIN!IRQOUT enable input & output IRQs
         stb  [V.PORT,U] set control register
Read.a   ldb  INXTO,U    (input buffer) next-out ptr
         leax INPBUF,U   address of input buffer
         orcc #IntMasks  calm interrupts
         cmpb INXTI,U    any data available?
         beq  READ00
         abx
         lda  0,X        the char
         dec  INCNT,U    decrement char count
         incb            ADVANCE Next-out ptr
         cmpb #INPSIZ-1  end of circular buffer?
         bls  READ10     ..no
         clrb            reset ptr to start of buffer
READ10   stb  INXTO,U    save updated buffer ptr
         clrb
         ldb  V.ERR,U    Transmission error?
         beq  READ90     ..no; return
         stb  PD.ERR,Y   return error bits in pd
         clr  V.ERR,U
         comb            return carry set
         ldb  #E$Read    signal read error
READ90   andcc #^IntMasks enable IRQ requests
         rts

ErrNtRdy comb
         ldb  #E$NotRdy
         rts

**********
* Acslep - Sleep for I/O activity
*  This version Hogs Cpu if signal pending
*
* Passed: (cc)=Irq's Must be disabled
*         (U)=Global Storage
*         V.Busy,U=current proc id
* Destroys: possibly Pc
ACSLEP   pshs D,X
         lda  V.BUSY,U   get current process id
         sta  V.Wake,U   arrange wake up signal
         andcc #^IntMasks interrupts ok now
         ldx  #0
         OS9  F$Sleep    wait for input data
         ldx  D.Proc
         ldb  P$Signal,X signal present?
         beq  ACSL90     ..no; return
         cmpb #S$Intrpt  Deadly signal?
         bls  ACSLER     ..yes; return error
ACSL90   clra            clear carry
         lda  P$State,X  check process state flags
         bita #Condem    has process died?
         bne  ACSLER     ..Yes; return error
         puls D,X,PC     return

ACSLER   leas 6,S        Exit to caller's caller
         coma            return carry set
         rts

***************
* Write
*   Write char Through Acia
*
* Passed: (A)=char to write
*         (Y)=Path Descriptor
*         (U)=Static Storage address
* returns: CC=Set If Busy (output buffer Full)
*
WRIT00   bsr  ACSLEP     sleep a bit
WRITE    leax OUTBUF,U   output buffer address
         ldb  ONXTI,U    (output) next-out ptr
         abx
         sta  0,X        Put char in buffer
         incb            ADVANCE the ptr
         cmpb #OUTSIZ-1  end of circular buffer?
         bls  WRIT10     ..no
         clrb            reset ptr to start of buffer
WRIT10   orcc #IntMasks  disable interrupts
         cmpb ONXTO,U    buffer full?
         beq  WRIT00     ..yes; sleep and retry
         stb  ONXTI,U    save updated next-in ptr
         lda  HALTED,U   output already enabled?
         beq  Write80    ..yes; don't re-enable
         anda #^H.EMPTY  no longer halted due to empty
         sta  HALTED,U
         bne  Write80    ..Still HALTED; don't enable IRQ
         lda  V.TYPE,U   Parity control
         ora  #IRQIN!IRQOUT enable input & output IRQs
         sta  [V.PORT,U] Enable output interrupts
Write80  andcc #^IntMasks enable IRQs
Write90  clrb            (return carry clear)
         rts

***************
* Getsta/Putsta
*   Get/Put Acia Status
*
* Passed: (A)=Status Code
*         (Y)=Path Descriptor
*         (U)=Static Storage address
* returns: varies
GETSTA   cmpa #SS.Ready  Ready status?
         bne  GETS10     ..no
         ldb  INCNT,U    get input character count
         beq  ErrNtRdy   ..No; return not ready error
         ldx  PD.RGS,Y
         stb  R$B,X      return bytecount to caller (!)
STATUS99 clrb
         rts

GETS10   cmpa #SS.EOF    End of file?
         beq  Write90    ..yes; return carry clear

PUTSTA   comb            return carry set
         ldb  #E$UnkSvc  Unknown service code
         rts

***************
* Subroutine TRMNAT
*   Terminate Acia processing
*
* Passed: (U)=Static Storage
* returns: Nothing
*
TRMN00   lbsr ACSLEP     wait for I/O activity
TRMNAT   ldx  D.Proc
         lda  P$ID,X
         sta  V.BUSY,U
         sta  V.LPRC,U
         ldb  ONXTI,U
         orcc #IntMasks  disable interrupts
         cmpb ONXTO,U    output done?
         bne  TRMN00     ..no; sleep a bit
         lda  V.TYPE,U
         sta  [V.PORT,U] disable acia interrupts
         andcc #^IntMasks enable interrupts
         ldx  #0
         OS9  F$IRQ      remove acia from polling tbl
         rts

***************
* AcIRQ
*   process Interrupt (input or output) from Acia
*
* Passed: (U)=Static Storage addr
*         (X)=Port address
*         (A)=polled status
* Returns: Nothing
*
ACIRQ    ldx  V.PORT,U   get port address
         tfr  A,B        copy status
         andb #INPERR    mask status error bits
         orb  V.ERR,U
         stb  V.ERR,U    update cumulative errors
         bita #5         input ready (or carrier lost)?
         bne  InIRQ      ..yes; go get it
* Fall Through to Do output

****************
* OutIRQ
*   output to Acia Interrupt Routine
*
* Passed: (A)=Acia Status Register Contents
*         (X)=Acia port address
*         (U)=Static Storage address

OutIRQ   lda  INHALT,U   send X-ON or X-OFF?
         bpl  OutI.a     branch if not
         anda #^Sign     clear sign bit
         sta  1,X        send character
         eora V.XON,U    get zero if X-ON
         sta  INHALT,U   mark it sent
         lda  HALTED,U   is output halted?
         bne  OutIRQ3    branch if so
         clrb            clear carry
         rts
OutI.a   leay OUTBUF,U   output buffer ptr
         ldb  ONXTO,U    (output) next-out ptr
         cmpb ONXTI,U    output buffer already empty?
         beq  OutIRQ2    ..yes; disable output IRQ, return
         clra
         lda  D,Y        next output char
         incb            ADVANCE Next-out ptr
         cmpb #OUTSIZ-1  end of circular buffer?
         bls  OutIRQ1    ..no
         clrb
OutIRQ1  stb  ONXTO,U    save updated next-out ptr
         sta  1,X        Write the char
         cmpb ONXTI,U    last char in output buffer?
         bne  WAKEUP     ..no
OutIRQ2  lda  HALTED,U
         ora  #H.EMPTY
         sta  HALTED,U
OutIRQ3  ldb  V.TYPE,U
         orb  #IRQIN     disable output IRQs
         stb  0,X

WAKEUP   ldb  #S$Wake    Wake up signal
         lda  V.Wake,U   Owner waiting?
Wake10   beq  Wake90     ..no; return
         clr  V.Wake,U
SendSig  OS9  F$Send     send signal
Wake90   clrb            return carry clear
         rts

***************
* Inacia
*   process Acia input Interrupt
*
* Passed: (A)=Acia Status Register data
*         (X)=Acia port address
*         (U)=Static Storage address
*
* Notice the Absence of Error Checking Here
*
InIRQ    lda  1,X        Read input char
         beq  InIRQ1     ..NULL, impossible Ctl Chr
         cmpa V.INTR,U   keyboard Interrupt?
         beq  InAbort    ..Yes
         cmpa V.QUIT,U   keyboard Quit?
         beq  InQuit     ..Yes
         cmpa V.PCHR,U   keyboard Pause?
         beq  InPause    ..Yes
         cmpa V.XON,U    X-ON continue?
         beq  InXON      ..Yes
         cmpa V.XOFF,U   X-OFF Immediate Pause request?
         beq  InXOFF     ..Yes

InIRQ1   leax INPBUF,U   input buffer
         ldb  INXTI,U    (input) next-in ptr
         abx
         sta  0,X        save char in buffer
         incb            update Next-in ptr
         cmpb #INPSIZ-1  end of circular buffer?
         bls  InIRQ2     ..no
         clrb
InIRQ2   cmpb INXTO,U    input overrun?
         bne  InIRQ30    ..no; good
         ldb  #OVERUN    mark overrun error
         orb  V.ERR,U
         stb  V.ERR,U
         bra  WAKEUP     throw away character

InIRQ30  stb  INXTI,U    update next-in ptr
         inc  INCNT,U

InIRQ4   lda  V.XOFF,U   get X-OFF char
         beq  WAKEUP     branch if not enabled
         ldb  INCNT,U    get input count
         cmpb #INPSIZ-10 is buffer almost full?
         blo  WAKEUP     bra if not
         ldb  INHALT,U   have we sent XOFF?
         bne  WAKEUP     yes then don't send it again
         anda #^Sign     insure sign clear
         sta  V.XOFF,U
         ora  #Sign      set sign bit
         sta  INHALT,U   flag input halt
         ldb  V.TYPE,U   get control value
         orb  #IRQIN!IRQOUT enable input & output IRQs
         stb  [V.PORT,U]
         bra  WAKEUP

***************
* Control character routines

InPause  ldx  V.DEV2,U   get echo device static ptr
         beq  InIRQ1     ..None; buffer char, exit
         sta  V.PAUS,X   request pause
         bra  InIRQ1     buffer char, exit

InAbort  ldb  #S$Intrpt  keyboard INTERRUPT signal
         bra  InQuit10

InQuit   ldb  #S$Abort   Abort signal
InQuit10 pshs A          save input char
         lda  V.LPRC,U   last process id
         lbsr Wake10     Send error signal
         puls A          restore input char
         bra  InIRQ1     buffer char, exit

InXON    lda  HALTED,U
         anda #^H.XOFF
         sta  HALTED,U   enable output
         bne  InXON99    ..exit if otherwise disabled
         lda  V.TYPE,U   parity control
         ora  #IRQIN!IRQOUT enable input & output IRQs
         sta  0,X
InXON99  clrb
         rts

InXOFF   lda  HALTED,U
         bne  InXOFF10   ..already halted, continue
         ldb  V.TYPE,U   get acia control code
         orb  #IRQIN     enable only input IRQs
         stb  0,X
InXOFF10 ora  #H.XOFF
         sta  HALTED,U   restrict output
         clrb
         rts

         emod            Module Crc
ACIEND   equ  *