Added a serial driver for the builtin 6551 of the Plus/4 (untested, but taken
mostly from the C64 version which is tested and works). Improved interrupt handling (was needed for the driver). git-svn-id: svn://svn.cc65.org/cc65/trunk@2754 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
parent
ba079ae6a1
commit
ad6a85b255
5 changed files with 509 additions and 86 deletions
|
@ -1 +1,4 @@
|
||||||
|
*.emd
|
||||||
*.joy
|
*.joy
|
||||||
|
*.ser
|
||||||
|
*.tgi
|
||||||
|
|
|
@ -20,6 +20,9 @@
|
||||||
%.joy: %.o ../runtime/zeropage.o
|
%.joy: %.o ../runtime/zeropage.o
|
||||||
@$(LD) -t module -o $@ $^
|
@$(LD) -t module -o $@ $^
|
||||||
|
|
||||||
|
%.ser: %.o ../runtime/zeropage.o
|
||||||
|
@$(LD) -t module -o $@ $^
|
||||||
|
|
||||||
%.tgi: %.o ../runtime/zeropage.o
|
%.tgi: %.o ../runtime/zeropage.o
|
||||||
@$(LD) -t module -o $@ $^
|
@$(LD) -t module -o $@ $^
|
||||||
|
|
||||||
|
@ -73,6 +76,8 @@ EMDS =
|
||||||
|
|
||||||
JOYS = plus4-stdjoy.joy
|
JOYS = plus4-stdjoy.joy
|
||||||
|
|
||||||
|
SERS = plus4-stdser.ser
|
||||||
|
|
||||||
TGIS =
|
TGIS =
|
||||||
|
|
||||||
#--------------------------------------------------------------------------
|
#--------------------------------------------------------------------------
|
||||||
|
@ -80,14 +85,14 @@ TGIS =
|
||||||
|
|
||||||
.PHONY: all clean zap
|
.PHONY: all clean zap
|
||||||
|
|
||||||
all: $(OBJS) $(EMDS) $(JOYS) $(TGIS)
|
all: $(OBJS) $(EMDS) $(JOYS) $(SERS) $(TGIS)
|
||||||
|
|
||||||
../runtime/zeropage.o:
|
../runtime/zeropage.o:
|
||||||
$(MAKE) -C $(dir $@) $(notdir $@)
|
$(MAKE) -C $(dir $@) $(notdir $@)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
@$(RM) $(OBJS) $(EMDS:.emd=.o) $(JOYS:.joy=.o) $(TGIS:.tgi=.o)
|
@$(RM) $(OBJS) $(EMDS:.emd=.o) $(JOYS:.joy=.o) $(SERS:.ser=.o) $(TGIS:.tgi=.o)
|
||||||
|
|
||||||
zap: clean
|
zap: clean
|
||||||
@$(RM) $(EMDS) $(JOYS) $(TGIS)
|
@$(RM) $(EMDS) $(JOYS) $(SERS) $(TGIS)
|
||||||
|
|
||||||
|
|
|
@ -55,11 +55,12 @@ uservec: jmp $FFFF ; Patched at runtime
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
; Break handler, called if a break occurs. Note: Y is not on the stack!
|
; Break handler, called if a break occurs.
|
||||||
|
|
||||||
.proc brk_handler
|
.proc brk_handler
|
||||||
|
|
||||||
sty _brk_y
|
pla
|
||||||
|
sta _brk_y
|
||||||
pla
|
pla
|
||||||
sta _brk_x
|
sta _brk_x
|
||||||
pla
|
pla
|
||||||
|
|
|
@ -41,33 +41,19 @@ Head: .word @Next
|
||||||
ldx #zpspace-1
|
ldx #zpspace-1
|
||||||
L1: lda sp,x
|
L1: lda sp,x
|
||||||
sta zpsave,x ; save the zero page locations we need
|
sta zpsave,x ; save the zero page locations we need
|
||||||
dex
|
dex
|
||||||
bpl L1
|
bpl L1
|
||||||
sta ENABLE_ROM
|
sta ENABLE_ROM
|
||||||
cli
|
cli
|
||||||
|
|
||||||
; Close open files
|
; Close open files
|
||||||
|
|
||||||
jsr $FFCC ; CLRCH
|
jsr $FFCC ; CLRCH
|
||||||
|
|
||||||
; Switch to second charset
|
; Switch to second charset
|
||||||
|
|
||||||
lda #14
|
lda #14
|
||||||
jsr $FFD2 ; BSOUT
|
jsr $FFD2 ; BSOUT
|
||||||
|
|
||||||
; Setup the IRQ vector in the banked RAM and switch off the ROM
|
|
||||||
|
|
||||||
sei ; No ints, handler not yet in place
|
|
||||||
sta ENABLE_RAM
|
|
||||||
lda #<IRQ
|
|
||||||
sta $FFFE ; Install interrupt handler
|
|
||||||
lda #>IRQ
|
|
||||||
sta $FFFF
|
|
||||||
cli ; Allow interrupts
|
|
||||||
|
|
||||||
; Clear the BSS data
|
|
||||||
|
|
||||||
jsr zerobss
|
|
||||||
|
|
||||||
; Save system stuff and setup the stack. The stack starts at the top of the
|
; Save system stuff and setup the stack. The stack starts at the top of the
|
||||||
; usable RAM.
|
; usable RAM.
|
||||||
|
@ -80,88 +66,110 @@ L1: lda sp,x
|
||||||
lda #>$FD00
|
lda #>$FD00
|
||||||
sta sp+1
|
sta sp+1
|
||||||
|
|
||||||
|
; Setup the IRQ vector in the banked RAM and switch off the ROM
|
||||||
|
|
||||||
|
ldx #<IRQ
|
||||||
|
ldy #>IRQ
|
||||||
|
sei ; No ints, handler not yet in place
|
||||||
|
sta ENABLE_RAM
|
||||||
|
stx $FFFE ; Install interrupt handler
|
||||||
|
sty $FFFF
|
||||||
|
cli ; Allow interrupts
|
||||||
|
|
||||||
|
; Clear the BSS data
|
||||||
|
|
||||||
|
jsr zerobss
|
||||||
|
|
||||||
; Call module constructors
|
; Call module constructors
|
||||||
|
|
||||||
jsr initlib
|
jsr initlib
|
||||||
|
|
||||||
; If we have IRQ functions, chain our stub into the IRQ vector
|
; Initialize irqcount, which means that from now own custom linked in IRQ
|
||||||
|
; handlers (via condes) will be called.
|
||||||
|
|
||||||
lda #<__IRQFUNC_COUNT__
|
lda #.lobyte(__IRQFUNC_COUNT__*2)
|
||||||
beq NoIRQ1
|
sta irqcount
|
||||||
lda IRQVec
|
|
||||||
ldx IRQVec+1
|
|
||||||
sta IRQInd+1
|
|
||||||
stx IRQInd+2
|
|
||||||
lda #<IRQStub
|
|
||||||
ldx #>IRQStub
|
|
||||||
sei
|
|
||||||
sta IRQVec
|
|
||||||
stx IRQVec+1
|
|
||||||
cli
|
|
||||||
|
|
||||||
; Push arguments and call main()
|
; Push arguments and call main()
|
||||||
|
|
||||||
NoIRQ1: jsr callmain
|
jsr callmain
|
||||||
|
|
||||||
; Back from main (this is also the _exit entry). Reset the IRQ vector if
|
; Back from main (this is also the _exit entry). Run module destructors.
|
||||||
; we chained it.
|
|
||||||
|
|
||||||
_exit: lda #<__IRQFUNC_COUNT__
|
_exit: lda #0
|
||||||
beq NoIRQ2
|
sta irqcount ; Disable custom IRQ handlers
|
||||||
lda IRQInd+1
|
jsr donelib ; Run module destructors
|
||||||
ldx IRQInd+2
|
|
||||||
sei
|
|
||||||
sta IRQVec
|
|
||||||
stx IRQVec+1
|
|
||||||
cli
|
|
||||||
|
|
||||||
; Run module destructors.
|
|
||||||
|
|
||||||
NoIRQ2: jsr donelib ; Run module destructors
|
|
||||||
|
|
||||||
; Restore system stuff
|
; Restore system stuff
|
||||||
|
|
||||||
ldx spsave
|
ldx spsave
|
||||||
txs
|
txs
|
||||||
|
|
||||||
; Copy back the zero page stuff
|
; Copy back the zero page stuff
|
||||||
|
|
||||||
ldx #zpspace-1
|
ldx #zpspace-1
|
||||||
L2: lda zpsave,x
|
L2: lda zpsave,x
|
||||||
sta sp,x
|
sta sp,x
|
||||||
dex
|
dex
|
||||||
bpl L2
|
bpl L2
|
||||||
|
|
||||||
; Enable the ROM, reset changed vectors and return to BASIC
|
; Enable the ROM, reset changed vectors and return to BASIC
|
||||||
|
|
||||||
sta ENABLE_ROM
|
sta ENABLE_ROM
|
||||||
jmp $FF8A ; RESTOR
|
jmp $FF8A ; RESTOR
|
||||||
|
|
||||||
|
|
||||||
; ------------------------------------------------------------------------
|
; ------------------------------------------------------------------------
|
||||||
; IRQ handler
|
; IRQ handler. The handler in the ROM enables the kernal and jumps to
|
||||||
|
; $CE00, where the ROM code checks for a BRK or IRQ and branches via the
|
||||||
|
; indirect vectors at $314/$316.
|
||||||
|
; To make our stub as fast as possible, we skip the whole part of the ROM
|
||||||
|
; handler and jump to the indirect vectors directly. We do also call our
|
||||||
|
; own interrupt handlers if we have any, so they need not use $314.
|
||||||
|
|
||||||
.segment "LOWCODE"
|
.segment "LOWCODE"
|
||||||
|
|
||||||
IRQ: pha
|
IRQ: cld ; Just to be sure
|
||||||
|
pha
|
||||||
txa
|
txa
|
||||||
pha
|
pha
|
||||||
|
tya
|
||||||
|
pha
|
||||||
tsx ; Get the stack pointer
|
tsx ; Get the stack pointer
|
||||||
lda $0103,x ; Get the saved status register
|
lda $0104,x ; Get the saved status register
|
||||||
tax ; Save for later
|
|
||||||
and #$10 ; Test for BRK bit
|
and #$10 ; Test for BRK bit
|
||||||
bne dobreak
|
bne dobreak
|
||||||
lda #>irq_ret ; Push new return address
|
|
||||||
|
; It's an IRQ and RAM is enabled. If we have handlers, call them. We will use
|
||||||
|
; a flag here instead of loading __IRQFUNC_COUNT__ directly, since the condes
|
||||||
|
; function is not reentrant. The irqcount flag will be set/reset from the main
|
||||||
|
; code, to avoid races.
|
||||||
|
|
||||||
|
ldy irqcount
|
||||||
|
beq @L1
|
||||||
|
lda #<__IRQFUNC_TABLE__
|
||||||
|
ldx #>__IRQFUNC_TABLE__
|
||||||
|
jsr condes ; Call the IRQ functions
|
||||||
|
|
||||||
|
; Since the ROM handler will end with an RTI, we have to fake an IRQ return
|
||||||
|
; on stack, so we get control of the CPU after the ROM handler and can switch
|
||||||
|
; back to RAM.
|
||||||
|
|
||||||
|
@L1: lda #>irq_ret ; Push new return address
|
||||||
pha
|
pha
|
||||||
lda #<irq_ret
|
lda #<irq_ret
|
||||||
pha
|
pha
|
||||||
txa
|
php ; Push faked IRQ frame on stack
|
||||||
pha
|
pha ; Push faked A register
|
||||||
|
pha ; Push faked X register
|
||||||
|
pha ; Push faked Y register
|
||||||
sta ENABLE_ROM ; Switch to ROM
|
sta ENABLE_ROM ; Switch to ROM
|
||||||
jmp ($FFFE) ; Jump to kernal irq handler
|
jmp (IRQVec) ; Jump indirect to kernal irq handler
|
||||||
|
|
||||||
irq_ret:
|
irq_ret:
|
||||||
sta ENABLE_RAM ; Switch back to RAM
|
sta ENABLE_RAM ; Switch back to RAM
|
||||||
|
pla
|
||||||
|
tay
|
||||||
pla
|
pla
|
||||||
tax
|
tax
|
||||||
pla
|
pla
|
||||||
|
@ -175,27 +183,9 @@ dobreak:
|
||||||
; No break handler installed, jump to ROM
|
; No break handler installed, jump to ROM
|
||||||
|
|
||||||
nohandler:
|
nohandler:
|
||||||
tya
|
|
||||||
pha ; ROM handler expects Y on stack
|
|
||||||
sta ENABLE_ROM
|
sta ENABLE_ROM
|
||||||
jmp (BRKVec) ; Jump indirect to the break vector
|
jmp (BRKVec) ; Jump indirect to the break vector
|
||||||
|
|
||||||
; ------------------------------------------------------------------------
|
|
||||||
; Stub for the IRQ chain. Is used only if there are IRQs defined. Needed in
|
|
||||||
; low memory because of the banking.
|
|
||||||
|
|
||||||
.segment "LOWCODE"
|
|
||||||
|
|
||||||
IRQStub:
|
|
||||||
cld ; Just to be sure
|
|
||||||
sta ENABLE_RAM ; Switch to RAM
|
|
||||||
ldy #<(__IRQFUNC_COUNT__*2)
|
|
||||||
lda #<__IRQFUNC_TABLE__
|
|
||||||
ldx #>__IRQFUNC_TABLE__
|
|
||||||
jsr condes ; Call the IRQ functions
|
|
||||||
sta ENABLE_ROM
|
|
||||||
jmp IRQInd ; Jump to the saved IRQ vector
|
|
||||||
|
|
||||||
; ------------------------------------------------------------------------
|
; ------------------------------------------------------------------------
|
||||||
; Data
|
; Data
|
||||||
|
|
||||||
|
@ -205,8 +195,8 @@ zpsave: .res zpspace
|
||||||
; BRK handling
|
; BRK handling
|
||||||
brk_jmp: jmp $0000
|
brk_jmp: jmp $0000
|
||||||
|
|
||||||
.bss
|
|
||||||
spsave: .res 1
|
spsave: .res 1
|
||||||
|
|
||||||
|
.bss
|
||||||
|
irqcount: .byte 0
|
||||||
|
|
||||||
|
|
424
libsrc/plus4/plus4-stdser.s
Normal file
424
libsrc/plus4/plus4-stdser.s
Normal file
|
@ -0,0 +1,424 @@
|
||||||
|
;
|
||||||
|
; Serial driver for the builtin 6551 ACIA of the Plus/4.
|
||||||
|
;
|
||||||
|
; Ullrich von Bassewitz, 2003-12-13
|
||||||
|
;
|
||||||
|
; The driver is based on the cc65 rs232 module, which in turn is based on
|
||||||
|
; Craig Bruce device driver for the Switftlink/Turbo-232.
|
||||||
|
;
|
||||||
|
; SwiftLink/Turbo-232 v0.90 device driver, by Craig Bruce, 14-Apr-1998.
|
||||||
|
;
|
||||||
|
; This software is Public Domain. It is in Buddy assembler format.
|
||||||
|
;
|
||||||
|
; This device driver uses the SwiftLink RS-232 Serial Cartridge, available from
|
||||||
|
; Creative Micro Designs, Inc, and also supports the extensions of the Turbo232
|
||||||
|
; Serial Cartridge. Both devices are based on the 6551 ACIA chip. It also
|
||||||
|
; supports the "hacked" SwiftLink with a 1.8432 MHz crystal.
|
||||||
|
;
|
||||||
|
; The code assumes that the kernal + I/O are in context. On the C128, call
|
||||||
|
; it from Bank 15. On the C64, don't flip out the Kernal unless a suitable
|
||||||
|
; NMI catcher is put into the RAM under then Kernal. For the SuperCPU, the
|
||||||
|
; interrupt handling assumes that the 65816 is in 6502-emulation mode.
|
||||||
|
;
|
||||||
|
|
||||||
|
.include "zeropage.inc"
|
||||||
|
.include "ser-kernel.inc"
|
||||||
|
.include "ser-error.inc"
|
||||||
|
.include "plus4.inc"
|
||||||
|
|
||||||
|
|
||||||
|
; ------------------------------------------------------------------------
|
||||||
|
; Header. Includes jump table
|
||||||
|
|
||||||
|
.segment "JUMPTABLE"
|
||||||
|
|
||||||
|
; Driver signature
|
||||||
|
|
||||||
|
.byte $73, $65, $72 ; "ser"
|
||||||
|
.byte SER_API_VERSION ; Serial API version number
|
||||||
|
|
||||||
|
; Jump table.
|
||||||
|
|
||||||
|
.word INSTALL
|
||||||
|
.word UNINSTALL
|
||||||
|
.word OPEN
|
||||||
|
.word CLOSE
|
||||||
|
.word GET
|
||||||
|
.word PUT
|
||||||
|
.word STATUS
|
||||||
|
.word IOCTL
|
||||||
|
.word IRQ
|
||||||
|
|
||||||
|
;----------------------------------------------------------------------------
|
||||||
|
; I/O definitions
|
||||||
|
|
||||||
|
ACIA = $DE00
|
||||||
|
ACIA_DATA = ACIA+0 ; Data register
|
||||||
|
ACIA_STATUS = ACIA+1 ; Status register
|
||||||
|
ACIA_CMD = ACIA+2 ; Command register
|
||||||
|
ACIA_CTRL = ACIA+3 ; Control register
|
||||||
|
|
||||||
|
;----------------------------------------------------------------------------
|
||||||
|
;
|
||||||
|
; Global variables
|
||||||
|
;
|
||||||
|
|
||||||
|
.bss
|
||||||
|
RecvHead: .res 1 ; Head of receive buffer
|
||||||
|
RecvTail: .res 1 ; Tail of receive buffer
|
||||||
|
RecvFreeCnt: .res 1 ; Number of bytes in receive buffer
|
||||||
|
SendHead: .res 1 ; Head of send buffer
|
||||||
|
SendTail: .res 1 ; Tail of send buffer
|
||||||
|
SendFreeCnt: .res 1 ; Number of bytes in send buffer
|
||||||
|
|
||||||
|
Stopped: .res 1 ; Flow-stopped flag
|
||||||
|
RtsOff: .res 1 ;
|
||||||
|
|
||||||
|
; Send and receive buffers: 256 bytes each
|
||||||
|
RecvBuf: .res 256
|
||||||
|
SendBuf: .res 256
|
||||||
|
|
||||||
|
.rodata
|
||||||
|
|
||||||
|
; Tables used to translate RS232 params into register values
|
||||||
|
|
||||||
|
BaudTable: ; bit7 = 1 means setting is invalid
|
||||||
|
.byte $FF ; SER_BAUD_45_5
|
||||||
|
.byte $01 ; SER_BAUD_50
|
||||||
|
.byte $02 ; SER_BAUD_75
|
||||||
|
.byte $03 ; SER_BAUD_110
|
||||||
|
.byte $04 ; SER_BAUD_134_5
|
||||||
|
.byte $05 ; SER_BAUD_150
|
||||||
|
.byte $06 ; SER_BAUD_300
|
||||||
|
.byte $07 ; SER_BAUD_600
|
||||||
|
.byte $08 ; SER_BAUD_1200
|
||||||
|
.byte $09 ; SER_BAUD_1800
|
||||||
|
.byte $0A ; SER_BAUD_2400
|
||||||
|
.byte $0B ; SER_BAUD_3600
|
||||||
|
.byte $0C ; SER_BAUD_4800
|
||||||
|
.byte $0D ; SER_BAUD_7200
|
||||||
|
.byte $0E ; SER_BAUD_9600
|
||||||
|
.byte $0F ; SER_BAUD_19200
|
||||||
|
.byte $FF ; SER_BAUD_38400
|
||||||
|
.byte $FF ; SER_BAUD_57600
|
||||||
|
.byte $FF ; SER_BAUD_115200
|
||||||
|
.byte $FF ; SER_BAUD_230400
|
||||||
|
|
||||||
|
BitTable:
|
||||||
|
.byte $60 ; SER_BITS_5
|
||||||
|
.byte $40 ; SER_BITS_6
|
||||||
|
.byte $20 ; SER_BITS_7
|
||||||
|
.byte $00 ; SER_BITS_8
|
||||||
|
|
||||||
|
StopTable:
|
||||||
|
.byte $00 ; SER_STOP_1
|
||||||
|
.byte $80 ; SER_STOP_2
|
||||||
|
|
||||||
|
ParityTable:
|
||||||
|
.byte $00 ; SER_PAR_NONE
|
||||||
|
.byte $20 ; SER_PAR_ODD
|
||||||
|
.byte $60 ; SER_PAR_EVEN
|
||||||
|
.byte $A0 ; SER_PAR_MARK
|
||||||
|
.byte $E0 ; SER_PAR_SPACE
|
||||||
|
|
||||||
|
.code
|
||||||
|
|
||||||
|
;----------------------------------------------------------------------------
|
||||||
|
; 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.
|
||||||
|
;
|
||||||
|
; Since we don't have to manage the IRQ vector on the Plus/4, this is actually
|
||||||
|
; the same as:
|
||||||
|
;
|
||||||
|
; UNINSTALL routine. Is called before the driver is removed from memory.
|
||||||
|
; Must return an SER_ERR_xx code in a/x.
|
||||||
|
|
||||||
|
|
||||||
|
INSTALL:
|
||||||
|
UNINSTALL:
|
||||||
|
|
||||||
|
; Deactivate DTR and disable 6551 interrupts
|
||||||
|
|
||||||
|
lda #%00001010
|
||||||
|
sta ACIA_CMD
|
||||||
|
|
||||||
|
; Done, return an error code
|
||||||
|
|
||||||
|
lda #<SER_ERR_OK
|
||||||
|
tax ; A is zero
|
||||||
|
rts
|
||||||
|
|
||||||
|
;----------------------------------------------------------------------------
|
||||||
|
; PARAMS routine. A pointer to a ser_params structure is passed in ptr1.
|
||||||
|
; Must return an SER_ERR_xx code in a/x.
|
||||||
|
|
||||||
|
OPEN:
|
||||||
|
|
||||||
|
; Check if the handshake setting is valid
|
||||||
|
|
||||||
|
ldy #SER_PARAMS::HANDSHAKE ; Handshake
|
||||||
|
lda (ptr1),y
|
||||||
|
cmp #SER_HS_HW ; This is all we support
|
||||||
|
bne InvParam
|
||||||
|
|
||||||
|
; Initialize buffers
|
||||||
|
|
||||||
|
jsr InitBuffers
|
||||||
|
|
||||||
|
; Set the value for the control register, which contains stop bits, word
|
||||||
|
; length and the baud rate.
|
||||||
|
|
||||||
|
ldy #SER_PARAMS::BAUDRATE
|
||||||
|
lda (ptr1),y ; Baudrate index
|
||||||
|
tay
|
||||||
|
lda BaudTable,y ; Get 6551 value
|
||||||
|
bmi InvBaud ; Branch if rate not supported
|
||||||
|
sta tmp1
|
||||||
|
|
||||||
|
ldy #SER_PARAMS::DATABITS ; Databits
|
||||||
|
lda (ptr1),y
|
||||||
|
tay
|
||||||
|
lda BitTable,y
|
||||||
|
ora tmp1
|
||||||
|
sta tmp1
|
||||||
|
|
||||||
|
ldy #SER_PARAMS::STOPBITS ; Stopbits
|
||||||
|
lda (ptr1),y
|
||||||
|
tay
|
||||||
|
lda StopTable,y
|
||||||
|
ora tmp1
|
||||||
|
ora #%00010000 ; Receiver clock source = baudrate
|
||||||
|
sta ACIA_CTRL
|
||||||
|
|
||||||
|
; Set the value for the command register. We remember the base value in
|
||||||
|
; RtsOff, since we will have to manipulate ACIA_CMD often.
|
||||||
|
|
||||||
|
ldy #SER_PARAMS::PARITY ; Parity
|
||||||
|
lda (ptr1),y
|
||||||
|
tay
|
||||||
|
lda ParityTable,y
|
||||||
|
ora #%00000001 ; DTR active
|
||||||
|
sta RtsOff
|
||||||
|
ora #%00001000 ; Enable receive interrupts
|
||||||
|
sta ACIA_CMD
|
||||||
|
|
||||||
|
; Done
|
||||||
|
|
||||||
|
lda #<SER_ERR_OK
|
||||||
|
tax ; A is zero
|
||||||
|
rts
|
||||||
|
|
||||||
|
; Invalid parameter
|
||||||
|
|
||||||
|
InvParam:
|
||||||
|
lda #<SER_ERR_INIT_FAILED
|
||||||
|
ldx #>SER_ERR_INIT_FAILED
|
||||||
|
rts
|
||||||
|
|
||||||
|
; Baud rate not available
|
||||||
|
|
||||||
|
InvBaud:
|
||||||
|
lda #<SER_ERR_BAUD_UNAVAIL
|
||||||
|
ldx #>SER_ERR_BAUD_UNAVAIL
|
||||||
|
rts
|
||||||
|
|
||||||
|
;----------------------------------------------------------------------------
|
||||||
|
; CLOSE: Close the port, disable interrupts and flush the buffer. Called
|
||||||
|
; without parameters. Must return an error code in a/x.
|
||||||
|
;
|
||||||
|
|
||||||
|
CLOSE:
|
||||||
|
|
||||||
|
; Stop interrupts, drop DTR
|
||||||
|
|
||||||
|
lda #%00001010
|
||||||
|
sta ACIA_CMD
|
||||||
|
|
||||||
|
; Initalize buffers.
|
||||||
|
|
||||||
|
jsr InitBuffers
|
||||||
|
|
||||||
|
; Return OK
|
||||||
|
|
||||||
|
lda #<SER_ERR_OK
|
||||||
|
tax ; A is zero
|
||||||
|
rts
|
||||||
|
|
||||||
|
;----------------------------------------------------------------------------
|
||||||
|
; 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.
|
||||||
|
;
|
||||||
|
|
||||||
|
GET: ldx SendFreeCnt ; Send data if necessary
|
||||||
|
inx ; X == $FF?
|
||||||
|
beq @L1
|
||||||
|
lda #$00
|
||||||
|
jsr TryToSend
|
||||||
|
|
||||||
|
; Check for buffer empty
|
||||||
|
|
||||||
|
@L1: lda RecvFreeCnt ; (25)
|
||||||
|
cmp #$ff
|
||||||
|
bne @L2
|
||||||
|
lda #<SER_ERR_NO_DATA
|
||||||
|
ldx #>SER_ERR_NO_DATA
|
||||||
|
rts
|
||||||
|
|
||||||
|
; Check for flow stopped & enough free: release flow control
|
||||||
|
|
||||||
|
@L2: ldx Stopped ; (34)
|
||||||
|
beq @L3
|
||||||
|
cmp #63
|
||||||
|
bcc @L3
|
||||||
|
lda #$00
|
||||||
|
sta Stopped
|
||||||
|
lda RtsOff
|
||||||
|
ora #%00001000
|
||||||
|
sta ACIA_CMD
|
||||||
|
|
||||||
|
; Get byte from buffer
|
||||||
|
|
||||||
|
@L3: ldx RecvHead ; (41)
|
||||||
|
lda RecvBuf,x
|
||||||
|
inc RecvHead
|
||||||
|
inc RecvFreeCnt
|
||||||
|
ldx #$00 ; (59)
|
||||||
|
sta (ptr1,x)
|
||||||
|
txa ; Return code = 0
|
||||||
|
rts
|
||||||
|
|
||||||
|
;----------------------------------------------------------------------------
|
||||||
|
; PUT: Output character in A.
|
||||||
|
; Must return an error code in a/x.
|
||||||
|
;
|
||||||
|
|
||||||
|
PUT:
|
||||||
|
|
||||||
|
; Try to send
|
||||||
|
|
||||||
|
ldx SendFreeCnt
|
||||||
|
inx ; X = $ff?
|
||||||
|
beq @L2
|
||||||
|
pha
|
||||||
|
lda #$00
|
||||||
|
jsr TryToSend
|
||||||
|
pla
|
||||||
|
|
||||||
|
; Put byte into send buffer & send
|
||||||
|
|
||||||
|
@L2: ldx SendFreeCnt
|
||||||
|
bne @L3
|
||||||
|
lda #<SER_ERR_OVERFLOW ; X is already zero
|
||||||
|
rts
|
||||||
|
|
||||||
|
@L3: ldx SendTail
|
||||||
|
sta SendBuf,x
|
||||||
|
inc SendTail
|
||||||
|
dec SendFreeCnt
|
||||||
|
lda #$ff
|
||||||
|
jsr TryToSend
|
||||||
|
lda #<SER_ERR_OK
|
||||||
|
tax
|
||||||
|
rts
|
||||||
|
|
||||||
|
;----------------------------------------------------------------------------
|
||||||
|
; STATUS: Return the status in the variable pointed to by ptr1.
|
||||||
|
; Must return an error code in a/x.
|
||||||
|
;
|
||||||
|
|
||||||
|
STATUS: lda ACIA_STATUS
|
||||||
|
ldx #0
|
||||||
|
sta (ptr1,x)
|
||||||
|
txa ; SER_ERR_OK
|
||||||
|
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 error code in a/x.
|
||||||
|
;
|
||||||
|
|
||||||
|
IOCTL: lda #<SER_ERR_INV_IOCTL ; We don't support ioclts for now
|
||||||
|
ldx #>SER_ERR_INV_IOCTL
|
||||||
|
; rts ; Run into IRQ instead
|
||||||
|
|
||||||
|
;----------------------------------------------------------------------------
|
||||||
|
; IRQ: Called from the builtin runtime IRQ handler as a subroutine. All
|
||||||
|
; registers are already save, no parameters are passed and no return code
|
||||||
|
; is expected.
|
||||||
|
;
|
||||||
|
|
||||||
|
IRQ: lda ACIA_STATUS ; Check ACIA status for receive interrupt
|
||||||
|
and #$08
|
||||||
|
beq @L9 ; Jump if no ACIA interrupt
|
||||||
|
lda ACIA_DATA ; Get byte from ACIA
|
||||||
|
ldx RecvFreeCnt ; Check if we have free space left
|
||||||
|
beq @L1 ; Jump if no space in receive buffer
|
||||||
|
ldy RecvTail ; Load buffer pointer
|
||||||
|
sta RecvBuf,y ; Store received byte in buffer
|
||||||
|
inc RecvTail ; Increment buffer pointer
|
||||||
|
dec RecvFreeCnt ; Decrement free space counter
|
||||||
|
cpx #33 ; Check for buffer space low
|
||||||
|
bcc @L1 ; Assert flow control if buffer space low
|
||||||
|
@L9: rts
|
||||||
|
|
||||||
|
; Assert flow control if buffer space too low
|
||||||
|
|
||||||
|
@L1: lda RtsOff
|
||||||
|
sta ACIA_CMD
|
||||||
|
sta Stopped
|
||||||
|
rts
|
||||||
|
|
||||||
|
;----------------------------------------------------------------------------
|
||||||
|
; Try to send a byte. Internal routine. A = TryHard
|
||||||
|
|
||||||
|
.proc TryToSend
|
||||||
|
|
||||||
|
sta tmp1 ; Remember tryHard flag
|
||||||
|
@L0: lda SendFreeCnt
|
||||||
|
cmp #$ff
|
||||||
|
beq @L3 ; Bail out
|
||||||
|
|
||||||
|
; Check for flow stopped
|
||||||
|
|
||||||
|
@L1: lda Stopped
|
||||||
|
bne @L3 ; Bail out
|
||||||
|
|
||||||
|
; Check that swiftlink is ready to send
|
||||||
|
|
||||||
|
@L2: lda ACIA_STATUS
|
||||||
|
and #$10
|
||||||
|
bne @L4
|
||||||
|
bit tmp1 ;keep trying if must try hard
|
||||||
|
bmi @L0
|
||||||
|
@L3: rts
|
||||||
|
|
||||||
|
; Send byte and try again
|
||||||
|
|
||||||
|
@L4: ldx SendHead
|
||||||
|
lda SendBuf,x
|
||||||
|
sta ACIA_DATA
|
||||||
|
inc SendHead
|
||||||
|
inc SendFreeCnt
|
||||||
|
jmp @L0
|
||||||
|
|
||||||
|
.endproc
|
||||||
|
|
||||||
|
|
||||||
|
;----------------------------------------------------------------------------
|
||||||
|
; Initialize buffers
|
||||||
|
|
||||||
|
InitBuffers:
|
||||||
|
ldx #0
|
||||||
|
stx Stopped
|
||||||
|
stx RecvHead
|
||||||
|
stx RecvTail
|
||||||
|
stx SendHead
|
||||||
|
stx SendTail
|
||||||
|
dex ; X = 255
|
||||||
|
stx RecvFreeCnt
|
||||||
|
stx SendFreeCnt
|
||||||
|
rts
|
||||||
|
|
Loading…
Add table
Reference in a new issue