Blame | Last modification | View Log | Download | RSS feed
;;
;; Copyright (c) 2016 Marco Granati <mg@unet.bz>
;;
;; Permission to use, copy, modify, and distribute this software for any
;; purpose with or without fee is hereby granted, provided that the above
;; copyright notice and this permission notice appear in all copies.
;;
;; THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
;; WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
;; MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
;; ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
;; WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
;; ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
;; OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
;;
;; name: sp2.asm
;; rev.: 2017/07/04
;; bios C816 version v1.0
;; serial port 65C51 & 16C550 handler
_ADDSER_INC_ .SET 1
.INCLUDE inc\global.inc
.INCLUDE inc\dirp00.inc
.INCLUDE inc\dirp05.inc
.LIST on
.CODEF8
.LONGA off
.LONGI off
; set serial port #2 - 65C51
; A=mode
spset2:
sei ; disable interrupt
phd
pea #DP05ADDR
pld
sta spmode3 ; save mode
tax
sta !ACIASR ; software reset
lda #ACIACMDOFF ; disable all
sta !ACIACMD
lda !ACIADR ; clear flags
lda !ACIASR
and #01000000B ; get /DSR status
beq ?dsrl
tsb splin3 ; /DSR high
bra ?cts
?dsrl: lda #01000000B
trb splin3 ; /DSR low
?cts: ldy #$80
lda #00001000B ; check /CTS line level: PA<3>
bit !VIA2+VIAPRANH
beq ?ctsl ; /CTS is low
tya
tsb splin3 ; /CTS is high
bra ?br
?ctsl: tya
trb splin3 ; /CTS is low
?br: txa ; <1:0> = baud rate select
and #00000011B
sta sptmp3
lda !VIA2+VIAPRANH
and #11111000B ; /RTS low
ora sptmp3
sta !VIA2+VIAPRANH
lda #00010000B ; 8 bits, 1 stop bit, divisor = 1/16
sta !ACIACTRL
txa ; mode
and #00001100B ; mask on bits 3 & 2 (parity mode)
asl a ; shift <3:2> to <6:5>
asl a
asl a
ora #00000101B ; enable all int., /DTR=low
sta sptmp3 ; byte for command register
stz sppause3 ; init work area
stz spout3
stz spstat3
bit spmode3
CPU16 ; init buffer's pointer's
bvs ?hw ; hardware handshake
lda #NGUARD31
ldy #NFREE31
bra ?do
?hw: lda #NGUARD32
ldy #NFREE32
?do: sta icntmax3
sty icntmin3
sec
lda #SIBUFSIZ3
sbc icntmax3
sta icntmax3
stz ibuftail3
stz ibufhead3
stz ibufcnt3
stz obuftail3
stz obufhead3
stz obufcnt3
CPU08
bit spmode3
bpl ?ok ; no handshake
bvc ?ok ; software handshake
bit splin3 ; check /DSR line
bvc ?ok ; remote terminal is connected
;lda #$20
;tsb spstat3 ; remote terminal not connected now
?ok: lda .ABS.ACIADR ; discard any pending received data
lda .ABS.ACIASR ; read current interrupt status
lda sptmp3 ; enable interrupts
sta .ABS.ACIACMD
pld
cli
rts
; reset serial port #2 - 65C51
spres2:
sta !ACIASR ; software reset
lda #ACIACMDOFF ; disable all
sta !ACIACMD
lda !ACIADR ; clear flags
lda !ACIASR
rts
; send A to serial port 65C51
spput2:
sei ; disable interrupt
phd
pea #DP05ADDR
pld
stx sptmp3 ; save X reg.
ldy #0 ; Y = 0
INDEX16
ldx obufcnt3
cpx #SOBUFSIZ3 ; output buffer is full?
bcc ?str ; no, store byte
bit splin3
bvc ?done ; exit with CF=1, Y=0: output buffer is full
dey
bra ?done ; exit with CF=1, Y=$FF: remote terminal off
?str: inx ; update count
stx obufcnt3
ldx obuftail3 ; output buffer tail pointer
sta >SOBUFADDR3,x ; store byte in output buffer
inx ; update tail pointer
cpx #SOBUFSIZ3
bcc ?upd
tyx ; circular queue
?upd: stx obuftail3
; here at least one byte to send so check if tx interrupt is enabled
;
xba ; save A
lda !ACIACMD
bit #00000100B ; check CMD<2>
bne ?xba ; tx interrupt enabled
bit sppause3
bvs ?xba ; local pause is on, can't enable tx interrupt
lda #00001000B ; first clear CMD<3>
trb !ACIACMD
lda #00000100B ; then set CMD<2>
tsb !ACIACMD ; re-enable tx interrupt
?xba: xba ; return A = sent data
clc ; no error
?done: INDEX08
ldx sptmp3 ; restore X reg.
pld
cli
rts
spget2:
sei ; disable interrupt
phd
pea #DP05ADDR
pld
sec ; assume error
stx sptmp3 ; save X reg.
lda spstat3 ; rx pending error?
bmi ?done ; yes, exit
lda #0 ; assume no data available
tay ; Y = 0
INDEX16
ldx ibufcnt3 ; available new data?
beq ?done ; input queue is empty (exit with CF=1, A=0)
dex ; update count
stx ibufcnt3
ldx ibufhead3 ; head input buffer pointer
lda >SIBUFADDR3,x ; get byte from queue
inx ; update head pointer
cpx #SIBUFSIZ3
bcc ?upd
tyx ; circular queue
?upd: stx ibufhead3
bit sppause3 ; remote pause is on?
bpl ?ok ; no
ldx ibufcnt3
cpx icntmin3 ; can clear remote pause?
bcs ?ok ; no
bit spmode3 ; handshake is on?
bpl ?ok ; no
xba ; save data
bvs ?hw ; hardware handshake
lda #SPXON ; software handshake: send an XON
sta spout3 ; XON is deffered
lda #00001100B ; re-enable tx interrupt
trb !ACIACMD
lda #00000100B
tsb !ACIACMD
bra ?xba
?hw: lda #$04 ; hardware handshake: set RTS=0
trb .ABS.VIA2+VIAPRANH
lda #$80
trb sppause3 ; clear remote pause flag
?xba: xba ; recover data
?ok: clc
?done: INDEX08
ldx sptmp3 ; restore X reg.
pld
cli
rts ; CF=1 & A=0 mean: no data available
;------------------
; set serial port 16C550
; A=mode
spset3:
sei ; disable interrupt
phd
pea #DP05ADDR
pld
sta spmode4 ; save mode
stz !UART_LCR
stz !UART_IER ; disable all UART interrupts
stz !UART_MCR ; /RTS and /DTR high
stz !UART_FCR ; disable FIFO
ldx .ABS.UART_RXTX ; clear any pending interrupt
ldx .ABS.UART_LSR
ldx .ABS.UART_IIR
ldx #$80 ; set DLAB = 1 in LCR
stx .ABS.UART_LCR
tay ; save mode
and #00000011B ; baud rate select
tax
lda >?div,x ; select divisor
sta !UART_DLL ; set low latch
stz !UART_DLH ; set high latch
tya ; mode
and #00001100B ; mask on bits 3 & 2 (parity mode)
asl a ; shift <3:2> to <4:3>
ora #00000011B ; 8N1 (8 bits data, 1 stop bit)
sta !UART_LCR
lda !UART_MSR ; get /DSR & /CTS status
tax
asl a
asl a ; <7>: /DSR, <6>: /CTS
and #11000000B
eor #11000000B
sta splin4 ; update line status
stz sppause4 ; init work area
stz spstat4
lda #1 ; set tx count = 1
sta spcnt4
CPU16 ; init buffer's pointer's
lda #NGUARD32
ldy #NFREE32
sta icntmax4
sty icntmin4
sec
lda #SIBUFSIZ4
sbc icntmax4
sta icntmax4
stz ibuftail4
stz ibufhead4
stz ibufcnt4
stz obuftail4
stz obufhead4
stz obufcnt4
CPU08
lda #00000011B ; set /RTS = /DTR low
sta !UART_MCR
lda #$20
bit spmode4
bne ?nof ; no fifo
lda #1
sta !UART_FCR
lda #10000111B ; enable fifo, reset rx/tx fifo, trigger level = 8
sta !UART_FCR ; rx fifo trigger = 8
lda #16 ; set tx count = 16 in FIFO mode
sta spcnt4
?nof: lda !UART_LSR ; again reset all interrupts
lda !UART_MSR
lda !UART_IIR
lda #00001111B ; enable all interrupts
sta !UART_IER
pld
cli
rts
; 19.200, 38.400, 57.600, 115.200
?div: .DB 6, 3, 2, 1
spres3:
;stz !UART_LCR
stz !UART_IER ; clear all interrupts
;stz !UART_MCR ; /RTS and /DTR high
lda #10000111B ; enable fifo, reset rx/tx fifo
stz !UART_FCR ; rx fifo trigger = 8
lda !UART_LSR
lda !UART_MSR
rts
; send A to serial port 16C550
spput3:
sei ; disable interrupt
phd
pea #DP05ADDR
pld
stx sptmp4 ; save X reg.
ldy #0 ; Y = 0
INDEX16
ldx obufcnt4
cpx #SOBUFSIZ4 ; output buffer is full?
bcc ?str ; no, store byte
bit splin4 ; test /DSR line status
bmi ?ofl ; remote terminal disconnected
xba ; save A
lda #00000010B ; enable TX interrupt...
tsb !UART_IER ; ... hoping that ISR can make room in output buffer
xba
bra ?done ; exit with CF=1, Y=0: output buffer is full
?ofl: dey ; /DSR high
xba
lda #00000010B
trb !UART_IER ; disable tx interrupt
xba
bra ?done ; exit with CF=1, Y=$FF: remote terminal offline
?str: inx ; update count
stx obufcnt4
ldx obufhead4 ; output buffer head pointer
sta >SOBUFADDR4,x ; store byte in output buffer
inx ; update head pointer
cpx #SOBUFSIZ4
bcc ?upd
tyx ; circular queue
?upd: stx obufhead4
xba
;lda #00000010B
;trb !UART_IER ; re-enable tx interrupt
lda #00000010B
tsb !UART_IER ; re-enable tx interrupt
xba ; return A = sent data
clc ; no error
?done: INDEX08
ldx sptmp4 ; restore X reg.
pld
cli
rts
spget3:
sei ; disable interrupt
phd
pea #DP05ADDR
pld
sec ; assume error
stx sptmp4 ; save X reg.
lda spstat4 ; rx pending error?
bmi ?done ; yes, exit (CF = 1, A = error code)
lda #0 ; assume no data available
tay ; Y = 0
INDEX16
ldx ibufcnt4 ; available new data?
beq ?done ; input queue is empty (exit with CF=1, A=0)
dex ; update count
stx ibufcnt4
ldx ibuftail4 ; tail input buffer pointer
lda >SIBUFADDR4,x ; get byte from queue
inx ; update tail pointer
cpx #SIBUFSIZ4
bcc ?upd
tyx ; circular queue
?upd: stx ibuftail4
bit spmode4 ; handshake is on?
bpl ?ok ; no, exit
bit sppause4 ; remote pause is on?
bpl ?ok ; no, exit
ldx ibufcnt4
cpx icntmin4 ; can clear remote pause?
bcs ?ok ; no, exit
xba ; save data
lda #00000010B ; hardware handshake...
tsb !UART_MCR ; ...set /RTS=0
lda #$80
trb sppause4 ; clear remote pause flag
lda #00000010B ; set IER<1>
tsb !UART_IER ; re-enable tx interrupt
xba ; recover data
?ok: clc ; no error
?done: CPU08
ldx sptmp4 ; restore X reg.
pld
cli
rts ; CF=1 & A=0 mean: no data available
;------------------
lspget2:
.PUBLIC lspget2
phb ; save DBR
ldy #0 ; set DBR = $00
phy
plb
txy
bne ?get2
jsr spget3
plb
rtl
?get2: jsr spget2
plb
rtl
lspput2:
.PUBLIC lspput2
phb ; save DBR
ldy #0 ; set DBR = $00
phy
plb
txy
bne ?put2
jsr spput3
plb
rtl
?put2: jsr spput2
plb
rtl
lspset2:
.PUBLIC lspset2
phb ; save DBR
ldy #0 ; set DBR = $00
phy
plb
txy
bne ?set2
jsr spset3
plb
rtl
?set2: jsr spset2
plb
rtl
lspres2:
.PUBLIC lspres2
phb ; save DBR
ldy #0 ; set DBR = $00
phy
plb
txy
bne ?res2
jsr spres3
plb
rtl
?res2: jsr spres2
plb
rtl
test0:
sei
phd
pea #DP05ADDR
pld
sta sptmp4
lda #0
sta !UART_FCR
lda sptmp4
?00: dec a
bne ?00
lda #'@'
ldx #15
xba
?01: lda #$20
bit !UART_LSR
nop
nop
nop
nop
beq ?01
lda sptmp4
?02: dec a
bne ?02
xba
sta !UART_RXTX
inc a
xba
lda sptmp4
?02a: dec a
bne ?02a
dex
bne ?01
?03: lda #$20
bit !UART_LSR
nop
nop
nop
nop
beq ?03
lda sptmp4
?02b: dec a
bne ?02b
lda #$0D
sta !UART_RXTX
lda sptmp4
pld
cli
brk
test1:
sei
phd
pea #DP05ADDR
pld
sta sptmp4
lda #1
sta !UART_FCR
lda sptmp4
?00: dec a
bne ?00
lda #'@'
ldx #15
xba
?01: lda #$20
bit !UART_LSR
nop
nop
nop
nop
beq ?01
lda sptmp4
?02: dec a
bne ?02
?0l: xba
sta !UART_RXTX
inc a
xba
lda sptmp4
?02a: dec a
bne ?02a
dex
bne ?0l
lda #$0D
sta !UART_RXTX
lda sptmp4
pld
cli
brk
test2:
sei
phd
pea #DP05ADDR
pld
ldy #0
lda #1
sta !UART_FCR
?00: lda #'@'
ldx #15
xba
?01: lda #$20
bit !UART_LSR
nop
nop
nop
nop
beq ?01
?ll: xba
sta !UART_RXTX
inc a
xba
dex
bne ?ll
lda #$0D
sta !UART_RXTX
dey
bne ?00
pld
cli
brk
;==========================================
; UM245R
umgetcmd:
.PUBLIC umgetcmd
lda #$40
trb usbum ; clear bit <6>: fifo data not available
bit usbum
bmi ?cmd ; already connected: check command
; check connession request
ldx #7
?chk1: lda usbbuf,x
cmp >?usbconn,x
beq ?nxt
?nack: lda #$55 ; NACK
sta !UM245R
rtl
?nxt: dex
bpl ?chk1
lda #$AA ; ACK
sta !UM245R
lda #$80
tsb usbum
rtl
?cmd: ldx #(?usbtab2 - ?usbtab1 - 1)
lda usbbuf
?cmdl: cmp >?usbtab1,x
beq ?cmd2
dex
bpl ?cmdl
bmi ?nack ; not found
?cmd2: lda usbbuf+1
cmp >?usbtab2,x
bne ?nack ; not found
txa
asl a
tax
lda #CA2IFRB ; disable CA2 interrupt
sta !VIA2+VIAIER
sta !VIA2+VIAIFR
jsr usbsndack
jsr (?umjmp,x)
sei
lda #SETFRB.OR.CA2IFRB ; enable CA2 interrupt
sta !VIA2+VIAIER
sta !VIA2+VIAIFR
rtl
?umjmp:
.DW usbgetfmw
?usbconn:
.DB $87, $E9, $5D, $93, $B7, $57, $7D, $3B
?usbtab1:
.DB $99
?usbtab2:
.DB $51
; get firmware (512K)
usbgetfmw:
cli
stz usbptr
stz usbptr+1
lda #$70
sta usbptr+2 ; put firmware in bank $30
stz usbsiz ; full 64K bank
stz usbsiz+1
lda #$08 ; 8 banks
sta usbtmp
?lp: lda #$08
sec
sbc usbtmp
pha
phk
pea #!?fmt1
lda #5
pha
BPRINTF
jsr usbgetblk
bcs ?err ; error
jsr usbsndack
SCNPRINT
.DB 'done.', 13, 0
inc usbptr+2
dec usbtmp
bne ?lp
lda #$70
sta usbptr+2
stz usbcmp
lda #$08 ; 8 banks
sta usbtmp
?lp2: lda #$08
sec
sbc usbtmp
pha
phk
pea #!?fmt3
lda #5
pha
BPRINTF
;jsr usbcmpblk
;bcs ?err ; error
;bit usbcmp
;bpl ?ok
;jsr usbsndnack
;bra ?err
?ok: ;jsr usbsndack
jsr usbputbank
bcs ?err
SCNPRINT
.DB 'done.', 13, 0
inc usbptr+2
dec usbtmp
bne ?lp2
.COMMENT @
; send back for check
lda #$08 ; 8 banks
sta usbtmp
lda #$70
sta usbptr+2
?lp1: lda #$08
sec
sbc usbtmp
pha
phk
pea #!?fmt2
lda #5
pha
BPRINTF
;jsr usbputblk
jsr usbputbank
;jsr usbrx
bcs ?err
;bne ?err ; NACK
SCNPRINT
.DB 'done.', 13, 0
inc usbptr+2
dec usbtmp
bne ?lp1
@
; wait final ACK
jsr usbrx
bcs ?err
bne ?err ; NACK
SCNPRINT
.DB 'OK.', 13, 0
rts
?err:
SCNPRINT
.DB 'error.', 13, 0
rts
?fmt1: .DB 'get firmware bank %bu...', 0
?fmt2: .DB 'send back bank %bu...', 0
?fmt3: .DB 'verf. firmw. bank %bu...', 0
; get block: size in usbsiz, dest in usbptr
usbgetblk:
ldy #0
INDEX16
ldx usbsiz
lda #CA2IFRB ; check CA2 flag
?lp: bit !VIA2+VIAPRANH ; check /TXE
bvs ?err ; /TXE is high: disconnession?
bit VIA2+VIAIFR ; check CA2 flag
beq ?lp
sta !VIA2+VIAIFR ; clear CA2 flag
xba
lda !UM245R
sta [usbptr],y
xba
iny
dex
bne ?lp
clc
INDEX08
rts
?err: CPU08SEC
rts
; cmp block: size in usbsiz, dest in usbptr
usbcmpblk:
ldy #0
INDEX16
ldx usbsiz
lda #CA2IFRB ; check CA2 flag
?lp: bit !VIA2+VIAPRANH ; check /TXE
bvs ?err ; /TXE is high: disconnession?
bit VIA2+VIAIFR ; check CA2 flag
beq ?lp
sta !VIA2+VIAIFR ; clear CA2 flag
xba
lda !UM245R
cmp [usbptr],y
beq ?02
lda #$80
sta usbcmp
?02: xba
iny
dex
bne ?lp
clc
INDEX08
rts
?err: CPU08SEC
rts
; put a full: source in usbptr
usbputbank:
sei
ldy #0
?lp: lda !VIA2+VIAPRANH ; check /TXE
cmp !VIA2+VIAPRANH
bne ?lp
asl a
bmi ?lp
lda [usbptr],y
sta >UM245R
iny
bne ?lp
;jsr usbrx
;bcs ?rts
;bne ?err ; NACK
inc usbptr+1
bne ?lp
clc
?rts: cli
rts
?err: sec
cli
rts
; put block: size in usbsiz, dest in usbptr
usbputblk:
ldy #0
INDEX16
ldx usbsiz
; bra ?lp
;?lp0: bit !VIA2+VIAPRANH ; check /TXE
; bvs ?lp
; bvc ?lp0
?lp: bit !VIA2+VIAPRANH ; check /TXE
;cmp !VIA2+VIAPRANH
;bne ?lp
;asl a
;bmi ?lp ; /TXE is high
bvs ?lp
lda [usbptr],y
sta !UM245R
iny
dex
bne ?lp
clc
INDEX08
rts
; send nack
usbsndnack:
lda #$55
bra usbsnd
; send ack
usbsndack:
lda #$AA
; send a byte
usbsnd:
?lp: bit !VIA2+VIAPRANH ; check /TXE
bvs ?lp ; /TXE is high
sta !UM245R
rts
usbrx:
lda #CA2IFRB ; check CA2 flag
?lp: bit !VIA2+VIAPRANH ; check /TXE
bvs ?err ; /TXE is high: disconnession?
bit VIA2+VIAIFR ; check CA2 flag
beq ?lp
sta !VIA2+VIAIFR ; clear CA2 flag
lda !UM245R
cmp #$AA
clc
rts
?err: sec
rts