From: Alan Cox Date: Thu, 20 Sep 2018 00:52:50 +0000 (+0100) Subject: nascom: add support for tickless mode X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=6b5d61b06a5f582681998d5a57181297333e4f09;p=FUZIX.git nascom: add support for tickless mode We will need this once we get it up and running as many of the clock chips were not wired for interrupt or some more bizarrely wired it to NMI! --- diff --git a/Kernel/platform-nascom/README b/Kernel/platform-nascom/README index 4f9bab31..2f604d85 100644 --- a/Kernel/platform-nascom/README +++ b/Kernel/platform-nascom/README @@ -12,8 +12,7 @@ FC00 - FFFF Udata and common data (unbanked block) Once we have a vaguely sensible port and the split banking we need to move things around a bit to avoid stacks FC00-FFFF because of video contention. -However that means supporting double stack switches as the Cromenco and -32K/32K banked pair code will need. +However that means switching to the thunked model (as the SC108 uses) Target Hardware @@ -23,7 +22,7 @@ Required: Nascom I/II/II 192K "page mode" RAM (may be able to do a 128K port as well) eg RAM64/GM802 - A timer interrupt source (* indicates possible options) + GM816 or compatible 58174 clock at 0x20 Options: GM833 Ramdisc. Driver written, also steals up to 1MB of it for @@ -45,16 +44,16 @@ Boot Loaders Needed Options: -Nascom AVC (384x256 / 768x256) (* if jumpered for Vblank port A bit1) +Nascom AVC (384x256 / 768x256) (can be jumpered for Vblank port A bit1) Nascom Floppy Controller Nascom I/O card (PIO, CTC, UART) - Mostek 3882 CTC (Z80 CTC) * + Mostek 3882 CTC (Z80 CTC) 6402 UART MK3881 PIO (Z80 PIO) GM805 'Henelec' single density floppy GM810 IVC -GM816 (CTC 3x PIO optional serial GM818 - dual 8250) * +GM816 (CTC 3x PIO optional serial GM818 - dual 8250) GM822 RTC over PIO ? GM832 SVC GM837 Climax Colour @@ -62,10 +61,11 @@ BE847 Maths card GM848 quad serial GM862 RAM MAP80 256K RAM -MAP80 MPI (serial, CTC, FDC, SASI) ? * +MAP80 MPI (serial, CTC, FDC, SASI) ? MAP80 VFC WT625 Viewdata -Other RTC options (some RTC have 2Hz or so interrupt - not much use!) +Other RTC options (some RTC have 2Hz or so interrupt - not much use but +better than nothing - it'll get you out of a stuck process loop) Useful Disk Formats diff --git a/Kernel/platform-nascom/config.h b/Kernel/platform-nascom/config.h index 9824ccbe..f8527723 100644 --- a/Kernel/platform-nascom/config.h +++ b/Kernel/platform-nascom/config.h @@ -1,5 +1,7 @@ /* Set if you want RTC support */ -#undef CONFIG_RTC +#define CONFIG_RTC +/* We don't have a clock interrupt */ +#define CONFIG_NO_CLOCK /* Enable to make ^Z dump the inode table for debug */ #undef CONFIG_IDUMP /* Enable to make ^A drop back into the monitor */ diff --git a/Kernel/platform-nascom/discard.c b/Kernel/platform-nascom/discard.c index e977c6e3..b7d58c5c 100644 --- a/Kernel/platform-nascom/discard.c +++ b/Kernel/platform-nascom/discard.c @@ -14,7 +14,7 @@ void device_init(void) { #ifdef CONFIG_RTC /* Time of day clock */ - inittod(); + // FIXME : once we merge both versions of the RTC handling inittod(); #endif devscsi_init(); /* Must come last as we want to allocate this for swap if no other diff --git a/Kernel/platform-nascom/main.c b/Kernel/platform-nascom/main.c index 6ceee02d..5ab287c9 100644 --- a/Kernel/platform-nascom/main.c +++ b/Kernel/platform-nascom/main.c @@ -7,15 +7,19 @@ uint16_t ramtop = PROGTOP; uint8_t vtattr_cap; uint16_t swap_dev; +uint8_t clk_irq; /* Set if the clock can cause interrupts */ struct blkbuf *bufpool_end = bufpool + NBUFS; +/* FIXME: missing prototype ? */ +extern int strcmp(const char *, const char *); /* On idle we spin checking for the terminals. Gives us more responsiveness for the polled ports */ void platform_idle(void) { irqflags_t irq = di(); tty_poll(); + sync_clock(); irqrestore(irq); } @@ -23,18 +27,42 @@ void do_beep(void) { } +__sfr __at 0x21 clk_tenths; +__sfr __at 0x22 clk_secs; +__sfr __at 0x23 clk_tsecs; +__sfr __at 0x2F clk_stat; + uint8_t platform_param(char *p) { + if (strcmp(p, "clkint") == 0) { + clk_irq = 1; + /* FIXME: do a reset cycle first */ + clk_stat = 0x9; /* Repeating 0.5 sec - really 0.516.6 sec + so we need to fix clock tracking on + tickless FIXME */ + clk_stat | clk_stat | clk_stat; + return 1; + } used(p); return 0; } void platform_interrupt(void) { - /* TODO */ + /* We don't have interrupts for the keyboard */ kbd_poll(); tty_poll(); - timer_interrupt(); + if (clk_irq) { + if (clk_stat & 0x08) { /* Check 4 or 8 - need datasheet */ + /* Not ideal but we need to work out how to handle + the different clocks gracefully */ + timer_interrupt(); + timer_interrupt(); + timer_interrupt(); + timer_interrupt(); + /* Do we need to read again ? */ + } + } } /* @@ -58,3 +86,82 @@ void platform_discard(void) bp->bf_busy = BF_FREE; } } + +/* + * Logic for tickless system. If you have an RTC with a timer tick + * you can ignore this. + */ + +static uint16_t newticks = 0xFFFF; +static uint16_t oldticks; + +static uint8_t re_enter; + +/* + * We have a 1/10ths timer which is nice but it's easy to overrun so we + * collect up tens/units/tenths. + * + * Any ready can return 0xF not a BCD digit which means 'the time changed' + */ +static void sync_clock_read(void) +{ + uint8_t r[3]; + oldticks = newticks; + + do { + r[0] = clk_tenths & 0x0F ; + r[1] = clk_secs & 0x0F; + r[2] = clk_tsecs & 0x0F; + } while (r[0] == 0xF || r[1] == 0xF || r[2] == 0xF); + + newticks = r[0] + 10 * r[1] + 100 * r[2]; +} + +/* + * The OS core will invoke this routine when idle (via platform_idle) but + * also after a system call and in certain other spots to ensure the clock + * is roughly valid. It may be called from interrupts, without interrupts + * or even recursively so it must protect itself using the framework + * below. + * + * Having worked out how much time has passed in 1/10ths of a second it + * performs that may timer_interrupt events in order to advance the clock. + * The core kernel logic ensures that we won't do anything silly from a + * jump forward of many seconds. + * + * We also choose to poll the ttys here so the user has some chance of + * getting control back on a messed up process. + */ +void sync_clock(void) +{ + irqflags_t irq = di(); + int16_t tmp; + + if (clk_irq) + return; + + if (!re_enter++) { + sync_clock_read(); + if (oldticks != 0xFF) { + tmp = newticks - oldticks; + if (tmp < 0) + tmp += 600; + while(tmp--) { + timer_interrupt(); + } + /* Poll the keyboard */ + platform_interrupt(); + } + } + re_enter--; + irqrestore(irq); +} + +/* + * This method is called if the kernel has changed the system clock. We + * don't work out how much work we need to do by using it as a reference + * so we don't care. + */ +void update_sync_clock(void) +{ +}