From 743f3fae3a5c80575af426dc748d1ec087eac6f4 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Tue, 27 Nov 2018 12:51:23 +0000 Subject: [PATCH] tc2068: initial upload of the TC2068 support This is just an initial cut - it's got lots that needs fixing (like Timex video mode support) and it currently has some memory corruption bugs that need nailing. --- Kernel/platform-tc2068/Makefile | 51 ++++ Kernel/platform-tc2068/README | 66 ++++ Kernel/platform-tc2068/commonmem.s | 8 + Kernel/platform-tc2068/config.h | 73 +++++ Kernel/platform-tc2068/crt0.s | 117 +++++++ Kernel/platform-tc2068/devices.c | 45 +++ Kernel/platform-tc2068/devinput.c | 103 +++++++ Kernel/platform-tc2068/devinput.h | 2 + Kernel/platform-tc2068/devtty.c | 148 +++++++++ Kernel/platform-tc2068/devtty.h | 19 ++ Kernel/platform-tc2068/discard.c | 43 +++ Kernel/platform-tc2068/fuzix.lnk | 48 +++ Kernel/platform-tc2068/kernel.def | 14 + Kernel/platform-tc2068/loader-divide.s | 142 +++++++++ Kernel/platform-tc2068/main.c | 69 +++++ Kernel/platform-tc2068/platform_ide.h | 29 ++ Kernel/platform-tc2068/rules.mk | 1 + Kernel/platform-tc2068/target.mk | 1 + Kernel/platform-tc2068/tc2068.s | 200 ++++++++++++ Kernel/platform-tc2068/tricks.s | 5 + Kernel/platform-tc2068/zxvideo.s | 405 +++++++++++++++++++++++++ 21 files changed, 1589 insertions(+) create mode 100644 Kernel/platform-tc2068/Makefile create mode 100644 Kernel/platform-tc2068/README create mode 100644 Kernel/platform-tc2068/commonmem.s create mode 100644 Kernel/platform-tc2068/config.h create mode 100644 Kernel/platform-tc2068/crt0.s create mode 100644 Kernel/platform-tc2068/devices.c create mode 100644 Kernel/platform-tc2068/devinput.c create mode 100644 Kernel/platform-tc2068/devinput.h create mode 100644 Kernel/platform-tc2068/devtty.c create mode 100644 Kernel/platform-tc2068/devtty.h create mode 100644 Kernel/platform-tc2068/discard.c create mode 100644 Kernel/platform-tc2068/fuzix.lnk create mode 100644 Kernel/platform-tc2068/kernel.def create mode 100644 Kernel/platform-tc2068/loader-divide.s create mode 100644 Kernel/platform-tc2068/main.c create mode 100644 Kernel/platform-tc2068/platform_ide.h create mode 100644 Kernel/platform-tc2068/rules.mk create mode 100644 Kernel/platform-tc2068/target.mk create mode 100644 Kernel/platform-tc2068/tc2068.s create mode 100644 Kernel/platform-tc2068/tricks.s create mode 100644 Kernel/platform-tc2068/zxvideo.s diff --git a/Kernel/platform-tc2068/Makefile b/Kernel/platform-tc2068/Makefile new file mode 100644 index 00000000..7c03dea3 --- /dev/null +++ b/Kernel/platform-tc2068/Makefile @@ -0,0 +1,51 @@ +CSRCS = devtty.c devices.c main.c devinput.c +CDSRCS = discard.c +DSRCS = ../dev/devide.c ../dev/blkdev.c +DDSRCS = ../dev/devide_discard.c ../dev/mbr.c +DZSRCS = ../dev/zx/divide.c ../dev/zx/zxkeyboard.c +DDZSRCS = +ASRCS = crt0.s tc2068.s zxvideo.s +ASRCS += tricks.s commonmem.s loader-divide.s + +COBJS = $(CSRCS:.c=.rel) +CDOBJS = $(CDSRCS:.c=.rel) +AOBJS = $(ASRCS:.s=.rel) +DOBJS = $(patsubst ../dev/%.c,%.rel, $(DSRCS)) +DDOBJS = $(patsubst ../dev/%.c,%.rel, $(DDSRCS)) +DZOBJS = $(patsubst ../dev/zx/%.c,%.rel, $(DZSRCS)) +DDZOBJS = $(patsubst ../dev/zx/%.c,%.rel, $(DDZSRCS)) +OBJS = $(COBJS) $(CDOBJS) $(AOBJS) $(DOBJS) $(DDOBJS) $(DZOBJS) $(DDZOBJS) + +CROSS_CCOPTS += -I../dev/ -I../dev/zx/ + +CROSS_CC_SEG3 = --codeseg CODE3 + +all: $(OBJS) + +$(COBJS): %.rel: %.c + $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_SEG3) -c $< + +$(CDOBJS): %.rel: %.c + $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_SEGDISC) -c $< + +$(DOBJS): %.rel: ../dev/%.c + $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_SEG3) -c $< + +$(DDOBJS): %.rel: ../dev/%.c + $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_SEGDISC) -c $< + +$(DZOBJS): %.rel: ../dev/zx/%.c + $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_SEG3) -c $< + +$(DDZOBJS): %.rel: ../dev/zx/%.c + $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_SEGDISC) -c $< + +$(AOBJS): %.rel: %.s + $(CROSS_AS) $(ASOPTS) $< + +clean: + rm -f $(OBJS) *.lst *.asm *.sym *.rst *.rel core *~ + +image: + ../tools/makedck ../fuzix.bin fuzix.dck + dd if=../fuzix.bin of=fuzix.load bs=32768 count=1 diff --git a/Kernel/platform-tc2068/README b/Kernel/platform-tc2068/README new file mode 100644 index 00000000..dbaeadea --- /dev/null +++ b/Kernel/platform-tc2068/README @@ -0,0 +1,66 @@ +Experimental porting work for the TS2068 and TC2068 Timex spectrum like +systems. + +Not yet usable (eats itself with memory corruption) + +---- + +This port requires a TC2068/TS2068 system with a 64K cartridge configured +with the low 32K RAM and high 32K ROM (or all battery backed RAM also works +of course except maybe in the reboot case) + +At the moment you need a DivIDE interface and twister attached to the +machine in order to boot it, as it will load the low 32K from the CF card +boot area. The DivIDE needs to be set to not interfere with boot in order +to run with a TC2068/TS2068 system without the spectrum ROM compatibility +cartridge. + +Memory is laid out as follows + +Kernel mode + +0000-3FFF Dock RAM - common and other kernel data +4000-7FFF Dock RAM - kernel data +8000-FFFF Dock ROM - kernel boot and kernel code + +Video updating + +0000-3FFF Dock RAM - common and other kernel data + (including font and video) +4000-7FFF Home RAM - screens +8000-FFFF Dock ROM - kernel boot and kernel code + +User mode + +0000-3FFF Dock RAM - common and other kernel data +4000-77FF Home RAM - screens +7800-FFFF Home RAM - user space + +(if we kept to the 256 pixel screen we can go to a much bigger user space) + + +If using with FUSE then create an hdf file for the disk, add a filesystem +image to it and then + dd if=fuzix.load of=tc2068.hdf bs=1046 seek=1 conv=notrunc + +to place it in blocks 1+ after the partition table (in the gap left for loaders) + +For real media just change the offset so as not to include the 534 bytes of +header on the hdf file. + +Make a copy of the media as right now it eats the disks ! + + +Debugging state: + +Looks like we may have some obscure interrupt corruption case or similar +(we bomb weirdly late on or see a bit of random display corruption and +fsck fails part way with corruption like results) + +Need to try cutting down IRQ handler. One mess was on the video display which +suggests whatever happened occurred with the video mapped at one point (same +char was later printed correctly) + +Disabling pre-empt doesn't help and fsck shows corruption in execution which +suggests its not task switch related + diff --git a/Kernel/platform-tc2068/commonmem.s b/Kernel/platform-tc2068/commonmem.s new file mode 100644 index 00000000..dc31c24e --- /dev/null +++ b/Kernel/platform-tc2068/commonmem.s @@ -0,0 +1,8 @@ +; +; Multiple app sizes and the fact the kernel and apps share the same banks +; means we need to put this somewhere low +; + .module commonmem + .area _COMMONDATA + + .include "../cpu-z80/std-commonmem.s" diff --git a/Kernel/platform-tc2068/config.h b/Kernel/platform-tc2068/config.h new file mode 100644 index 00000000..54d28ab0 --- /dev/null +++ b/Kernel/platform-tc2068/config.h @@ -0,0 +1,73 @@ +#define CONFIG_IDE +#define CONFIG_LARGE_IO_DIRECT /* We support direct to user I/O */ + +/* Enable to make ^Z dump the inode table for debug */ +#undef CONFIG_IDUMP +/* Enable to make ^A drop back into the monitor */ +#undef CONFIG_MONITOR +/* Profil syscall support (not yet complete) */ +#define CONFIG_PROFIL +/* Multiple processes in memory at once */ +#define CONFIG_MULTI +/* Single tasking */ +#undef CONFIG_SINGLETASK +/* CP/M emulation */ +#undef CONFIG_CPM_EMU + +/* Input layer support */ +#define CONFIG_INPUT +#define CONFIG_INPUT_GRABMAX 3 +/* Video terminal, not a serial tty */ +#define CONFIG_VT +/* Keyboard contains non-ascii symbols */ +#define CONFIG_UNIKEY +#define CONFIG_FONT8X8 +#define CONFIG_FONT8X8SMALL + +/* Swap based one process in RAM */ +#define CONFIG_SWAP_ONLY +#define CONFIG_SPLIT_UDATA +#define UDATA_BLKS 1 +#define UDATA_SIZE 0x200 +#define CONFIG_DYNAMIC_BUFPOOL +#define CONFIG_DYNAMIC_SWAP + +/* Custom banking */ + +/* Banks as reported to user space */ +#define CONFIG_BANKS 1 + +/* Vt definitions */ +#define VT_WIDTH 32 +#define VT_HEIGHT 24 +#define VT_RIGHT 31 +#define VT_BOTTOM 23 + +#define TICKSPERSEC 50 /* Ticks per second */ +#define PROGBASE 0x7800 /* also data base */ +#define PROGLOAD 0x7800 /* also data base */ +#define PROGTOP 0xFE00 /* Top of program, below high page */ + /* Can probably use to FFFF FIXME */ + +#define BOOT_TTY (513) /* Set this to default device for stdio, stderr */ + /* In this case, the default is the first TTY device */ + +/* We need a tidier way to do this from the loader */ +#define CMDLINE NULL /* Location of root dev name */ + +/* Device parameters */ +#define NUM_DEV_TTY 1 + +#define TTYDEV BOOT_TTY /* Device used by kernel for messages, panics */ +#define NBUFS 5 /* Number of block buffers */ +#define NMOUNTS 4 /* Number of mounts at a time */ +#define MAX_BLKDEV 4 /* 2 IDE drives, 2 SD drive */ + +#define SWAPBASE 0x7800 +#define SWAPTOP 0xFE00UL +#define SWAP_SIZE 0x44 +#define MAX_SWAPS 16 +#define SWAPDEV (swap_dev) /* Device for swapping (dynamic). */ + +/* We swap by hitting the user map */ +#define swap_map(x) ((uint8_t *)(x)) diff --git a/Kernel/platform-tc2068/crt0.s b/Kernel/platform-tc2068/crt0.s new file mode 100644 index 00000000..ab70d163 --- /dev/null +++ b/Kernel/platform-tc2068/crt0.s @@ -0,0 +1,117 @@ + .module crt0 + + ; + ; High space - read only + ; + + .area _CODE + .area _CODE2 + ; + ; Tru and keep code in the top 32K + ; + + + ; + ; Our common lives low + ; + .area _COMMONDATA + .area _COMMONMEM + .area _CODE3 + .area _FONT + .area _VIDEO ; must end below 0x4000 + .area _INITIALIZED + .area _HOME + .area _CONST + + ; + ; Beyond this point we just zero. + ; + + .area _DATA + .area _BSEG + .area _BSS + .area _HEAP + .area _GSINIT + .area _GSFINAL + ; + ; Finally the buffers so they can expand + ; + .area _BUFFERS + + .area _DISCARD + ; Somewhere to throw it out of the way + .area _INITIALIZER + + + + ; imported symbols + .globl _fuzix_main + .globl init_early + .globl init_hardware + .globl l__BUFFERS + .globl s__BUFFERS + .globl l__DATA + .globl s__DATA + .globl kstack_top + + .globl unix_syscall_entry + .globl nmi_handler + .globl interrupt_handler + + .include "../kernel.def" + .include "kernel.def" + + ; + ; startup code + ; + ; We loaded the rest of the kernel from disk and jumped here + ; + + .area _CODE + + .globl _start + +_start: + + di + + ; We need to wipe the BSS but the rest of the job is done. + + ld hl, #s__DATA + ld de, #s__DATA+1 + ld bc, #l__DATA-1 + ld (hl), #0 + ldir + ld hl, #s__BUFFERS + ld de, #s__BUFFERS+1 + ld bc, #l__BUFFERS-1 + ld (hl), #0 + ldir + + ld sp, #kstack_top + + ; Configure memory map + call init_early + + ; Hardware setup + call init_hardware + + ; Call the C main routine + call _fuzix_main + + ; main shouldn't return, but if it does... + di +stop: halt + jr stop + + .area _BUFFERS +; +; Buffers (we use asm to set this up as we need them in a special segment +; so we can recover the discard memory into the buffer pool +; + + .globl _bufpool + .area _BUFFERS + +_bufpool: + .ds BUFSIZE * NBUFS diff --git a/Kernel/platform-tc2068/devices.c b/Kernel/platform-tc2068/devices.c new file mode 100644 index 00000000..90c608d1 --- /dev/null +++ b/Kernel/platform-tc2068/devices.c @@ -0,0 +1,45 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct devsw dev_tab[] = /* The device driver switch table */ +{ + /* 0: /dev/hd Hard disc block devices */ + { blkdev_open, no_close, blkdev_read, blkdev_write, blkdev_ioctl }, + /* 1: /dev/fd Floppy disc block devices: nope */ + { no_open, no_close, no_rdwr, no_rdwr, no_ioctl }, + /* 2: /dev/tty TTY devices */ + { tty_open, tty_close, tty_read, tty_write, gfx_ioctl }, + /* 3: /dev/lpr Printer devices */ + { no_open, no_close, no_rdwr, no_rdwr, no_ioctl }, + /* 4: /dev/mem etc System devices (one offs) */ + { no_open, no_close, sys_read, sys_write, sys_ioctl }, + /* 5: Pack to 7 with nxio if adding private devices and start at 8 */ +}; + +bool validdev(uint16_t dev) +{ + /* This is a bit uglier than needed but the right hand side is + a constant this way */ + if(dev > ((sizeof(dev_tab)/sizeof(struct devsw)) << 8) - 1) + return false; + else + return true; +} + +void device_init(void) +{ +#ifdef CONFIG_IDE + devide_init(); +#endif +#ifdef CONFIG_SD + devsd_init(); +#endif +} diff --git a/Kernel/platform-tc2068/devinput.c b/Kernel/platform-tc2068/devinput.c new file mode 100644 index 00000000..179e973c --- /dev/null +++ b/Kernel/platform-tc2068/devinput.c @@ -0,0 +1,103 @@ +/* + * Joysticks off the AY sound chip + */ +#include +#include +#include +#include + +static uint8_t ay_p1_save, ay_p2_save; + +__sfr __at 0xF5 ay_reg; +__sfr __banked __at 0x01F6 ay_player1; +__sfr __banked __at 0x02F6 ay_player2; + +static char buf[32]; + +static struct s_queue kqueue = { + buf, buf, buf, sizeof(buf), 0, sizeof(buf) / 2 +}; + +/* Queue a character to the input device */ +void queue_input(uint8_t c) +{ + insq(&kqueue, c); + wakeup(&kqueue); +} + +static uint8_t ay_encode(uint8_t r) +{ + uint8_t k = 0; + r = ~r; + if (r & 1) + k = STICK_DIGITAL_U; + if (r & 2) + k |= STICK_DIGITAL_D; + if (r & 4) + k |= STICK_DIGITAL_L; + if (r & 8) + k |= STICK_DIGITAL_R; + if (r & 128) + k |= BUTTON(0); + return k; +} + +static uint8_t ay_js(uint8_t *slot) +{ + uint8_t r = ay_player1; + if (r == ay_p1_save) + return 0; + ay_p1_save = r; + *slot++ = STICK_DIGITAL; + *slot = ay_encode(r); + return 2; +} + +static uint8_t ay_js2(uint8_t *slot) +{ + uint8_t r = ay_player2; + if (r == ay_p2_save) + return 0; + ay_p2_save = r; + *slot++ = STICK_DIGITAL | 1; + *slot = ay_encode(r); + return 2; +} + +int platform_input_read(uint8_t *slot) +{ + uint8_t r, k; + if (remq(&kqueue, &r)) { + remq(&kqueue, &k); + *slot++ = KEYPRESS_CODE | r; + *slot = k; + return 2; + } + + ay_reg = 0x0E; + if (ay_js(slot)) + return 2; + if (ay_js2(slot)) + return 2; + return 0; +} + +void platform_input_wait(void) +{ + psleep(&kqueue); /* We wake this on timers so it works for sticks */ +} + +int platform_input_write(uint8_t flag) +{ + flag; + udata.u_error = EINVAL; + return -1; +} + +void poll_input(void) +{ + ay_reg=0x0E; + if (ay_player1 != ay_p1_save || ay_player2 != ay_p2_save) + wakeup(&kqueue); +} + \ No newline at end of file diff --git a/Kernel/platform-tc2068/devinput.h b/Kernel/platform-tc2068/devinput.h new file mode 100644 index 00000000..981f7024 --- /dev/null +++ b/Kernel/platform-tc2068/devinput.h @@ -0,0 +1,2 @@ +extern void queue_input(uint8_t); +extern void poll_input(void); diff --git a/Kernel/platform-tc2068/devtty.c b/Kernel/platform-tc2068/devtty.c new file mode 100644 index 00000000..36ac5d3c --- /dev/null +++ b/Kernel/platform-tc2068/devtty.c @@ -0,0 +1,148 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +char tbuf1[TTYSIZ]; + +uint8_t vtattr_cap = VTA_INVERSE|VTA_FLASH|VTA_UNDERLINE; +extern uint8_t curattr; + +static tcflag_t console_mask[4] = { + _ISYS, + _OSYS, + _CSYS, + _LSYS +}; + +tcflag_t *termios_mask[NUM_DEV_TTY + 1] = { + NULL, + console_mask +}; + + +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}, +}; + +/* tty1 is the screen */ + +/* Output for the system console (kprintf etc) */ +void kputchar(char c) +{ + if (c == '\n') + tty_putc(0, '\r'); + tty_putc(0, c); +} + +/* Both console and debug port are always ready */ +ttyready_t tty_writeready(uint8_t minor) +{ + minor; + return TTY_READY_NOW; +} + +void tty_putc(uint8_t minor, unsigned char c) +{ + minor; + vtoutput(&c, 1); +} + +int tty_carrier(uint8_t minor) +{ + minor; + return 1; +} + +void tty_setup(uint8_t minor, uint8_t flags) +{ + minor; +} + +void tty_sleeping(uint8_t minor) +{ + minor; +} + +void tty_data_consumed(uint8_t minor) +{ +} + + +/* This is used by the vt asm code, but needs to live in the kernel */ +uint16_t cursorpos; + +static struct display specdisplay = { + 0, + 256, 192, + 256, 192, + 0xFF, 0xFF, + FMT_SPECTRUM, + HW_UNACCEL, + GFX_VBLANK|GFX_MAPPABLE|GFX_TEXT, + 0 +}; + +static struct videomap specmap = { + 0, + 0, + 0x4000, + 6912, + 0, + 0, + 0, + MAP_FBMEM|MAP_FBMEM_SIMPLE +}; + +/* + * Graphics ioctls. Very minimal for this platform. It's a single fixed + * mode with direct memory mapping. + */ +int gfx_ioctl(uint8_t minor, uarg_t arg, char *ptr) +{ + if (minor != 1 || arg >> 8 != 0x03) + return vt_ioctl(minor, arg, ptr); + switch(arg) { + case GFXIOC_GETINFO: + return uput(&specdisplay, ptr, sizeof(struct display)); + case GFXIOC_MAP: + return uput(&specmap, ptr, sizeof(struct videomap)); + case GFXIOC_UNMAP: + return 0; + case GFXIOC_WAITVB: + /* Our system clock is vblank */ + timer_wait++; + psleep(&timer_interrupt); + timer_wait--; + chksigs(); + if (udata.u_cursig) { + udata.u_error = EINTR; + return -1; + } + return 0; + } + return -1; +} + +void vtattr_notify(void) +{ + /* Attribute byte fixups: not hard as the colours map directly + to the spectrum ones */ + if (vtattr & VTA_INVERSE) + curattr = ((vtink & 7) << 3) | (vtpaper & 7); + else + curattr = (vtink & 7) | ((vtpaper & 7) << 3); + if (vtattr & VTA_FLASH) + curattr |= 0x80; + /* How to map the bright bit - we go by either */ + if ((vtink | vtpaper) & 0x10) + curattr |= 0x40; +} diff --git a/Kernel/platform-tc2068/devtty.h b/Kernel/platform-tc2068/devtty.h new file mode 100644 index 00000000..40a67f5c --- /dev/null +++ b/Kernel/platform-tc2068/devtty.h @@ -0,0 +1,19 @@ +#ifndef __DEVTTY_DOT_H__ +#define __DEVTTY_DOT_H__ + +void tty_pollirq(void); +static void keydecode(void); + +#define KEY_ROWS 8 +#define KEY_COLS 5 +extern uint8_t keymap[8]; +extern uint8_t keyboard[8][5]; +extern uint8_t shiftkeyboard[8][5]; + +extern uint8_t timer_wait; + +extern int gfx_ioctl(uint8_t minor, uarg_t arg, char *ptr); + +extern uint8_t vtborder; + +#endif diff --git a/Kernel/platform-tc2068/discard.c b/Kernel/platform-tc2068/discard.c new file mode 100644 index 00000000..724a24f4 --- /dev/null +++ b/Kernel/platform-tc2068/discard.c @@ -0,0 +1,43 @@ +#include +#include +#include +#include +#include +#include + +uint8_t platform_param(char *p) +{ + return 0; +} + +/* Nothing to do for the map of init */ +void map_init(void) +{ +} + +void platform_copyright(void) +{ +} + +/* + * This function is called for partitioned devices if a partition is found + * and marked as swap type. The first one found will be used as swap. We + * only support one swap device. + */ +void platform_swap_found(uint8_t letter, uint8_t m) +{ + blkdev_t *blk = blk_op.blkdev; + uint16_t n; + if (swap_dev != 0xFFFF) + return; + letter -= 'a'; + kputs("(swap) "); + swap_dev = letter << 4 | m; + n = blk->lba_count[m - 1] / SWAP_SIZE; + if (n > MAX_SWAPS) + n = MAX_SWAPS; +#ifdef SWAPDEV + while (n) + swapmap_init(n--); +#endif +} diff --git a/Kernel/platform-tc2068/fuzix.lnk b/Kernel/platform-tc2068/fuzix.lnk new file mode 100644 index 00000000..9f25f92b --- /dev/null +++ b/Kernel/platform-tc2068/fuzix.lnk @@ -0,0 +1,48 @@ +-mwxuy +-i fuzix.ihx +-l z80 +-b _CODE=0x8000 +-b _COMMONDATA=0x0080 +platform-tc2068/loader-divide.rel +platform-tc2068/crt0.rel +platform-tc2068/commonmem.rel +platform-tc2068/tc2068.rel +platform-tc2068/zxvideo.rel +platform-tc2068/main.rel +platform-tc2068/discard.rel +start.rel +version.rel +lowlevel-z80.rel +usermem_std-z80.rel +platform-tc2068/tricks.rel +timer.rel +kdata.rel +usermem.rel +platform-tc2068/devices.rel +devio.rel +filesys.rel +process.rel +inode.rel +syscall_exec16.rel +syscall_fs.rel +syscall_fs2.rel +syscall_fs3.rel +syscall_proc.rel +syscall_other.rel +tty.rel +vt.rel +font8x8.rel +mm.rel +simple.rel +swap.rel +devsys.rel +devinput.rel +platform-tc2068/devtty.rel +platform-tc2068/devide.rel +platform-tc2068/devide_discard.rel +platform-tc2068/divide.rel +platform-tc2068/mbr.rel +platform-tc2068/blkdev.rel +platform-tc2068/devinput.rel +platform-tc2068/zxkeyboard.rel +-e diff --git a/Kernel/platform-tc2068/kernel.def b/Kernel/platform-tc2068/kernel.def new file mode 100644 index 00000000..470f4d56 --- /dev/null +++ b/Kernel/platform-tc2068/kernel.def @@ -0,0 +1,14 @@ +; UZI mnemonics for memory addresses etc + +; We stick it straight after the tag +U_DATA .equ 0x0080 ; (this is struct u_data from kernel.h) +U_DATA__TOTALSIZE .equ 0x200 ; 256+256+256 bytes. + +Z80_TYPE .equ 1 + +PROGBASE .equ 0x7800 +PROGLOAD .equ 0x7800 + +NBUFS .equ 5 + +Z80_MMU_HOOKS .equ 0 diff --git a/Kernel/platform-tc2068/loader-divide.s b/Kernel/platform-tc2068/loader-divide.s new file mode 100644 index 00000000..42aed5f8 --- /dev/null +++ b/Kernel/platform-tc2068/loader-divide.s @@ -0,0 +1,142 @@ +; +; We are run from the ROM start of the cartridge. Because this is a +; TS2068/TC2068 the DivIDE will have the ROM paging disabled +; + .area _CODE + + + .globl _start + + .globl boot + +; +; From 0x8000 +; +; AROS header + + .byte 0x02 ; Machine code + .byte 0x02 ; AROS + .word boot ; address to run + .byte 0x0f ; page us in the top 32K please (our ROM) + .byte 0x01 ; autostart + .word 0x0021 ; reserve us no memory (yet another crappy + ; 2068 bug) +boot: + ; We are entered with cartridge ROM in the top 32K, system RAM in + ; the low 32K + + di ; we are going to blow stuff away + ; Hide the screen contents + ld hl,#0x5800 + ld de,#0x5801 + ld bc,#0x02FF + ld (hl),#0 + ldir + + ld sp,#0x8000 ; We don't load 7E00-7FFF right now + + ; Black border + xor a + out (254),a + + ; + ; The kernel needs cartridge RAM mapped in 0x0000-7FFF + ; and cartridge ROM to 8000-FFFF + ; + ld a,#0xFF + out (0xF4),a + + ; + ; Ensure the master drive is selected + ; +wait1: + in a,(191) + rla + jr c, wait1 + ld a,#0xE0 + out (187),a + nop +wait2: + in a,(191) + and #0xC0 + cp #0x40 ; want busy off, drdy + jr nz, wait2 + + ; + ; Load sectors. We shortcut stuff here because we never + ; load over 256 sectors + ; + ; Most stuff is in ROM already. We just need to load the + ; remaining chunk from 0000-3FFF and 5B00-7FFF (and it's easier + ; just to load through the screen) + ; + xor a ; LBA28 high bits + out (179),a + out (183),a + + ld de,#0x3F01 ; Load 63 sectors + ; from sector 1 + ld hl,#0x0000 ; Starting address to load + +load_loop: + ld a,e + inc e + out (175),a ; sector number to load + ld a,#1 ; load one sector + out (171),a + ld a,#0x20 ; READ + out (191),a + nop +wait3: + in a, (191) + rlca + jr c, wait3 ; Busy + bit 4,a ; DRQ ? + jr z, failed ; Nope - bad + ld bc,#163 ; Data port + inir + inir + dec d + jr nz, load_loop + + ; And we are done + + jp _start ; Enter entirely cartridge mapped +failed: + ld a,#0x05 + out (0xFF),a + di + halt + +; +; Zero page +; + .area _PAGE0 (ABS) + + .globl null_handler + .globl unix_syscall_entry + .globl interrupt_handler + + .org 0 +loader: + jp boot + .ds 5 +rst_8: + .ds 8 +rst_10: + .ds 8 +rst_18: + .ds 8 +rst_20: + .ds 8 +rst_28: + .ds 8 +rst_30: + jp unix_syscall_entry + .ds 5 +rst_38: + jp interrupt_handler + .ds 0x66-0x3B +nmi: ret ; magic... + retn + diff --git a/Kernel/platform-tc2068/main.c b/Kernel/platform-tc2068/main.c new file mode 100644 index 00000000..6e78d217 --- /dev/null +++ b/Kernel/platform-tc2068/main.c @@ -0,0 +1,69 @@ +#include +#include +#include +#include +#include +#include + +uint16_t ramtop = PROGTOP; +uint16_t swap_dev = 0xFFFF; + +/* On idle we spin checking for the terminals. Gives us more responsiveness + for the polled ports */ +void platform_idle(void) +{ + /* We don't want an idle poll and IRQ driven tty poll at the same moment */ + __asm + halt + __endasm; +} + +uint8_t timer_wait; + +void platform_interrupt(void) +{ + tty_pollirq(); + timer_interrupt(); + poll_input(); + if (timer_wait) + wakeup(&timer_interrupt); +} + +/* This points to the last buffer in the disk buffers. There must be at least + four buffers to avoid deadlocks. */ +struct blkbuf *bufpool_end = bufpool + NBUFS; + +/* + * We pack discard into the memory image is if it were just normal + * code but place it at the end after the buffers. When we finish up + * booting we turn everything from the buffer pool to the start of + * user space into buffers. + * + * Discard gets turned into buffers + */ +void platform_discard(void) +{ + uint16_t discard_size = 0x8000 - (uint16_t)bufpool_end; + bufptr bp = bufpool_end; + + discard_size /= sizeof(struct blkbuf); + + kprintf("%d buffers added\n", discard_size); + + bufpool_end += discard_size; + + memset( bp, 0, discard_size * sizeof(struct blkbuf) ); + + for( bp = bufpool + NBUFS; bp < bufpool_end; ++bp ){ + bp->bf_dev = NO_DEVICE; + bp->bf_busy = BF_FREE; + } +} + +#ifndef SWAPDEV +/* Adding dummy swapper since it is referenced by tricks.s */ +void swapper(ptptr p) +{ + p; +} +#endif \ No newline at end of file diff --git a/Kernel/platform-tc2068/platform_ide.h b/Kernel/platform-tc2068/platform_ide.h new file mode 100644 index 00000000..2141fda7 --- /dev/null +++ b/Kernel/platform-tc2068/platform_ide.h @@ -0,0 +1,29 @@ +/* + * DivIDE interface + * + * This is a 16bit interface with a latched data port. Each read + * from A3 fetches a word then returns low then high etc. In the other + * direction it latches then writes. + * + * The latch is reset to the first state by any other port access in the + * IDE space (so the command write sets it up nicely for us) + */ + +#define ide_select(x) +#define ide_deselect() + +#define IDE_DRIVE_COUNT 2 + +#define IDE_REG_DATA 0xA3 +#define IDE_REG_ERROR 0xA7 +#define IDE_REG_FEATURES 0xA7 +#define IDE_REG_SEC_COUNT 0xAB +#define IDE_REG_LBA_0 0xAF +#define IDE_REG_LBA_1 0xB3 +#define IDE_REG_LBA_2 0xB7 +#define IDE_REG_LBA_3 0xBB +#define IDE_REG_DEVHEAD 0xBB +#define IDE_REG_STATUS 0xBF +#define IDE_REG_COMMAND 0xBF + +#define IDE_NONSTANDARD_XFER diff --git a/Kernel/platform-tc2068/rules.mk b/Kernel/platform-tc2068/rules.mk new file mode 100644 index 00000000..b24847af --- /dev/null +++ b/Kernel/platform-tc2068/rules.mk @@ -0,0 +1 @@ +export CROSS_CC_SYS5=--codeseg CODE3 diff --git a/Kernel/platform-tc2068/target.mk b/Kernel/platform-tc2068/target.mk new file mode 100644 index 00000000..3bffcde0 --- /dev/null +++ b/Kernel/platform-tc2068/target.mk @@ -0,0 +1 @@ +export CPU = z80 diff --git a/Kernel/platform-tc2068/tc2068.s b/Kernel/platform-tc2068/tc2068.s new file mode 100644 index 00000000..924f8a59 --- /dev/null +++ b/Kernel/platform-tc2068/tc2068.s @@ -0,0 +1,200 @@ +; +; TC2068 hardware support +; + + .module zx128 + + ; exported symbols + .globl init_early + .globl init_hardware + .globl _program_vectors + .globl platform_interrupt_all + .globl interrupt_handler + .globl unix_syscall_entry + .globl null_handler + + .globl map_kernel + .globl map_process_always + .globl map_process + .globl map_kernel_di + .globl map_process_always_di + .globl map_save_kernel + .globl map_restore + .globl map_kernel_restore + .globl map_for_swap + .globl map_video + .globl current_map + + .globl _need_resched + .globl _int_disabled + .globl _vtborder + + ; exported debugging tools + .globl _platform_monitor + .globl _platform_reboot + .globl outchar + + ; imported symbols + .globl _ramsize + .globl _procmem + + .globl _vtoutput + .globl _vtinit + + .globl outcharhex + .globl outhl, outde, outbc + .globl outnewline + .globl outstring + .globl outstringhex + + .include "kernel.def" + .include "../kernel.def" + +; ----------------------------------------------------------------------------- +; COMMON MEMORY BANK (below 0x4000) +; ----------------------------------------------------------------------------- + .area _COMMONMEM + +_platform_monitor: + ; + ; Not so much a monitor as wait for space + ; + ld a, #0x7F + in a, (0xFE) + rra + jr c, _platform_monitor + +_platform_reboot: + di + rst 0 ; back into our booter + +platform_interrupt_all: + ret + + .area _COMMONDATA + +_int_disabled: + .db 1 + +_vtborder: ; needs to be common + .db 0 + + +; ----------------------------------------------------------------------------- +; KERNEL CODE BANK (above 0x8000, only accessible when the kernel is mapped) +; ----------------------------------------------------------------------------- + .area _CODE + +init_early: + ld a,#0xFF + out (0xF4),a ; Map kernel fully + ret + + .area _VIDEO + +init_hardware: + ; set system RAM size + ld hl, #80 + ld (_ramsize), hl + ld hl, #(34) ; 32K for kernel/screen/etc + ld (_procmem), hl + + ; screen initialization + call _vtinit + + ret + +;------------------------------------------------------------------------------ +; COMMON MEMORY PROCEDURES FOLLOW + + .area _COMMONMEM + +_program_vectors: + ret + + ; Swap helper. Map the page in A into the address space such + ; that swap_map() gave the correct pointer to use. Undone by + ; a map_kernel_{restore} +map_process: + ld a, h + or l + jr z, map_kernel +map_for_swap: +map_process_always: +map_process_always_di: + push af + ld a,#0x03 ; catridge in low 16K only + out (0xF4),a + ld (current_map),a + pop af + ret +; +; Save and switch to kernel +; +map_save_kernel: + push af + ld a, (current_map) + ld (map_store), a + pop af +map_kernel_di: +map_kernel: +map_kernel_restore: + push af + ld a,#0xFF ; entirely from cartridge + ld (current_map),a + out (0xF4),a + pop af + ret + +map_video: + push af + ld a,#0xF3 ; entirely from cartridge except video + ld (current_map),a + out (0xF4),a + pop af + ret + +map_restore: + push af + ld a, (map_store) + ld (current_map),a + out (0xF4),a + pop af + ret + +; +; We have no easy serial debug output instead just breakpoint this +; address when debugging. +; +outchar: + ld (_tmpout), a + push bc + push de + push hl + push ix + ld hl, #1 + push hl + ld hl, #_tmpout + push hl + call _vtoutput + pop af + pop af + pop ix + pop hl + pop de + pop bc + ret + + .area _COMMONDATA +_tmpout: + .db 1 + +current_map: ; place to store current page number. Is needed + .db 0 ; because we have no ability to read 0xF4 port + ; to detect what page is mapped currently +map_store: + .db 0 + +_need_resched: + .db 0 + diff --git a/Kernel/platform-tc2068/tricks.s b/Kernel/platform-tc2068/tricks.s new file mode 100644 index 00000000..0113d75b --- /dev/null +++ b/Kernel/platform-tc2068/tricks.s @@ -0,0 +1,5 @@ + .include "kernel.def" + .include "../kernel.def" + + .include "../lib/z80single.s" + diff --git a/Kernel/platform-tc2068/zxvideo.s b/Kernel/platform-tc2068/zxvideo.s new file mode 100644 index 00000000..ea74d6b5 --- /dev/null +++ b/Kernel/platform-tc2068/zxvideo.s @@ -0,0 +1,405 @@ +; +; zx128 vt primitives +; + + .module zxvideo + + ; exported symbols + .globl _plot_char + .globl _scroll_down + .globl _scroll_up + .globl _cursor_on + .globl _cursor_off + .globl _cursor_disable + .globl _clear_lines + .globl _clear_across + .globl _do_beep + .globl _fontdata_8x8 + .globl _curattr + .globl _vtattr + .globl map_kernel + .globl map_video + + ; Build the video library as the only driver + +ZXVID_ONLY .equ 1 + + .area _VIDEO + +; +; zx128 vt primitives hacked a bit +; +; Will be replaced by Timex video shortly +; + ; exported symbols + .globl zx_plot_char + .globl zx_scroll_down + .globl zx_scroll_up + .globl zx_cursor_on + .globl zx_cursor_off + .globl zx_cursor_disable + .globl zx_clear_lines + .globl zx_clear_across + .globl zx_do_beep + .globl _fontdata_8x8 + .globl _curattr + .globl _vtattr + +videopos: + ld a,e + and #7 + rrca + rrca + rrca + add a,d + ld d,e + ld e,a + ld a,d + and #0x18 + or #0x40 ; Standard screen + ld d,a + jp map_video + +videoattr: + ; 32 x E + D into HL + ld a,e + rrca + rrca + rrca ; A is now 32xE with the top bits overflowed + ; into the low 2 bits + ld l,a + and #3 ; Extract the low 2 bits for the high + add #0x58 ; Attributes start 0x5800 + ld h,a + ld a,l + and #0xE0 ; mask the bits that are valid + add d ; add the low 5 bits from D + ld l,a ; and done (the add can't overflow) + ret + + .if ZXVID_ONLY +_plot_char: + .endif +zx_plot_char: + pop hl + pop de ; D = x E = y + pop bc + push bc + push de + push hl + + ld hl,(_vtattr) ; l is vt attributes + push de + push hl ; save attributes as inaccessible once vid mapped + + call videopos + + ld b, #0 ; calculating offset in font table + ld a, c + or a ; clear carry + rla + rl b + rla + rl b + rla + rl b + ld c, a + + ld hl, #_fontdata_8x8-32*8 ; font + add hl, bc ; hl points to first byte of char data + + pop bc + ; We do underline for now - not clear italic or bold are useful + ; with the font we have. + + ; printing +plot_char_loop: + ld a, (hl) + ld (de), a + inc hl ; next byte of char data + inc d ; next screen line + + ld a, (hl) + ld (de), a + inc hl ; next byte of char data + inc d ; next screen line + + ld a, (hl) + ld (de), a + inc hl ; next byte of char data + inc d ; next screen line + + ld a, (hl) + ld (de), a + inc hl ; next byte of char data + inc d ; next screen line + + ld a, (hl) + ld (de), a + inc hl ; next byte of char data + inc d ; next screen line + + ld a, (hl) + ld (de), a + inc hl ; next byte of char data + inc d ; next screen line + + ld a, (hl) + ld (de), a + inc hl ; next byte of char data + inc d ; next screen line + + ld a, (hl) + bit 1,c ; underline ? + jr nz, last_ul +plot_attr: + ld (de), a + + pop de + call videoattr + ld a,(_curattr) + ld (hl),a + jp map_kernel + +last_ul: + ld a,#0xff + jr plot_attr + + .if ZXVID_ONLY +_clear_lines: + .endif +zx_clear_lines: + pop hl + pop de ; E = line, D = count + push de + push hl + ; This way we handle 0 correctly + inc d + jr nextline + +clear_next_line: + push de + ld d, #0 ; from the column #0 + ld b, d ; b = 0 + ld c, #32 ; clear 32 cols + push bc + push de + call _clear_across + pop hl ; clear stack + pop hl + + pop de + inc e +nextline: + dec d + jr nz, clear_next_line + + ret + + + .if ZXVID_ONLY +_clear_across: + .endif +zx_clear_across: + pop hl + pop de ; DE = coords + pop bc ; C = count + push bc + push de + push hl + ld a,c + or a + ret z ; No work to do - bail out + push de + push bc + call videopos ; first pixel line of first character in DE + push de + pop hl ; copy to hl + xor a + + ; no boundary checks. Assuming that D + C < SCREEN_WIDTH + +clear_line: + ld b, #8 ; 8 pixel lines to clear for this char +clear_char: + ld (de), a + inc d + djnz clear_char + + ex de, hl + inc de + push de + pop hl + + dec c + jr nz, clear_line + pop bc + pop de + call videoattr + ld a,(_curattr) + ld b,c +setattr: + ld (hl),a + inc hl + djnz setattr + jp map_kernel + +copy_line: + ; HL - source, DE - destination + + ; convert line coordinates to screen coordinates both for DE and HL + push de + ex de, hl + call videopos + ex de, hl + pop de + call videopos + + ld c, #8 + +copy_line_nextchar: + push hl + push de + + ld b, #32 + +copy_pixel_line: + ld a, (hl) + ld (de), a + inc e + inc l + djnz copy_pixel_line + + pop de + pop hl + inc d + inc h + dec c + jr nz, copy_line_nextchar + ret + + ; TODO: the LDIR way should be much faster + + .if ZXVID_ONLY +_scroll_down: + .endif +zx_scroll_down: + ; set HL = (0,22), DE = (0, 23) + xor a + ld d, a + ld h, a + ld l, #22 + ld e, #23 + ld c, #23 ; 23 lines to move + + call map_video + +loop_scroll_down: + push hl + push de + push bc + + call copy_line + + pop bc + pop de + pop hl + + dec l + dec e + dec c + jr nz, loop_scroll_down + + ; Attributes + ld hl,#0x5ADF + ld de,#0x5AFF + ld bc,#0x02E0 + lddr + + jp map_kernel + + + .if ZXVID_ONLY +_scroll_up: + .endif +zx_scroll_up: + ; set HL = (0,1), DE = (0, 0) + xor a + ld d, a + ld e, a + ld h, a + ld l, #1 + ld c, #23 ; 23 lines to move + + call map_video + +loop_scroll_up: + push hl + push de + push bc + + call copy_line + + pop bc + pop de + pop hl + + inc l + inc e + dec c + jr nz, loop_scroll_up + + ld hl,#0x5820 + ld de,#0x5800 + ld bc,#0x02E0 + ldir + jp map_kernel + + .if ZXVID_ONLY +_cursor_on: + .endif +zx_cursor_on: + pop hl + pop de + push de + push hl + ld (cursorpos), de + + call videopos + ld a, #7 + add a, d + ld d, a + ld a, #0xFF + ld (de), a + jp map_kernel + .if ZXVID_ONLY +_cursor_disable: +_cursor_off: + .endif +zx_cursor_disable: +zx_cursor_off: + ld de, (cursorpos) + call videopos + ld a, #7 + add a, d + ld d, a + xor a + ld (de), a + jp map_kernel + + .if ZXVID_ONLY +_do_beep: + .endif +zx_do_beep: + ret + + .area _DATA + +cursorpos: + .dw 0 + + .area _COMMONDATA + +_curattr: + .db 7 + -- 2.34.1