Mercurial > hg > Members > kono > nitros9-code
view level1/modules/sc6551dragon.asm @ 3246:be3446f758ca
Updated dwread.asm and dwwrite.asm so that the 6551 routines could have specially defined
flags so that some of the addresses could be overridden by the make files if needed.
author | David Ladd <drencor-xeen@users.sourceforge.net> |
---|---|
date | Sun, 11 Mar 2018 01:30:30 -0600 |
parents | d3b51489cb58 |
children |
line wrap: on
line source
* * Dragon 64/Alpha 6551 serial port driver * * Disassembled 2005/04/25 00:12:02 by Disasm v1.5 (C) 1988 by RML * * The Dragon 64 and Dragon Alpha have a hardware serial port driven * by a Rockwell 6551, mapped from $FF04-$FF07. * * Communication between the read/write routines and the ACIA, is buffered * using a pair of ring buffers, when disassembling labels have been assigned * so that bytes are placed into the Rx/Tx queue Tail, and removed from the * head. When the queues become full the calling process is put to sleep * while it awiaits Rx/Tx from the remote device. * * 2005-05-01, P.Harvey-Smith. * Initial disassembly. * * 2005-10-24, P.Harvey-Smith. * Code clean up/commenting. * nam sc6551 ttl os9 device driver ifp1 use defsfile endc * Following definitions borrowed from sc6551.asm * Status bit definitions Stat.IRQ equ %10000000 IRQ occurred Stat.DSR equ %01000000 DSR level (clear = active) Stat.DCD equ %00100000 DCD level (clear = active) Stat.TxE equ %00010000 Tx data register Empty Stat.RxF equ %00001000 Rx data register Full Stat.Ovr equ %00000100 Rx data Overrun error Stat.Frm equ %00000010 Rx data Framing error Stat.Par equ %00000001 Rx data Parity error Stat.Err equ Stat.Ovr!Stat.Frm!Stat.Par Status error bits Stat.Flp equ $00 all Status bits active when set Stat.Msk equ Stat.IRQ!Stat.RxF active IRQs * Control bit definitions Ctl.Stop equ %10000000 stop bits (set=two, clear=one) Ctl.DBit equ %01100000 see data bit table below Ctl.RxCS equ %00010000 Rx clock source (set=baud rate, clear=external) Ctl.Baud equ %00001111 see baud rate table below * data bit table DB.8 equ %00000000 eight data bits per character DB.7 equ %00100000 seven data bits per character DB.6 equ %01000000 six data bits per character DB.5 equ %01100000 five data bits per character * baud rate table org $00 BR.ExClk rmb 1 16x external clock (not supported) org $11 BR.00050 rmb 1 50 baud (not supported) BR.00075 rmb 1 75 baud (not supported) BR.00110 rmb 1 109.92 baud BR.00135 rmb 1 134.58 baud (not supported) BR.00150 rmb 1 150 baud (not supported) BR.00300 rmb 1 300 baud BR.00600 rmb 1 600 baud BR.01200 rmb 1 1200 baud BR.01800 rmb 1 1800 baud (not supported) BR.02400 rmb 1 2400 baud BR.03600 rmb 1 3600 baud (not supported) BR.04800 rmb 1 4800 baud BR.07200 rmb 1 7200 baud (not supported) BR.09600 rmb 1 9600 baud BR.19200 rmb 1 19200 baud * Command bit definitions Cmd.Par equ %11100000 see parity table below Cmd.Echo equ %00010000 local echo (set=activated) Cmd.TIRB equ %00001100 see Tx IRQ/RTS/Break table below Cmd.RxI equ %00000010 Rx IRQ (set=disabled) Cmd.DTR equ %00000001 DTR output (set=enabled) * parity table Par.None equ %00000000 Par.Odd equ %00100000 Par.Even equ %01100000 Par.Mark equ %10100000 Par.Spac equ %11100000 * Tx IRQ/RTS/Break table TIRB.Off equ %00000000 RTS & Tx IRQs disabled TIRB.On equ %00000100 RTS & Tx IRQs enabled TIRB.RTS equ %00001000 RTS enabled, Tx IRQs disabled TIRB.Brk equ %00001100 RTS enabled, Tx IRQs disabled, Tx line Break * V.ERR bit definitions DCDLstEr equ %00100000 DCD lost error OvrFloEr equ %00000100 Rx data overrun or Rx buffer overflow error FrmingEr equ %00000010 Rx data framing error ParityEr equ %00000001 Rx data parity error * FloCtlRx bit definitions FCRxSend equ %10000000 send flow control character FCRxSent equ %00010000 Rx disabled due to XOFF sent FCRxDTR equ %00000010 Rx disabled due to DTR FCRxRTS equ %00000001 Rx disabled due to RTS * FloCtlTx bit definitions FCTxXOff equ %10000000 due to XOFF received FCTxBrk equ %00000010 due to currently transmitting Break * Wrk.Type bit definitions Parity equ %11100000 parity bits MdmKill equ %00010000 modem kill option RxSwFlow equ %00001000 Rx data software (XON/XOFF) flow control TxSwFlow equ %00000100 Tx data software (XON/XOFF) flow control RTSFlow equ %00000010 CTS/RTS hardware flow control DSRFlow equ %00000001 DSR/DTR hardware flow control * Wrk.Baud bit definitions StopBits equ %10000000 number of stop bits code WordLen equ %01100000 word length code BaudRate equ %00001111 baud rate code * Wrk.XTyp bit definitions SwpDCDSR equ %10000000 swap DCD+DSR bits (valid for 6551 only) ForceDTR equ %01000000 don't drop DTR in term routine RxBufPag equ %00001111 input buffer page count * End of borrowed stuff :) tylg set Drivr+Objct atrv set ReEnt+rev rev set $01 mod eom,name,tylg,atrv,start,size RxQueueTailOffset rmb 1 ; Tail of Rx queue, Rx inturrupt inserts here RxQueueHeadOffset rmb 1 ; Head of Rx queue, read call fetches from here u001F rmb 1 TxQueueTailOffset rmb 1 ; Tail of Tx queue, write call inserts here TxQueueHeadOffset rmb 1 ; Head of Tx queue, Tx inturrupt fetches here u0022 rmb 1 u0023 rmb 1 ; something to do with XON/XOFF u0024 rmb 2 SavedDSRDCD rmb 1 ; Saved DSR and DCD ststus RxQueue rmb 80 ; Rx Queue RxQueueLen EQU *-RxQueue ; Rx queue length TxQueue rmb 140 ; Tx Queue TxQueueLen EQU *-TxQueue ; Tx Queue length size equ . fcb $03 name equ * fcs /sc6551/ fcb $04 start equ * lbra Init lbra Read lbra Write lbra GetSta lbra SetSta lbra Term IRQPkt FCB $00 ; Normal bits (flip byte) FCB $80 ; Bit 1 is interrupt request flag (Mask byte) FCB $0A ; Priority byte * Init * * Entry: * Y = address of device descriptor * U = address of device memory area * * Exit: * CC = carry set on error * B = error code * Init LDX V.PORT,U ; 1,U Get port address $FF04 stb AciaStat,x ; Write to status reg, this resets ACIA ldb #$02 stb <u0022,u ldd <IT.PAR,y ; Get parity & baud rate <$26,y andb #$0F leax <BaudRateTable,pcr ; Calculate baud rate values for Acia ldb b,x anda #$F0 sta V.TYPE,u ; Save parity bits for later use ldx V.PORT,u ; Get port address $FF04 std AciaCmd,x ; Setup Command (A), Control (B,Baud rates). lda ,x lda ,x tst AciaStat,x ; Get status lbmi ErrorExit ; Error if int occoured clra ; Init some static storage clrb std <RxQueueTailOffset,u ; Init Rx queue std <TxQueueTailOffset,u ; Init Tx queue sta <u0023,u sta <u001F,u std <u0024,u ldd V.PORT,u ; Get port address $FF04 addd #$0001 ; Setup V$IRQ on status reg changes leax >IRQPkt,pcr ; Point to packet leay >IRQService,pcr ; Point to handler os9 F$IRQ ; Install it ! bcs InitExit ; Error : Exit ldx V.PORT,u ; Get port address $FF04 ldb V.TYPE,u ; Get device parity settings orb #Cmd.DTR ; SET DTR, flag us as ready stb AciaCmd,x clrb ; Flag no error InitExit rts ; ; Baud rate table, all baud rates use external clock. ; BaudRateTable fcb Ctl.RxCS+BR.00110 fcb Ctl.RxCS+BR.00300 fcb Ctl.RxCS+BR.00600 fcb Ctl.RxCS+BR.01200 fcb Ctl.RxCS+BR.02400 fcb Ctl.RxCS+BR.04800 fcb Ctl.RxCS+BR.09600 fcb Ctl.RxCS+BR.19200 PutProcToSleep bsr DoPutProcToSleep * * Input U = Address of device static data storage * Y = Address of path descriptor module * * Output * A = Character read * CC = carry set on error, clear on none * B = error code if CC.C set. * Read lda <u0023,u ble L00A1 ldb <u001F,u cmpb #$0A bhi L00A1 ldb V.XON,u orb #$80 stb <u0023,u ldb V.TYPE,u ; Get prity settings orb #TIRB.On+Cmd.DTR ; Enable tranmitter inturrupt & DTR ($05) ldx V.PORT,u ; Get port address $FF04 stb AciaCmd,x ; Write to ACIA L00A1 tst <u0024,u bne ErrorExit ldb <RxQueueHeadOffset,u ; Get queue head ptr leax <RxQueue,u ; Get Rx Queue address orcc #$50 ; Disable Inturrupts cmpb <RxQueueTailOffset,u ; Is Head=Tail, and therefore queue empty ? beq PutProcToSleep ; Yes : sleep and await input from remote device abx ; Calculate pos in queue for next char lda ,x ; Get byte from read queue dec <u001F,u incb cmpb #RxQueueLen-1 ; Reached end of queue area ? bls L00BF ; no : continue clrb ; Wrap tail pointer to the beginning of queue space L00BF stb <RxQueueHeadOffset,u ; save new queue pointer clrb ldb V.ERR,u beq L00CF ; No error : exit stb <$3A,y clr V.ERR,u comb ; Flag and return error ldb #$F4 L00CF andcc #$AF ; Enable inturrupts rts ErrorExit comb ; Flag error & return ldb #$F6 rts ; ; Put calling process to sleep while we await input or output from remote device. ; DoPutProcToSleep pshs x,b,a lda V.BUSY,u ; Get busy process sta V.WAKE,u ; Store in proc to wake andcc #$AF ; Enable inturrupts ldx #$0000 ; Sleep indefinatly os9 F$Sleep ; Put caller to sleep ldx <D.Proc ; Get current proces descriptor addr ldb <P$Signal,x ; Get signal code of proc beq L00EF cmpb #$03 bls L00F8 L00EF clra lda P$State,x ; Get process state bita #Condem ; Process condemed ? (being killed ?) bne L00F8 ; yes : error, exit puls pc,x,b,a ; Return L00F8 leas $06,s coma rts L00FC bsr DoPutProcToSleep * * Input U = Address of device static data storage * Y = Address of path descriptor module * A = Character to write * * Output * CC = carry set on error, clear on none * B = error code if CC.C set. * Write leax <TxQueue,u ; Get pointer to transmit queue ldb <TxQueueTailOffset,u ; Get offset of end of TX queue abx ; Calculate next free queue slot sta ,x ; Put byte to transmit in queue incb ; Increment queue tail ptr cmpb #TxQueueLen-1 ; End of Queue area ? bls L010D ; no, continue clrb ; Point at begining of queue area L010D orcc #$50 ; Disable inturrupts cmpb <TxQueueHeadOffset,u ; is Head=Tail therefore queue full ? beq L00FC ; Yes : sleep process until room in queue stb <TxQueueTailOffset,u ; Re-save tail pointer lda <u0022,u beq L012B anda #$FD sta <u0022,u bne L012B lda V.TYPE,u ; Get parity bits ora #TIRB.On+Cmd.DTR ; Enable tranmitter inturrupt & DTR ($05) ldx V.PORT,u ; Get port address $FF04 sta AciaCmd,x ; Write to ACIA L012B andcc #$AF ; Enable Inturrupts L012D clrb ; Flag no error rts * * Input U = Address of device static data storage * Y = Address of path descriptor module * A = Status code * * Output * Depends on status code. * GetSta cmpa #SS.Ready ; Device ready ? ($01) bne L013E ldb <u001F,u beq ErrorExit ldx $06,y stb $02,x L013C clrb rts L013E cmpa #SS.EOF ; EOF ? ($06) beq L012D L0142 comb ; Flag error ldb #$D0 rts * * Input U = Address of device static data storage * Y = Address of path descriptor module * A = Status code * * Output * Depends on status code. * SetSta cmpa #SS.SSig ; Send signal on data ready ? ($1A) bne L0161 lda PD.CPR,y ; Get caller's process id ldx PD.RGS,y ; Get caller's Regs ldb $05,x ; Get lower half of X ???? orcc #$50 ; Disable inturrupts tst <u001F,u bne L015C std <u0024,u bra L012B L015C andcc #$AF lbra L01F8 L0161 cmpa #SS.Relea ; Release device ? ($1B) bne L0142 lda PD.CPR,y ; Get calling process ID cmpa <u0024,u ; Same process ? bne L013C ; no ! clr <u0024,u ; Yes : release rts L0170 lbsr DoPutProcToSleep * * Input U = Address of device static data storage * * Output * CC = carry set on error, clear on none * B = error code if CC.C set. * Term ldx <D.Proc ; Get current process descriptor addr lda P$ID,x ; Get process ID sta V.BUSY,u ; Save it in busy and last processs sta V.LPRC,u ldb <TxQueueTailOffset,u ; Check we have sent all bytes ? orcc #$50 cmpb <TxQueueHeadOffset,u bne L0170 ; Still bytes left to send, wait to send them lda V.TYPE,u ; Get Parity settings ldx V.PORT,u ; Get port address $FF04 sta AciaCmd,x ; Set parity in ACIA andcc #$AF ; Enable inturrupts ldx #$0000 ; Remove IRQ handler os9 F$IRQ rts * * F$IRQ handler, * * Input : * A = Status byte XOR flip * U = our data area * * In this case, since flip byte is zero, and any value XOR zero * remains uncahanged, A contains the contents of the ACIA status * register ($FF05) * IRQService ldx V.PORT,u ; Get port address $FF04 tfr a,b ; Take a copy of status andb #Stat.DSR+Stat.DCD ; Mask all but DSR & DCD ($60) cmpb <SavedDSRDCD,u ; Compare to saved beq L01AB ; not changed, check other bits stb <SavedDSRDCD,u ; Save DSR & DCD values bitb #$60 ; Was either set ??? lbne L02AE ; yes lbra L029C L01AB bita #Stat.RxF ; Rx register full ? ($08) bne L01FD ; yes lda <u0023,u bpl L01C4 anda #$7F sta ,x eora V.XON,u sta <u0023,u lda <u0022,u bne L01EA clrb rts L01C4 leay <TxQueue,u ; Point to transmit queue ldb <TxQueueHeadOffset,u ; Check that there are bytes to transmit cmpb <TxQueueTailOffset,u beq L01E2 ; no : skip clra lda d,y ; Get byte to transmit incb ; Increment head offset ptr cmpb #TxQueueLen-1 ; Head at end of Queue area ? bls L01D8 clrb ; Yes : point it at beginning L01D8 stb <TxQueueHeadOffset,u ; Save it sta AciaData,x ; Transmit byte cmpb <TxQueueTailOffset,u ; Head=Tail therefore Tx queue empty ? bne L01F0 ; no : skip ahead L01E2 lda <u0022,u ora #$02 sta <u0022,u L01EA ldb V.TYPE,u ; Get parity settings orb #Cmd.DTR ; Enable DTR, ready stb AciaCmd,x ; Write to ACIA L01F0 ldb #S$Wake ; Wake up calling process lda V.WAKE,u ; Get proc ID to wake L01F4 beq L01FB clr V.WAKE,u ; Clear saved wake proc ID L01F8 os9 F$Send ; send wakeup signal L01FB clrb ; Flag no error rts L01FD bita #Stat.Par+Stat.Frm+Stat.Ovr ; Check for Parity/Framing/Overrun errors ($07) beq L0213 ; No Error detected, do read tfr a,b ; Copy status tst ,x anda #$07 ora V.ERR,u sta V.ERR,u lda $02,x sta $01,x sta $02,x bra L01FB L0213 lda ,x ; Read byte from ACIA beq L022E ; zero, branch ahead cmpa V.INTR,u ; Inturrupt char ? beq L028B cmpa V.QUIT,u ; Quit char ? beq L028F cmpa V.PCHR,u ; Pause char ? beq L0283 cmpa V.XON,u ; Xon char ? beq L029C cmpa <V.XOFF,u ; Xoff char ? lbeq L02AE ; ; If we reach here, char is nothing special, so just put it in queue ; L022E leax <RxQueue,u ; Point to receive queue ldb <RxQueueTailOffset,u ; Get tail offset abx ; Calculate address sta ,x ; Put char in queue incb ; increment tail ptr cmpb #RxQueueLen-1 ; End of queue area ? bls L023D ; no : continue clrb ; point to begining of Rx queue area L023D cmpb <RxQueueHeadOffset,u ; Same as head of queue ? bne L024A ; no : ldb #$04 orb V.ERR,u ; accumulated errors stb V.ERR,u bra L01F0 L024A stb <RxQueueTailOffset,u ; Save tail ptr inc <u001F,u tst <u0024,u beq L025D ldd <u0024,u clr <u0024,u bra L01F8 L025D lda <V.XOFF,u beq L01F0 ldb <u001F,u cmpb #$46 bcs L01F0 ldb <u0023,u bne L01F0 anda #$7F sta <V.XOFF,u ora #$80 sta <u0023,u ldb V.TYPE,u ; Get parity settings orb #TIRB.On+Cmd.DTR ; Enable tranmitter inturrupt & DTR ($05) ldx V.PORT,u ; Get port address $FF04 stb AciaCmd,x ; Write to acia lbra L01F0 L0283 ldx V.DEV2,u beq L022E sta $08,x bra L022E L028B ldb #$03 bra L0291 L028F ldb #$02 L0291 pshs a lda V.LPRC,u ; Get last active proc ID lbsr L01F4 ; Wake process puls a bra L022E L029C lda <u0022,u anda #$FE sta <u0022,u bne L02AC lda V.TYPE,u ; Get parity settings ora #TIRB.On+Cmd.DTR ; Enable tranmitter inturrupt & DTR ($05) sta AciaCmd,x ; Write to ACIA L02AC clrb ; Flag no error rts L02AE lda <u0022,u bne L02B9 ldb V.TYPE,u ; Get parity settings orb #Cmd.DTR ; Enable DTR stb AciaCmd,x ; Write to ACIA L02B9 ora #$01 sta <u0022,u clrb rts emod eom equ * end