From 29aeb801589db18b0512fa37c2b22aa42e78ce22 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Sun, 27 Jan 2019 17:55:31 +0000 Subject: [PATCH] rc2014: Support for CTC, fix a load of serial related bugs Also add support for a second SIO2 card --- Kernel/platform-rc2014/README | 38 ++---- Kernel/platform-rc2014/config.h | 7 +- Kernel/platform-rc2014/devices.c | 2 +- Kernel/platform-rc2014/devtty.c | 220 +++++++++++++++++++++++-------- Kernel/platform-rc2014/devtty.h | 6 +- Kernel/platform-rc2014/discard.c | 11 +- Kernel/platform-rc2014/main.c | 60 +++++---- Kernel/platform-rc2014/rc2014.h | 26 ++-- Kernel/platform-rc2014/rc2014.s | 147 +++++++++++++++++---- 9 files changed, 359 insertions(+), 158 deletions(-) diff --git a/Kernel/platform-rc2014/README b/Kernel/platform-rc2014/README index 0f262c65..5bb10b06 100644 --- a/Kernel/platform-rc2014/README +++ b/Kernel/platform-rc2014/README @@ -17,14 +17,12 @@ Supported Hardware default ROM and RAM boards. A serial IO board. Either an RC2014 SIO/2 board or a 68B50 ACIA board. - If you have a Scott Baker SIO/2 card you'll need to see config.h - DS1302 RTC at 0xC0 (eventually CTC and no RTC will be allowed too) + DS1302 RTC at 0xC0 } You must have one or both + RC2014 CTC at 0x88 } CTC strongly recommended Options: - CTC board at 0x88 - VFD Display. If config.h:CONFIG_VFD_TERM is defined, then the VFD Terminal will be supported. This will display all output to the serial port on the VFD. @@ -35,22 +33,19 @@ Supported Hardware RC2014 Joystick -In Progress - PPIDE Unsupported Hardware - SC108/SC114 or other CPU boards with their own banking instead of the - 512K ROM/RAM + SC108/SC114/Z80SBC64 or other CPU boards with their own banking instead + of the 512K ROM/RAM SC114 bit bang serial Z80 PIO cards (really because I've no idea how to present them) - SC110 CTC/serial (it uses CTC 1 for the serial baud but we try and - use it for other things). Will rework the core code to use the CTCs - differently to fix this at some point + SC110 CTC/serial (does not appear to be able to chain CTC pairs, as + is neeed for IM1 mode). Things To Note When Modifying @@ -67,26 +62,9 @@ Things that don't work * Flow control isn't yet enabled for the serial port. - * PPIDE - Stuff To Do - * Rework the CTCs if we can so we use CTC2 as a timer for the CTC clock and - use CTC3 to count CTC0 overflows. That way we can use the CTC2 interrupt - and the CTC3 value together in order to a) spot missed events and b) allow - us to run without using IM2 given the poor IM2 support on RC2014. That - then still allows us to use CTC1 for UART speed, and hopefully CTC0 for - single step debugging. Note that we are forced to use CTC1 for serial - for the SC110 card, and we want adjacent CTCs for jumpering convenience - for the timer. Also there is no ZT3 so it's the one timer that can't - chain so is best for the tick counter. - - * Detect and optimize code paths in CTC mode - the extra DS1302 accesses we - have to do are really expensive. - - * Can we detect which kind of SIO and CTC we have and where - - * Other tty options - can we autodetect 16550A at 0x80. Detect SIO at 0x84. + * Other tty options - can we autodetect 16550A at 0x80. * Probe both 0x10 and 0xE0 for CF ? @@ -107,7 +85,7 @@ Stuff To Do do some of the combinations we have today with the TMS9918A as well unless we go to banked syscall (Which is doable) - * Push the tty buffers into the banked space to give us room for four ttys + * Push the tty buffers into the banked space to give us room for more ttys * Go the soft IRQ route with fast SIO serial handling for rx interrupts and flip buffers. Also raises space issues as we'll need 256 bytes per SIO diff --git a/Kernel/platform-rc2014/config.h b/Kernel/platform-rc2014/config.h index 6de7c589..506bfb99 100644 --- a/Kernel/platform-rc2014/config.h +++ b/Kernel/platform-rc2014/config.h @@ -99,7 +99,7 @@ extern unsigned int swap_dev; #define CONFIG_INPUT /* Input device for joystick */ #define CONFIG_INPUT_GRABMAX 0 /* No keyboard to grab */ -#define NUM_DEV_TTY 2 +#define NUM_DEV_TTY 4 /* UART0 as the console */ #define BOOT_TTY (512 + 1) @@ -107,9 +107,4 @@ extern unsigned int swap_dev; #define TTYDEV BOOT_TTY /* Device used by kernel for messages, panics */ -/* The Scott Baker SIO has a non-standard layout (it predates the official one) */ -/* You'll need to define this if you have a Scott Baker SIO2 card, or submit - a fancier autodetect! Also you'll need to change rc2014.s */ -#undef CONFIG_SIO_BAKER - #define platform_copyright() // for now diff --git a/Kernel/platform-rc2014/devices.c b/Kernel/platform-rc2014/devices.c index 7b5a8fc5..0e919f75 100644 --- a/Kernel/platform-rc2014/devices.c +++ b/Kernel/platform-rc2014/devices.c @@ -25,7 +25,7 @@ struct devsw dev_tab[] = /* The device driver switch table */ { no_open, no_close, no_rdwr, no_rdwr, no_ioctl}, #endif /* 2: /dev/tty -- serial ports */ - { tty_open, tty_close, tty_read, tty_write, tty_ioctl}, + { rctty_open, tty_close, tty_read, tty_write, tty_ioctl}, /* 3: RAM disk */ { no_open, no_close, no_rdwr, no_rdwr, no_ioctl}, /* 4: /dev/mem etc System devices (one offs) */ diff --git a/Kernel/platform-rc2014/devtty.c b/Kernel/platform-rc2014/devtty.c index ae965385..fe2761d2 100644 --- a/Kernel/platform-rc2014/devtty.c +++ b/Kernel/platform-rc2014/devtty.c @@ -10,15 +10,17 @@ static char tbuf1[TTYSIZ]; static char tbuf2[TTYSIZ]; +static char tbuf3[TTYSIZ]; +static char tbuf4[TTYSIZ]; static uint8_t sleeping; -uint8_t ser_type = 1; - struct s_queue ttyinq[NUM_DEV_TTY + 1] = { /* ttyinq[0] is never used */ {NULL, NULL, NULL, 0, 0, 0}, {tbuf1, tbuf1, tbuf1, TTYSIZ, 0, TTYSIZ / 2}, {tbuf2, tbuf2, tbuf2, TTYSIZ, 0, TTYSIZ / 2}, + {tbuf3, tbuf3, tbuf3, TTYSIZ, 0, TTYSIZ / 2}, + {tbuf4, tbuf2, tbuf2, TTYSIZ, 0, TTYSIZ / 2}, }; static tcflag_t uart0_mask[4] = { @@ -40,7 +42,9 @@ static tcflag_t uart1_mask[4] = { tcflag_t *termios_mask[NUM_DEV_TTY + 1] = { NULL, uart0_mask, - uart1_mask + uart1_mask, + uart0_mask, + uart0_mask }; uint8_t sio_r[] = { @@ -49,13 +53,52 @@ uint8_t sio_r[] = { 0x05, 0xEA }; +static uint16_t siobaud[] = { + 0xC0, /* 0 */ + 0, /* 50 */ + 0, /* 75 */ + 0, /* 110 */ + 0, /* 134 */ + 0, /* 150 */ + 0xC0, /* 300 */ + 0x60, /* 600 */ + 0xC0, /* 1200 */ + 0x60, /* 2400 */ + 0x30, /* 4800 */ + 0x18, /* 9600 */ + 0x0C, /* 19200 */ + 0x06, /* 38400 */ + 0x04, /* 57600 */ + 0x02 /* 115200 */ +}; + static void sio2_setup(uint8_t minor, uint8_t flags) { struct termios *t = &ttydata[minor].termios; uint8_t r; + uint8_t baud; + + used(flags); + + baud = t->c_cflag & CBAUD; + if (baud < B300) + baud = B300; + /* Set bits per character */ sio_r[1] = 0x01 | ((t->c_cflag & CSIZE) << 2); + r = 0xC4; + if (ctc_present && minor == 3) { + CTC_CH1 = 0x55; + CTC_CH1 = siobaud[baud]; + if (baud > B600) /* Use x16 clock and CTC divider */ + r = 0x44; + } else + baud = B115200; + + t->c_cflag &= CBAUD; + t->c_cflag |= baud; + if (t->c_cflag & CSTOPB) r |= 0x08; if (t->c_cflag & PARENB) @@ -68,13 +111,13 @@ static void sio2_setup(uint8_t minor, uint8_t flags) void tty_setup(uint8_t minor, uint8_t flags) { - if (ser_type == 1) { + if (sio_present || sio1_present) { sio2_setup(minor, flags); sio2_otir(SIO0_BASE + 2 * (minor - 1)); /* We need to do CTS/RTS support and baud setting on channel 2 yet */ } - if (ser_type == 2) { + if (acia_present) { struct termios *t = &ttydata[1].termios; uint8_t r = t->c_cflag & CSIZE; /* No CS5/CS6 CS7 must have parity enabled */ @@ -117,31 +160,30 @@ void tty_setup(uint8_t minor, uint8_t flags) int tty_carrier(uint8_t minor) { uint8_t c; - if (ser_type == 1) { - if (minor == 1) { - SIOA_C = 0; - c = SIOA_C; - } else { - SIOB_C = 0; - c = SIOB_C; - } - if (c & 0x8) - return 1; - return 0; - } else /* ACIA isn't wired for carrier on any board */ + uint8_t port; + + /* No carrier on ACIA */ + if (sio_present == 0) + return 1; + + port = SIO0_BASE + 2 * (minor - 1); + out(port, 0); + c = in(port); + if (c & 0x08) return 1; + return 0; } -void tty_pollirq_sio(void) +void tty_pollirq_sio0(void) { static uint8_t old_ca, old_cb; uint8_t ca, cb; uint8_t progress; /* Check for an interrupt */ -// SIOA_C = 0; -// if (!(SIOA_C & 2)) -// return; + SIOA_C = 0; + if (!(SIOA_C & 2)) + return; /* FIXME: need to process error/event interrupts as we can get spurious characters or lines on an unused SIO floating */ @@ -159,7 +201,7 @@ void tty_pollirq_sio(void) SIOA_C = 2 << 5; /* Output pending */ if ((ca & 4) && (sleeping & 2)) { - tty_outproc(1); + tty_outproc(2); sleeping &= ~2; SIOA_C = 5 << 3; // reg 0 CMD 5 - reset transmit interrupt pending } @@ -176,9 +218,9 @@ void tty_pollirq_sio(void) tty_inproc(2, SIOB_D); progress = 1; } - if ((cb & 4) && (sleeping & 4)) { - tty_outproc(2); - sleeping &= ~4; + if ((cb & 4) && (sleeping & 8)) { + tty_outproc(3); + sleeping &= ~8; SIOB_C = 5 << 3; // reg 0 CMD 5 - reset transmit interrupt pending } if ((cb ^ old_cb) & 8) { @@ -190,6 +232,64 @@ void tty_pollirq_sio(void) } while(progress); } +void tty_pollirq_sio1(void) +{ + static uint8_t old_ca, old_cb; + uint8_t ca, cb; + uint8_t progress; + + /* Check for an interrupt */ + SIOC_C = 0; + if (!(SIOC_C & 2)) + return; + + /* FIXME: need to process error/event interrupts as we can get + spurious characters or lines on an unused SIO floating */ + do { + progress = 0; + SIOC_C = 0; // read register 0 + ca = SIOC_C; + /* Input pending */ + if ((ca & 1) && !fullq(&ttyinq[3])) { + progress = 1; + tty_inproc(3, SIOC_D); + } + /* Break */ + if (ca & 2) + SIOC_C = 2 << 5; + /* Output pending */ + if ((ca & 4) && (sleeping & 8)) { + tty_outproc(3); + sleeping &= ~8; + SIOC_C = 5 << 3; // reg 0 CMD 5 - reset transmit interrupt pending + } + /* Carrier changed */ + if ((ca ^ old_ca) & 8) { + if (ca & 8) + tty_carrier_raise(3); + else + tty_carrier_drop(3); + } + SIOD_C = 0; // read register 0 + cb = SIOD_C; + if ((cb & 1) && !fullq(&ttyinq[4])) { + tty_inproc(4, SIOD_D); + progress = 1; + } + if ((cb & 4) && (sleeping & 16)) { + tty_outproc(4); + sleeping &= ~16; + SIOD_C = 5 << 3; // reg 0 CMD 5 - reset transmit interrupt pending + } + if ((cb ^ old_cb) & 8) { + if (cb & 8) + tty_carrier_raise(4); + else + tty_carrier_drop(4); + } + } while(progress); +} + void tty_pollirq_acia(void) { uint8_t ca; @@ -204,22 +304,17 @@ void tty_pollirq_acia(void) } } -static char hex[] = { "0123456789ABCDEF" }; - void tty_putc(uint8_t minor, unsigned char c) { - if (ser_type == 1) { - if (minor == 1) { - SIOA_D = c; #ifdef CONFIG_VFD_TERM - vfd_term_write(c); + if (minor == 1) + vfd_term_write(c); #endif - } else if (minor == 2) - SIOB_D = c; - } else if (minor == 1) - ACIA_D = c; - else if (minor = 3) { - /* FIXME: implement */ + if (acia_present) + SIOA_D = c; + else { + uint8_t port = SIO0_BASE + 1 + 2 * (minor - 1); + out(port, c); } } @@ -240,35 +335,29 @@ ttyready_t tty_writeready(uint8_t minor) { irqflags_t irq; uint8_t c; - if (ser_type == 1) { - irq = di(); - if (minor == 1) { - SIOA_C = 0; /* read register 0 */ - c = SIOA_C; - irqrestore(irq); - if (c & 0x04) /* THRE? */ - return TTY_READY_NOW; - return TTY_READY_SOON; - } else if (minor == 2) { - SIOB_C = 0; /* read register 0 */ - c = SIOB_C; - irqrestore(irq); - if (c & 0x04) /* THRE? */ - return TTY_READY_NOW; - return TTY_READY_SOON; - } - irqrestore(irq); - } else if (ser_type == 2 && minor == 1) { + uint8_t port; + + if (acia_present) { c = ACIA_C; if (c & 0x02) /* THRE? */ return TTY_READY_NOW; return TTY_READY_SOON; } - return TTY_READY_NOW; + + irq = di(); + port = SIO0_BASE+ 2 * (minor - 1); + out(port, 0); + c = in(port); + irqrestore(irq); + + if (c & 0x04) /* THRE? */ + return TTY_READY_NOW; + return TTY_READY_SOON; } void tty_data_consumed(uint8_t minor) { + used(minor); } /* kernel writes to system console -- never sleep! */ @@ -280,3 +369,20 @@ void kputchar(char c) while(tty_writeready(TTYDEV - 512) != TTY_READY_NOW); tty_putc(TTYDEV - 512, c); } + +int rctty_open(uint8_t minor, uint16_t flag) +{ + if (acia_present && minor != 1) { + udata.u_error = ENODEV; + return -1; + } + if ((minor == 1 || minor == 2) && !sio_present) { + udata.u_error = ENODEV; + return -1; + } + if ((minor == 3 || minor == 4) && !sio1_present) { + udata.u_error = ENODEV; + return -1; + } + return tty_open(minor, flag); +} diff --git a/Kernel/platform-rc2014/devtty.h b/Kernel/platform-rc2014/devtty.h index 518450e6..6bc732cd 100644 --- a/Kernel/platform-rc2014/devtty.h +++ b/Kernel/platform-rc2014/devtty.h @@ -2,9 +2,9 @@ #define __DEVTTY_DOT_H__ void tty_putc(uint8_t minor, unsigned char c); -void tty_pollirq_sio(void); +void tty_pollirq_sio0(void); +void tty_pollirq_sio1(void); void tty_pollirq_acia(void); - -extern uint8_t ser_type; +int rctty_open(uint8_t minor, uint16_t flag); #endif diff --git a/Kernel/platform-rc2014/discard.c b/Kernel/platform-rc2014/discard.c index c4016dea..7245ea3f 100644 --- a/Kernel/platform-rc2014/discard.c +++ b/Kernel/platform-rc2014/discard.c @@ -6,8 +6,8 @@ #include #include #include +#include #include "config.h" -#include "devrd.h" #include "vfd-term.h" /* Everything in here is discarded after init starts */ @@ -36,6 +36,15 @@ void pagemap_init(void) /* finally add the common area */ pagemap_add(32 + 3); + + if (acia_present) + kputs("6850 ACIA detected at 0x80.\n"); + if (sio_present) + kputs("Z80 SIO detected at 0x80.\n"); + if (sio1_present) + kputs("Z80 SIO detected at 0x84.\n"); + if (ctc_present) + kputs("Z80 CTC detected at 0x88.\n"); } void map_init(void) diff --git a/Kernel/platform-rc2014/main.c b/Kernel/platform-rc2014/main.c index 9740df1e..d5e9ed1b 100644 --- a/Kernel/platform-rc2014/main.c +++ b/Kernel/platform-rc2014/main.c @@ -7,27 +7,29 @@ #include #include #include +#include extern unsigned char irqvector; -uint8_t timermsr = 0; uint16_t swap_dev = 0xFFFF; +uint8_t acia_present; +uint8_t ctc_present; +uint8_t sio_present; +uint8_t sio1_present; + void platform_discard(void) { } void platform_idle(void) { - /* FIXME: for the non CTC case we should poll the DS1302 here and - fake up appopriate timer events */ - /* Let's go to sleep while we wait for something to interrupt us; - * Makes the HALT LED go yellow, which amuses me greatly. */ -// __asm halt __endasm; - irqflags_t irq = di(); - sync_clock(); - /* FIXME: need to cover ACIA option.. */ - tty_pollirq_sio(); - irqrestore(irq); + if (ctc_present) + __asm halt __endasm; + else { + irqflags_t irq = di(); + sync_clock(); + irqrestore(irq); + } } uint8_t platform_param(unsigned char *p) @@ -36,18 +38,32 @@ uint8_t platform_param(unsigned char *p) return 0; } +static int16_t timerct; + +/* Call timer_interrupt at 10Hz */ +static void timer_tick(uint8_t n) +{ + timerct += n; + while (timerct >= 20) { + timer_interrupt(); + timerct -= 20; + } +} + void platform_interrupt(void) { - if (1) { /* CTC == 0 when we do the work */ -#ifdef CONFIG_FLOPPY - fd_tick(); -#endif -// poll_input(); -// timer_interrupt(); + if (acia_present) + tty_pollirq_acia(); + if (sio_present) + tty_pollirq_sio0(); + if (sio1_present) + tty_pollirq_sio1(); + if (ctc_present) { + uint8_t n = 255 - CTC_CH3; + CTC_CH3 = 0x47; + CTC_CH3 = 255; + timer_tick(n); } - /* FIXME: need to cover ACIA option.. */ - tty_pollirq_sio(); - return; } /* @@ -90,7 +106,7 @@ static void sync_clock_read(void) */ void sync_clock(void) { - if (!timermsr) { + if (!ctc_present) { irqflags_t irq = di(); int16_t tmp; if (!re_enter++) { @@ -103,8 +119,6 @@ void sync_clock(void) while(tmp--) { timer_interrupt(); } - /* FIXME: need to cover ACIA option.. */ - tty_pollirq_sio(); } } re_enter--; diff --git a/Kernel/platform-rc2014/rc2014.h b/Kernel/platform-rc2014/rc2014.h index 0dcf1a8e..aaf0cd48 100644 --- a/Kernel/platform-rc2014/rc2014.h +++ b/Kernel/platform-rc2014/rc2014.h @@ -3,22 +3,18 @@ #include "config.h" -#define SIO0_IVT 8 - -#ifdef CONFIG_SIO_BAKER -#define SIO0_BASE 0x80 -__sfr __at (SIO0_BASE + 2) SIOA_C; -__sfr __at (SIO0_BASE + 0) SIOA_D; -__sfr __at (SIO0_BASE + 3) SIOB_C; -__sfr __at (SIO0_BASE + 1) SIOB_D; -#else /* Standard RC2014 */ #define SIO0_BASE 0x80 __sfr __at (SIO0_BASE + 0) SIOA_C; __sfr __at (SIO0_BASE + 1) SIOA_D; __sfr __at (SIO0_BASE + 2) SIOB_C; __sfr __at (SIO0_BASE + 3) SIOB_D; -#endif + +#define SIO1_BASE 0x84 +__sfr __at (SIO1_BASE + 0) SIOC_C; +__sfr __at (SIO1_BASE + 1) SIOC_D; +__sfr __at (SIO1_BASE + 2) SIOD_C; +__sfr __at (SIO1_BASE + 3) SIOD_D; /* ACIA is at same address as SIO but we autodetect */ @@ -26,8 +22,16 @@ __sfr __at (SIO0_BASE + 3) SIOB_D; __sfr __at (ACIA_BASE + 0) ACIA_C; __sfr __at (ACIA_BASE + 1) ACIA_D; -extern bool boot_from_rom; +__sfr __at 0x88 CTC_CH0; +__sfr __at 0x89 CTC_CH1; +__sfr __at 0x8A CTC_CH2; +__sfr __at 0x8B CTC_CH3; extern void sio2_otir(uint8_t port) __z88dk_fastcall; +extern uint8_t acia_present; +extern uint8_t ctc_present; +extern uint8_t sio_present; +extern uint8_t sio1_present; + #endif diff --git a/Kernel/platform-rc2014/rc2014.s b/Kernel/platform-rc2014/rc2014.s index 1dbf0d9b..7e8439f2 100644 --- a/Kernel/platform-rc2014/rc2014.s +++ b/Kernel/platform-rc2014/rc2014.s @@ -36,11 +36,14 @@ .globl unix_syscall_entry .globl nmi_handler .globl null_handler - .globl _ser_type + .globl _acia_present + .globl _ctc_present + .globl _sio_present + .globl _sio1_present ; exported debugging tools - .globl inchar .globl outchar + .globl inchar .include "kernel.def" .include "../kernel.def" @@ -57,12 +60,16 @@ RTS_LOW .EQU 0xEA ; Base address of SIO/2 chip 0x80 ; For the Scott Baker SIO card adjust the order to match rc2014.h + SIOA_C .EQU 0x80 -SIOA_D .EQU SIOA_D+1 -SIOB_C .EQU SIOA_D+2 -SIOB_D .EQU SIOA_D+3 +SIOA_D .EQU SIOA_C+1 +SIOB_C .EQU SIOA_C+2 +SIOB_D .EQU SIOA_C+3 -SIO_IV .EQU 8 ; Interrupt vector table entry to use +SIOC_C .EQU 0x84 +SIOC_D .EQU SIOC_C+1 +SIOD_C .EQU SIOC_C+2 +SIOD_D .EQU SIOC_C+3 ACIA_C .EQU 0x80 ACIA_D .EQU 0x81 @@ -139,8 +146,8 @@ try_acia: ld a, #ACIA_RTS_LOW_A out (ACIA_C),a ; Initialise ACIA - ld a,#2 - ld (_ser_type),a + ld a,#1 + ld (_acia_present),a jp serial_up ; @@ -149,14 +156,12 @@ try_acia: ; At least until RC2014 grows a nice keyboard/display card! ; not_acia_either: - xor a - ld (_ser_type),a jp serial_up ; ; We have an SIO so do the required SIO hdance ; -is_sio: ld a,b - ld (_ser_type),a +is_sio: ld a,#1 + ld (_sio_present),a ld hl,#sio_setup ld bc,#0xA00 + SIOA_C ; 10 bytes to SIOA_C @@ -165,28 +170,118 @@ is_sio: ld a,b ld bc,#0x0A00 + SIOB_C ; and to SIOB_C otir + xor a + ld c,#SIOC_C + out (c),a ; RR0 + in b,(c) ; Save RR0 value + inc a + out (c),a ; RR1 + in a,(c) + cp b ; Same from both reads - not an SIO + + jr z, serial_up + + ; Repeat the check on SIO B + + xor a + ld c,#SIOD_C + out (c),a ; RR0 + in b,(c) ; Save RR0 value + inc a + out (c),a ; RR1 + in a,(c) + cp b ; Same from both reads - not an SIO + + jr z, serial_up + + ld a,#0x01 + ld (_sio1_present),a + + ld hl,#sio_setup + ld bc,#0xA00 + SIOC_C ; 10 bytes to SIOC_C + otir + ld hl,#sio_setup + ld bc,#0x0A00 + SIOD_C ; and to SIOD_C + otir + + serial_up: + ; --------------------------------------------------------------------- ; Initialize CTC ; + ; Need to do autodetect on this + ; ; We must initialize all channels of the CTC. The documentation ; states that the initial CTC state is undefined and we don't want ; random interrupt surprises + ; ; --------------------------------------------------------------------- - ld a,#0x57 ; counter mode, disable interrupts + ; + ; Defense in depth - shut everything up first + ; + + ld a,#0x43 out (CTC_CH0),a ; set CH0 mode - ld a,#0 ; time constant = 256 - out (CTC_CH0),a ; set CH0 time constant - ld a,#0x57 ; counter mode, FIXME C7 enable interrupts out (CTC_CH1),a ; set CH1 mode - ld a,#180 ; time constant = 180 - out (CTC_CH1),a ; set CH1 time constant - ld a,#0x57 ; counter mode, disable interrupts out (CTC_CH2),a ; set CH2 mode - ld a,#0x57 ; counter mode, disable interrupts out (CTC_CH3),a ; set CH3 mode + ; + ; Probe for a CTC + ; + + ld a,#0x47 ; CTC 2 as counter + out (CTC_CH2),a + ld a,#0xAA ; Set a count + out (CTC_CH2),a + in a,(CTC_CH2) + cp #0xAA ; Should not have changed + jr nz, no_ctc + + ld a,#0x07 + out (CTC_CH2),a + ld a,#2 + out (CTC_CH2),a + + ; We are now counting down from 2 very fast, so should only see + ; those values on the bus + + ld b,#0 +ctc_check: + in a,(CTC_CH2) + and #0xFC + jr nz, no_ctc + djnz ctc_check + + ; + ; Looks like we have a CTC + ; + +have_ctc: + ld a,#1 + ld (_ctc_present),a + + ; + ; Set up timer for 200Hz + ; + + ld a,#0xB5 + out (CTC_CH2),a + ld a,#144 + out (CTC_CH2),a ; 200 Hz + + ; + ; Set up counter CH3 for official SIO (the SC110 sadly can't be + ; used this way). + + ld a,#0x47 + out (CTC_CH3),a + ld a,#255 + out (CTC_CH3),a + +no_ctc: ; Done CTC Stuff ; --------------------------------------------------------------------- @@ -469,9 +564,9 @@ _sio2_otir: outchar: push af - ld a,(_ser_type) - cp #2 - jr z, ocloop_acia + ld a, (_acia_present) + or a + jr nz, ocloop_acia ; wait for transmitter to be idle ocloop_sio: @@ -503,9 +598,9 @@ out_done: ; Outputs: A - received character, F destroyed ;========================================================================= inchar: - ld a,(_ser_type) - cp #2 - jr z,inchar_acia + ld a,(_acia_present) + or a + jr nz,inchar_acia inchar_s: xor a ; read register 0 out (SIOA_C), a -- 2.34.1