Newer
Older
uBix-Retro / dump / oa-2.0.9 / devices / ser_uart.a65
/****************************************************************************
   
    OS/A65 Version 2.0.0
    Multitasking Operating System for 6502 Computers
    Generic UART 16550 serial line device

    Copyright (C) 1989-1998 Andre Fachat 

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

****************************************************************************/

/*
 * This is an UART 16550A serial line driver for CS/A65.
 * It uses the hardware installed in my personal C64. The
 * 16550A is mapped at $d600, above the SID.
 *
 * The 16550 is not really an easy chip, but it has 16 byte
 * input and output FIFO buffers, which allows much higher
 * interrupt latencies.
 */

#ifdef UARTBASE
#define	UART		UARTBASE
#else
#define UART		$d600
#endif

#ifdef UARTXTAL
#define	XTALMULT	UARTXTAL
#else
#define	XTALMULT	1
#endif

#include "chips/uart16550.i65"

#define	Anzdev	1

          .(
	  .word devend2
	  jmp prg1
	  .asc "ser",sernr, 0

-sernr += 1

/*
 * status: Bit 	0 = 1= handshake enabled
 *		1 : 1= no ACIA found
 * 		5 : 1= set RTS hi
 *		6 : 1= we are transmitting
 *	  	7 : 1= we are receiving
 *
 */

/* 
 * 16550 divisor values for BAUD rates ?, 50, 75, 110, 134.5, 150, 
 * 300, 600, 1200, 1800, 2400, 3600, 4800, 7200, 9600, 19200
 */
divisor	.word 	-1, 2304 * XTALMULT, 1536 * XTALMULT, 1047 * XTALMULT
	.word   857 * XTALMULT, 768 * XTALMULT, 384 * XTALMULT
	.word   192 * XTALMULT, 96 * XTALMULT
	.word	64 * XTALMULT, 48 * XTALMULT, 32 * XTALMULT
	.word   24 * XTALMULT, 16 * XTALMULT, 12 * XTALMULT
	.word   6 * XTALMULT

	.data
dev       .byt 0
div       .byt 0
status    .dsb Anzdev
instr     .dsb Anzdev
outstr    .dsb Anzdev
brkkey	  .dsb Anzdev
	.text

prg1      ldx #0

          stx dev
          cmp #DC_RES
          beq devini
          pha
          lda status,x
          and #2
          beq prgok
          pla
          lda #E_NOTIMP
          sec
          rts
prgok     pla
          cmp #DC_IRQ
          beq devirq2
          jmp others
devirq2	  jmp devirq

/*****************************************************************/

devini    lda #0
          sta status,x
          sta instr,x
          sta outstr,x

	lda #3
	sta brkkey,x

	ldy UART+UART_MCR
	lda #$10
	sta UART+UART_MCR
	lda UART+UART_MSR
	and #$f0
	bne nodev
	lda #$1f
	sta UART+UART_MCR
	lda UART+UART_MSR
	and #$f0
	cmp #$f0
	bne nodev
	sty UART+UART_MCR

	ldy UART+UART_SCR
	lda #%10101010
	sta UART+UART_SCR
	cmp UART+UART_SCR
	bne dev8250
	lsr
	sta UART+UART_SCR
	cmp UART+UART_SCR
	bne dev8250
	sty UART+UART_SCR

	lda #1
	sta UART+UART_FCR
	lda UART+UART_IIR
	ldy #0
	sty UART+UART_FCR
	asl
	bcc dev16450
	asl
	bcc dev16550
	; else dev16550A; currently only this one is supported

	lda #%10000000
	sta UART+UART_LCR
	ldx #14*2			; 9600 BAUD
	lda divisor,x
	sta UART+UART_DLL
	lda divisor+1,x
	sta UART+UART_DLH
	lda #%00000011			; 8N1
	sta UART+UART_LCR
 
 	lda #7				; no FIFO enable and clear FIFOs, 
	sta UART+UART_FCR		; trigger at 1 byte
	lda #0
	sta UART+UART_IER		; polled mode (so far) 
	lda UART+UART_MCR
	and #%00001100			; keep OUT1, OUT2 values
	sta UART+UART_MCR		; reset DTR, RTS

          clc
          rts

nodev					; no UART at all
dev8250					; no Scratchpad, no FIFO
dev16450				; scratchpad, no FIFO
dev16550				; FIFO bug
	  lda status,x
          ora #2
          sta status,x
          lda #E_NOTIMP
          sec
          rts
          
/*****************************************************************/

devirq    
        .(
	lda UART+UART_IIR
	lsr
	bcc intr
irqend  lda #E_NOIRQ		; no irq source found
	;rts			; not this one
	jmp irqe

	;-----------------------------------------------

intr
	and #%00000011		; interrupt mask - makes four possible IRQs
	tay
	bne int_tx
	
	lda UART+UART_MSR
	jmp checkint

int_tx
	dey
	bne int_rx
tx_loop
	jsr tx2
	jmp checkint

int_rx
	dey
	bne int_status
rx_loop
	jsr rx2			; get one char
	lda UART+UART_LSR
	lsr
	bcs rx_loop
;	and #$20		; THRE ($40/2)
;	bne tx_loop
	jmp checkint

int_status
	lda UART+UART_LSR

checkint
	lda UART+UART_IIR
	lsr
	bcc intr		; irq still pending

;	lda UART+UART_LSR
;	and #$40
;	beq nbyt
;	jsr tx2
;nbyt
	jsr nobyt

irqok   lda #E_OK		; irq source removed
irqe	pha

	lda UART+UART_LSR
	and #$40
	beq nbyt
	jsr tx2
	jsr nobyt
nbyt
	pla
	rts

	;-----------------------------------------------

rx2	.(
	lda UART+UART_RXTX
	bit status
	bpl rx2end
        ldx outstr

	cmp brkkey
	bne nobrk
	lda #SC_SSTAT
	ldy #SCE_BRK
	jsr STRCMD
	lda brkkey
nobrk
        jsr PUTC
        bcc rx2end
	cmp #E_SLWM		; this happens most and is caught by nobyt
	bne test
rx2end	rts

&nobyt  ldx outstr
	bit status
	bpl rx2end
        lda #SC_STAT
        jsr STRCMD
        bcc rx2end
test
        cmp #E_NUL
        bne tstwater
        jmp rxoff
tstwater  
	cmp #E_SEMPTY
        beq wl
        tax
        lda status
        and #1
        bne wh
        txa
        cmp #E_SHWM
        beq wh
        cmp #E_SFULL
        bne twl
;inc $d020
wh      ldx #0  
	jmp rtshi
twl     cmp #E_SLWM
        bne rx2end
wl      ldx #0  
	jmp rtslo
	.)

	;-----------------------------------------------

tx2 	.(
	bit status
        bvc txrt		; reading IIR should clear this line

	lda UART+UART_MSR
	and #%00110000
	cmp #%00110000		; cts or dsr inactive
	bne txrt

	ldy #15			
txloop
        ldx instr		; send new data byte
        jsr GETC
        bcs test2
        sta UART+UART_RXTX
	dey
	bne txloop		; fill up FIFO
        bcc txrt

test2   cmp #E_EOF
        bne txrt
        jmp txoff
txrt	rts
	.)

          .)

/*****************************************************************/

dtrhi
	lda UART+UART_MCR
	and #%11111110
	sta UART+UART_MCR
	lda #0
	sta UART+UART_IER
	rts

dtrlo
	lda UART+UART_MCR
	ora #%00000001
	sta UART+UART_MCR
	lda #3
	sta UART+UART_IER
	rts

rtshi
	lda UART+UART_MCR
	and #%11111101
	sta UART+UART_MCR
	lda status,x
	ora #%0010000
	sta status,x
	rts

rtslo
	lda UART+UART_MCR
	ora #%00000010
	sta UART+UART_MCR
	lda status,x
	and #%11011111
	sta status,x
	rts

/*****************************************************************/

others    cmp #DC_GS		; set stream to get data from
          bne o1
          lda status,x
          and #DC_SW_TX
          bne devonx
          tya
          sta instr,x
          jmp ok
devonx    jmp devon
o1        cmp #DC_PS		; set stream to put data to
          bne o2
          lda status,x
          and #DC_SW_RX
          bne devonx
          tya
          sta outstr,x
okx       jmp ok
o2        cmp #DC_RX_ON		; switch receiver on
          bne o3
	; lda #3
	; sta brkkey
	jsr rtslo
	jsr dtrlo
          lda #DC_SW_RX
          bne o2a
o3        cmp #DC_TX_ON		; switch sender on
          bne o4
	jsr dtrlo
          lda #DC_SW_TX
o2a       ora status,x
          sta status,x
          bne okx
o4        cmp #DC_RX_OFF	; switch receiver off, send eof to stream
          bne o5
rxoff     ldx dev
          lda status,x
          and #DC_SW_RX
          beq devoffx
	jsr rtshi
          lda outstr,x
          tax
          lda #SC_EOF
          jsr STRCMD
          ldx dev
          lda status,x
          and #255-DC_SW_RX
          sta status,x
	  jmp checkdtr

devoffx   jmp  devoff

o5        cmp #DC_TX_OFF	; switch sender off, send nul to stream
          bne o6
txoff     ldx dev
          lda status,x
          and #DC_SW_TX
          beq devoffx
          lda instr,x
          tax
          lda #SC_NUL
          jsr STRCMD
          ldx dev
          lda status,x
          and #255-DC_SW_TX
          sta status,x
checkdtr
	and #DC_SW_TX+DC_SW_RX
	bne active
	jsr dtrhi
active 	jmp ok

o6        cmp #DC_HS		; set handshake -- currently ignored (TODO)
          bne o6a
          lda status,x
          and #255-1
          sta status,x
          tya
          and #1
          ora status,x
          sta status,x
          jmp ok

o6a       cmp #DC_SPD		; set speed
          bne o7
          tya
          and #%00001111
	  asl
          tax
	  beq ok

	lda UART+UART_LCR
	ora #$80
	sta UART+UART_LCR
  	lda divisor,x
	sta UART+UART_DLL
	lda divisor+1,x
	sta UART+UART_DLH
	lda UART+UART_LCR
	and #$7f
	sta UART+UART_LCR

          jmp ok

o7        cmp #DC_ST		; get status...
          beq ok 
          cmp #DC_EXIT		; disable everything
          bne o8		; onotimp
          jsr rxoff
          jsr txoff
          ldx dev 
          lda status,x
          ora #2
          sta status,x
	  bne ok
o8
	  cmp #DC_BRKKEY
	  bne onotimp
          lda brkkey
	  sty brkkey
	  tay
	  ; jmp ok

ok        lda #E_OK
          .byt $2c
devon     lda #E_DON
          .byt $2c
devoff    lda #E_DOFF
          .byt $2c
onotimp   lda #E_NOTIMP
          cmp #1
          rts

#undef UART
#undef XTALMULT

devend2   .)