From 2eb8466bead6ff43c42d8ef8c1ece5daa77ba308 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 27 Mar 2015 20:13:00 +0000 Subject: [PATCH] px4plus: Further updates This fleshes out the task switching, splits up the various ROM and cartridge logic and begins to put the rest of the system together --- Kernel/platform-px4plus/Makefile | 4 +- Kernel/platform-px4plus/README | 46 ++-- Kernel/platform-px4plus/config.h | 16 +- Kernel/platform-px4plus/crt0.s | 62 +++++- Kernel/platform-px4plus/devfd.c | 263 ++++++++++++++++++----- Kernel/platform-px4plus/devfd.h | 20 +- Kernel/platform-px4plus/devices.c | 4 +- Kernel/platform-px4plus/fuzix.lnk | 8 +- Kernel/platform-px4plus/main.c | 36 +++- Kernel/platform-px4plus/px4plus.s | 337 +++++++++++------------------- Kernel/platform-px4plus/romdisc.s | 79 +++++++ Kernel/platform-px4plus/sio.c | 43 ++++ Kernel/platform-px4plus/sio.h | 13 ++ Kernel/platform-px4plus/swapdev.s | 214 +++++++++++++++++++ Kernel/platform-px4plus/tricks.s | 100 +++++++-- 15 files changed, 907 insertions(+), 338 deletions(-) create mode 100644 Kernel/platform-px4plus/romdisc.s create mode 100644 Kernel/platform-px4plus/sio.c create mode 100644 Kernel/platform-px4plus/sio.h create mode 100644 Kernel/platform-px4plus/swapdev.s diff --git a/Kernel/platform-px4plus/Makefile b/Kernel/platform-px4plus/Makefile index 068d17bd..7bb6c689 100644 --- a/Kernel/platform-px4plus/Makefile +++ b/Kernel/platform-px4plus/Makefile @@ -1,5 +1,5 @@ -CSRCS = devlpr.c devtty.c devfd.c +CSRCS = devlpr.c devtty.c devfd.c sio.c CSRCS += devices.c CCSRCS = main.c @@ -7,7 +7,7 @@ CCSRCS = main.c CDSRCS = init.c ASRCS = crt0.s px4plus.s video.s -ASRCS += tricks.s commonmem.s +ASRCS += tricks.s commonmem.s swapdev.s romdisc.s COBJS = $(CSRCS:.c=.rel) CCOBJS = $(CCSRCS:.c=.rel) diff --git a/Kernel/platform-px4plus/README b/Kernel/platform-px4plus/README index 87db9257..ad5d2ba6 100644 --- a/Kernel/platform-px4plus/README +++ b/Kernel/platform-px4plus/README @@ -3,44 +3,42 @@ A FUZIX target for the PX4plus (and PX4 with 128K RAM disc) Just playing to see if we can make it fit. The PX4Plus has 64K of RAM, and can overlay 6000-DFFF with one of two -different ROMpacks (usually 'basic' and 'utility'). We build the kernel -at 0x6000 but for now plonk it into RAM so we can debug it. The small 8K -top window is awkward as we need to get udata and our kernel data/common in -that space if possible. We can hide the font/video below that under the top of -the ROM however. +different ROMpacks (usually 'basic' and 'utility'). Our kernel is a two +ROM set of 'P' type ROMs that can be plugged into the ROMpack sockets to +give a resident CP/M app that can be run as "B:FUZIX" + Banked Memory Map ----------------- 0x0000-0x00FF Vectors (which IM ? PX8 is IM2) -0x0100-0x5FFF Kernel mappings +0x0100-0x01FF Needed by resident OS (or could rewrite bits and + save them) +0x0200-0x5FFF Kernel mappings 0x6000-0xDFFF Switched segments 8/16/32K ROM x 2 or RAM 0x6000-0xDFFF Application space (32K) [need to use a bit under as 120K not 128K of swap] - 0x6000-0xDFFF CODE1/CODE2 } Both with copies of some of common - 0x6000-0xDFFF CODE3/Video } and rodata at same address range - [ Do we want to generate interleaved banking ? ] - -0xE000-0xFCFF Writable kernel data - Framebuffer (4K) -0xFD00-0xFFFF UDATA + 0x6000-0xDFFF CODE1/CODE2 + 0x6000-0xDFFF CODE3/Video/FONT + [ Do we want to generate interleaved banking or stubs in all banks ? ] + [ Could also save space by putting CONST at the top of both ROM + images ? ] -We also need to put a catalogue in the middle of one of the two ROM blocks -annoyingly. However that plays into our hands in other ways as we can -minimally fake a disk rom holding a CP/M app which in fact runs the OS. +0xE000-0xFBFF Currently unused +0xFC00-0xFFFF Framebuffer (2K) +We need to keep EF28 clear so we can set it to 1 for resident mode warm +start when we do suspend/resume. -Applications are swapped to/from the PX4Plus RAM disc (120K) allowing about -4 apps of just under 32K each. Storage I/O is via the serial floppy and/or -optional RAM/ROM cartriges. External 128K cartridges would also work for -swap with floppy for OS. If the swap is custom handled in switching then -we can switch the 32K rather than copy and gain another process, plus real -floppy swap option. +Applications are switched to/from the 128K side car or built in 128K ramdisc +on the plus. Alternatively they can be switched to/from the 32K or 64K +cartridge module on the PX4 (or in theory both). -CP/M BIOS can be used (it's another 32K map over 0-7FFF, but as that maps -over the vectors we must ensure its always called with interrupts off). +Storage I/O is via the serial floppy and/or optional ROM cartriges. The +floppy interface will also be usable for swap (once it works) The PX-8 is different: There is only a single 32K system ROM, but no video overhead. In theory its sufficient if we are replacing the OS ROM, and using the intelligent RAM disc, or the homebrew 512K one, plus floppies +The PX4 has a parallel port, can we run an SD card off it ? diff --git a/Kernel/platform-px4plus/config.h b/Kernel/platform-px4plus/config.h index da94d3c6..b08190c2 100644 --- a/Kernel/platform-px4plus/config.h +++ b/Kernel/platform-px4plus/config.h @@ -14,14 +14,12 @@ #define CONFIG_FONT8X8 /* CP/M emulation */ #undef CONFIG_CPM_EMU -/* Fixed banking */ -#undef CONFIG_BANK_FIXED +/* Fixed banking (although we must do magic in tricks.s to fake banking */ +#define CONFIG_BANK_FIXED +#define MAX_MAPS 7 +#define MAP_SIZE 0x8000 /* Swap only */ -#define CONFIG_SWAP_ONLY -/* Simple user copies for now (change when ROM the kernel) */ -#define CONFIG_USERMEM_C -#define BANK_KERNEL -#define BANK_PROCESS +#undef CONFIG_SWAP_ONLY /* Banks as reported to user space */ #define CONFIG_BANKS 1 @@ -35,10 +33,10 @@ /* FIXME: treat the banks of the ramdisc as memory not swap, also trim to 30K as only have 120K of RAMdisc */ -#define SWAP_SIZE 0x3C /* 30K in blocks (with uarea means 29.25K max app size) */ +#define SWAP_SIZE 0x40 /* 32K in blocks (with uarea means 31.25K max app size) */ #define SWAPBASE (uint8_t *)0x5D00 /* We swap the lot in one, include the */ #define SWAPTOP (uint8_t *)0xDD00 /* vectors so its a round number of sectors */ -#define MAX_SWAPS 4 /* We have a whopping 120K of RAMDISC! */ +#define MAX_SWAPS 4 /* We have a whopping 128K of RAMDISC! */ #define BOOT_TTY (512 + 1)/* Set this to default device for stdio, stderr */ /* In this case, the default is the first TTY device */ diff --git a/Kernel/platform-px4plus/crt0.s b/Kernel/platform-px4plus/crt0.s index 558ed26c..e3f3daca 100644 --- a/Kernel/platform-px4plus/crt0.s +++ b/Kernel/platform-px4plus/crt0.s @@ -42,10 +42,64 @@ .globl l__DATA .globl kstack_top - ; startup code .area _CODE -init: - di + ; Special headers for the type 'P' ROM + + ; Entry 0 is a dummy directory entry holding the volume info + .db 0xE5 ; Empty + .db 0x50 ; Program + .db 0xA0 ; 2 x 32K ROM + .dw 0xFFFF ; Checksum (but unused) - FIXME set this + .ascii 'H80' ; Magic string + .ascii '*FUZIX OS ROM*' + .db 0x04 ; Four directory entries + .ascii 'V01' ; Version + .ascii '032615' ; so much for Y2K + + ; Entry 1 + .db 0x00 ; Directory entry + .ascii 'FUZIX COM' ; name of executable + .dw 0x00 ; Extents + .db 0x00 ; Reserved + .db 0x01 ; 1 record + .db 0x01,0x00,0x00,0x00 ; 16 blocks + .db 0x00,0x00,0x00,0x00 + .db 0x00,0x00,0x00,0x00 + .db 0x00,0x00,0x00,0x00 + + ; Entry 2 + .db 0xE5 + .ds 31 ; 32 bytes per entry + ; Entry 3 + .db 0xE5 + .ds 31 + + ; Header of first block of "code" + .db 0xDD ; indicate "run from ROM" + .db 0xDE + .db 0xC3, 0x0B, 0x01 + jp coldstart + jp warmstart + ; + ; Reference code + ; + .db 0x0E, 0x1A, 0x11, 0x3A, 0xF9, 0xCD, 0x05, 0x00 + .db 0x21, 0x5C, 0x00, 0x11, 0x5D, 0x00, 0x01, 0x23 + .db 0x00, 0xAF, 0x77, 0xED, 0xB0, 0x21, 0x59, 0x01 + .db 0x11, 0x67, 0x00, 0x0E, 0x0B, 0xED, 0xB8, 0xCD + .db 0x99, 0xFF, 0x0E, 0x09, 0x11, 0x3E, 0x01, 0xCD + .db 0x05, 0x00, 0xAF, 0x32, 0x28, 0xEF, 0x0E, 0x00 + .db 0xCD, 0x05, 0x00, 0x52, 0x4F, 0x4D, 0x20, 0x41 + .db 0x43, 0x43, 0x49, 0x44, 0x45, 0x4E, 0x54, 0x20 + .db 0x21, 0x21, 0x07, 0x24 + ; Name + .ascii 'FUZIX COM' + + + + ; startup codeinit: +coldstart: +warmstart: ; Until we have suspend/resume done ld sp, #kstack_top ; Configure memory map @@ -71,4 +125,4 @@ stop: halt .area _STUBS stubs: - .ds 768 + .ds 512 diff --git a/Kernel/platform-px4plus/devfd.c b/Kernel/platform-px4plus/devfd.c index e6778dc6..f7bd4cc6 100644 --- a/Kernel/platform-px4plus/devfd.c +++ b/Kernel/platform-px4plus/devfd.c @@ -1,101 +1,248 @@ -/* +/* * Disk driver */ #include #include #include +#include #include +#include -static int fd_transfer(bool is_read, uint8_t minor, uint8_t rawflag); -static int hd_transfer(bool is_read, uint8_t minor, uint8_t rawflag); +#define FD_RESET 0x0D +#define FD_READ 0x77 +#define FD_WRITE 0x78 +#define FD_WRITEHST 0x79 /* Flush buffer */ +#define FD_COPY 0x7A /* Offline copy */ +/* 0x7B appears to have been redacted from docs ? */ +#define FD_FORMAT 0x7C /* Format disk */ + +#define FD_OK 0x00 +#define FD_ERR_READ 0xFA +#define FD_ERR_WRITE 0xFB +#define FD_ERR_DRIVESEL 0xFC +#define FD_ERR_WPROT 0xFD + +/* Worst case size */ +static uint8_t buf[0x89]; + +static void fd_reset(uint8_t minor) +{ + buf[0] = 0x00; + buf[1] = 0x30 + minor >> 1; + buf[2] = 0x23; + buf[3] = 0x0D; + buf[4] = 0x00; + buf[5] = 0x00; + sio_write(buf, 6); + sio_read(buf, 6); + if (buf[5]) + kprintf("fd%d: reset error %d\n", minor, buf[5]); +} + +int fd_transfer(uint8_t minor, bool is_read, uint8_t rawflag) +{ + blkno_t block; + uint16_t dptr; + uint16_t ct; + uint8_t tries; + uint16_t nblock; + staticfast uint8_t page; + staticfast int old_sio; + staticfast int err; + + ct = 0; + + if (rawflag == 0) { + dptr = (uint16_t)udata.u_buf->bf_data; + block = udata.u_buf->bf_blk << 2 ; + nblock = 4; + page = 0; /* Kernel */ + } else if (rawflag == 1) { + if (((uint16_t)udata.u_offset|udata.u_count) & BLKMASK) + goto bad2; + dptr = (uint16_t)udata.u_base; + nblock = udata.u_count >> 7; + block = udata.u_offset >> 7; /* 128 bytes/sector */ + page = udata.u_page; /* User */ + } else if (rawflag == 2) { + nblock = swapcnt >> 7; /* in 128 byte chunks */ + dptr = (uint16_t)swapbase; + page = swapproc->p_page; + block = swapblk << 2; + } else + goto bad; + + + old_sio = select_sio(); + + /* Loop over each 128 byte chunk */ + while (ct < nblock) { + buf[0] = 0x00; + buf[1] = 0x31 + minor >> 1; /* Which FDD ? */ + buf[2] = 0x23; + buf[6] = (block >> 6); /* 64 logical sectors/track */ + buf[7] = (block & 63) + 1; /* Sectors are 1 based */ + + for (tries = 0; tries < 4; tries ++) { + if (is_read) { + /* Write command to the drive, wait for reply */ + buf[3] = FD_READ; + buf[4] = 0x02; + sio_write(buf, 8); + err = sio_read(buf, 0x86); + if (!err) { + err = buf[0x86]; + if (!err) + /* Buffer goes to user space for this process or + to kernel. We always page in ourself */ + if (rawflag) + _uput(buf + 0x05, (uint8_t *)dptr, 128); + else + memcpy((uint8_t *)dptr, buf + 0x05, 128); + } + } else { + /* Write the buffer and data, then wait for an ack */ + buf[3] = FD_WRITE; + buf[4] = 0x83; + buf[8] = (((uint8_t)block) & 3) == 3 ? 0x00 : 0x02; + /* We need a special I/O helper for swapping out as we may + be swapping memory from an I/O mapped ram device to + the floppy disc */ + read_from_bank(page, dptr, buf + 0x09, 128); + sio_write(buf, 0x89); + err = sio_read(buf, 0x06); + if (!err) + err = buf[0x05]; + } + /* If it worked no more retries */ + if (err == 0) + break; + /* Errors not worth a retry */ + if (err >= FD_ERR_DRIVESEL) + goto bad2; + /* Failed ? */ + if (tries == 3) + goto bad2; + if (tries > 1) + fd_reset(minor); + } + /* Move on 128 bytes */ + block++; + dptr += 128; + ct++; + } + deselect_sio(old_sio); + return ct >> 2; +bad2: + deselect_sio(old_sio); +bad: + kprintf("fd%d: I/O error %d.\n", minor, err); + udata.u_error = EIO; + return -1; +} int fd_read(uint8_t minor, uint8_t rawflag, uint8_t flag) { - flag; - return fd_transfer(true, minor, rawflag); + used(flag); + return fd_transfer(minor, true, rawflag); } int fd_write(uint8_t minor, uint8_t rawflag, uint8_t flag) { - flag; - return fd_transfer(false, minor, rawflag); + used(flag); + return fd_transfer(minor, false, rawflag); } -/* hd is only used for swapping */ -int hd_read(uint8_t minor, uint8_t rawflag, uint8_t flag) +int fd_open(uint8_t minor, uint16_t flag) { flag; - return hd_transfer(true, minor, rawflag); + if(minor >= 3) { + udata.u_error = ENODEV; + return -1; + } + return 0; } -int hd_write(uint8_t minor, uint8_t rawflag, uint8_t flag) +static void mdelay(uint16_t d) { - flag; - return hd_transfer(false, minor, rawflag); + used(d); + /* FIXME */ } -static int fd_transfer(bool is_read, uint8_t minor, uint8_t rawflag) +__sfr __at 0x19 rom_ctrl; + +static void rom_on(void) { - /* Serial floppy driver - to write */ - is_read; - minor; - rawflag; - return -EIO; + mod_ioctrlr(0x08,0x00); /* Cartridge out of reset */ + mdelay(10); + rom_ctrl = 1; /* Power on */ + mdelay(60); } -/* Easier to use statics as is this is single threaded and talking to asm - code in a critical path */ - -uint16_t ramd_off; -uint16_t ramd_size; -uint16_t ramd_uaddr; +static void rom_off(void) +{ + rom_ctrl = 0; + mod_ioctrlr(0x00,0x08); +} -/* Really only ever used for swap */ -static int hd_transfer(bool is_read, uint8_t minor, uint8_t rawflag) +/* hd is actually the ROM image files */ +int rom_read(uint8_t minor, uint8_t rawflag, uint8_t flag) { - minor; + used(flag); if(rawflag == 1) { - ramd_size = udata.u_count; - ramd_uaddr = (uint16_t)udata.u_base; - ramd_off = udata.u_offset << 1; + romd_size = udata.u_count; + romd_addr = (uint16_t)udata.u_base; + romd_off = udata.u_offset >> 8; /* Should check this higher up ? */ - if (((uint16_t)ramd_size | ramd_off) & BLKMASK) - return -EIO; - } else if (rawflag == 2) { /* Swap device special */ - ramd_size = swapcnt << 9; - ramd_uaddr = (uint16_t)swapbase; - ramd_off = swapblk << 1; + if (((uint16_t)udata.u_offset | romd_size) & BLKMASK) + goto bad; + } else if (rawflag == 2) { + goto bad; } else { /* rawflag == 0 */ - ramd_uaddr = (uint16_t)udata.u_buf->bf_data; - ramd_off = udata.u_buf->bf_blk << 8; - ramd_size = 512; + romd_addr = (uint16_t)udata.u_buf->bf_data; + romd_off = udata.u_buf->bf_blk << 1; + romd_size = 512; + } + romd_mode = rawflag; + if (minor == 0) + rom_sidecar_read(); + else { + rom_on(); + rom_cartridge_read(); + rom_off(); } - /* Block copy to/from the RAM disc I/O */ - if (is_read) - hd_xferin(); - else - hd_xferout(); - return ramd_size; + return romd_size; +bad: + udata.u_error = EIO; + return -1; } -int fd_open(uint8_t minor, uint16_t flag) + +int rom_write(uint8_t minor, uint8_t rawflag, uint8_t flag) { - flag; - if(minor >= 3) { - udata.u_error = ENODEV; - return -1; - } - return 0; + used(minor); + used(rawflag); + used(flag); + + udata.u_error = EIO; + return -1; } -int hd_open(uint8_t minor, uint16_t flag) +int rom_open(uint8_t minor, uint16_t flag) { flag; - if(minor) { - udata.u_error = ENODEV; - return -1; + switch (minor) { + case 0: + if (sidecar) + return 0; + break; + case 1: + if (carttype == 1) /* ROM */ + return 0; + break; } - return 0; + udata.u_error = ENODEV; + return -1; } diff --git a/Kernel/platform-px4plus/devfd.h b/Kernel/platform-px4plus/devfd.h index 629628ae..30c26df4 100644 --- a/Kernel/platform-px4plus/devfd.h +++ b/Kernel/platform-px4plus/devfd.h @@ -6,12 +6,22 @@ int fd_read(uint8_t minor, uint8_t rawflag, uint8_t flag); int fd_write(uint8_t minor, uint8_t rawflag, uint8_t flag); int fd_open(uint8_t minor, uint16_t flag); -int hd_read(uint8_t minor, uint8_t rawflag, uint8_t flag); -int hd_write(uint8_t minor, uint8_t rawflag, uint8_t flag); -int hd_open(uint8_t minor, uint16_t flag); +int rom_read(uint8_t minor, uint8_t rawflag, uint8_t flag); +int rom_write(uint8_t minor, uint8_t rawflag, uint8_t flag); +int rom_open(uint8_t minor, uint16_t flag); /* asm code */ -void hd_xferin(void); -void hd_xferout(void); +void rom_sidecar_read(void); +void rom_cartridge_read(void); + +/* In common */ +extern uint16_t romd_size; +extern uint16_t romd_addr; +extern uint16_t romd_off; +extern uint8_t romd_mode; + +/* Set up by boot code */ +extern uint8_t sidecar; +extern uint8_t carttype; #endif /* __DEVRD_DOT_H__ */ diff --git a/Kernel/platform-px4plus/devices.c b/Kernel/platform-px4plus/devices.c index 87a2f8bf..fbd7369a 100644 --- a/Kernel/platform-px4plus/devices.c +++ b/Kernel/platform-px4plus/devices.c @@ -14,8 +14,8 @@ struct devsw dev_tab[] = /* The device driver switch table */ // ----------------------------------------------------------------- /* 0: /dev/fd Floppy disc block devices */ { fd_open, no_close, fd_read, fd_write, no_ioctl }, - /* 1: /dev/hd Hard disc block devices (absent) */ - { hd_open, no_close, hd_read, hd_write, no_ioctl }, + /* 1: /dev/hd Hard disc (we use for ROMs) */ + { rom_open, no_close, rom_read, rom_write, no_ioctl }, /* 2: /dev/tty TTY devices */ { tty_open, tty_close, tty_read, tty_write, tty_ioctl }, /* 3: /dev/lpr Printer devices */ diff --git a/Kernel/platform-px4plus/fuzix.lnk b/Kernel/platform-px4plus/fuzix.lnk index 2dbacb51..3083b6b8 100644 --- a/Kernel/platform-px4plus/fuzix.lnk +++ b/Kernel/platform-px4plus/fuzix.lnk @@ -1,6 +1,6 @@ -mwxuy -i fuzix.ihx --b _COMMONMEM=0x0100 +-b _COMMONMEM=0x0200 -b _UDATA=0x5D00 -b _DISCARD=0x4000 -b _CODE=0x6000 @@ -14,11 +14,15 @@ platform-px4plus/main.rel start.rel version.rel lowlevel-z80-banked.rel +usermem_std-z80-banked.rel platform-px4plus/tricks.rel +platform-px4plus/swapdev.rel timer.rel kdata.rel usermem.rel platform-px4plus/devfd.rel +platform-px4plus/romdisc.rel +platform-px4plus/sio.rel platform-px4plus/devices.rel devio.rel filesys.rel @@ -31,7 +35,7 @@ syscall_proc.rel syscall_other.rel tty.rel mm.rel -simple.rel +bankfixed.rel swap.rel devsys.rel platform-px4plus/devlpr.rel diff --git a/Kernel/platform-px4plus/main.c b/Kernel/platform-px4plus/main.c index f3632799..87ed3875 100644 --- a/Kernel/platform-px4plus/main.c +++ b/Kernel/platform-px4plus/main.c @@ -3,6 +3,7 @@ #include #include #include +#include uint16_t ramtop = PROGTOP; @@ -26,8 +27,39 @@ void platform_interrupt(void) timer_interrupt(); } -/* Nothing to do for the map of init */ -void map_init(void) +extern uint8_t map_translate[MAX_MAPS]; + +/* Add map numbers. These are logical mappings one of which is the current + memory image and the others indexes into the sidecar or cartridge memory. + + Put map #1 last as it means "in memory" and we want it for init */ + +void pagemap_init(void) { + uint8_t n = procmem / 32; + uint8_t *p = map_translate; + uint8_t nv = 0xFF; + uint8_t ct; + uint8_t i; + + if (!sidecar && carttype != 2) + panic("No suitable memory extension"); + n /= 32; + /* Handle sidecar memory */ + if (sidecar) { + nv = n - 4; /* Number of non sidecar blocks (including in RAM) */ + ct = 0x83; /* 0x80-0x83 are sidecar maps */ + } else + ct = n; /* 1..n are cartridge (1 = in memory) */ + + for (i = n; i > 0; i--) { + if (i == nv) + ct = nv; + *p++ = ct--; + pagemap_add(i); + } } +void map_init(void) +{ +} diff --git a/Kernel/platform-px4plus/px4plus.s b/Kernel/platform-px4plus/px4plus.s index b9bcddfc..a73e7cb6 100644 --- a/Kernel/platform-px4plus/px4plus.s +++ b/Kernel/platform-px4plus/px4plus.s @@ -1,15 +1,7 @@ ; -; Z80Pack hardware support -; -; -; This goes straight after udata for common. Because of that the first -; 256 bytes get swapped to and from disk with the uarea (512 byte disk -; blocks). This isn't a problem but don't put any variables in here. -; -; If you make this module any shorter, check what follows next +; PX4 Plus hardware support ; - .module px4plus ; exported symbols @@ -22,7 +14,11 @@ .globl map_process_always .globl map_save .globl map_restore + .globl map_process_save + .globl map_kernel_restore .globl _kernel_flag + .globl _sidecar + .globl _carttype .globl platform_interrupt_all @@ -34,39 +30,31 @@ .globl _ramsize .globl _procmem .globl _vtinit + .globl _cartridge_size .globl unix_syscall_entry .globl null_handler .globl nmi_handler .globl interrupt_handler - ; RAM drive - .globl _hd_xferin - .globl _hd_xferout - .globl _ramd_off - .globl _ramd_size - .globl _ramd_uaddr + ; ROM interfaces + .globl _rom_sidecar_read + .globl _rom_cartridge_read + .globl _romd_off + .globl _romd_size + .globl _romd_addr + .globl _romd_mode .globl __bank_0_1 - .globl __bank_0_2 .globl __bank_0_3 - .globl __bank_1_2 .globl __bank_1_3 - .globl __bank_2_1 - .globl __bank_2_3 .globl __bank_3_1 - .globl __bank_3_2 .globl __stub_0_1 - .globl __stub_0_2 .globl __stub_0_3 - .globl __stub_1_2 .globl __stub_1_3 - .globl __stub_2_1 - .globl __stub_2_3 .globl __stub_3_1 - .globl __stub_3_2 .include "kernel.def" @@ -86,10 +74,26 @@ platform_interrupt_all: ret ; -; FIXME: this probably needs to be a new "commondata" area +; FIXME: this probably needs to be a new "commondata" area so we can ; _kernel_flag: .db 1 +kernel_map: ; Last kernel map we were using + .db 0xA2 +saved_map: ; Saved mapping for IRQ entry/exit + .db 0 +_sidecar: + .db 0 +_carttype: + .db 0 +_romd_off: + .dw 0 +_romd_size: + .dw 0 +_romd_addr: + .dw 0 +_romd_mode: + .db 0 ; ----------------------------------------------------------------------------- ; KERNEL MEMORY BANK (only accessible when the kernel is mapped) @@ -97,14 +101,40 @@ _kernel_flag: .area _CODE init_early: + ld a, (0xF53F) ; BIOS cartridge type + ld (_carttype), a ret init_hardware: ; set system RAM size - ; Not strictly correct FIXME: set right when ROM the image + ; We have 64K RAM + 64K ROM to immediate hand, but we should + ; try and include the "swap" like RAM here to give a sensible + ; number, as we won't treat it as disk ld hl, #64 + in a, (0x94) + add a + jr nc, notplus + ld hl, #192 ; Sidecar always has 128K on the PX4 + ; PX8 version is 120K if we ever do + ; PX8 + ld a, #1 + ld (_sidecar), a ; Sidecar present +notplus: ; Not a PX4plus or PX4 with sidecar + ; See if we have a RAM cartridge fitted + ld a, (_carttype) + cp #2 + jr nz, noramcart + push hl + push af + call _cartridge_size + pop af + pop de + add hl, de +noramcart: ld (_ramsize), hl - ld hl, #32 ; 32K for kernel + or a + ld de, #32 ; 32K for kernel + sbc hl, de ld (_procmem), hl ; set up interrupt vectors for the kernel @@ -169,14 +199,40 @@ _program_vectors: ; falls through - ; Map functions are trivial for now - ; FIXME: will need to play with BANKR once we ROM the image map_kernel: +map_kernel_restore: + push af + ld a, (kernel_map) + out (0x05), a + pop af + ret map_process: + ld a, h + or l + jr z, map_kernel map_process_always: +map_process_save: + push af + in a,(0x05) + cp #0x42 ; Already in user map + jr z, reto + ld (kernel_map), a + ld a, #0x42 ; user map (ROMs out) + out (0x05), a +reto: + pop af + ret + map_save: + in a, (0x05) + ld (saved_map), a + ret map_restore: - ret + ld a, (saved_map) + and #0xF0 + or #0x02 + out (0x05), a + ret ; outchar: Wait for UART TX idle, then print the char in A outchar: @@ -189,101 +245,20 @@ outcharw: out (0x14), a ret -; -; RAM disc -; -_hd_xferin: -; -; Load the full 24 bit address to start -; - xor a ; always aligned - out (0x90), a - ld hl, #_ramd_off + 1 - ld de, (_ramd_size) -hd_xiloop: - ld a, (hl) - out (0x91), a - inc hl - ld a, (hl) - out (0x92), a - ld bc, #0x93 -; -; With a 256 byte block it autoincrements -; - ld hl, (_ramd_uaddr) - inir - dec d - ret z -; -; Move on a block -; - ld (_ramd_uaddr), hl - ld hl, #_ramd_off + 1 - inc (hl) - jr nz, hd_xiloop - inc hl - inc (hl) - dec hl - jr hd_xiloop - -_hd_xferout: -; -; Load the full 24 bit address to start -; - xor a ; always aligned - out (0x90), a - ld hl, #_ramd_off + 1 - ld de, (_ramd_size) -hd_xoloop: - ld a, (hl) - out (0x91), a - inc hl - ld a, (hl) - out (0x92), a - ld bc, #0x93 -; -; With a 256 byte block it autoincrements -; - ld hl, (_ramd_uaddr) - otir - dec d - ret z -; -; Move on a block -; - ld (_ramd_uaddr), hl - ld hl, #_ramd_off + 1 - inc (hl) - jr nz, hd_xoloop - inc hl - inc (hl) - dec hl - jr hd_xiloop - -; -; FIXME -current_map: - .byte 0 -switch_bank: - ret ; ; ; Banking helpers ; -; FIXME: these are from zx128 - not yet converted to px4plus. We -; should also be able to dump all to/from bank2 versions -; -; ; Logical Physical -; 0 COMMON (0x4000) -; 1 0 -; 2 1 -; 3 7 +; 0 COMMON +; 1 ROM1 +; 2 *unused* +; 3 ROM2 ; ; __bank_0_1: - xor a ; switch to physical bank 0 (logical 1) + ld a, #0xA2 ; switch to 32K ROM 1 bankina0: ; ; Get the target address first, otherwise we will change @@ -295,158 +270,98 @@ bankina0: ld d, (hl) inc hl push hl ; Restore corrected return pointer - ld bc, (current_map) ; get current bank into B - call switch_bank ; Move to new bank + ld c, #0x05 + in b, (c) + out (c), a ; figure out which bank to map on the return path - ld a, c - or a + ld a, #0xA2 + cp b jr z, __retmap1 - dec a - jr z, __retmap2 jr __retmap3 callhl: jp (hl) -__bank_0_2: - ld a, #1 ; logical 2 -> physical 1 - jr bankina0 + __bank_0_3: - ld a, #7 ; logical 3 -> physical 7 + ld a, #0xE2 ; 32K ROM 2 jr bankina0 -__bank_1_2: - ld a, #1 -bankina1: +__bank_1_3: + ld a, #0xE2 ; 32K ROM 2 pop hl ; Return address (points to true function address) ld e, (hl) ; DE = function to call inc hl ld d, (hl) inc hl push hl ; Restore corrected return pointer - call switch_bank ; Move to new bank + out (0x05), a __retmap1: ex de, hl call callhl ; call the function - xor a ; return to bank 1 (physical 0) - jp switch_bank + ld a,#0xA2 ; return to ROM1 + out (0x05), a + ret -__bank_1_3: - ld a, #7 - jr bankina1 -__bank_2_1: - xor a -bankina2: - pop hl ; Return address (points to true function address) - ld e, (hl) ; DE = function to call - inc hl - ld d, (hl) - inc hl - push hl ; Restore corrected return pointer - call switch_bank ; Move to new bank -__retmap2: - ex de, hl - call callhl ; call the function - ld a, #1 ; return to bank 2 - jp switch_bank -__bank_2_3: - ld a, #7 - jr bankina2 __bank_3_1: - xor a -bankina3: + ld a,#0xA2 ; 32K ROM 1 pop hl ; Return address (points to true function address) ld e, (hl) ; DE = function to call inc hl ld d, (hl) inc hl push hl ; Restore corrected return pointer - call switch_bank ; Move to new bank + out (0x05), a __retmap3: ex de, hl call callhl ; call the function - ld a, #7 ; return to bank 0 - jp switch_bank - -__bank_3_2: - ld a, #1 - jr bankina3 + ld a, #0xE2 ; return to ROM 2 + out (0x05), a + ret ; ; Stubs need some stack munging and use DE ; - __stub_0_1: - xor a + ld a, #0xA2 __stub_0_a: pop hl ; the return ex (sp), hl ; write it over the discard - ld bc, (current_map) - call switch_bank - ld a, c - or a + ld c, #0x05 + in b, (c) + out (c), a + ld a, #0xA2 + cp b jr z, __stub_1_ret - dec a - jr z, __stub_2_ret jr __stub_3_ret -__stub_0_2: - ld a, #1 - jr __stub_0_a __stub_0_3: - ld a, #7 + ld a, #0xE2 jr __stub_0_a -__stub_1_2: - ld a, #1 -__stub_1_a: +__stub_1_3: + ld a, #0xE2 pop hl ; the return ex (sp), hl ; write it over the discad - call switch_bank + out (0x05), a __stub_1_ret: ex de, hl call callhl - xor a - call switch_bank - pop de - push de ; dummy the caller will discard - push de - ret -__stub_1_3: - ld a, #7 - jr __stub_1_a - -__stub_2_1: - xor a -__stub_2_a: - pop hl ; the return - ex (sp), hl ; write it over the discad - call switch_bank -__stub_2_ret: - ex de, hl ; DE is our target - call callhl - ld a,#1 - call switch_bank + ld a, #0xA2 + out (0x05), a pop de push de ; dummy the caller will discard push de ret -__stub_2_3: - ld a, #7 - jr __stub_2_a __stub_3_1: - xor a -__stub_3_a: + ld a, #0xA2 pop hl ; the return ex (sp), hl ; write it over the discad - call switch_bank + out (0x05), a __stub_3_ret: ex de, hl call callhl - ld a,#7 - call switch_bank + ld a,#0xE2 + out (0x05), a pop de push de ; dummy the caller will discard push de ret -__stub_3_2: - ld a, #1 - jr __stub_3_a diff --git a/Kernel/platform-px4plus/romdisc.s b/Kernel/platform-px4plus/romdisc.s new file mode 100644 index 00000000..9d718d06 --- /dev/null +++ b/Kernel/platform-px4plus/romdisc.s @@ -0,0 +1,79 @@ +; +; ROM drive interfaces +; + .globl _rom_sidecar_read + .globl _rom_cartridge_read + + .globl _romd_mode + .globl _romd_addr + .globl _romd_size + .globl _romd_off + + .globl map_process_save + .globl map_kernel_restore + + .area _COMMONMEM + +_rom_sidecar_read: + ld a, (_romd_mode) + or a + push af + call nz, map_process_save + xor a + out (0x90), a ; low byte is always zero + ld hl, #_romd_off + ld de, (_romd_size) ; Always multiple of 512 - don't need low FIXME +rom_sc_loop: + ld a, (hl) + out (0x91), a ; mid byte + inc hl + ld a, (hl) + out (0x92), a ; top + ld bc, #0x93 ; port 93, 256 repeats + ld hl, (_romd_addr) + inir ; copy 256 + dec d + jr z, rom_sc_done + ld (_romd_addr), hl ; save pointer + ld hl, #_romd_off + inc (hl) ; next page + jr rom_sc_loop +rom_sc_done: + pop af + ret z + jp map_kernel_restore + + +_rom_cartridge_read: + ld a, (_romd_mode) + or a +rom_cr1: + push af + call nz, map_process_save + xor a + out (0x10), a ; low byte is always zero + ld hl, #_romd_off + ld de, (_romd_size) ; Always multiple of 512 - don't need low FIXME +rom_ca_loop: + ld a, (hl) + out (0x11), a ; mid byte + ld bc, #0x10 ; port 10, 256 repeats + ld hl, (_romd_addr) +rom_ca_cp: + out (c), b ; set low byte + in a, (0x12) ; fetch from ROM + ld (hl), a ; save + inc hl + inc b + jr nz, rom_ca_cp ; For the 256 byte block + dec d + jr z, rom_ca_done + ld (_romd_addr), hl ; save pointer + ld hl, #_romd_off + inc (hl) ; next page + jr rom_ca_loop +rom_ca_done: + pop af + ret z + jp map_kernel_restore + diff --git a/Kernel/platform-px4plus/sio.c b/Kernel/platform-px4plus/sio.c new file mode 100644 index 00000000..53e44a12 --- /dev/null +++ b/Kernel/platform-px4plus/sio.c @@ -0,0 +1,43 @@ +#include +#include + +__sfr __at 0x00 baudrate; +__sfr __at 0x15 artmr; + +/* Select SIO */ +int select_sio(void) +{ + /* FIXME: save old modem bits, baud etc. We can't do this via hw + so probably need some kind of tty callbacks here */ + baudrate = 0xB0; /* 38400 */ + artmr = 0x04; /* 8N1 */ + /* FIXME: disable ART IRQ */ + return 0; +} + +void deselect_sio(int old) +{ + /* FIXME */ + used(old); +} + +__sfr __at 0x14 artwr; +__sfr __at 0x15 artsr; + +void sio_write(uint8_t *buf, int len) +{ + while(len--) { + while(!(artsr & 1)); + artwr = *buf++; + } +} + +int sio_read(uint8_t *buf, int len) +{ + /* FIXME: timeouts etc */ + while(len--) { + while(!(artsr & 2)) + *buf++ = artwr; + } + return 0; +} diff --git a/Kernel/platform-px4plus/sio.h b/Kernel/platform-px4plus/sio.h new file mode 100644 index 00000000..260f3b34 --- /dev/null +++ b/Kernel/platform-px4plus/sio.h @@ -0,0 +1,13 @@ +#ifndef _DEV_SIO_H +#define _DEV_SIO_H + +extern int select_sio(void); +extern void deselect_sio(int old); + +extern void sio_write(uint8_t *buf, int len); +extern int sio_read(uint8_t *buf, int len); + +/* These don't truely belong here but it will do for now */ +extern void read_from_bank(uint16_t bank, uint16_t dptr, uint8_t *buf, uint16_t len); + +#endif \ No newline at end of file diff --git a/Kernel/platform-px4plus/swapdev.s b/Kernel/platform-px4plus/swapdev.s new file mode 100644 index 00000000..de6397e4 --- /dev/null +++ b/Kernel/platform-px4plus/swapdev.s @@ -0,0 +1,214 @@ +; +; Support code for swap device activity +; + + .globl _cartridge_copy + .globl _cartridge_size + .globl _sidecar_copy + + .globl _make_mapped + + .globl _map_translate + .globl _map_live + + + .area _COMMONMEM + +; +; A holds the bank to use (1 = RAM 2/3 for cartridge 128+ sidecar +; +_cartridge_copy: + push bc + push de + push hl + ld de, #0x80 ; d is top half of I/O offset, e is the + ; block counter + cp #2 + jr z, lowcopy + ld d, #0x80 +lowcopy: + ld hl, #0x5D00 +cart_copy: + ld a, d + out (0x11), a ; high byte + ld bc, #0x10 ; port 10, 256 repeats +cart_copy256: + out (c), b ; set low byte to access + ld a, (hl) + out (0x12), a ; write to cartridge + inc hl + inc b + jr nz, cart_copy256 + inc d ; move on a page + dec e + jr nz, cart_copy + pop hl + pop de + pop bc + ret + +; +; Exchange the process in bank a with the process in RAM +; +_cartridge_exchange: + push bc + push de + push hl + ld de, #0x80 ; d is top half of I/O offset, e is the + ; block counter + cp #2 + jr z, lowx + ld d, #0x80 +lowx: + ld hl, #0x5D00 +cart_x: + ld a, d + out (0x11), a ; high byte + ld bc, #0x10 ; port 10, 256 repeats +cart_x256: + out (c), b ; set low byte to access + in a, (0x12) ; existing byte + push af + ld a, (hl) + out (0x12), a ; write to cartridge + pop af + ld (hl), a ; write to RAM + inc hl + inc b + jr nz, cart_x256 + inc d ; move on a page + dec e + jr nz, cart_x + pop hl + pop de + pop bc + ret + + + .area _CODE + +_cartridge_size: + ld c, #0xA512 + xor a + out (0x11), a ; low byte 0 + ld a, #0x40 + out (0x10), a ; address 0x4000 selected + out (c), b + in a, (0x12) + cp b + jr nz, size16 + ld a, #0x80 + out (0x10), a + out (c), b + in a, (0x12) + cp b + jr nz, size32 + ld hl, #64 + ret +size16: + ld hl, #16 + ret +size32: + ld hl, #32 + ret + + .area _COMMONMEM + +_sidecar_copy: + push bc + push de + push hl + and #0x7F ; strip the magic bit for the bank code + ld e, #0 + rra + rl e + ld d, #0x80 + out (0x92), a ; pick the right 64K bank + ld hl, #0x5D00 ; memory area to process + xor a + out (0x90), a ; align the low byte on the page boundary +sidecar_cnext: + ld a, e + out (0x91), a ; mid part of the address + ld bc, #0x94 ; 256 bytes into 0x94 + otir ; also adjusts HL for us + inc e ; next page + dec d ; count of pages to do + jr nz, sidecar_cnext + pop hl + pop de + pop bc + ret + +_sidecar_exchange: + push bc + push de + push hl + and #0x7F ; strip the magic bit for the bank code + ld e, #0 + rra + rl e + ld d, #0x80 + out (0x92), a ; pick the right 64K bank + ld hl, #0x5D00 ; memory area to process +sidecar_xnext: + ld a, e + out (0x91), a ; mid part of the address + ld bc, #0x90 ; 256 bytes into 0x94 +; +; FIXME: this loop wants optimising properly +; +sidecar_xnl: + out (c), b ; set low byte + in a, (0x12) + out (c), b ; it auto-increments so put it back + push af + ld a, (hl) + out (0x12), a + pop af + ld (hl), a + inc hl + inc b + jr nz, sidecar_xnl + inc e ; next page + dec d ; count of pages to do + jr nz, sidecar_xnext + pop hl + pop de + pop bc + ret + +; +; Make the requested process the current one in memory. We use this +; on task switching but also on the floppy I/O when swapping in or +; out. Preserves DE. +; +_make_mapped: + ld c, a + ld b, #0 + ld hl, #_map_translate + add hl, bc + ld a, (hl) ; Are we in RAM ? + cp #1 + ret z + ; + ; We need to do an exchange + ; + push de + ld de, (_map_live) ; current RAM owner + ld (de), a ; current owner gets our page + ld (hl), #1 ; we get its page + + bit 7, a + jr z, in_sidecar + ; + ; We are in the cartridge + ; Swap ourselves with whoever is current RAM task + ; + call _cartridge_exchange + jr in_memory2 +in_sidecar: + call _sidecar_exchange +in_memory2: + pop de ; recover task pointer + ret diff --git a/Kernel/platform-px4plus/tricks.s b/Kernel/platform-px4plus/tricks.s index 00a546e3..d6f1a565 100644 --- a/Kernel/platform-px4plus/tricks.s +++ b/Kernel/platform-px4plus/tricks.s @@ -19,6 +19,12 @@ .globl _swapper .globl _swapout + .globl _map_translate + .globl _map_live + .globl _sidecar_copy + .globl _cartridge_copy + .globl _make_mapped + ; imported debug symbols .globl outstring, outde, outhl, outbc, outnewline, outchar, outcharhex @@ -89,25 +95,24 @@ _switchin: add hl, de ; process ptr pop de - ld a, (hl) + ; + ; Always use the swapstack, otherwise when we call map_kernel + ; having copied the udata stash back to udata we will crap + ; somewhere up the stackframe and it's then down to luck + ; if those bytes are discarded or not. + ; + ; Yes - this was a bitch to debug, please don't break it ! + ; + ld sp, #_swapstack + ld a, (hl) or a jr nz, not_swapped ; - ; We are still on the departing processes stack, which is - ; fine for now. + ; Let the swapper run ; - ld sp, #_swapstack push hl - ; We will always swap out the current process - ld hl, (U_DATA__U_PTAB) - push hl - push af - call _swapout - pop af - pop hl - pop hl push de push af call _swapper @@ -116,8 +121,17 @@ _switchin: pop hl ld a, (hl) -not_swapped: +not_swapped: + ; + ; On the PX4 this is only half the game. The process we want + ; is probably stuffed into the sidecar or cartridge + ; + ; Make bank A mapped bank. Preserves DE, trashes AF,BC,HL + ; + call _make_mapped + ; ; check u_data->u_ptab matches what we wanted + ; ld hl, (U_DATA__U_PTAB) ; u_data->u_ptab or a ; clear carry flag sbc hl, de ; subtract, result will be zero if DE==IX @@ -201,15 +215,26 @@ _dofork: ; now we're in a safe state for _switchin to return in the parent ; process. - ld hl, (U_DATA__U_PTAB) - push hl + ; now the copy operation is complete we can get rid of the stuff + ; _switchin will be expecting from our copy of the stack. + ; --------- copy process --------- + + ld hl, (fork_proc_ptr) + ld de, #P_TAB__P_PAGE_OFFSET + add hl, de + ; load p_page + ld c, (hl) + ; load existing page ptr push af - call _swapout + ld a, c + call outcharhex pop af - pop hl + ld a, (U_DATA__U_PAGE) + + call bankfork ; do the bank to bank copy + + ; Fix up stack - ; now the copy operation is complete we can get rid of the stuff - ; _switchin will be expecting from our copy of the stack. pop bc pop bc pop bc @@ -231,6 +256,43 @@ _dofork: ; to be the live uarea. The parent is frozen in time and space as ; if it had done a switchout(). ret + +; +; A is the parent C is the child bank. Both of these are of course +; logical banks. The logical bank of A right now is 1 (in memory), +; but this will all change +; +; We do a copy to the I/O mapped sidecar or cartridge rather than the +; usual LDIR. We also update our logical mapping table as we +; effectively swapped ram between parent and child. +; +bankfork: + push af + ld b, #0 + ld hl, #_map_translate + add hl, bc + push hl + ld a, (hl) + bit 7, a + jr nz, copy_to_sidecar + ; + ; Forking to cartridge + ; + call _cartridge_copy + jr bankcopy_done +copy_to_sidecar: + call _sidecar_copy +bankcopy_done: + pop hl ; child translation entry + ld a, (hl) ; entry that was allocated + ld (hl), #1 ; child is now main memory + ld de, (_map_live) ; parent entry + ld (de), a ; parent now gets "new" entry as child has + ; the RAM + ld (_map_live), hl ; live task map + ld b, #0 + pop af + ret ; ; We can keep a stack in common because we will complete our ; use of it before we switch common block. In this case we have -- 2.34.1