1
0
mirror of https://github.com/cc65/cc65.git synced 2025-01-18 11:29:45 +00:00

Merge pull request #64 from groessler/something_to_pull

Serial driver for Atari
This commit is contained in:
Oliver Schmidt 2013-12-07 07:36:22 -08:00
commit 925cd95131
8 changed files with 619 additions and 391 deletions

View File

@ -48,6 +48,7 @@
SER_ERR_INIT_FAILED ; Initialization failed
SER_ERR_INV_IOCTL ; IOCTL not supported
SER_ERR_INSTALLED ; A driver is already installed
SER_ERR_NOT_OPEN ; Driver not open
SER_ERR_COUNT ; Special: Number of error codes
.endenum

View File

@ -96,6 +96,7 @@ SER_BAUD_115200 = $12
SER_BAUD_230400 = $13
SER_BAUD_31250 = $14
SER_BAUD_62500 = $15
SER_BAUD_56_875 = $16
; Data bit settings
SER_BITS_5 = $00

View File

@ -67,6 +67,7 @@
#define SER_BAUD_230400 0x13
#define SER_BAUD_31250 0x14
#define SER_BAUD_62500 0x15
#define SER_BAUD_56_875 0x16
/* Data bit settings */
#define SER_BITS_5 0x00
@ -111,6 +112,7 @@
#define SER_ERR_INIT_FAILED 0x08 /* Initialization failed */
#define SER_ERR_INV_IOCTL 0x09 /* IOCTL not supported */
#define SER_ERR_INSTALLED 0x0A /* A driver is already installed */
#define SER_ERR_NOT_OPEN 0x0B /* Driver is not open */
/* Struct containing parameters for the serial port */
struct ser_params {

View File

@ -2,11 +2,13 @@
; Oliver Schmidt, 2013-05-31
;
.export em_libref, joy_libref, tgi_libref
.export em_libref, joy_libref, tgi_libref, ser_libref
.import _exit
.import atari_ser_libref
em_libref := _exit
joy_libref := _exit
ser_libref := atari_ser_libref
.ifdef __ATARIXL__
.import CIO_handler
tgi_libref := CIO_handler

View File

@ -1,389 +0,0 @@
;
; Christian Groessler, Dec-2001
;
; RS232 routines using the R: device (currently tested with an 850 only)
;
; unsigned char __fastcall__ rs232_init (char hacked);
; unsigned char __fastcall__ rs232_params (unsigned char params, unsigned char parity);
; unsigned char __fastcall__ rs232_done (void);
; unsigned char __fastcall__ rs232_get (char* B);
; unsigned char __fastcall__ rs232_put (char B);
; unsigned char __fastcall__ rs232_pause (void); [TODO]
; unsigned char __fastcall__ rs232_unpause (void); [TODO]
; unsigned char __fastcall__ rs232_status (unsigned char* status,
; unsigned char* errors); [TODO]
;
.import findfreeiocb
.import __do_oserror
.import fddecusage
.import fdtoiocb
.import __inviocb
.import clriocb
.import newfd
.import _close, pushax, popax, popa
.importzp ptr1, tmp2, tmp3
.export _rs232_init, _rs232_params, _rs232_done, _rs232_get
.export _rs232_put, _rs232_pause, _rs232_unpause, _rs232_status
.include "atari.inc"
.include "errno.inc"
.include "rs232.inc"
.rodata
rdev: .byte "R:", ATEOL, 0
.bss
; receive buffer
RECVBUF_SZ = 256
recv_buf: .res RECVBUF_SZ
cm_run: .res 1 ; concurrent mode running?
.data
rshand: .word $ffff
.code
;----------------------------------------------------------------------------
;
; unsigned char __fastcall__ rs232_init (char hacked);
; /* Initialize the serial port. The parameter is ignored in the Atari version.
; * return 0/-1 for OK/Error
; */
;
.proc _rs232_init
jsr findfreeiocb
bne init_err
txa
tay ; move iocb # into Y
lda #3
sta tmp3 ; name length + 1
lda #<rdev
ldx #>rdev
jsr newfd
tya
bcs doopen ; C set: open needed / device not already open
pha
jsr _rs232_done ;** shut down if started @@@TODO check this out!!
pla
doopen: tax
pha
jsr clriocb
pla
tax
lda #<rdev
sta ICBAL,x
lda #>rdev
sta ICBAH,x
lda #OPEN
sta ICCOM,x
lda #$0D ; mode in+out+concurrent
sta ICAX1,x
lda #0
sta ICAX2,x
sta ICBLL,x ; zap buf len
sta ICBLH,x
jsr CIOV
bmi cioerr1
lda tmp2 ; get fd
sta rshand
ldx #0
stx rshand+1
txa
rts
cioerr1:jsr fddecusage ; decrement usage counter of fd as open failed
init_err:
ldx #0
lda #RS_ERR_INIT_FAILED
rts
.endproc ; _rs232_init
;----------------------------------------------------------------------------
;
; unsigned char __fastcall__ rs232_params (unsigned char params, unsigned char parity);
;
; Set communication parameters.
;
; params contains baud rate, stop bits and word size
; parity contains parity
;
; 850 manual documents restrictions on the baud rate (not > 300), when not
; using 8 bit word size. So only 8 bit is currently tested.
;
.proc _rs232_params
sta tmp2
lda rshand
cmp #$ff
bne work ; work only if initialized
lda #RS_ERR_NOT_INITIALIZED
bne done
work: lda rshand
ldx #0
jsr fdtoiocb ; get iocb index into X
bmi inverr ; shouldn't happen
tax
; set handshake lines
lda #34 ; xio 34, set cts, dtr etc
sta ICCOM,x
lda #192+48+3 ; DTR on, RTS on, XMT on
sta ICAX1,x
lda #0
sta ICBLL,x
sta ICBLH,x
sta ICBAL,x
sta ICBAH,x
sta ICAX2,x
jsr CIOV
bmi cioerr
; set baud rate, word size, stop bits and ready monitoring
lda #36 ; xio 36, baud rate
sta ICCOM,x
jsr popa ; get parameter
sta ICAX1,x
;ICAX2 = 0, monitor nothing
jsr CIOV
bmi cioerr
; set translation and parity
lda #38 ; xio 38, translation and parity
sta ICCOM,x
lda tmp2
ora #32 ; no translation
sta ICAX1,x
jsr CIOV
bmi cioerr
lda #0
done: ldx #0
rts
inverr: jmp __inviocb
.endproc ;_rs232_params
cioerr: jmp __do_oserror
;----------------------------------------------------------------------------
;
; unsigned char __fastcall__ rs232_done (void);
; /* Close the port, deinstall the interrupt hander. You MUST call this function
; * before terminating the program, otherwise the machine may crash later. If
; * in doubt, install an exit handler using atexit(). The function will do
; * nothing, if it was already called.
; */
;
.proc _rs232_done
lda rshand
cmp #$ff
beq done
work: ldx rshand+1
jsr pushax
jsr _close
pha
txa
pha
ldx #$ff
stx rshand
stx rshand+1
inx
stx cm_run
pla
tax
pla
done: rts
.endproc ;rs232_done
;----------------------------------------------------------------------------
;
; unsigned char __fastcall__ rs232_get (char* B);
; /* Get a character from the serial port. If no characters are available, the
; * function will return RS_ERR_NO_DATA, so this is not a fatal error.
; */
;
.proc _rs232_get
ldy rshand
cpy #$ff
bne work ; work only if initialized
lda #RS_ERR_NOT_INITIALIZED
bne nierr
work: sta ptr1
stx ptr1+1 ; store pointer to received char
lda rshand
ldx #0
jsr fdtoiocb
tax
lda cm_run ; concurrent mode already running?
bne go
jsr ena_cm ; turn on concurrent mode
go: ; check whether there is any input available
lda #STATIS ; status request, returns bytes pending
sta ICCOM,x
jsr CIOV
bmi cioerr ; @@@ error handling
lda DVSTAT+1 ; get byte count pending
ora DVSTAT+2
beq nix_da ; no input waiting...
; input is available: get it!
lda #GETCHR ; get raw bytes
sta ICCOM,x ; in command code
lda #0
sta ICBLL,x
sta ICBLH,x
sta ICBAL,x
sta ICBAH,x
jsr CIOV ; go get it
bmi cioerr ; @@@ error handling
ldx #0
sta (ptr1,x) ; return received byte
txa
rts
nierr: ldx #0
rts
nix_da: lda #RS_ERR_NO_DATA
ldx #0
rts
.endproc ;_rs232_get
;----------------------------------------------------------------------------
;
; unsigned char __fastcall__ rs232_put (char B);
; /* Send a character via the serial port. There is a transmit buffer, but
; * transmitting is not done via interrupt. The function returns
; * RS_ERR_OVERFLOW if there is no space left in the transmit buffer.
; */
;
.proc _rs232_put
ldy rshand
cpy #$ff
bne work ; work only if initialized
lda #RS_ERR_NOT_INITIALIZED
bne nierr
work: pha
lda rshand
ldx #0
jsr fdtoiocb
tax
lda cm_run ; concurrent mode already running?
bne go
jsr ena_cm ; turn on concurrent mode
; @@@TODO: check output buffer overflow
go: lda #PUTCHR ; put raw bytes
sta ICCOM,x ; in command code
lda #0
sta ICBLL,x
sta ICBLH,x
sta ICBAL,x
sta ICBAH,x
pla ; get the char back
jsr CIOV ; go do it
rts
nierr: ldx #0
rts
.endproc ;_rs232_put
;----------------------------------------------------------------------------
;
; unsigned char __fastcall__ rs232_pause (void);
; /* Assert flow control and disable interrupts. */
;
_rs232_pause:
;----------------------------------------------------------------------------
;
; unsigned char __fastcall__ rs232_unpause (void);
; /* Re-enable interrupts and release flow control */
;
_rs232_unpause:
;----------------------------------------------------------------------------
;
; unsigned char __fastcall__ rs232_status (unsigned char* status,
; unsigned char* errors);
; /* Return the serial port status. */
;
_rs232_status:
lda #255
tax
rts
; enable concurrent rs232 mode
; gets iocb index in X
; all registers destroyed
.proc ena_cm
lda #40 ; XIO 40, start concurrent IO
sta ICCOM,x
sta cm_run ; indicate concurrent mode is running
lda #0
sta ICAX1,x
sta ICAX2,x
lda #<recv_buf
sta ICBAL,x
lda #>recv_buf
sta ICBAH,x
lda #<RECVBUF_SZ
sta ICBLL,x
lda #>RECVBUF_SZ
sta ICBLH,x
lda #$0D ; value from 850 man, p62. must be 0D?,
sta ICAX1,x ; or any non-zero?
jmp CIOV
.endproc ;ena_cm
.end

579
libsrc/atari/ser/atrrdev.s Normal file
View File

@ -0,0 +1,579 @@
;
; Christian Groessler, Dec-2001
; converted to driver interface Dec-2013
;
; RS232 routines using the R: device (currently tested with an 850 only)
;
.include "zeropage.inc"
.include "ser-kernel.inc"
.include "ser-error.inc"
.include "atari.inc"
; ------------------------------------------------------------------------
; Header. Includes jump table
.segment "JUMPTABLE"
; Driver signature
.byte $73, $65, $72 ; "ser"
.byte SER_API_VERSION ; Serial API version number
; Library reference
libref: .addr $0000
; Jump table
.word SER_INSTALL
.word SER_UNINSTALL
.word SER_OPEN
.word SER_CLOSE
.word SER_GET
.word SER_PUT
.word SER_STATUS
.word SER_IOCTL
.word SER_IRQ
.rodata
rdev: .byte "R:", ATEOL, 0
bauds: .byte 1 ; SER_BAUD_45_5
.byte 2 ; SER_BAUD_50
.byte 4 ; SER_BAUD_75
.byte 5 ; SER_BAUD_110
.byte 6 ; SER_BAUD_134_5
.byte 7 ; SER_BAUD_150
.byte 8 ; SER_BAUD_300
.byte 9 ; SER_BAUD_600
.byte 10 ; SER_BAUD_1200
.byte 11 ; SER_BAUD_1800
.byte 12 ; SER_BAUD_2400
.byte 0 ; SER_BAUD_3600
.byte 13 ; SER_BAUD_4800
.byte 0 ; SER_BAUD_7200
.byte 14 ; SER_BAUD_9600
.byte 0 ; SER_BAUD_19200
.byte 0 ; SER_BAUD_38400
.byte 0 ; SER_BAUD_57600
.byte 0 ; SER_BAUD_115200
.byte 0 ; SER_BAUD_230400
.byte 0 ; SER_BAUD_31250
.byte 0 ; SER_BAUD_62500
.byte 3 ; SER_BAUD_56_875
num_bauds = * - bauds
databits:
.byte 48 ; SER_BITS_5
.byte 32 ; SER_BITS_6
.byte 16 ; SER_BITS_7
.byte 0 ; SER_BITS_8
num_databits = * - databits
parities:
.byte 0 ; SER_PAR_NONE
.byte 4+1 ; SER_PAR_ODD
.byte 2+8 ; SER_PAR_EVEN
;.byte 0 ; SER_PAR_MARK
;.byte 0 ; SER_PAR_SPACE
num_parities = * - parities
.bss
; receive buffer
RECVBUF_SZ = 256
recv_buf: .res RECVBUF_SZ
cm_run: .res 1 ; concurrent mode running?
.data
rshand: .word $ffff
; jump table into main program, initialized from libref
my_newfd:
.byte $4C
.word 0
my__close:
.byte $4C
.word 0
my_pushax:
.byte $4C
.word 0
my_popax:
.byte $4C
.word 0
my_findfreeiocb:
.byte $4C
.word 0
my___do_oserror:
.byte $4C
.word 0
my_fddecusage:
.byte $4C
.word 0
my_fdtoiocb:
.byte $4C
.word 0
my___inviocb:
.byte $4C
.word 0
my_clriocb:
.byte $4C
.word 0
my_CIOV:
.byte $4C
.word 0
.code
invbaud:
lda #<SER_ERR_BAUD_UNAVAIL
ldx #>SER_ERR_BAUD_UNAVAIL
openerr:
rts
;----------------------------------------------------------------------------
; SER_OPEN: A pointer to a ser_params structure is passed in ptr1.
; Must return an SER_ERR_xx code in a/x.
SER_OPEN:
jsr do_open
bne openerr
; set line parameters
lda rshand
ldx #0
jsr my_fdtoiocb ; get iocb index into X
bmi openerr ; shouldn't happen
tax
; set baud rate, word size, stop bits and ready monitoring
; build ICAX1 value
ldy #SER_PARAMS::BAUDRATE
lda (ptr1),y
cmp #num_bauds
bcs invbaud
tay
lda bauds,y
beq invbaud
sta ICAX1,x
ldy #SER_PARAMS::DATABITS
lda (ptr1),y
cmp #num_databits
bcs init_err
tay
lda databits,y
ora ICAX1,x
sta ICAX1,x
ldy #SER_PARAMS::STOPBITS
lda (ptr1),y
clc
ror a
ror a
ora ICAX1,x
sta ICAX1,x
lda #36 ; xio 36, baud rate
sta ICCOM,x
lda #0
;ICAX2 = 0, monitor nothing
sta ICAX2,x
sta ICBLL,x
sta ICBLH,x
sta ICBAL,x
sta ICBAH,x
jsr my_CIOV
bmi cioerr
; check if the handshake setting is valid
ldy #SER_PARAMS::HANDSHAKE
lda (ptr1),y
cmp #SER_HS_HW ; this is all we support
bne init_err
; set handshake lines
lda #34 ; xio 34, set cts, dtr etc
sta ICCOM,x
lda #192+48+3 ; DTR on, RTS on, XMT on
sta ICAX1,x
jsr my_CIOV
bmi cioerr
; set translation and parity
ldy #SER_PARAMS::PARITY
lda (ptr1),y
cmp #num_parities
bcs init_err
tay
lda parities,y
ora #32 ; no translation
sta ICAX1,x
lda #38 ; xio 38, translation and parity
sta ICCOM,x
jsr my_CIOV
bmi cioerr
lda #<SER_ERR_OK
tax ; A is zero
rts
inverr: jmp my___inviocb
cioerr:
; @@@ need to close IOCB here
jsr my_fddecusage ; decrement usage counter of fd as open failed
init_err:
ldx #0
lda #SER_ERR_INIT_FAILED
rts
;---- open the device
do_open:
jsr my_findfreeiocb
bne init_err
txa
tay ; move iocb # into Y
lda #3
sta tmp3 ; name length + 1
lda #<rdev
ldx #>rdev
jsr my_newfd
tya
bcs @doopen ; C set: open needed / device not already open
pha
jsr SER_CLOSE ;** shut down if started @@@TODO check this out!!
pla
@doopen:tax
pha
jsr my_clriocb
pla
tax
lda #<rdev
sta ICBAL,x
lda #>rdev
sta ICBAH,x
lda #OPEN
sta ICCOM,x
lda #$0D ; mode in+out+concurrent
sta ICAX1,x
lda #0
sta ICAX2,x
sta ICBLL,x ; zap buf len
sta ICBLH,x
jsr my_CIOV
bmi cioerr
lda tmp2 ; get fd (from newfd)
sta rshand
ldx #0
stx rshand+1
txa
rts
;----------------------------------------------------------------------------
; CLOSE: Close the port, disable interrupts and flush the buffer. Called
; without parameters. Must return an error code in a/x.
;
;----------------------------------------------------------------------------
; SER_UNINSTALL routine. Is called before the driver is removed from memory.
; Must return an SER_ERR_xx code in a/x.
;
SER_UNINSTALL:
SER_CLOSE:
lda rshand
cmp #$ff
beq @done
ldx rshand+1
jsr my__close
ldx #$ff
stx rshand
stx rshand+1
inx
stx cm_run
@done: lda #<SER_ERR_OK
ldx #>SER_ERR_OK
rts
;----------------------------------------------------------------------------
; SER_GET: Will fetch a character from the receive buffer and store it into the
; variable pointer to by ptr1. If no data is available, SER_ERR_NO_DATA is
; return.
;
SER_GET:
ldy rshand
cpy #$ff
beq ni_err ; work only if initialized
lda rshand
ldx #0
jsr my_fdtoiocb
tax
lda cm_run ; concurrent mode already running?
bne @go
jsr ena_cm ; turn on concurrent mode
@go: ; check whether there is any input available
lda #STATIS ; status request, returns bytes pending
sta ICCOM,x
jsr my_CIOV
bmi ser_error
lda DVSTAT+1 ; get byte count pending
ora DVSTAT+2
beq @nix_da ; no input waiting...
; input is available: get it!
lda #GETCHR ; get raw bytes
sta ICCOM,x ; in command code
lda #0
sta ICBLL,x
sta ICBLH,x
sta ICBAL,x
sta ICBAH,x
jsr my_CIOV ; go get it
bmi ser_error
ldx #0
sta (ptr1,x) ; return received byte
txa
rts
@nix_da:lda #SER_ERR_NO_DATA
ldx #0
rts
ser_error:
lda #SER_ERR_OVERFLOW ; there is no large selection of serial error codes... :-/
ldx #0
rts
ni_err: lda #SER_ERR_NOT_OPEN
ldx #0
rts
;----------------------------------------------------------------------------
; SER_PUT: Output character in A.
; Must return an error code in a/x.
;
SER_PUT:
ldy rshand
cpy #$ff
beq ni_err ; work only if initialized
pha ; remember char to write
lda rshand
ldx #0
jsr my_fdtoiocb
tax
lda cm_run ; concurrent mode already running?
bne @go
jsr ena_cm ; turn on concurrent mode
; @@@TODO: check output buffer overflow
@go: lda #PUTCHR ; put raw bytes
sta ICCOM,x ; in command code
lda #0
sta ICBLL,x
sta ICBLH,x
sta ICBAL,x
sta ICBAH,x
pla ; get the char back
jsr my_CIOV ; go do it
bmi ser_error
lda #0
tax
rts
;----------------------------------------------------------------------------
; SER_STATUS: Return the status in the variable pointed to by ptr1.
; Must return an error code in a/x.
;
SER_STATUS:
; fall through to SER_IOCTL
;----------------------------------------------------------------------------
; SER_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 error code in a/x.
;
SER_IOCTL:
lda #<SER_ERR_INV_IOCTL ; We don't support ioclts for now
ldx #>SER_ERR_INV_IOCTL
rts
;----------------------------------------------------------------------------
; SER_IRQ: Not used on the Atari
;
SER_IRQ = $0000
;----------------------------------------------------------------------------
; SER_INSTALL routine. Is called after the driver is loaded into memory. If
; possible, check if the hardware is present.
; Must return an SER_ERR_xx code in a/x.
SER_INSTALL:
; check if R: device is installed
ldy #0
search: lda HATABS,y ; get device name
cmp #'R'
beq found
iny
iny
iny
cpy #MAXDEV
bcc search
; R: device not found, return error
lda #<SER_ERR_NO_DEVICE
ldx #0
rts
; R: device found, initialize jump table into main program
found: lda ptr3
pha
lda ptr3+1
pha
lda libref
sta ptr3
lda libref+1
sta ptr3+1
ldy #0
lda (ptr3),y
sta my_newfd+1
iny
lda (ptr3),y
sta my_newfd+2
iny
lda (ptr3),y
sta my__close+1
iny
lda (ptr3),y
sta my__close+2
iny
lda (ptr3),y
sta my_pushax+1
iny
lda (ptr3),y
sta my_pushax+2
iny
lda (ptr3),y
sta my_popax+1
iny
lda (ptr3),y
sta my_popax+2
iny
lda (ptr3),y
sta my_findfreeiocb+1
iny
lda (ptr3),y
sta my_findfreeiocb+2
iny
lda (ptr3),y
sta my___do_oserror+1
iny
lda (ptr3),y
sta my___do_oserror+2
iny
lda (ptr3),y
sta my_fddecusage+1
iny
lda (ptr3),y
sta my_fddecusage+2
iny
lda (ptr3),y
sta my_fdtoiocb+1
iny
lda (ptr3),y
sta my_fdtoiocb+2
iny
lda (ptr3),y
sta my___inviocb+1
iny
lda (ptr3),y
sta my___inviocb+2
iny
lda (ptr3),y
sta my_clriocb+1
iny
lda (ptr3),y
sta my_clriocb+2
iny
lda (ptr3),y
sta my_CIOV+1
iny
lda (ptr3),y
sta my_CIOV+2
;iny
pla
sta ptr3+1
pla
sta ptr3
lda #<SER_ERR_OK
tax ; A is zero
rts
; enable concurrent rs232 mode
; gets iocb index in X
; all registers destroyed
.proc ena_cm
lda #40 ; XIO 40, start concurrent IO
sta ICCOM,x
sta cm_run ; indicate concurrent mode is running
lda #$0D ; value from 850 manual, p62. must be $0D?,
sta ICAX1,x ; or any non-zero?
lda #0
sta ICAX2,x
lda #<recv_buf
sta ICBAL,x
lda #>recv_buf
sta ICBAH,x
lda #<RECVBUF_SZ
sta ICBLL,x
lda #>RECVBUF_SZ
sta ICBLH,x
jmp my_CIOV
.endproc ;ena_cm

28
libsrc/atari/ser_libref.s Normal file
View File

@ -0,0 +1,28 @@
.include "atari.inc"
.import _close, pushax, popax
.import findfreeiocb
.import __do_oserror
.import fddecusage
.import fdtoiocb
.import __inviocb
.import clriocb
.import newfd
.export atari_ser_libref
.rodata
atari_ser_libref:
.word newfd
.word _close
.word pushax
.word popax
.word findfreeiocb
.word __do_oserror
.word fddecusage
.word fdtoiocb
.word __inviocb
.word clriocb
.word CIOV

View File

@ -17,6 +17,10 @@
#define DRIVERNAME "a2e.ssc.ser"
#elif defined(__APPLE2__)
#define DRIVERNAME "a2.ssc.ser"
#elif defined(__ATARIXL__)
#define DRIVERNAME "atrxrdev.ser"
#elif defined(__ATARI__)
#define DRIVERNAME "atrrdev.ser"
#else
#define DRIVERNAME "unknown"
#error "Unknown target system"
@ -24,7 +28,7 @@
static const struct ser_params Params = {
SER_BAUD_19200, /* Baudrate */
SER_BAUD_9600, /* Baudrate */
SER_BITS_8, /* Number of data bits */
SER_STOP_1, /* Number of stop bits */
SER_PAR_NONE, /* Parity setting */