TARGET_LIST = platform-nc100 platform-micropack platform-pcw8256 platform-socz80 platform-spec3 platform-trs80 platform-z80pack platform-z80pack-lite
-export TARGET= nc100
+export TARGET= msx2
export CPU = z80
#export TARGET = 6809test
#export CPU = 6809
--- /dev/null
+
+CSRCS = devtty.c devfd.c devhd.c devlpr.c
+CSRCS += devices.c main.c
+
+ASRCS = msx2.s crt0.s vdp.s
+ASRCS += tricks.s commonmem.s
+
+COBJS = $(CSRCS:.c=.rel)
+AOBJS = $(ASRCS:.s=.rel)
+OBJS = $(COBJS) $(AOBJS)
+
+JUNK = $(CSRCS:.c=.lst) $(CSRCS:.c=.asm) $(CSRCS:.c=.sym) $(ASRCS:.s=.lst) $(ASRCS:.s=.sym) $(CSRCS:.c=.rst) $(ASRCS:.s=.rst)
+
+all: $(OBJS)
+
+$(COBJS): %.rel: %.c
+ $(CROSS_CC) $(CROSS_CCOPTS) -c $<
+
+$(AOBJS): %.rel: %.s
+ $(CROSS_AS) $(ASOPTS) $<
+
+clean:
+ rm -f $(OBJS) $(JUNK) core *~
+
+image:
--- /dev/null
+First wild guess at an MSX2 target
+
+And it is exactly that a guess 8)
+
--- /dev/null
+;
+; Put the udata at the start of common. We have four 16K banks so we
+; keep the non .common kernel elements below C000 and then keep bank 3 as a
+; true common bank
+;
+ .module commonmem
+
+ ; exported symbols
+ .globl _ub
+ .globl _udata
+ .globl kstack_top
+ .globl istack_top
+ .globl istack_switched_sp
+
+ .area _COMMONMEM
+
+_ub: ; first 512 bytes: starts with struct u_block, with the kernel stack working down from above
+_udata:
+kstack_base:
+ .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+kstack_top:
+
+ ; next 256 bytes: 254 byte interrupt stack, then 2 byte saved stack pointer
+istack_base:
+ .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+istack_top:
+istack_switched_sp: .dw 0
--- /dev/null
+/* 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 - for now while we get it booting */
+#undef CONFIG_SINGLETASK
+/* Video terminal, not a serial tty */
+#define CONFIG_VT
+/* 16K banking so use the helper */
+#define CONFIG_BANK16
+#define MAX_MAPS 255
+
+/* As reported to user space - 4 banks, 16K page size */
+#define CONFIG_BANKS 4
+
+/* Vt definitions */
+#define VT_WIDTH 80
+#define VT_HEIGHT 24
+#define VT_RIGHT 79
+#define VT_BOTTOM 23
+
+#define TICKSPERSEC 50 /* Ticks per second (actually should be dynamic FIXME) */
+#define PROGBASE ((char *)(0x0100)) /* also data base */
+#define PROGTOP ((char *)(0xF000)) /* Top of program, base of U_DATA */
+
+#define BOOT_TTY (512 + 1) /* Set this to default device for stdio, stderr */
+ /* In this case, the default is the first TTY device */
+ /* Temp FIXME set to serial port for debug ease */
+
+/* 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 2
+#define TTYDEV BOOT_TTY /* Device used by kernel for messages, panics */
+#define NBUFS 10 /* Number of block buffers */
+#define NMOUNTS 4 /* Number of mounts at a time */
--- /dev/null
+ ; Ordering of segments for the linker.
+ ; WRS: Note we list all our segments here, even though
+ ; we don't use them all, because their ordering is set
+ ; when they are first seen.
+ .area _CODE
+ .area _CODE2
+ .area _VIDEO
+ .area _CONST
+ .area _DISCARD
+ .area _DATA
+ .area _INITIALIZED
+ .area _BSEG
+ .area _BSS
+ .area _HEAP
+ ; note that areas below here may be overwritten by the heap at runtime, so
+ ; put initialisation stuff in here
+ .area _INITIALIZER
+ .area _GSINIT
+ .area _GSFINAL
+ .area _COMMONMEM
+
+ ; imported symbols
+ .globl _fuzix_main
+ .globl init_early
+ .globl init_hardware
+ .globl s__DATA
+ .globl l__DATA
+ .globl s__COMMONMEM
+ .globl l__COMMONMEM
+ .globl s__INITIALIZER
+ .globl kstack_top
+
+ ; startup code @0
+ .area _CODE
+
+;
+; Execution begins with us correctly mapped and at 0x0x100
+;
+start: di
+ ld sp, #kstack_top
+ ; move the common memory where it belongs
+ ld hl, #s__INITIALIZER
+ ld de, #s__COMMONMEM
+ ld bc, #l__COMMONMEM
+ ldir
+ ; then zero the data area
+ ld hl, #s__DATA
+ ld de, #s__DATA + 1
+ ld bc, #l__DATA - 1
+ ld (hl), #0
+ ldir
+
+ call init_early
+ call init_hardware
+ call _fuzix_main
+ di
+stop: halt
+ jr stop
+
--- /dev/null
+/*
+ * Dummy fd driver code
+ *
+ */
+
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devfd.h>
+
+static int fd_transfer(bool is_read, uint8_t rawflag)
+{
+ blkno_t block;
+ int block_xfer;
+ uint16_t dptr;
+ int dlen;
+ int ct = 0;
+ int map;
+
+ is_read;
+
+ /* FIXME: raw is broken unless nicely aligned */
+ if(rawflag) {
+ dlen = udata.u_count;
+ dptr = (uint16_t)udata.u_base;
+ if (dptr & 0x1FF) {
+ udata.u_error = EIO;
+ return -1;
+ }
+ block = udata.u_offset >> 9;
+ block_xfer = dlen >> 9;
+ map = 1;
+ } else { /* rawflag == 0 */
+ dlen = 512;
+ dptr = (uint16_t)udata.u_buf->bf_data;
+ block = udata.u_buf->bf_blk;
+ block_xfer = 1;
+ map = 0;
+ }
+
+ while (ct < block_xfer) {
+ /* FIXME: Do stuff */
+ block++;
+ ct++;
+ }
+ return ct;
+}
+
+int fd_open(uint8_t minor, uint16_t flag)
+{
+ flag;
+ if(minor != 0) {
+ udata.u_error = ENODEV;
+ return -1;
+ }
+ return 0;
+}
+
+int fd_read(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+ flag;minor;
+ return fd_transfer(true, rawflag);
+}
+
+int fd_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+ flag;minor;
+ return fd_transfer(false, rawflag);
+}
+
--- /dev/null
+#ifndef __DEVFD_DOT_H__
+#define __DEVFD_DOT_H__
+
+/* public interface */
+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);
+
+#endif /* __DEVRD_DOT_H__ */
+
--- /dev/null
+/*
+ * Dummy hd driver code
+ *
+ */
+
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devhd.h>
+
+static int hd_transfer(bool is_read, uint8_t rawflag)
+{
+ blkno_t block;
+ int block_xfer;
+ uint16_t dptr;
+ int dlen;
+ int ct = 0;
+ int map;
+
+ is_read;
+
+ /* FIXME: raw is broken unless nicely aligned */
+ if(rawflag) {
+ dlen = udata.u_count;
+ dptr = (uint16_t)udata.u_base;
+ if (dptr & 0x1FF) {
+ udata.u_error = EIO;
+ return -1;
+ }
+ block = udata.u_offset >> 9;
+ block_xfer = dlen >> 9;
+ map = 1;
+ } else { /* rawflag == 0 */
+ dlen = 512;
+ dptr = (uint16_t)udata.u_buf->bf_data;
+ block = udata.u_buf->bf_blk;
+ block_xfer = 1;
+ map = 0;
+ }
+
+ while (ct < block_xfer) {
+ /* FIXME: Do stuff */
+ block++;
+ ct++;
+ }
+ return ct;
+}
+
+int hd_open(uint8_t minor, uint16_t flag)
+{
+ flag;
+ if(minor != 0) {
+ udata.u_error = ENODEV;
+ return -1;
+ }
+ return 0;
+}
+
+int hd_read(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+ flag;minor;
+ return hd_transfer(true, rawflag);
+}
+
+int hd_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+ flag;minor;
+ return hd_transfer(false, rawflag);
+}
+
--- /dev/null
+#ifndef __DEVHD_DOT_H__
+#define __DEVHD_DOT_H__
+
+/* public interface */
+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);
+
+#endif /* __DEVRD_DOT_H__ */
+
--- /dev/null
+#include <kernel.h>
+#include <version.h>
+#include <kdata.h>
+#include <devhd.h>
+#include <devfd.h>
+#include <devlpr.h>
+#include <devsys.h>
+#include <tty.h>
+#include <devtty.h>
+
+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 (and RAM etc) */
+ { hd_open, no_close, hd_read, hd_write, no_ioctl },
+ /* 2: /dev/tty TTY devices */
+ { tty_open, tty_close, tty_read, tty_write, tty_ioctl },
+ /* 3: /dev/lpr Printer devices */
+ { lpr_open, no_close, no_rdwr, lpr_write, no_ioctl },
+ /* 4: /dev/mem etc System devices (one offs) */
+ { no_open, no_close, sys_read, sys_write, sys_ioctl },
+ /* 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) + 255)
+ return false;
+ else
+ return true;
+}
+
+void device_init(void)
+{
+}
--- /dev/null
+#include <kernel.h>
+#include <version.h>
+#include <kdata.h>
+#include <devlpr.h>
+
+__sfr __at 0x90 lpstat;
+__sfr __at 0x91 lpdata;
+
+int lpr_open(uint8_t minor, uint16_t flag)
+{
+ minor;
+ flag; // shut up compiler
+ return 0;
+}
+
+int lpr_close(uint8_t minor)
+{
+ minor; // shut up compiler
+ return 0;
+}
+
+int lpr_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+ int c = udata.u_count;
+ char *p = udata.u_base;
+ uint16_t ct;
+
+ minor;
+ rawflag;
+ flag; // shut up compiler
+
+ while (c-- > 0) {
+ ct = 0;
+
+ /* Try and balance polling and sleeping */
+ while (lpstat & 2) {
+ ct++;
+ if (ct == 10000) {
+ udata.u_ptab->p_timeout = 3;
+ if (psleep_flags(NULL, flag)) {
+ if (udata.u_count)
+ udata.u_error = 0;
+ return udata.u_count;
+ }
+ ct = 0;
+ }
+ }
+ /* Data */
+ lpdata = ugetc(p++);
+ /* Strobe */
+ lpstat |= 1;
+ lpstat &= ~1;
+ }
+ return udata.u_count;
+}
--- /dev/null
+#ifndef __DEVLPR_DOT_H__
+#define __DEVLPR_DOT_H__
+
+int lpr_open(uint8_t minor, uint16_t flag);
+int lpr_close(uint8_t minor);
+int lpr_write(uint8_t minor, uint8_t rawflag, uint8_t flag);
+
+#endif
--- /dev/null
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <stdbool.h>
+#include <devtty.h>
+#include <vt.h>
+#include <tty.h>
+
+#undef DEBUG /* UNdefine to delete debug code sequences */
+
+__sfr __at 0x2F tty_debug2;
+
+char tbuf1[TTYSIZ];
+char tbuf2[TTYSIZ];
+
+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}
+};
+
+/* tty1 is the screen tty2 is the debug port */
+
+/* Output for the system console (kprintf etc) */
+void kputchar(char c)
+{
+ /* Debug port for bringup */
+ if (c == '\n')
+ tty_putc(2, '\r');
+ tty_putc(2, c);
+}
+
+/* Both console and debug port are always ready */
+bool tty_writeready(uint8_t minor)
+{
+ minor;
+ return 1;
+}
+
+void tty_putc(uint8_t minor, unsigned char c)
+{
+ minor;
+ if (minor == 1) {
+ vtoutput(&c, 1);
+ return;
+ }
+ tty_debug2 = c;
+}
+
+int tty_carrier(uint8_t minor)
+{
+ minor;
+ return 1;
+}
+
+void tty_setup(uint8_t minor)
+{
+ minor;
+}
+
+
+#if 0
+static uint8_t keymap[10];
+static uint8_t keyin[10];
+static uint8_t keybyte, keybit;
+static uint8_t newkey;
+static int keysdown = 0;
+static uint8_t shiftmask[10] = {
+ 3, 3, 2, 0, 0, 0, 0, 0x10, 0, 0
+};
+
+static void keyproc(void)
+{
+ int i;
+ uint8_t key;
+
+ for (i = 0; i < 10; i++) {
+ key = keyin[i] ^ keymap[i];
+ if (key) {
+ int n;
+ int m = 128;
+ for (n = 0; n < 8; n++) {
+ if ((key & m) && (keymap[i] & m)) {
+ if (!(shiftmask[i] & m))
+ keysdown--;
+ }
+ if ((key & m) && !(keymap[i] & m)) {
+ if (!(shiftmask[i] & m))
+ keysdown++;
+ keybyte = i;
+ keybit = n;
+ newkey = 1;
+ }
+
+ }
+ }
+ keymap[i] = keyin[i];
+ }
+}
+
+static uint8_t keyboard[10][8] = {
+ {0, 0, 0, 10, '?' /*left */ , 0, 0, 0},
+ {0, '5', 0, 0, ' ', 27, 0, 0},
+ {0, 0, 0, 0, '\t', '1', 0, 0},
+ {'d', 's', 0, 'e', 'w', 'q', '2', '3'},
+ {'f', 'r', 0, 'a', 'x', 'z', 0, '4'},
+ {'c', 'g', 'y', 't', 'v', 'b', 0, 0},
+ {'n', 'h', '/', '#', '?' /*right */ , 127, '?' /*down */ , '6'},
+ {'k', 'm', 'u', 0, '?' /*up */ , '\\', '7', '='},
+ {',', 'j', 'i', '\'', '[', ']', '-', '8'},
+ {'.', 'o', 'l', ';', 'p', 8, '9', '0'}
+};
+
+static uint8_t shiftkeyboard[10][8] = {
+ {0, 0, 0, 10, '?' /*left */ , 0, 0, 0},
+ {0, '%', 0, 0, ' ', 3, 0, 0},
+ {0, 0, 0, 0, '\t', '!', 0, 0},
+ {'D', 'S', 0, 'E', 'W', 'Q', '"', '?' /* pound */ },
+ {'F', 'R', 0, 'A', 'X', 'Z', 0, '$'},
+ {'C', 'G', 'Y', 'T', 'V', 'B', 0, 0},
+ {'N', 'H', '?', '~', '?' /*right */ , 127, '?' /*down */ , '^'},
+ {'K', 'M', 'U', 0, '?' /*up */ , '|', '&', '+'},
+ {'<', 'J', 'I', '@', '{', '}', '_', '*'},
+ {'>', 'O', 'L', ':', 'P', 8, '(', ')'}
+};
+
+static uint8_t capslock = 0;
+
+static void keydecode(void)
+{
+ uint8_t c;
+
+ if (keybyte == 2 && keybit == 7) {
+ capslock = 1 - capslock;
+ return;
+ }
+
+ if (keymap[0] & 3) /* shift */
+ c = shiftkeyboard[keybyte][keybit];
+ else
+ c = keyboard[keybyte][keybit];
+ if (keymap[1] & 2) { /* control */
+ if (c > 31 && c < 96)
+ c &= 31;
+ }
+ if (keymap[1] & 1) { /* function: not yet used */
+ ;
+ }
+// kprintf("char code %d\n", c);
+ if (keymap[2] & 1) { /* symbol */
+ ;
+ }
+ if (capslock && c >= 'a' && c <= 'z')
+ c -= 'a' - 'A';
+ if (keymap[7] & 0x10) { /* menu: not yet used */
+ ;
+ }
+ tty_inproc(1, c);
+}
+
+#endif
+
+void platform_interrupt(void)
+{
+#if 0
+ uint8_t a = irqmap;
+ uint8_t c;
+ if (!(a & 2))
+ wakeup(&ttydata[2]);
+ if (!(a & 1)) {
+ /* work around sdcc bug */
+ c = uarta;
+ tty_inproc(2, c);
+ }
+ if (!(a & 8)) {
+ keyin[0] = kmap0;
+ keyin[1] = kmap1;
+ keyin[2] = kmap2;
+ keyin[3] = kmap3;
+ keyin[4] = kmap4;
+ keyin[5] = kmap5;
+ keyin[6] = kmap6;
+ keyin[7] = kmap7;
+ keyin[8] = kmap8;
+ keyin[9] = kmap9; /* This resets the scan for 10mS on */
+
+ newkey = 0;
+ keyproc();
+ if (keysdown < 3 && newkey)
+ keydecode();
+ timer_interrupt();
+ }
+
+ /* clear the mask */
+ irqmap = a;
+#endif
+}
+
+/* This is used by the vt asm code, but needs to live in the kernel */
+uint16_t cursorpos;
+
--- /dev/null
+#ifndef __DEVTTY_DOT_H__
+#define __DEVTTY_DOT_H__
+
+#endif
--- /dev/null
+; UZI mnemonics for memory addresses etc
+
+U_DATA .equ 0xF000 ; (this is struct u_data from kernel.h)
+U_DATA__TOTALSIZE .equ 0x300 ; 256+256+256 bytes.
+
--- /dev/null
+#include <kernel.h>
+#include <timer.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devtty.h>
+
+uint16_t vdpport = 0x98;
+
+void platform_idle(void)
+{
+ __asm
+ halt
+ __endasm;
+}
+
+void do_beep(void)
+{
+}
+
+/*
+ * Map handling: We have flexible paging. Each map table consists of a set
+ * of pages with the last page repeated to fill any holes.
+ */
+
+void pagemap_init(void)
+{
+ int i = /*FIXME*/ 16; /* in 16K banks */
+ /* Add all the RAM, except 0,1,2 , which is the kernel data/bss, add 3
+ last to become the common for init */
+ while (i > 0)
+ pagemap_add(i--);
+}
+
+void map_init(void)
+{
+}
--- /dev/null
+;
+; MSX2 hardware support
+;
+
+ .module msx2
+
+ ; exported symbols
+ .globl init_early
+ .globl init_hardware
+ .globl interrupt_handler
+ .globl _program_vectors
+ .globl map_kernel
+ .globl map_process
+ .globl map_process_always
+ .globl map_save
+ .globl map_restore
+
+ ; video driver
+ .globl _vtinit
+
+ ; exported debugging tools
+ .globl _trap_monitor
+ .globl outchar
+
+ ; imported symbols
+ .globl _ramsize
+ .globl _procmem
+ .globl _tty_inproc
+ .globl unix_syscall_entry
+ .globl trap_illegal
+ .globl nmi_handler
+ .globl null_handler
+
+ ; debug symbols
+ .globl outcharhex
+ .globl outhl, outde, outbc
+ .globl outnewline
+ .globl outstring
+ .globl outstringhex
+
+ .include "kernel.def"
+ .include "../kernel.def"
+
+; -----------------------------------------------------------------------------
+; COMMON MEMORY BANK (0xF000 upwards)
+; -----------------------------------------------------------------------------
+ .area _COMMONMEM
+
+trapmsg: .ascii "Trapdoor: SP="
+ .db 0
+trapmsg2: .ascii ", PC="
+ .db 0
+tm_user_sp: .dw 0
+
+tm_stack:
+ .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+tm_stack_top:
+
+; Ideally return to any debugger/monitor
+_trap_monitor:
+ di
+ halt
+
+
+_trap_reboot:
+;FIXME: TODO
+ di
+ halt
+
+; -----------------------------------------------------------------------------
+; KERNEL MEMORY BANK (below 0xF000, only accessible when the kernel is mapped)
+; -----------------------------------------------------------------------------
+ .area _CODE
+
+init_early:
+ ld a, #0x33 ; multibyte/ascii
+ out (0x2E), a
+ ret
+
+init_hardware:
+ ; set up interrupt vectors for the kernel mapped low page and
+ ; data area
+ ld hl, #0
+ push hl
+ call _program_vectors
+ pop hl
+
+ im 1 ; set CPU interrupt mode
+ call _vtinit ; init the console video
+ ret
+
+
+;------------------------------------------------------------------------------
+; COMMON MEMORY PROCEDURES FOLLOW
+
+ .area _COMMONMEM
+
+_program_vectors:
+ ; we are called, with interrupts disabled, by both newproc() and crt0
+ ; will exit with interrupts off
+ di ; just to be sure
+ pop de ; temporarily store return address
+ pop hl ; function argument -- base page number
+ push hl ; put stack back as it was
+ push de
+
+ ; At this point the common block has already been copied
+ call map_process
+
+ ; write zeroes across all vectors
+ ld hl, #0
+ ld de, #1
+ ld bc, #0x007f ; program first 0x80 bytes only
+ ld (hl), #0x00
+ ldir
+
+ ; now install the interrupt vector at 0x0038
+ ld a, #0xC3 ; JP instruction
+ ld (0x0038), a
+ ld hl, #interrupt_handler
+ ld (0x0039), hl
+
+ ; set restart vector for Fuzix system calls
+ ld (0x0030), a ; (rst 30h is unix function call vector)
+ ld hl, #unix_syscall_entry
+ ld (0x0031), hl
+
+ ld (0x0000), a
+ ld hl, #null_handler ; to Our Trap Handler
+ ld (0x0001), hl
+
+ ld (0x0066), a ; Set vector for NMI
+ ld hl, #nmi_handler
+ ld (0x0067), hl
+ jr map_kernel
+
+;
+; All registers preserved
+;
+map_process_always:
+ push hl
+ push af
+ ld hl, #U_DATA__U_PAGE
+ call map_process_2
+ pop af
+ pop hl
+ ret
+;
+; HL is the page table to use, A is eaten, HL is eaten
+;
+map_process:
+ ld a, h
+ or l
+ jr nz, map_process_2
+;
+; Map in the kernel below the current common, all registers preserved
+; This maps 0-3 but I guess we should save the map from the boot
+; somehow and use that?
+;
+map_kernel:
+ push af
+ xor a
+ out (0xFC), a
+ inc a
+ out (0xFD), a
+ inc a
+ out (0xFE), a
+ inc a
+ out (0xFF), a
+ pop af
+ ret
+map_process_2:
+ push de
+ ld de, #map_table ; Write only so cache in RAM
+ ld a, (hl)
+ ld (de), a
+ out (0xFC), a ; Low 16K
+ inc hl
+ inc de
+ ld a, (hl)
+ out (0xFD), a ; Next 16K
+ ld (de), a
+ inc hl
+ inc de
+ ld a, (hl) ; Next 16K. Leave the common for the task
+ out (0xFE), a ; switcher
+ ld (de), a
+ pop de
+ ; NOTE: map_restore relies on the HL for
+ ; exit of this
+ ret
+;
+; Restore a saved mapping. We are guaranteed that we won't switch
+; common copy between save and restore. Preserve all registers
+;
+map_restore:
+ push hl
+ push af
+ ld hl,#map_savearea
+ call map_process_2 ; Put the mapper back right
+ pop af
+ pop hl
+ ret
+;
+; Save the current mapping.
+;
+map_save: push hl
+ ld hl, (map_table)
+ ld (map_savearea), hl
+ ld hl, (map_table + 2)
+ ld (map_savearea + 2), hl
+ pop hl
+ ret
+
+map_table:
+ .db 0,0,0,0
+map_savearea:
+ .db 0,0,0,0
+
+; emulator debug port for now
+outchar:
+ push af
+outcharw:
+ out (0x2F), a
+ ret
+
--- /dev/null
+; 2013-12-21 William R Sowerbutts
+
+ .module tricks
+
+ .globl _ptab_alloc
+ .globl _newproc
+ .globl _chksigs
+ .globl _getproc
+ .globl _trap_monitor
+ .globl trap_illegal
+ .globl _inint
+ .globl _switchout
+ .globl _switchin
+ .globl _doexec
+ .globl _dofork
+ .globl _runticks
+ .globl unix_syscall_entry
+ .globl interrupt_handler
+ .globl dispatch_process_signal
+ .globl map_kernel
+ .globl _ramtop
+
+ ; imported debug symbols
+ .globl outstring, outde, outhl, outbc, outnewline, outchar, outcharhex
+
+ .include "kernel.def"
+ .include "../kernel.def"
+
+ .area _COMMONMEM
+
+; ramtop must be in common for single process swapping cases
+; and its a constant for the others from before init forks so it'll be fine
+; here
+_ramtop:
+ .dw 0
+
+; Switchout switches out the current process, finds another that is READY,
+; possibly the same process, and switches it in. When a process is
+; restarted after calling switchout, it thinks it has just returned
+; from switchout().
+;
+; This function can have no arguments or auto variables.
+_switchout:
+ di
+ call _chksigs
+ ; save machine state
+
+ ld hl, #0 ; return code set here is ignored, but _switchin can
+ ; return from either _switchout OR _dofork, so they must both write
+ ; U_DATA__U_SP with the following on the stack:
+ push hl ; return code
+ push ix
+ push iy
+ ld (U_DATA__U_SP), sp ; this is where the SP is restored in _switchin
+
+ ; set inint to false
+ xor a
+ ld (_inint), a
+
+ ; find another process to run (may select this one again)
+ call _getproc
+
+ push hl
+ call _switchin
+
+ ; we should never get here
+ call _trap_monitor
+
+badswitchmsg: .ascii "_switchin: FAIL"
+ .db 13, 10, 0
+
+_switchin:
+ di
+ pop bc ; return address
+ pop de ; new process pointer
+;
+; FIXME: do we actually *need* to restore the stack !
+;
+ push de ; restore stack
+ push bc ; restore stack
+
+ ld hl, #P_TAB__P_PAGE_OFFSET+3 ; Common
+ add hl, de ; process ptr
+ ld a, (hl)
+ out (0xFF), a ; *CAUTION* our stack just left the building
+
+ ; ------- No stack -------
+ ; 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
+ jr nz, switchinfail
+
+ ; wants optimising up a bit
+ ld hl, #P_TAB__P_STATUS_OFFSET
+ add hl, de
+ ld (hl), #P_RUNNING
+
+ ; runticks = 0
+ ld hl, #0
+ ld (_runticks), hl
+
+ ; restore machine state -- note we may be returning from either
+ ; _switchout or _dofork
+ ld sp, (U_DATA__U_SP)
+
+ ; ---- New task stack ----
+
+ ld hl, #0
+ add hl, sp
+
+ pop iy
+ pop ix
+ pop hl ; return code
+
+ ; enable interrupts, if the ISR isn't already running
+ ld a, (_inint)
+ or a
+ ret z ; in ISR, leave interrupts off
+ ei
+ ret ; return with interrupts on
+
+switchinfail:
+ ; This will crap somewhere random in the stack space of the failure
+ ; case. We aren't coming back, it doesn't matter
+ call outhl
+ ld hl, #badswitchmsg
+ call outstring
+ ; something went wrong and we didn't switch in what we asked for
+ jp _trap_monitor
+
+fork_proc_ptr: .dw 0 ; (C type is struct p_tab *) -- address of child process p_tab entry
+
+;
+; Called from _fork. We are in a syscall, the uarea is live as the
+; parent uarea. The kernel is the mapped object.
+;
+_dofork:
+ ; always disconnect the vehicle battery before performing maintenance
+ di ; should already be the case ... belt and braces.
+
+ pop de ; return address
+ pop hl ; new process p_tab*
+ push hl
+ push de
+
+ ld (fork_proc_ptr), hl
+
+ ; prepare return value in parent process -- HL = p->p_pid;
+ ld de, #P_TAB__P_PID_OFFSET
+ add hl, de
+ ld a, (hl)
+ inc hl
+ ld h, (hl)
+ ld l, a
+
+ ; Save the stack pointer and critical registers.
+ ; When this process (the parent) is switched back in, it will be as if
+ ; it returns with the value of the child's pid.
+ push hl ; HL still has p->p_pid from above, the return value in the parent
+ push ix
+ push iy
+
+ ; save kernel stack pointer -- when it comes back in the parent we'll be in
+ ; _switchin which will immediately return (appearing to be _dofork()
+ ; returning) and with HL (ie return code) containing the child PID.
+ ; Hurray.
+ ld (U_DATA__U_SP), sp
+
+ ; now we're in a safe state for _switchin to return in the parent
+ ; process.
+
+ ; --------- we switch stack copies in this call -----------
+ call fork_copy ; copy 0x0000 to udata.u_top and the
+ ; uarea and return on the childs
+ ; common
+ ; We are now in the kernel child context
+
+ ; 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
+
+ ; The child makes its own new process table entry, etc.
+ ld hl, (fork_proc_ptr)
+ push hl
+ call _newproc
+ pop bc
+
+ ; any calls to map process will now map the childs memory
+
+ ; runticks = 0;
+ ld hl, #0
+ ld (_runticks), hl
+ ; in the child process, fork() returns zero.
+ ;
+ ; And we exit, with the kernel mapped, the child now being deemed
+ ; to be the live uarea. The parent is frozen in time and space as
+ ; if it had done a switchout().
+ ret
+
+;
+; Interrupts need to be off here (if not we need to fix map_save
+; and map_restore
+;
+fork_copy:
+ ld hl, (U_DATA__U_TOP)
+ ld de, #0x0fff
+ add hl, de ; + 0x1000 (-1 for the rounding to follow)
+ ld a, h
+ rlca
+ rlca ; get just the number of banks in the bottom
+ ; bits
+ and #3
+ inc a ; and round up to the next bank
+ ld b, a
+ ; we need to copy the relevant chunks
+ ld hl, (fork_proc_ptr)
+ ld de, #P_TAB__P_PAGE_OFFSET
+ add hl, de
+ ; hl now points into the child pages
+ ld de, #U_DATA__U_PAGE
+ ; and de is the parent
+fork_next:
+ ld a,(hl)
+ out (0xFD), a ; 0x4000 map the child
+ ld c, a
+ inc hl
+ ld a, (de)
+ out (0xFE), a ; 0x8000 maps the parent
+ inc de
+ exx
+ ld hl, #0x8000 ; copy the bank
+ ld de, #0x4000
+ ld bc, #0x4000 ; we copy the whole bank, we could optimise
+ ; further
+ ldir
+ exx
+ call map_kernel ; put the maps back so we can look in p_tab
+ djnz fork_next
+ ld a, c
+ out (0xFF), a ; our last bank repeats up to common
+ ; --- we are now on the stack copy, parent stack is locked away ---
+ ret ; this stack is copied so safe to return on
+
+
--- /dev/null
+-mwxuy
+-i uzi.ihx
+-b _CODE=0x0100
+-b _COMMONMEM=0xF000
+-k /usr/share/sdcc/lib/z80
+-l z80
+platform-msx2/crt0.rel
+platform-msx2/commonmem.rel
+platform-msx2/msx2.rel
+platform-msx2/vdp.rel
+start.rel
+version.rel
+lowlevel-z80.rel
+platform-msx2/tricks.rel
+platform-msx2/main.rel
+timer.rel
+kdata.rel
+platform-msx2/devtty.rel
+platform-msx2/devfd.rel
+platform-msx2/devhd.rel
+platform-msx2/devlpr.rel
+platform-msx2/devices.rel
+devio.rel
+filesys.rel
+process.rel
+inode.rel
+syscall_fs.rel
+syscall_fs2.rel
+syscall_proc.rel
+syscall_other.rel
+mm.rel
+swap.rel
+bank16k.rel
+tty.rel
+vt.rel
+devsys.rel
+usermem.rel
+usermem_std-z80.rel
+-e
--- /dev/null
+ .module vdp
+
+ .include "kernel.def"
+ .include "../kernel.def"
+
+ ; video driver
+ .globl _scroll_up
+ .globl _scroll_down
+ .globl _plot_char
+ .globl _clear_lines
+ .globl _clear_across
+ .globl _cursor_on
+ .globl _cursor_off
+ .globl _cursorpos
+
+ .globl _vdpport
+
+ .area _CODE
+;
+; Register write value E to register A
+;
+vdpout: ld bc, (_vdpport)
+ out (c), e
+ out (c), d
+ ret
+
+;
+; FIXME: table.. and move into init ROM
+;
+vdpinit: ld de, #0x8004 ; M4 }
+ call vdpout ; } 80x25 mode
+ ld de, #0x8170 ; M1 } screen on, virq on hirq off
+ call vdpout
+ ld de, #0x8200 ; characters at VRAM 0
+ call vdpout
+ ld de, #0x8320 ; blink at 0x800
+ ld de, #0x8402 ; font at 0x1000
+ call vdpout
+ ld de, #0x870F ; white text on black
+ call vdpout
+ ; FIXME: read reg 9 and set bit 7 to 0
+ ld de, #0x8C00 ; vanish for blink
+ call vdpout
+ ld de, #0x8D33 ; blink time
+ call vdpout
+ ld de, #0x8A00 ; zero high bits of blink
+ call vdpout
+ ld de, #0x8F00 ; and we want status register 0 visible
+ call vdpout
+ ld de, #0x8E00 ; we only look at the low area
+ call vdpout
+ ; R45 - banking off ???
+ ; Wipe ram ?
+ ret
+
+;
+; FIXME: need to IRQ protect the pairs of writes
+;
+
+
+_videopos: ; turn E=Y D=X into HL = addr
+ ; pass B = 0x40 if writing
+ ; preserves C
+ ld a, e ; 0-24 Y
+ add a, a
+ add a, a
+ add a, a ; x 8
+ ld l, a
+ ld h, #0
+ add hl, hl ; x 16
+ push hl
+ add hl, hl
+ add hl, hl ; x 64
+ ld a, e
+ pop de
+ add hl, de ; x 80
+ ld l, a
+ ld h, b ; 0 for read 0x40 for write
+ add hl, de ; + X
+ ret
+;
+; Eww.. wonder if VT should provide a hint that its the 'next char'
+;
+_plot_char: pop hl
+ pop de ; D = x E = y
+ pop bc
+ push bc
+ push de
+ push hl
+plotit:
+ ld b, #0x40 ; writing
+ call _videopos
+ ld a, c
+ ld bc, (_vdpport)
+ out (c), l ; address
+ out (c), h ; address | 0x40
+ out (c), a ; character
+ ret
+
+;
+; FIXME: on the VDP9958 we can set R25 bit 6 and use the GPU
+; operations
+;
+;
+; Painful
+;
+ .area _DATA
+
+scrollbuf: .ds 80
+
+ .area _CODE
+;
+; We don't yet use attributes...
+;
+_scroll_down:
+ ld b, #23
+ ld de, #0x730 ; start of bottom line
+upline:
+ push bc
+ ld bc, (_vdpport) ; vdpport + 1 always holds #80
+ ld hl, #scrollbuf
+ out (c), e ; our position
+ out (c), d
+ inir ; safe on MSX2 but not MSX1
+ ld hl, #0x4080 ; go down one line and into write mode
+ add hl, de ; relative to our position
+ out (c), l
+ out (c), h
+ ld b, #0x80
+ ld hl, #scrollbuf
+ otir ; video ptr is to the line below so keep going
+ pop bc ; recover line counter
+ ld hl, #0xffb0
+ add hl, de ; up 80 bytes
+ ex de, hl ; and back into DE
+ djnz upline
+ ret
+
+_scroll_up:
+ ld b, #23
+ ld de, #80 ; start of second line
+downline: push bc
+ ld bc, (_vdpport)
+ ld hl, #scrollbuf
+ out (c), e
+ out (c), d
+ inir
+ ld hl, #0x3FB0 ; up 80 bytes in the low 12 bits, add 0x40
+ ; for write ( we will carry one into the top
+ ; nybble)
+ add hl, de
+ out (c), l
+ out (c), h
+ ld hl, #scrollbuf
+ ld b, #0x80
+ otir
+ pop bc
+ ld hl, #80
+ add hl, de
+ ex de, hl
+ djnz downline
+ ret
+
+_clear_lines:
+ pop hl
+ pop de ; E = line, D = count
+ push de
+ push hl
+ ld c, d
+ ld d, #0
+ call _videopos
+ ld e, c
+ ld bc, (_vdpport)
+ out (c), l
+ out (c), h
+ ; Safe on MSX 2 to loop the data with IRQ on
+ ; but *not* on MSX 1
+ ld a, #' '
+l2: ld b, #80
+l1: out (c), a ; Inner loop clears a line, outer counts
+ ; need 20 clocks between writes. DJNZ is 13,
+ ; out is 11
+ djnz l1
+ dec e
+ jr nz, l2
+ ret
+
+_clear_across:
+ pop hl
+ pop de ; DE = coords
+ pop bc ; C = count
+ push bc
+ push de
+ push hl
+ call _videopos
+ ld a, c
+ ld bc, (_vdpport)
+ out (c), l
+ out (c), h
+ ld b, a
+ ld a, #' '
+l3: out (c), a
+ djnz l1
+ ret
+
+;
+; FIXME: should use attribute blink flag not a char
+;
+_cursor_on:
+ pop hl
+ pop de
+ push de
+ push hl
+ ld (cursorpos), de
+ ld c, #'_'
+ call plotit
+ ret
+_cursor_off:
+ ld de, (cursorpos)
+ ld c, #' '
+ call plotit
+ ret
+;
+; This must be in data or common not code
+;
+ .area _DATA
+cursorpos: .dw 0