# Object files
OBJS = cgetc.o \
- comlynx.o \
crt0.o \
ctype.o \
eeprom.o \
MOUS =
-SERS =
+SERS = lynx-comlynx.ser
TGIS = lynx-160-102-16.tgi
+++ /dev/null
-;
-; Serial driver for the Atari Lynx ComLynx port.
-;
-; Karri Kaksonen, 17.09.2009
-;
-
- .include "lynx.inc"
- .include "zeropage.inc"
- .include "ser-kernel.inc"
- .include "ser-error.inc"
-
-; ------------------------------------------------------------------------
-; Header. Includes jump table
-
- .segment "JUMPTABLE"
-
- ; Driver signature
- .byte $73, $65, $72 ; "ser"
- .byte SER_API_VERSION ; Serial API version number
-
- ; Jump table.
- .addr INSTALL
- .addr UNINSTALL
- .addr OPEN
- .addr CLOSE
- .addr GET
- .addr PUT
- .addr STATUS
- .addr IOCTL
- .addr IRQ
-
-;----------------------------------------------------------------------------
-; Global variables
-;
-; The ring buffers will be at the fixed place
-; Tx buffer $200 - $2ff. Rx buffer $300 - $3ff.
-; This memory area can usually not be used for anything as the encryption
-; stuff needs it. But for this purpose it fits perfectly.
-
- .bss
-
-TxBuffer = $0200
-RxBuffer = $0300
-RxPtrIn: .res 1
-RxPtrOut: .res 1
-TxPtrIn: .res 1
-TxPtrOut: .res 1
-contrl: .res 1
-SerialStat: .res 1
-TxDone: .res 1
-
- .code
-
-;----------------------------------------------------------------------------
-; INSTALL: Is called after the driver is loaded into memory.
-;
-; Must return an SER_ERR_xx code in a/x.
-
-INSTALL:
- ; Set up IRQ vector ?
-
-;----------------------------------------------------------------------------
-; UNINSTALL: Is called before the driver is removed from memory.
-; No return code required (the driver is removed from memory on return).
-;
-
-UNINSTALL:
-
-;----------------------------------------------------------------------------
-; CLOSE: Close the port and disable interrupts. Called without parameters.
-; Must return an SER_ERR_xx code in a/x.
-
-CLOSE:
- ; Disable interrupts
- ; Done, return an error code
- lda #<SER_ERR_OK
- ldx #>SER_ERR_OK
- rts
-
-;----------------------------------------------------------------------------
-; OPEN: A pointer to a ser_params structure is passed in ptr1.
-;
-; The Lynx has only two correct serial data formats:
-; 8 bits, parity mark, 1 stop bit
-; 8 bits, parity space, 1 stop bit
-;
-; It also has two wrong formats;
-; 8 bits, even parity, 1 stop bit
-; 8 bits, odd parity, 1 stop bit
-;
-; Unfortunately the parity bit includes itself in the calculation making
-; parity not compatible with the rest of the world.
-;
-; We can only specify a few baud rates.
-; Lynx has two non-standard speeds 31250 and 62500 which are
-; frequently used in games.
-;
-; The receiver will always read the parity and report parity errors.
-;
-; Must return an SER_ERR_xx code in a/x.
-
-OPEN:
- stz RxPtrIn
- stz RxPtrOut
- stz TxPtrIn
- stz TxPtrOut
-
- ; clock = 8 * 15625
- lda #%00011000
- sta TIM4CTLA
- ldy #SER_PARAMS::BAUDRATE
- lda (ptr1),y
-
- ldx #1
- cmp #SER_BAUD_62500
- beq setbaudrate
-
- ldx #2
- cmp #SER_BAUD_31250
- beq setbaudrate
-
- ldx #12
- cmp #SER_BAUD_9600
- beq setbaudrate
-
- ldx #25
- cmp #SER_BAUD_4800
- beq setbaudrate
-
- ldx #51
- cmp #SER_BAUD_2400
- beq setbaudrate
-
- ldx #103
- cmp #SER_BAUD_1200
- beq setbaudrate
-
- ldx #207
- cmp #SER_BAUD_600
- beq setbaudrate
-
- ; clock = 6 * 15625
- ldx #%00011010
- stx TIM4CTLA
-
- 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
- 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 #>SER_ERR_BAUD_UNAVAIL
- rts
-setprescaler:
- stx TIM4CTLA
- bra baudsuccess
-setbaudrate:
- stx TIM4BKUP
-baudsuccess:
- ldx #TxOpenColl|ParEven
- stx contrl
- ldy #SER_PARAMS::DATABITS ; Databits
- lda (ptr1),y
- cmp #SER_BITS_8
- bne invparameter
- ldy #SER_PARAMS::STOPBITS ; Stopbits
- lda (ptr1),y
- cmp #SER_STOP_1
- bne invparameter
- ldy #SER_PARAMS::PARITY ; Parity
- lda (ptr1),y
- cmp #SER_PAR_NONE
- beq invparameter
- cmp #SER_PAR_MARK
- beq checkhs
- cmp #SER_PAR_SPACE
- bne @L0
- ldx #TxOpenColl
- stx contrl
- bra checkhs
-@L0:
- ldx #TxParEnable|TxOpenColl|ParEven
- stx contrl
- cmp #SER_PAR_EVEN
- beq checkhs
- ldx #TxParEnable|TxOpenColl
- stx contrl
-checkhs:
- ldx contrl
- stx SERCTL
- ldy #SER_PARAMS::HANDSHAKE ; Handshake
- lda (ptr1),y
- cmp #SER_HS_NONE
- bne invparameter
- lda SERDAT
- lda contrl
- ora #RxIntEnable|ResetErr
- sta SERCTL
- lda #<SER_ERR_OK
- ldx #>SER_ERR_OK
- rts
-invparameter:
- lda #<SER_ERR_INIT_FAILED
- ldx #>SER_ERR_INIT_FAILED
- rts
-
-;----------------------------------------------------------------------------
-; GET: Will fetch a character from the receive buffer and store it into the
-; variable pointed to by ptr1. If no data is available, SER_ERR_NO_DATA is
-; returned.
-
-GET:
- lda RxPtrIn
- cmp RxPtrOut
- bne GetByte
- lda #<SER_ERR_NO_DATA
- ldx #>SER_ERR_NO_DATA
- rts
-GetByte:
- ldy RxPtrOut
- lda RxBuffer,y
- inc RxPtrOut
- ldx #$00
- sta (ptr1,x)
- txa ; Return code = 0
- rts
-
-;----------------------------------------------------------------------------
-; PUT: Output character in A.
-; Must return an SER_ERR_xx code in a/x.
-
-PUT:
- tax
- lda TxPtrIn
- ina
- cmp TxPtrOut
- bne PutByte
- lda #<SER_ERR_OVERFLOW
- ldx #>SER_ERR_OVERFLOW
- rts
-PutByte:
- ldy TxPtrIn
- txa
- sta TxBuffer,y
- inc TxPtrIn
-
- bit TxDone
- bmi @L1
- php
- sei
- lda contrl
- ora #TxIntEnable|ResetErr
- sta SERCTL ; Allow TX-IRQ to hang RX-IRQ
- sta TxDone
- plp
-@L1:
- lda #<SER_ERR_OK
- tax
- rts
-
-;----------------------------------------------------------------------------
-; STATUS: Return the status in the variable pointed to by ptr1.
-; Must return an SER_ERR_xx code in a/x.
-
-STATUS:
- ldy SerialStat
- ldx #$00
- sta (ptr1,x)
- txa ; Return code = 0
- rts
-
-;----------------------------------------------------------------------------
-; IOCTL: Driver defined entry point. The wrapper will pass a pointer to ioctl
-; specific data in ptr1, and the ioctl code in A.
-; Must return an SER_ERR_xx code in a/x.
-
-IOCTL:
- lda #<SER_ERR_INV_IOCTL
- ldx #>SER_ERR_INV_IOCTL
- rts
-
-;----------------------------------------------------------------------------
-; IRQ: Called from the builtin runtime IRQ handler as a subroutine. All
-; registers are already saved, no parameters are passed, but the carry flag
-; is clear on entry. The routine must return with carry set if the interrupt
-; was handled, otherwise with carry clear.
-;
-; Both the Tx and Rx interrupts are level sensitive instead of edge sensitive.
-; Due to this bug you have to disable the interrupt before clearing it.
-
-IRQ:
- lda INTSET ; Poll all pending interrupts
- and #SERIAL_INTERRUPT
- bne @L0
- clc
- rts
-@L0:
- bit TxDone
- bmi @tx_irq ; Transmit in progress
- ldx SERDAT
- lda SERCTL
- and #RxParityErr|RxOverrun|RxFrameErr|RxBreak
- beq @rx_irq
- tsb SerialStat ; Save error condition
- bit #RxBreak
- 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
-@rx_irq:
- lda contrl
- ora #RxIntEnable|ResetErr
- sta SERCTL
- 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
-@tx_irq:
- ldx TxPtrOut ; Has all bytes been sent?
- cpx TxPtrIn
- beq @allSent
-
- lda TxBuffer,x ; Send next byte
- sta SERDAT
- inc TxPtrOut
-
-@exit1:
- lda contrl
- ora #TxIntEnable|ResetErr
- sta SERCTL
- lda #SERIAL_INTERRUPT
- sta INTRST
- bra @IRQexit
-
-@allSent:
- lda SERCTL ; All bytes sent
- bit #TxEmpty
- beq @exit1
- bvs @exit1
- stz TxDone
- lda contrl
- ora #RxIntEnable|ResetErr
- sta SERCTL
-
- lda #SERIAL_INTERRUPT
- sta INTRST
-@IRQexit:
- clc
- rts
-
--- /dev/null
+;
+; Serial driver for the Atari Lynx ComLynx port.
+;
+; Karri Kaksonen, 17.09.2009
+;
+
+ .include "lynx.inc"
+ .include "zeropage.inc"
+ .include "ser-kernel.inc"
+ .include "ser-error.inc"
+
+; ------------------------------------------------------------------------
+; Header. Includes jump table
+
+ .segment "JUMPTABLE"
+
+ ; Driver signature
+ .byte $73, $65, $72 ; "ser"
+ .byte SER_API_VERSION ; Serial API version number
+
+ ; Jump table.
+ .addr INSTALL
+ .addr UNINSTALL
+ .addr OPEN
+ .addr CLOSE
+ .addr GET
+ .addr PUT
+ .addr STATUS
+ .addr IOCTL
+ .addr IRQ
+
+;----------------------------------------------------------------------------
+; Global variables
+;
+; The ring buffers will be at the fixed place
+; Tx buffer $200 - $2ff. Rx buffer $300 - $3ff.
+; This memory area can usually not be used for anything as the encryption
+; stuff needs it. But for this purpose it fits perfectly.
+
+ .bss
+
+TxBuffer = $0200
+RxBuffer = $0300
+RxPtrIn: .res 1
+RxPtrOut: .res 1
+TxPtrIn: .res 1
+TxPtrOut: .res 1
+contrl: .res 1
+SerialStat: .res 1
+TxDone: .res 1
+
+ .code
+
+;----------------------------------------------------------------------------
+; INSTALL: Is called after the driver is loaded into memory.
+;
+; Must return an SER_ERR_xx code in a/x.
+
+INSTALL:
+ ; Set up IRQ vector ?
+
+;----------------------------------------------------------------------------
+; UNINSTALL: Is called before the driver is removed from memory.
+; No return code required (the driver is removed from memory on return).
+;
+
+UNINSTALL:
+
+;----------------------------------------------------------------------------
+; CLOSE: Close the port and disable interrupts. Called without parameters.
+; Must return an SER_ERR_xx code in a/x.
+
+CLOSE:
+ ; Disable interrupts
+ ; Done, return an error code
+ lda #<SER_ERR_OK
+ ldx #>SER_ERR_OK
+ rts
+
+;----------------------------------------------------------------------------
+; OPEN: A pointer to a ser_params structure is passed in ptr1.
+;
+; The Lynx has only two correct serial data formats:
+; 8 bits, parity mark, 1 stop bit
+; 8 bits, parity space, 1 stop bit
+;
+; It also has two wrong formats;
+; 8 bits, even parity, 1 stop bit
+; 8 bits, odd parity, 1 stop bit
+;
+; Unfortunately the parity bit includes itself in the calculation making
+; parity not compatible with the rest of the world.
+;
+; We can only specify a few baud rates.
+; Lynx has two non-standard speeds 31250 and 62500 which are
+; frequently used in games.
+;
+; The receiver will always read the parity and report parity errors.
+;
+; Must return an SER_ERR_xx code in a/x.
+
+OPEN:
+ stz RxPtrIn
+ stz RxPtrOut
+ stz TxPtrIn
+ stz TxPtrOut
+
+ ; clock = 8 * 15625
+ lda #%00011000
+ sta TIM4CTLA
+ ldy #SER_PARAMS::BAUDRATE
+ lda (ptr1),y
+
+ ldx #1
+ cmp #SER_BAUD_62500
+ beq setbaudrate
+
+ ldx #2
+ cmp #SER_BAUD_31250
+ beq setbaudrate
+
+ ldx #12
+ cmp #SER_BAUD_9600
+ beq setbaudrate
+
+ ldx #25
+ cmp #SER_BAUD_4800
+ beq setbaudrate
+
+ ldx #51
+ cmp #SER_BAUD_2400
+ beq setbaudrate
+
+ ldx #103
+ cmp #SER_BAUD_1200
+ beq setbaudrate
+
+ ldx #207
+ cmp #SER_BAUD_600
+ beq setbaudrate
+
+ ; clock = 6 * 15625
+ ldx #%00011010
+ stx TIM4CTLA
+
+ 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
+ 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 #>SER_ERR_BAUD_UNAVAIL
+ rts
+setprescaler:
+ stx TIM4CTLA
+ bra baudsuccess
+setbaudrate:
+ stx TIM4BKUP
+baudsuccess:
+ ldx #TxOpenColl|ParEven
+ stx contrl
+ ldy #SER_PARAMS::DATABITS ; Databits
+ lda (ptr1),y
+ cmp #SER_BITS_8
+ bne invparameter
+ ldy #SER_PARAMS::STOPBITS ; Stopbits
+ lda (ptr1),y
+ cmp #SER_STOP_1
+ bne invparameter
+ ldy #SER_PARAMS::PARITY ; Parity
+ lda (ptr1),y
+ cmp #SER_PAR_NONE
+ beq invparameter
+ cmp #SER_PAR_MARK
+ beq checkhs
+ cmp #SER_PAR_SPACE
+ bne @L0
+ ldx #TxOpenColl
+ stx contrl
+ bra checkhs
+@L0:
+ ldx #TxParEnable|TxOpenColl|ParEven
+ stx contrl
+ cmp #SER_PAR_EVEN
+ beq checkhs
+ ldx #TxParEnable|TxOpenColl
+ stx contrl
+checkhs:
+ ldx contrl
+ stx SERCTL
+ ldy #SER_PARAMS::HANDSHAKE ; Handshake
+ lda (ptr1),y
+ cmp #SER_HS_NONE
+ bne invparameter
+ lda SERDAT
+ lda contrl
+ ora #RxIntEnable|ResetErr
+ sta SERCTL
+ lda #<SER_ERR_OK
+ ldx #>SER_ERR_OK
+ rts
+invparameter:
+ lda #<SER_ERR_INIT_FAILED
+ ldx #>SER_ERR_INIT_FAILED
+ rts
+
+;----------------------------------------------------------------------------
+; GET: Will fetch a character from the receive buffer and store it into the
+; variable pointed to by ptr1. If no data is available, SER_ERR_NO_DATA is
+; returned.
+
+GET:
+ lda RxPtrIn
+ cmp RxPtrOut
+ bne GetByte
+ lda #<SER_ERR_NO_DATA
+ ldx #>SER_ERR_NO_DATA
+ rts
+GetByte:
+ ldy RxPtrOut
+ lda RxBuffer,y
+ inc RxPtrOut
+ ldx #$00
+ sta (ptr1,x)
+ txa ; Return code = 0
+ rts
+
+;----------------------------------------------------------------------------
+; PUT: Output character in A.
+; Must return an SER_ERR_xx code in a/x.
+
+PUT:
+ tax
+ lda TxPtrIn
+ ina
+ cmp TxPtrOut
+ bne PutByte
+ lda #<SER_ERR_OVERFLOW
+ ldx #>SER_ERR_OVERFLOW
+ rts
+PutByte:
+ ldy TxPtrIn
+ txa
+ sta TxBuffer,y
+ inc TxPtrIn
+
+ bit TxDone
+ bmi @L1
+ php
+ sei
+ lda contrl
+ ora #TxIntEnable|ResetErr
+ sta SERCTL ; Allow TX-IRQ to hang RX-IRQ
+ sta TxDone
+ plp
+@L1:
+ lda #<SER_ERR_OK
+ tax
+ rts
+
+;----------------------------------------------------------------------------
+; STATUS: Return the status in the variable pointed to by ptr1.
+; Must return an SER_ERR_xx code in a/x.
+
+STATUS:
+ ldy SerialStat
+ ldx #$00
+ sta (ptr1,x)
+ txa ; Return code = 0
+ rts
+
+;----------------------------------------------------------------------------
+; IOCTL: Driver defined entry point. The wrapper will pass a pointer to ioctl
+; specific data in ptr1, and the ioctl code in A.
+; Must return an SER_ERR_xx code in a/x.
+
+IOCTL:
+ lda #<SER_ERR_INV_IOCTL
+ ldx #>SER_ERR_INV_IOCTL
+ rts
+
+;----------------------------------------------------------------------------
+; IRQ: Called from the builtin runtime IRQ handler as a subroutine. All
+; registers are already saved, no parameters are passed, but the carry flag
+; is clear on entry. The routine must return with carry set if the interrupt
+; was handled, otherwise with carry clear.
+;
+; Both the Tx and Rx interrupts are level sensitive instead of edge sensitive.
+; Due to this bug you have to disable the interrupt before clearing it.
+
+IRQ:
+ lda INTSET ; Poll all pending interrupts
+ and #SERIAL_INTERRUPT
+ bne @L0
+ clc
+ rts
+@L0:
+ bit TxDone
+ bmi @tx_irq ; Transmit in progress
+ ldx SERDAT
+ lda SERCTL
+ and #RxParityErr|RxOverrun|RxFrameErr|RxBreak
+ beq @rx_irq
+ tsb SerialStat ; Save error condition
+ bit #RxBreak
+ 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
+@rx_irq:
+ lda contrl
+ ora #RxIntEnable|ResetErr
+ sta SERCTL
+ 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
+@tx_irq:
+ ldx TxPtrOut ; Has all bytes been sent?
+ cpx TxPtrIn
+ beq @allSent
+
+ lda TxBuffer,x ; Send next byte
+ sta SERDAT
+ inc TxPtrOut
+
+@exit1:
+ lda contrl
+ ora #TxIntEnable|ResetErr
+ sta SERCTL
+ lda #SERIAL_INTERRUPT
+ sta INTRST
+ bra @IRQexit
+
+@allSent:
+ lda SERCTL ; All bytes sent
+ bit #TxEmpty
+ beq @exit1
+ bvs @exit1
+ stz TxDone
+ lda contrl
+ ora #RxIntEnable|ResetErr
+ sta SERCTL
+
+ lda #SERIAL_INTERRUPT
+ sta INTRST
+@IRQexit:
+ clc
+ rts
+