ld hl,#_sio_r
otir
ret
+
+
+ .area _COMMONMEM
+
;
; outchar: Wait for UART TX idle, then print the char in A
; destroys: AF
out (SIOA_D),a
ret
-;
-; SIO2 IM2 console driver
-;
-; The buffers are 256 bytes per channel and page aligned. The lower
-; half is used for receive the upper for transmit. Both are rings.
-
-;
-; Transmit data from the queue. We need a stop system for this but
-; actually the logical one might be to just turn that IRQ off, so long
-; as we remember to kickstart it again properly. Check if it's enough
-; to just unmask the IRQ bit ?
-;
-; All of this lives in common space so we don't bank switch so much.
-
- .area _CONSOLE
-
-sioa_rx:
- jp init ; for boot only
- .ds 128-3 ; we wrote a JP init in the first 3
-sioa_tx: ; that will be recycled
- .ds 128
-siob_rx:
- .ds 128
-siob_tx:
- .ds 128
-
- .area _COMMONMEM
-sioa_error:
- .db 0
-sioa_rxover:
- .db 0
-sioa_stat:
- .db 0
-sioa_txp:
- .dw sioa_tx
-sioa_txe:
- .dw sioa_tx
-sioa_rxp:
- .dw sioa_rx
-sioa_rxe:
- .dw sioa_rx
-
-siob_error:
- .db 0
-siob_rxover:
- .db 0
-siob_stat:
- .db 0
-siob_txp:
- .dw sioa_tx
-siob_txe:
- .dw sioa_tx
-siob_rxp:
- .dw sioa_rx
-siob_rxe:
- .dw sioa_rx
-
-;
-; Interrupt vector handler for port A transmit empty
-;
-sioa_txd:
- push af
- ld a,(_sioa_txl)
- or a
- jr z, tx_a_none
- push hl
- dec a
- ld (_sioa_txl),a
- ld hl,(sioa_txp)
- ld a,(hl)
- out (SIOA_D),a
- inc hl
- set 7,l
- ld (sioa_txp),hl
- pop hl
-tx_a_none:
- ld a,#0x28
- out (SIOA_C),a ; silence tx interrupt
- pop af
- ei
- reti
-;
-; Interrupt vector handler for port A receive ready
-;
-sioa_rx_ring:
- push af
- push hl
-sioa_rx_next:
- in a,(SIOA_D) ; read ASAP
- ld l,a
- ld a,(_sioa_rxl)
- inc a
- jp m, a_rx_over
- ld (_sioa_rxl),a
- ; should we check bit 5/6 and if appropriate flow control on bit 5/6
- ; high ?
- cp #0x60 ; flow control threshold
- call z, _sioa_flow_control_on
- ld a,l
- ld hl,(sioa_rxp)
- ld (hl),a
- inc l
- res 7,l
- ld (sioa_rxp),hl
- ;
- ; The chip has a small FIFO and bytes can also arrive as we
- ; read. To maximise performance try and empty it each time.
- ;
- ; This is bounded as worst case at high data rate and low
- ; CPU speed we will overrun and bail out.
- ;
- in a,(SIOA_C) ; RR 0
- rra
- jr c, sioa_rx_next
- pop hl
- pop af
- ei
- reti
-a_rx_over:
- ld a,(sioa_error)
- or #0x20 ; Fake an RX overflow bit
- ld (sioa_rxover),a
- pop af
- ei
- reti
-;
-; Interrupt vector for a port A status change
-;
-; FIXME:
-; log the or of changes seem (dcd down, up) and last state
-; of both CTS and DCD. The CTS last state is sufficient for flow
-; and we can use thw two edges of DCD to work out if we had a hangup
-; and if we are now open.
-;
-sioa_status:
- ; CTS or DCD change
- push af
- push hl
- ; RR0
- in a,(SIOA_C)
- ld (_sioa_state),a
- and #8
- jr z, no_dcd_drop_a
- ; \DCD went high
- ld (_sioa_dropdcd),a ; Set the dcdflag
-no_dcd_drop_a:
- ; Clear the latched values
- ld a,#0x10
- out (SIOA_C),a
- pop hl
- pop af
- ei
- reti
-
-;
-; Interrupt vector for a port A error
-;
-sioa_special:
- ; Parity, RX Overrun, Framing
- ; Probably want to record them, but we at least must clean up
- push af
- ld a,#1
- out (SIOA_C),a ; RR1 please
- in a,(SIOA_C) ; clear events
- ld (sioa_error),a ; Save error bits
- ; Clear the latched values
- ld a,#0x30
- out (SIOA_C),a
- pop af
- ei
- reti
-
-;
-; Interrupt vector handler for port B transmit empty
-;
-siob_txd:
- push af
- ld a,(_siob_txl)
- or a
- jr z, tx_b_none
- push hl
- dec a
- ld (_siob_txl),a
- ld hl,(siob_txp)
- ld a,(hl)
- out (SIOB_D),a
- inc hl
- set 7,l
- ld (siob_txp),hl
- pop hl
-tx_b_none:
- ld a,#0x28
- out (SIOB_C),a ; silence tx interrupt
- pop af
- ei
- reti
-;
-; Interrupt vector handler for port B receive ready
-;
-siob_rx_ring:
- push af
- push hl
-siob_rx_next:
- in a,(SIOB_D) ; read ASAP
- ld l,a
- ld a,(_siob_rxl)
- inc a
- jp m, b_rx_over
- ld (_siob_rxl),a
- ; should we check bit 5/6 and if appropriate flow control on bit 5/6
- ; high ?
- cp #0x60 ; flow control threshold
- call z, _siob_flow_control_on
- ld a,l
- ld hl,(siob_rxp)
- ld (hl),a
- inc l
- res 7,l
- ld (siob_rxp),hl
- ;
- ; The chip has a small FIFO and bytes can also arrive as we
- ; read. To maximise performance try and empty it each time.
- ;
- ; This is bounded as worst case at high data rate and low
- ; CPU speed we will overrun and bail out.
- ;
- in a,(SIOB_C) ; RR 0
- rra
- jr c, siob_rx_next
- pop hl
- pop af
- ei
- reti
-b_rx_over:
- ld a,(siob_error)
- or #0x20 ; Fake an RX overflow bit
- ld (siob_rxover),a
- pop af
- ei
- reti
-;
-; Interrupt vector for a port B status change
-;
-; FIXME:
-; log the or of changes seem (dcd down, up) and last state
-; of both CTS and DCD. The CTS last state is sufficient for flow
-; and we can use thw two edges of DCD to work out if we had a hangup
-; and if we are now open.
-;
-siob_status:
- ; CTS or DCD change
- push af
- push hl
- ; RR0
- in a,(SIOB_C)
- ld (_siob_state),a
- and #8
- jr z, no_dcd_drop_b
- ; \DCD went high
- ld (_siob_dropdcd),a ; Set the dcdflag
-no_dcd_drop_b:
- ; Clear the latched values
- ld a,#0x10
- out (SIOB_C),a
- pop hl
- pop af
- ei
- reti
-
-;
-; Interrupt vector for a port B error
-;
-siob_special:
- ; Parity, RX Overrun, Framing
- ; Probably want to record them, but we at least must clean up
- push af
- ld a,#1
- out (SIOB_C),a ; RR1 please
- in a,(SIOB_C) ; clear events
- ld (siob_error),a ; Save error bits
- ; Clear the latched values
- ld a,#0x30
- out (SIOB_C),a
- pop af
- ei
- reti
-
-;
-; C interface methods
-;
- .globl _sioa_txqueue
- .globl _sioa_flow_control_off
- .globl _sioa_flow_control_on
- .globl _sioa_rx_get
- .globl _sioa_error_get
-
- .globl _siob_txqueue
- .globl _siob_flow_control_off
- .globl _siob_flow_control_on
- .globl _siob_rx_get
- .globl _siob_error_get
-
.globl _sio_dropdcd
.globl _sio_flow
.globl _sio_rxl
.globl _sio_txl
.globl _sio_wr5
-; These are paid and exposed as arrays to C
+; These are laid out and exposed as arrays to C
_sio_wr5:
_sioa_wr5:
.db 0xEA ; DTR, 8bit, tx enabled
_siob_txl:
.db 0
-;
-; Queue a byte to be sent (DI required)
-;
-; l = byte
-;
-; Need a way to halt processing somewhere here or a_tx ?
-; (or can we use hardware ?)
-; 128 byte ring buffer aligned to upper half (rx is in lower)
-;
-_sioa_txqueue:
- ld a,(_sioa_txl)
- or a
- jr z, sioa_direct_maybe ; if can tx now then do
- inc a
- jp m, txa_overflow
-sioa_queue:
- ld (_sioa_txl),a
- ld a,l
- ld hl,(sioa_txe)
- ld (hl),a
- inc l
- set 7,l
- ld (sioa_txe),hl
- ld l,#0
- ret
-txa_overflow:
- ; some kind of flag for error
- ld l,#1
- ret
-sioa_direct_maybe:
- ; check RR
- in a,(SIOA_C)
- and #0x04 ; RX space ?
- ; if space
- ld a,#1
- jr nz, sioa_queue
- ; bypass the queue and kickstart the interrupt machine
- ld a,l
- out (SIOA_D),a
- ld l,#0
- ret
- ; Call with DI
-
-_sioa_flow_control_off:
- ld a,#5
- out(SIOA_C),a ; WR 5
- ld a,(_sioa_wr5)
- out (SIOA_C),a ; Turn off RTS
- ret
-
-_sioa_flow_control_on:
- ld a,#5
- out(SIOA_C),a ; WR 5
- ld a,(_sioa_wr5)
- and #0xFD
- out (SIOA_C),a ; Turn off RTS
- ret
-
- ; DI required
- ; Returns char in L
- ;
- ; Caller responsible for making post buffer fetch decisions about
- ; RTS
-_sioa_rx_get:
- ld a,(_sioa_rxl)
- or a
- ret z
- dec a
- ld (_sioa_rxl),a
- ld hl,(sioa_rxe)
- ld a,(hl)
- inc l
- res 7,l
- ld (sioa_rxe),hl
- scf
- ld l,a
- ret
-
- ; DI required
-_sioa_error_get:
- ld hl,#sioa_error
- ld a,(hl)
- ld (hl),#0
- ld l,a
- ret
-
-;
-; Queue a byte to be sent (DI required)
-;
-; l = byte
-;
-; Need a way to halt processing somewhere here or a_tx ?
-; (or can we use hardware ?)
-; 128 byte ring buffer aligned to upper half (rx is in lower)
-;
-_siob_txqueue:
- ld a,(_siob_txl)
- or a
- jr z, siob_direct_maybe ; if can tx now then do
- inc a
- jp m, txb_overflow
-siob_queue:
- ld (_siob_txl),a
- ld a,l
- ld hl,(siob_txe)
- ld (hl),a
- inc l
- set 7,l
- ld (siob_txe),hl
- ld l,#0
- ret
-txb_overflow:
- ; some kind of flag for error
- ld l,#1
- ret
-siob_direct_maybe:
- ; check RR
- in a,(SIOB_C)
- and #0x04 ; RX space ?
- ; if space
- ld a,#1
- jr z, siob_queue
- ; bypass the queue and kickstart the interrupt machine
- ld a,l
- out (SIOB_D),a
- ld l,#0
- ret
- ; Call with DI
-
-_siob_flow_control_off:
- ld a,#5
- out(SIOB_C),a ; WR 5
- ld a,(_siob_wr5)
- out (SIOB_C),a ; Turn off RTS
- ret
-
-_siob_flow_control_on:
- ld a, (_siob_flow)
- or a
- ret z
- ld a,#5
- out(SIOB_C),a ; WR 5
- ld a,(_siob_wr5)
- and #0xFD
- out (SIOB_C),a ; Turn off RTS
- ret
+ .include "../dev/z80sio.s"
- ; DI required
- ; Returns char in L
- ;
- ; Caller responsible for making post buffer fetch decisions about
- ; RTS
-_siob_rx_get:
- ld a,(_siob_rxl)
- or a
- ret z
- dec a
- ld (_siob_rxl),a
- ld hl,(siob_rxe)
- ld a,(hl)
- inc l
- res 7,l
- ld (siob_rxe),hl
- scf
- ld l,a
- ret
-
- ; DI required
-_siob_error_get:
- ld hl,#siob_error
- ld a,(hl)
- ld (hl),#0
- ld l,a
- ret
+sio_ports a
+sio_ports b
+sio_handler_im2 a, SIOA_C, SIOA_D, reti
+sio_handler_im2 b, SIOB_C, SIOB_D, reti
+ .area _BOOT
+ jp init