]> git.sur5r.net Git - cc65/commitdiff
Lynx patches by Karri Kaksonen. Improvements for the graphics driver, new
authoruz <uz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Sun, 20 Sep 2009 14:22:04 +0000 (14:22 +0000)
committeruz <uz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Sun, 20 Sep 2009 14:22:04 +0000 (14:22 +0000)
serial driver.

git-svn-id: svn://svn.cc65.org/cc65/trunk@4198 b7a2c559-68d2-44c3-8de9-860c34a00d81

asminc/lynx.inc
asminc/ser-kernel.inc
doc/lynx.sgml
include/serial.h
libsrc/Makefile
libsrc/lynx/Makefile
libsrc/lynx/comlynx.s [new file with mode: 0644]
libsrc/lynx/lynx-160-102-16.s

index 19ddef8ac12e3ea132c86481873ac00e3bac3d0f..7c720542e0a0be717b1e65b5e00ac85c44ac4405 100644 (file)
@@ -203,6 +203,20 @@ MSTEREO     = $FD50
 
 ; Mikey Misc
 
+; Interrupt bits in INTRST and INTSET
+TIMER0_INTERRUPT = $01
+TIMER1_INTERRUPT = $02
+TIMER2_INTERRUPT = $04
+TIMER3_INTERRUPT = $08
+TIMER4_INTERRUPT = $10
+TIMER5_INTERRUPT = $20
+TIMER6_INTERRUPT = $40
+TIMER7_INTERRUPT = $80
+
+HBL_INTERRUPT = TIMER0_INTERRUPT
+VBL_INTERRUPT = TIMER2_INTERRUPT
+SERIAL_INTERRUPT = TIMER4_INTERRUPT
+
 INTRST      = $FD80
 INTSET      = $FD81
 MAGRDY0     = $FD84
@@ -213,6 +227,21 @@ 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
 SERDAT      = $FD8D
 SDONEACK    = $FD90
index 5d448775f2bcd2549b825edc410790d6d137717c..50f8ec06de4400b813358ae5fc55d9dcdd68f87c 100644 (file)
@@ -93,6 +93,8 @@ SER_BAUD_38400                =       $10
 SER_BAUD_57600                 =       $11
 SER_BAUD_115200                =       $12
 SER_BAUD_230400                =       $13
+SER_BAUD_31250         =       $14
+SER_BAUD_62500         =       $15
 
 ; Data bit settings
 SER_BITS_5                     =       $00
index c897a4dad99495252dd68672bf1ffe26c0bfc020..e76b6060ae4122d2660ce019761a7b75c55d4b55 100644 (file)
@@ -168,8 +168,54 @@ No mouse drivers are currently available for the Lynx.
 
 <sect1>RS232 device drivers<p>
 
-No serial drivers are currently available for the Lynx.
+<descrip>
 
+  The ComLynx port has Tx and Rx wired together. Every byte is sent
+  to all connected Lynxes. Only one Lynx can send at a time. There is no
+  protocol created for communication. You are on your own.
+
+  If the Lynx returns framing error then it is likely that another Lynx is
+  sending data at the same time.
+
+  The Lynx can also send a break and receive a break. The Lynx break is
+  recognized if the bit is down for 24 bit cycles or more.
+
+  To send a break you just set the break bit. The length of the break depends
+  on how long this bit is down.
+
+  The driver supports the baudrates:
+  <itemize>
+  <item>62500
+  <item>31250
+  <item>9600
+  <item>7200
+  <item>4800
+  <item>3600
+  <item>2400
+  <item>1800
+  <item>1200
+  <item>600
+  <item>300
+  <item>150
+  <item>134.5
+  <item>110
+  <item>75
+  </itemize>
+  The parity bit supports MARK and SPACE. It also supports EVEN and ODD parity
+  but the parity bit is included in the calculation. Most of us don't want it
+  this way. But there is nothing we can do about it. Just don't use EVEN or ODD
+  when communicating to other equipment than the Lynx. 
+
+  There is always only one stop bit. And the data length is always 8 bits.
+
+  We have no handshaking available. Even software handshake is impossible
+  as ComLynx has only one wire for the data.
+
+  Both transmit and receive are interrupt driven. The driver reserves a fixed
+  area $200-$2ff for the transmit ring buffer and $300-$3ff for the receive
+  ring buffer. This area can not be used at startup for anything as the Lynx
+  ROM needs this area for decryption purposes.
+</descrip><p>
 
 
 <sect>Limitations<p>
index 23934e9264b4599f5288e2864d8b7b02e2e8d91f..671ec193ff12da997a42d8f2276f4be2250404b5 100644 (file)
@@ -65,6 +65,8 @@
 #define SER_BAUD_57600                 0x11
 #define SER_BAUD_115200                0x12
 #define SER_BAUD_230400                0x13
+#define SER_BAUD_31250         0x14
+#define SER_BAUD_62500         0x15
 
 /* Data bit settings */
 #define SER_BITS_5                     0x00
index 85a5a64f6f4ed10d2c170494b972b367a2e370a1..d03c4aec996a29c6e9226c9baebbd67e242dba1c 100644 (file)
@@ -191,12 +191,13 @@ geoslib:
 # Lynx
 
 lynxlib:
-       for i in lynx common conio runtime em joystick tgi zlib; do \
+       for i in lynx common conio runtime em joystick serial tgi zlib; do \
            $(MAKE) SYS=lynx -C $$i || exit 1; \
            $(AR) a lynx.lib $$i/*.o;\
        done
        cp lynx/*.joy .
        cp lynx/*.tgi .
+       cp lynx/*.ser .
 
 #-----------------------------------------------------------------------------
 # NES
index eaa52872df17364167b8687d17624b50f8fcd478..76643b0b74e74235706e6384699cbfc0020ebdef 100644 (file)
@@ -46,11 +46,11 @@ CFLAGS      = -Osir -g -T -t $(SYS) --forget-inc-paths -I . -I ../../include
 # Object files
 
 OBJS =  cgetc.o         \
+        comlynx.o       \
         crt0.o          \
        ctype.o         \
         eeprom.o        \
         extzp.o         \
-        framerate.o     \
         kbhit.o         \
        mainargs.o      \
        sysuname.o      \
diff --git a/libsrc/lynx/comlynx.s b/libsrc/lynx/comlynx.s
new file mode 100644 (file)
index 0000000..8b55e93
--- /dev/null
@@ -0,0 +1,412 @@
+;
+; 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
+
index a27496cbcf516489a0137879983da5c22b9ef3bc..625c01fb77d11d71816edd6c071944a738a4c06e 100644 (file)
@@ -196,6 +196,9 @@ UNINSTALL:
 ;
 
 INIT:
+; Enable interrupts for VBL
+       lda     #$80
+       tsb     VTIMCTLA
 ; Done, reset the error code
         lda     #TGI_ERR_OK
         sta     ERROR
@@ -434,19 +437,6 @@ SETDRAWPAGE:
 ; IRQ: VBL interrupt handler
 ;
 
-TIMER0_INTERRUPT = $01
-TIMER1_INTERRUPT = $02
-TIMER2_INTERRUPT = $04
-TIMER3_INTERRUPT = $08
-TIMER4_INTERRUPT = $10
-TIMER5_INTERRUPT = $20
-TIMER6_INTERRUPT = $40
-TIMER7_INTERRUPT = $80
-
-HBL_INTERRUPT = TIMER0_INTERRUPT
-VBL_INTERRUPT = TIMER2_INTERRUPT
-SERIAL_INTERRUPT = TIMER4_INTERRUPT
-
 IRQ:
                lda     INTSET          ; Poll all pending interrupts
                and     #VBL_INTERRUPT