ACIA module for Rockwell 6551
The ACIA module is responsible for communication with serial (RS-232) devices. This source code file was reverse-engineered from the Dragon 64 distribution.
nam ACIA51 ttl Interrupt-Driven Acia driver for Rockwell 6551 * 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! ifp1use defsfileendc Edition equ 4 Current Edition *************** * Interrupt-driven Acia Device Driver INPSIZ set 80 input buffer size (<=256) OUTSIZ set 140 output buffer size (<=256) DataReg equ 0 StatReg equ 1 CmndReg equ 2 CtrlReg equ 3 IRQReq set %10000000 Interrupt Request NOTDSR set %01000000 not data set ready DCDLST set %00100000 data carrier lost TDRE set %00010000 transmitter data register empty RDRF set %00001000 Rx data register Full OVERUN set %00000100 overrun error bit FRAME set %00000010 framing error bit PARITY set %00000001 parity error bit DTRRDY equ %00000001 data terminal ready IRQOUT equ %00000100 transmitter interrupt INPERR set NOTDSR+DCDLST tylg set Drivr+Objct atrv set ReEnt+rev rev set $01 mod ACIEND,ACINAM,tylg,atrv,ACIENT,ACIMEM ********** * 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 RDYSGNL rmb 2 first byte process id, second signal code ERRSTAT rmb 1 INPBUF rmb INPSIZ input buffer OUTBUF rmb OUTSIZ output buffer ACIMEM equ . * HALTED state conditions H.XOFF equ 1 V.XOFF char has been received; awaiting V.XON H.EMPTY equ 2 Output buffer is empty fcb UPDAT. ACINAM fcs "ACIA51" 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 stb StatReg,x reset acia ldb #H.EMPTY stb HALTED,U output IRQ's disabled; buffer empty ldd <$26,y IT.PAR a=Parity and b=baud rate andb #$0F mask lower 4 bits of IT.BAU leax <BAUDTBL,pcr ldb b,x anda #$F0 sta V.TYPE,u ldx V.PORT,u std CmndReg,x configure both command and ctrl register lda DataReg,x lda DataReg,x tst StatReg,x interrupt gone? lbmi 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 std <RDYSGNL,U clear signal process ldd V.PORT,U addd #StatReg Add location of status register 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 #DTRRDY stb CmndReg,x clrb INIT9 rts * BAUDTBL fcb $13 110 baud fcb $16 300 baud fcb $17 600 baud fcb $18 1200 baud fcb $1A 2400 baud fcb $1C 4800 baud fcb $1E 9600 baud fcb $1F 19200 baud ***************************** * READ * read a byte from Uart * Entry: U = Address of device static Storage * Y = Address of the path Descriptor * Output A = character read * 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 #IRQOUT!DTRRDY enable input & output IRQs ldx V.PORT,u stb CmndReg,x Read.a tst <RDYSGNL,u read while waiting for ready? bne ErrNtRdy ldb <INXTO,u 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 #IRQOUT!DTRRDY enable input & output IRQs ldx V.PORT,u sta CmndReg,x Write80 andcc #^IntMasks Allow I and F interrupts Write90 clrb 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 UNKSVC comb return carry set ldb #E$UnkSvc Unknown service code rts ************************** * PUTSTA * Set device Status * (U) = Address of device static storage PUTSTA cmpa #SS.SSig Send signal on data ready bne SetRel lda PD.CPR,y ldx PD.RGS,y ldb R$X+1,x Signal code orcc #IntMasks Block I and F interrupts tst <INCNT,u data ready already? bne PUTS10 ..Yes std <RDYSGNL,u bra Write80 PUTS10 andcc #^IntMasks Allow I and F interrupts lbra SendSig send code to process SetRel cmpa #SS.Relea bne UNKSVC lda PD.CPR,y cmpa <RDYSGNL,u bne STATUS99 clr <RDYSGNL,u 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 ldx V.PORT,u sta CmndReg,x 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 cmpb ERRSTAT,U compare to saved beq OutIRQ nothing changed stb ERRSTAT,U save error status bitb #INPERR inout error? lbne InXOFF ..yes; stop lbra InXON OutIRQ bita #RDRF receiver data register full? bne InIRQ ..yes lda INHALT,U send X-ON or X-OFF? bpl OutI.a branch if not anda #^Sign clear sign bit sta DataReg,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 DataReg,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 #DTRRDY set data terminal ready stb CmndReg,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 InIRQ bita #OVERUN!FRAME!PARITY check for errors beq InIRQ0 ..none tfr a,b tst ,x anda #OVERUN!FRAME!PARITY ora V.ERR,u sta V.ERR,u lda $02,x sta $01,x sta $02,x bra Wake90 *************** * Inacia * process Acia input Interrupt * * Passed: (A)=Acia Status Register data * (X)=Acia port address * (U)=Static Storage address * InIRQ0 lda DataReg,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? lbeq 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 tst <RDYSGNL,u process waiting for signal? beq InIRQ4 ..no ldd <RDYSGNL,u clr <RDYSGNL,u bra SendSig 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 #IRQOUT!DTRRDY enable input & output IRQs ldx V.PORT,U stb CmndReg,X lbra WAKEUP InPause ldx V.DEV2,u 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 #IRQOUT!DTRRDY enable input & output IRQs sta CmndReg,X InXON99 clrb rts InXOFF lda HALTED,U bne InXOFF10 ..already halted, continue ldb V.TYPE,U get acia control code orb #DTRRDY stb CmndReg,X InXOFF10 ora #$01 set bit 1 sta HALTED,U restrict output clrb rts emod Module Crc ACIEND equ *