1
0
mirror of https://github.com/cc65/cc65.git synced 2024-12-25 17:29:50 +00:00

Lynx patches by Karri Kaksonen. Improvements for the graphics driver, new

serial driver.


git-svn-id: svn://svn.cc65.org/cc65/trunk@4198 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
uz 2009-09-20 14:22:04 +00:00
parent 20eb942ab9
commit ec946cae51
8 changed files with 498 additions and 16 deletions

View 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

View 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

View 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>

View 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

View 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

View 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 \

412
libsrc/lynx/comlynx.s Normal file
View File

@ -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

View 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