Merge pull request #2410 from alexthissen/serial

Improvements and fixes in serial support for Atari Lynx
This commit is contained in:
Bob Andrews 2024-02-12 12:50:02 +01:00 committed by GitHub
commit 4bde3afd80
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 115 additions and 113 deletions

View File

@ -259,30 +259,44 @@ SND_INTERRUPT = TIMER7_INTERRUPT
INTRST = $FD80
INTSET = $FD81
MAGRDY0 = $FD84
MAGRDY1 = $FD85
AUDIN = $FD86
SYSCTL1 = $FD87
MIKEYHREV = $FD88
MIKEYSREV = $FD89
IODIR = $FD8A
IODAT = $FD8B
TxIntEnable = %10000000
RxIntEnable = %01000000
TxParEnable = %00010000
ResetErr = %00001000
TxOpenColl = %00000100
TxBreak = %00000010
ParEven = %00000001
TxReady = %10000000
RxReady = %01000000
TxEmpty = %00100000
RxParityErr = %00010000
RxOverrun = %00001000
RxFrameErr = %00000100
RxBreak = %00000010
ParityBit = %00000001
SERCTL = $FD8C
IODIR = $FD8A
IODAT = $FD8B
; IODIR and IODAT bit definitions
AUDIN_BIT = $10 ; Note that there is also the address AUDIN
READ_ENABLE = $10 ; Same bit for AUDIN_BIT
RESTLESS = $08
NOEXP = $04 ; If set, redeye is not connected
CART_ADDR_DATA = $02
CART_POWER_OFF = $02 ; Same bit for CART_ADDR_DATA
EXTERNAL_POWER = $01
SERCTL = $FD8C
; SERCTL bit definitions for write operations
TXINTEN = $80
RXINTEN = $40
PAREN = $10
RESETERR = $08
TXOPEN = $04
TXBRK = $02
PAREVEN = $01
; SERCTL bit definitions for read operations
TXRDY = $80
RXRDY = $40
TXEMPTY = $20
PARERR = $10
OVERRUN = $08
FRAMERR = $04
RXBRK = $02
PARBIT = $01
SERDAT = $FD8D
SDONEACK = $FD90
CPUSLEEP = $FD91

View File

@ -68,7 +68,7 @@ MikeyInitData: .byte $9e,$18,$68,$1f,$00,$00,$00,$00,$00,$ff,$1a,$1b,$04,$0d,$2
; Disable the TX/RX IRQ; set to 8E1.
lda #%00011101
lda #PAREN|RESETERR|TXOPEN|PAREVEN ; #%00011101
sta SERCTL
; Clear all pending interrupts.

View File

@ -73,7 +73,12 @@ SER_UNINSTALL:
; Must return an SER_ERR_xx code in a/x.
SER_CLOSE:
; Disable interrupts
; Disable interrupts and stop timer 4 (serial)
lda #TXOPEN|RESETERR
sta SERCTL
stz TIM4CTLA ; Disable count and no reload
stz SerialStat ; Reset status
; Done, return an error code
lda #SER_ERR_OK
.assert SER_ERR_OK = 0, error
@ -108,17 +113,17 @@ SER_OPEN:
stz TxPtrIn
stz TxPtrOut
; clock = 8 * 15625
lda #%00011000
sta TIM4CTLA
ldy #SER_PARAMS::BAUDRATE
lda (ptr1),y
; Source period is 1 us
ldy #%00011000 ; ENABLE_RELOAD|ENABLE_COUNT|AUD_1
ldx #1
cmp #SER_BAUD_62500
beq setbaudrate
ldx #2
ldx #3
cmp #SER_BAUD_31250
beq setbaudrate
@ -134,6 +139,10 @@ SER_OPEN:
cmp #SER_BAUD_2400
beq setbaudrate
ldx #68
cmp #SER_BAUD_1800
beq setbaudrate
ldx #103
cmp #SER_BAUD_1200
beq setbaudrate
@ -142,65 +151,22 @@ SER_OPEN:
cmp #SER_BAUD_600
beq setbaudrate
; clock = 6 * 15625
ldx #%00011010
stx TIM4CTLA
; Source period is 8 us
ldy #%00011011 ; ENABLE_RELOAD|ENABLE_COUNT|AUD_8
ldx #12
cmp #SER_BAUD_7200
beq setbaudrate
ldx #25
cmp #SER_BAUD_3600
beq setbaudrate
ldx #207
stx TIM4BKUP
; clock = 4 * 15625
ldx #%00011100
ldx #51
cmp #SER_BAUD_300
beq setprescaler
; clock = 6 * 15625
ldx #%00011110
cmp #SER_BAUD_150
beq setprescaler
; clock = 1 * 15625
ldx #%00011111
stx TIM4CTLA
cmp #SER_BAUD_75
beq baudsuccess
ldx #141
cmp #SER_BAUD_110
beq setbaudrate
; clock = 2 * 15625
ldx #%00011010
stx TIM4CTLA
ldx #68
cmp #SER_BAUD_1800
beq setbaudrate
; clock = 6 * 15625
ldx #%00011110
stx TIM4CTLA
ldx #231
cmp #SER_BAUD_134_5
beq setbaudrate
lda #SER_ERR_BAUD_UNAVAIL
ldx #0 ; return value is char
rts
setprescaler:
stx TIM4CTLA
bra baudsuccess
setbaudrate:
sty TIM4CTLA
stx TIM4BKUP
baudsuccess:
ldx #TxOpenColl|ParEven
ldx #TXOPEN|PAREVEN
stx contrl
ldy #SER_PARAMS::DATABITS ; Databits
lda (ptr1),y
@ -218,15 +184,15 @@ baudsuccess:
beq checkhs
cmp #SER_PAR_SPACE
bne @L0
ldx #TxOpenColl
ldx #TXOPEN
stx contrl
bra checkhs
@L0:
ldx #TxParEnable|TxOpenColl|ParEven
ldx #PAREN|TXOPEN|PAREVEN
stx contrl
cmp #SER_PAR_EVEN
beq checkhs
ldx #TxParEnable|TxOpenColl
ldx #PAREN|TXOPEN
stx contrl
checkhs:
ldx contrl
@ -234,15 +200,27 @@ checkhs:
ldy #SER_PARAMS::HANDSHAKE ; Handshake
lda (ptr1),y
cmp #SER_HS_NONE
beq redeye_ok
cmp #SER_HS_SW ; Software handshake will check for connected redeye
bne invparameter
lda IODAT
and #NOEXP ; Check if redeye bit flag is unset
beq redeye_ok
lda #SER_ERR_NO_DEVICE ; ComLynx cable is not inserted
ldx #0
rts
redeye_ok:
lda SERDAT
lda contrl
ora #RxIntEnable|ResetErr
ora #RXINTEN|RESETERR ; Turn on interrupts for receive
sta SERCTL
lda #SER_ERR_OK
.assert SER_ERR_OK = 0, error
tax
rts
invparameter:
lda #SER_ERR_INIT_FAILED
ldx #0 ; return value is char
@ -264,8 +242,8 @@ GetByte:
ldy RxPtrOut
lda RxBuffer,y
inc RxPtrOut
sta (ptr1)
ldx #$00
sta (ptr1,x)
txa ; Return code = 0
rts
@ -279,24 +257,26 @@ SER_PUT:
ina
cmp TxPtrOut
bne PutByte
lda #SER_ERR_OVERFLOW
ldx #0 ; return value is char
rts
PutByte:
ldy TxPtrIn
txa
sta TxBuffer,y
inc TxPtrIn
bit TxDone
bmi @L1
bit TxDone ; Check bit 7 of TxDone (TXINTEN)
bmi @L1 ; Was TXINTEN already set?
php
sei
lda contrl
ora #TxIntEnable|ResetErr
sta SERCTL ; Allow TX-IRQ to hang RX-IRQ
lda contrl ; contrl does not include RXINTEN setting
ora #TXINTEN|RESETERR
sta SERCTL ; Allow TX-IRQ to hang RX-IRQ (no receive while transmitting)
sta TxDone
plp
plp ; Restore processor and interrupt enable
@L1:
lda #SER_ERR_OK
.assert SER_ERR_OK = 0, error
@ -308,9 +288,9 @@ PutByte:
; Must return an SER_ERR_xx code in a/x.
SER_STATUS:
ldy SerialStat
lda SerialStat
sta (ptr1)
ldx #$00
sta (ptr1,x)
txa ; Return code = 0
rts
@ -342,48 +322,56 @@ SER_IRQ:
@L0:
bit TxDone
bmi @tx_irq ; Transmit in progress
ldx SERDAT
lda SERCTL
and #RxParityErr|RxOverrun|RxFrameErr|RxBreak
beq @rx_irq
ldx SERDAT ; Read received data
lda contrl
and #PAREN ; Parity enabled implies SER_PAR_EVEN or SER_PAR_ODD
tay
ora #OVERRUN|FRAMERR|RXBRK
and SERCTL ; Check presence of relevant error flags in SERCTL
beq @rx_irq ; No errors so far
tsb SerialStat ; Save error condition
bit #RxBreak
bit #RXBRK ; Check for break signal
beq @noBreak
stz TxPtrIn ; Break received - drop buffers
stz TxPtrOut
stz RxPtrIn
stz RxPtrOut
@noBreak:
lda contrl
ora #RxIntEnable|ResetErr
sta SERCTL
lda #$10
sta INTRST
bra @IRQexit
bra @exit0
@rx_irq:
tya
bne @2 ; Parity was enabled so no marker bit check needed
lda contrl
ora #RxIntEnable|ResetErr
sta SERCTL
eor SERCTL ; Should match current parity bit
and #PARBIT ; Check for mark or space value
bne @exit0
@2:
txa
ldx RxPtrIn
sta RxBuffer,x
txa
inx
@cont0:
cpx RxPtrOut
beq @1
stx RxPtrIn
lda #SERIAL_INTERRUPT
sta INTRST
bra @IRQexit
@1:
sta RxPtrIn
lda #$80
tsb SerialStat
bra @exit0
@tx_irq:
ldx TxPtrOut ; Has all bytes been sent?
ldx TxPtrOut ; Have all bytes been sent?
cpx TxPtrIn
beq @allSent
@ -393,24 +381,24 @@ SER_IRQ:
@exit1:
lda contrl
ora #TxIntEnable|ResetErr
ora #TXINTEN|RESETERR
sta SERCTL
lda #SERIAL_INTERRUPT
sta INTRST
bra @IRQexit
@allSent:
lda SERCTL ; All bytes sent
bit #TxEmpty
bit #TXEMPTY
beq @exit1
bvs @exit1
stz TxDone
@exit0:
lda contrl
ora #RxIntEnable|ResetErr
ora #RXINTEN|RESETERR ; Re-enable receive interrupt
sta SERCTL
@IRQexit:
lda #SERIAL_INTERRUPT
sta INTRST
@IRQexit:
clc
rts

View File

@ -40,14 +40,14 @@ cont1:
bra loop1
read_byte:
bit SERCTL
bit SERCTL ; Check for RXRDY ($40)
bvc read_byte
lda SERDAT
rts
_UpLoaderIRQ:
lda INTSET
and #$10
and #SERIAL_INTERRUPT
bne @L0
clc
rts
@ -69,7 +69,7 @@ again:
; last action : clear interrupt
;
exit:
lda #$10
lda #SERIAL_INTERRUPT
sta INTRST
clc
rts