From: Alan Cox Date: Sat, 13 Dec 2014 22:49:38 +0000 (+0000) Subject: mtx512: Initial port code X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=198381d92c2ca688668c6131c643a831e23d9d01;p=FUZIX.git mtx512: Initial port code Not yet bootable. Still to complete: CTC setup DART serial ports CP/M tools scripts to spit out a memotech floppy disk --- diff --git a/Kernel/platform-mtx/Makefile b/Kernel/platform-mtx/Makefile new file mode 100644 index 00000000..3bf371e8 --- /dev/null +++ b/Kernel/platform-mtx/Makefile @@ -0,0 +1,34 @@ + +CSRCS = devlpr.c devtty.c devfd.c devsil.c +CSRCS += devices.c main.c + +ASRCS = crt0.s mtx.s vdp.s floppy.s +ASRCS += tricks.s commonmem.s + +AOBJS = $(ASRCS:.s=.rel) +COBJS = $(CSRCS:.c=.rel) +DOBJS = $(patsubst ../dev/%.c,%.rel, $(DSRCS)) + +OBJS = $(AOBJS) $(COBJS) $(DOBJS) + +CROSS_CCOPTS += -I../dev/ + +JUNK = *.rel *.lst *.asm *.sym *.rst + +all: $(OBJS) + +$(AOBJS): %.rel: %.s + $(CROSS_AS) $(ASOPTS) $< + +$(COBJS): %.rel: %.c + $(CROSS_CC) $(CROSS_CCOPTS) -c $< + +$(DOBJS): %.rel: ../dev/%.c + $(CROSS_CC) $(CROSS_CCOPTS) -c $< + + +clean: + rm -f $(OBJS) $(JUNK) core *~ + +image: + cp ../fuzix.bin fuzix.com diff --git a/Kernel/platform-mtx/README b/Kernel/platform-mtx/README new file mode 100644 index 00000000..ff969d14 --- /dev/null +++ b/Kernel/platform-mtx/README @@ -0,0 +1,33 @@ +The MTX512 has the following relevant features + +- "FDX" WD1791 floppy (and an actual DMA controller) at 0x40 + SASI interface for floppies + (Not in emulator) +- "SDX" WD1791 style floppy (and no DMA controller) at 0x10 +- 9918/29 VDP graphics (equivalent to MSX1 but on ports 1/2) - interrupts + are fed to the CTC however +- Separate 80 column card (text mode only) (6845 on port 0x38/39) + this has its own memory port poked via port 30,31 (set 31 + bits 2-0 to the high address bits, bit 5 for attr, 6 for ascii, 7 for write + then port 30 for the low bits. Port 32 is the data port (read after write + before), port 33 for read/write is the attribute byte +- "silicon disc" (aka RAM discs) on 0x50-53 54-57 58-5b 5c-5f +- CTC timer (at CPU speed so can support single step) +- RS232 (Z80 DART) +- Sound (SN76489A) on I/O port 6, (strobe on port 3, 32uS reqired post + strobe) + +Memory is split into four banks the decode for which is dependent upon +whether the box is in "ROM based" or "RAM based" mode. The memory is then +switched in 48K banks with a 16K true common. + +All memory management is controlled by the page port (port 0). Bit 7 is set +to 1 to turn the ROMs off, bit 4-6 detemine the rom page address, bits 0-3 +select the RAM bank. + +Note that Rememorizer is different, it allows 0x0f to be written to the +low 3 bits of port 0, then port 0xd2, d0, d1 control the 3 16K banks and also +has an SD card. Not supported, if you want it supported fix MEMU ;-) + + + diff --git a/Kernel/platform-mtx/commonmem.s b/Kernel/platform-mtx/commonmem.s new file mode 100644 index 00000000..8c9f4063 --- /dev/null +++ b/Kernel/platform-mtx/commonmem.s @@ -0,0 +1,10 @@ +; +; Common is at 0xC000. We don't actually have any choice about that +; the platform is wired this way. +; + + .module commonmem + + .area _COMMONMEM + + .include "../cpu-z80/std-commonmem.s" diff --git a/Kernel/platform-mtx/config.h b/Kernel/platform-mtx/config.h new file mode 100644 index 00000000..e4364b58 --- /dev/null +++ b/Kernel/platform-mtx/config.h @@ -0,0 +1,53 @@ +/* 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 */ +#define CONFIG_CPM_EMU +/* Video terminal, not a serial tty */ +#define CONFIG_VT +/* Fixed banking */ +#define CONFIG_BANK_FIXED +/* 10 48K banks, 1 is kernel */ +#define MAX_MAPS 10 +#define MAP_SIZE 0xC000U + +/* Banks as reported to user space */ +#define CONFIG_BANKS 1 + +#define TICKSPERSEC 50 /* Ticks per second */ +#define PROGBASE 0x0000 /* also data base */ +#define PROGLOAD 0x0100 /* also data base */ +#define PROGTOP 0xBD00 /* Top of program, base of U_DATA copy */ +#define PROC_SIZE 48 /* Memory needed per process */ + +#define SWAP_SIZE 0x60 /* 48K in blocks */ +#define SWAPBASE 0x0000 /* We swap the lot in one, include the */ +#define SWAPTOP 0xC000 /* vectors so its a round number of sectors */ +#define MAX_SWAPS 64 /* How many swaps per disc */ + +#define BOOT_TTY (512 + 1)/* 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 2 /* Will be 4 two monitors, two serial */ + +#define TTYDEV BOOT_TTY /* Device used by kernel for messages, panics */ +#define SWAPDEV ((8*256) + 0) /* Device for swapping. - first silicon disk */ +#define NBUFS 16 /* Number of block buffers */ +#define NMOUNTS 4 /* Number of mounts at a time */ + +/* Terminal definitions */ +#define VT_WIDTH 40 +#define VT_HEIGHT 24 +#define VT_RIGHT 39 +#define VT_BOTTOM 23 diff --git a/Kernel/platform-mtx/crt0.s b/Kernel/platform-mtx/crt0.s new file mode 100644 index 00000000..d26bf28e --- /dev/null +++ b/Kernel/platform-mtx/crt0.s @@ -0,0 +1,72 @@ + .module crt0 + + ; 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 _CONST + .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 _DISCARD + .area _COMMONMEM + + ; imported symbols + .globl _fuzix_main + .globl init_early + .globl init_hardware + .globl s__INITIALIZER + .globl s__DATA + .globl l__DATA + .globl s__DISCARD + .globl l__DISCARD + .globl s__COMMONMEM + .globl l__COMMONMEM + + .globl kstack_top + + ; startup code + .area _CODE +init: + di + ld sp, #kstack_top + + ; Configure memory map + call init_early + + ; move the common memory where it belongs + ld hl, #s__INITIALIZER + ld de, #s__COMMONMEM + ld bc, #l__COMMONMEM + ldir + ; and the discard + ld de, #s__DISCARD + ld bc, #l__DISCARD + ldir + ; then zero the data area + ld hl, #s__DATA + ld de, #s__DATA + 1 + ld bc, #l__DATA - 1 + ld (hl), #0 + ldir + + ; 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 + diff --git a/Kernel/platform-mtx/devfd.c b/Kernel/platform-mtx/devfd.c new file mode 100644 index 00000000..122c7cab --- /dev/null +++ b/Kernel/platform-mtx/devfd.c @@ -0,0 +1,97 @@ +#include +#include +#include +#include + +/* Two drives but minors 2,3 are single density mode */ +#define MAX_FD 4 + +#define OPDIR_NONE 0 +#define OPDIR_READ 1 +#define OPDIR_WRITE 2 + +#define FD_READ 0x88 /* 2797 needs 0x88, 1797 needs 0x80 */ +#define FD_WRITE 0xA8 /* Likewise A8 v A0 */ + +static uint8_t motorct; +static uint8_t fd_selected = 0xFF; +static uint8_t fd_tab[MAX_FD]; + +/* + * We only support normal block I/O + */ + +static int fd_transfer(uint8_t minor, bool is_read, uint8_t rawflag) +{ + blkno_t block; + uint16_t dptr; + int ct = 0; + int tries; + uint8_t err = 0; + uint8_t *driveptr = fd_tab + minor; + uint8_t cmd[6]; + + if(rawflag) + goto bad2; + + if (fd_selected != minor) { + uint8_t err = fd_motor_on(minor|(minor > 1 ? 0: 0x10)); + if (err) + goto bad; + } + + dptr = (uint16_t)udata.u_buf->bf_data; + block = udata.u_buf->bf_blk; + +// kprintf("Issue command: drive %d\n", minor); + cmd[0] = is_read ? FD_READ : FD_WRITE; + cmd[1] = block / 8; /* 2 sectors per block */ + cmd[2] = ((block & 7) << 1) + 1; + cmd[3] = is_read ? OPDIR_READ: OPDIR_WRITE; + cmd[4] = dptr & 0xFF; + cmd[5] = dptr >> 8; + + while (ct < 2) { + for (tries = 0; tries < 4 ; tries++) { + err = fd_operation(cmd, driveptr); + if (err == 0) + break; + if (tries > 1) + fd_reset(driveptr); + } + /* FIXME: should we try the other half and then bale out ? */ + if (tries == 3) + goto bad; + cmd[5]++; + cmd[2]++; /* Next sector for next block */ + ct++; + } + return 1; +bad: + kprintf("fd%d: error %x\n", minor, err); +bad2: + udata.u_error = EIO; + return -1; +} + +int fd_open(uint8_t minor, uint16_t flag) +{ + flag; + if(minor >= MAX_FD) { + udata.u_error = ENODEV; + return -1; + } + return 0; +} + +int fd_read(uint8_t minor, uint8_t rawflag, uint8_t flag) +{ + flag; + return fd_transfer(minor, true, rawflag); +} + +int fd_write(uint8_t minor, uint8_t rawflag, uint8_t flag) +{ + flag; + return fd_transfer(minor, false, rawflag); +} diff --git a/Kernel/platform-mtx/devfd.h b/Kernel/platform-mtx/devfd.h new file mode 100644 index 00000000..5f945073 --- /dev/null +++ b/Kernel/platform-mtx/devfd.h @@ -0,0 +1,15 @@ +#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); + +/* low level interface */ +uint16_t fd_reset(uint8_t *driveptr); +uint16_t fd_operation(uint8_t *cmd, uint8_t *driveptr); +uint16_t fd_motor_on(uint16_t drivesel); +uint16_t fd_motor_off(uint16_t driveptr); + +#endif /* __DEVFD_DOT_H__ */ diff --git a/Kernel/platform-mtx/devices.c b/Kernel/platform-mtx/devices.c new file mode 100644 index 00000000..8fa0f482 --- /dev/null +++ b/Kernel/platform-mtx/devices.c @@ -0,0 +1,48 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct devsw dev_tab[] = /* The device driver switch table */ +{ +// minor open close read write ioctl +// ----------------------------------------------------------------- + /* 0: /dev/fd Floppy disc block devices */ + { fd_open, no_close, fd_read, fd_write, no_ioctl }, + /* 1: /dev/hd Hard disc block devices (hdx - not supported yet) */ + { no_open, no_close, no_rdwr, no_rdwr, no_ioctl }, + /* 2: /dev/tty TTY devices */ + { tty_open, tty_close, tty_read, tty_write, tty_ioctl }, + /* 3: /dev/lpr Printer devices */ + { lpr_open, lpr_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 */ + { no_open, no_close, no_rdwr, no_rdwr, no_ioctl }, + { no_open, no_close, no_rdwr, no_rdwr, no_ioctl }, + { no_open, no_close, no_rdwr, no_rdwr, no_ioctl }, + /* 8: /dev/sild Silicon disc block devices */ + { sil_open, no_close, sil_read, sil_write, no_ioctl }, +}; + +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) +{ +// int i; +// for (i = 0; i < MAX_SWAPS; i++) +// swapmap_add(i); +} diff --git a/Kernel/platform-mtx/devlpr.c b/Kernel/platform-mtx/devlpr.c new file mode 100644 index 00000000..60683846 --- /dev/null +++ b/Kernel/platform-mtx/devlpr.c @@ -0,0 +1,69 @@ +#include +#include +#include +#include + +__sfr __at 0x00 lpstrobel; +__sfr __at 0x04 lpdata; /* Data on write, status+strobe clr on read */ + +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; + uint8_t reg; + + minor; + rawflag; + flag; // shut up compiler + + while (c-- > 0) { + ct = 0; + + /* Try and balance polling and sleeping */ + while ((reg = lpdata) & 1) { + reg ^= 2; + if (reg & 6) { + if (c == udata.u_count) { + if (reg & 4) + udata.u_error = ENOSPC; + else + udata.u_error = EIO; + } + return udata.u_count - c; + } + ct++; + if (ct == 10000) { + udata.u_ptab->p_timeout = 3; + if (psleep_flags(NULL, flag)) { + if (c != udata.u_count) + udata.u_error = 0; + return udata.u_count - c; + } + ct = 0; + } + } + /* Data */ + lpdata = ugetc(p++); + /* Strobe - FIXME: should be 1uS */ + for (reg = 0; reg < 128; reg++); + reg = lpstrobel; + for (reg = 0; reg < 128; reg++); + /* Strobe back high */ + reg = lpdata; + } + return udata.u_count - c; +} diff --git a/Kernel/platform-mtx/devlpr.h b/Kernel/platform-mtx/devlpr.h new file mode 100644 index 00000000..7765c187 --- /dev/null +++ b/Kernel/platform-mtx/devlpr.h @@ -0,0 +1,8 @@ +#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 diff --git a/Kernel/platform-mtx/devsil.c b/Kernel/platform-mtx/devsil.c new file mode 100644 index 00000000..3f6e97f9 --- /dev/null +++ b/Kernel/platform-mtx/devsil.c @@ -0,0 +1,70 @@ +/* + * Memotech Silicon Disk Driver + * + * FIXME: would be sensible to add swap support to this driver + */ + +#include +#include +#include +#include + +#define NUM_SIL 4 + +static int sil_transfer(uint8_t minor, bool is_read, uint8_t rawflag) +{ + blkno_t block; + int block_xfer; + uint16_t dptr; + int dlen; + int ct = 0; + int map; + + 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 = udata.u_page; + } 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) { + sil_memcpy(is_read, map, dptr, block, 0x50 + 4 * minor); + block++; + ct++; + } + return ct; +} + +int sil_open(uint8_t minor, uint16_t flag) +{ + flag; + if(minor >= NUM_SIL) { + udata.u_error = ENODEV; + return -1; + } + return 0; +} + +int sil_read(uint8_t minor, uint8_t rawflag, uint8_t flag) +{ + flag;minor; + return sil_transfer(minor, true, rawflag); +} + +int sil_write(uint8_t minor, uint8_t rawflag, uint8_t flag) +{ + flag;minor; + return sil_transfer(minor, false, rawflag); +} + diff --git a/Kernel/platform-mtx/devsil.h b/Kernel/platform-mtx/devsil.h new file mode 100644 index 00000000..e14d2aae --- /dev/null +++ b/Kernel/platform-mtx/devsil.h @@ -0,0 +1,13 @@ +#ifndef __DEVSIL_DOT_H__ +#define __DEVSIL_DOT_H__ + +/* public interface */ +int sil_read(uint8_t minor, uint8_t rawflag, uint8_t flag); +int sil_write(uint8_t minor, uint8_t rawflag, uint8_t flag); +int sil_open(uint8_t minor, uint16_t flag); + +/* asm banking helper */ +void sil_memcpy(uint8_t isread, uint8_t map, uint16_t dptr, uint16_t block, uint16_t dev); + +#endif /* __DEVRD_DOT_H__ */ + diff --git a/Kernel/platform-mtx/devtty.c b/Kernel/platform-mtx/devtty.c new file mode 100644 index 00000000..12ae04b1 --- /dev/null +++ b/Kernel/platform-mtx/devtty.c @@ -0,0 +1,166 @@ +#include +#include +#include +#include +#include +#include +#include + +#undef DEBUG /* UNdefine to delete debug code sequences */ + +__sfr __at 0x0C serialAd; +__sfr __at 0x0D serialAc; +__sfr __at 0x0E serialBd; +__sfr __at 0x0F serialBc; + +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; + } + serialAd = c; +} + +int tty_carrier(uint8_t minor) +{ + minor; + return 1; +} + +void tty_setup(uint8_t minor) +{ + minor; +} + +static uint16_t keymap[8]; +static uint16_t keyin[8]; +static uint8_t keybyte, keybit; +static uint8_t newkey; +static int keysdown = 0; +static uint16_t shiftmask[8] = { + 0, 0, 1, 0, 1, 0, 63, 0 +}; +__sfr __at 0x05 keyport; +__sfr __at 0x06 keyporth; + +static void keyproc(void) +{ + int i; + uint8_t key; + + for (i = 0; i < 8; i++) { + /* Set the row */ + keyport = 0xff - (1 << i); + /* Read the matrix lines - 10 bit wide */ + keyin[i] = (keyport | ((uint16_t)keyporth << 8)) ^ 0xffff; + key = keyin[i] ^ keymap[i]; + if (key) { + int n; + int m = 1; + for (n = 0; n < 10; 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; + } + m += m; + + } + } + keymap[i] = keyin[i]; + } +} + +static uint8_t keyboard[8][10] = { + {'1', '3', '5', '7', '9' , '-', '\\', 0/*page */, 3/*brk*/, 0/*f1*/}, + { 27, '2', '4', '6', '8', '0', '^', 0/*eol*/, 8, 0/*f5*/}, + { 0/*ctrl*/, 'w', 'r', 'y', 'i', 'p', '[', 0/*up*/, 9, 0/*f2*/ }, + {'q', 'e', 't' , 'u', 'o', '@', 10, 8/*left*/, 127, 0 /* f6 */ }, + { 0/*capsl*/, 's', 'f', 'h', 'k', ';', ']', 0/*right*/, 0, 0/*f7*/ }, + { 'a', 'd', 'g', 'j', 'l', ':', 13, 12/*home*/, 0, 0 /*f3 */ }, + { 0/*shift*/, 'x', 'v', 'n', ',', '/', 0/*shift*/, 0/*down*/,0 , 0 /*f8 */}, + {'z', 'c', 'b', 'm', '.', '_', 0/*ins*/, 0/*cls*/, ' ', 0 /* f4 */ } +}; + +static uint8_t shiftkeyboard[8][10] = { + {'!', '#', '%', '\'', ')' , '=', '|', 0/*page */, 3/*brk*/, 0/*f1*/}, + { 27, '"', '$', '&', '(', 0, '~', 0/*eol*/, 8, 0/*f5*/}, + { 0/*ctrl*/, 'w', 'r', 'y', 'i', 'p', '{', 0/*up*/, 9, 0/*f2*/ }, + {'q', 'e', 't' , 'u', 'o', '`', 10, 8/*left*/, 127, 0 /* f6 */ }, + { 0/*capsl*/, 's', 'f', 'h', 'k', '+', '}', 0/*right*/, 0, 0/*f7*/ }, + { 'a', 'd', 'g', 'j', 'l', '*', 13, 12/*home*/, 0, 0 /*f3 */ }, + { 0/*shift*/, 'x', 'v', 'n', '>', '/', 0/*shift*/, 0/*down*/,0 , 0 /*f8 */}, + {'z', 'c', 'b', 'm', '<', '_', 0/*ins*/, 0/*cls*/, ' ', 0 /* f4 */ } +}; + +static uint8_t capslock = 0; + +static void keydecode(void) +{ + uint8_t c; + + if (keybyte == 4 && keybit == 0) { + capslock = 1 - capslock; + return; + } + + if (keymap[6] & 65) /* shift */ + c = shiftkeyboard[keybyte][keybit]; + else + c = keyboard[keybyte][keybit]; + if (keymap[2] & 1) { /* control */ + if (c > 31 && c < 96) + c &= 31; + } + if (capslock && c >= 'a' && c <= 'z') + c -= 'a' - 'A'; + tty_inproc(1, c); +} + +void kbd_interrupt(void) +{ + newkey = 0; + keyproc(); + if (keysdown < 3 && newkey) + keydecode(); +} + +/* This is used by the vt asm code, but needs to live in the kernel */ +uint16_t cursorpos; + diff --git a/Kernel/platform-mtx/devtty.h b/Kernel/platform-mtx/devtty.h new file mode 100644 index 00000000..f3fa2582 --- /dev/null +++ b/Kernel/platform-mtx/devtty.h @@ -0,0 +1,6 @@ +#ifndef __DEVTTY_DOT_H__ +#define __DEVTTY_DOT_H__ + +extern void kbd_interrupt(void); + +#endif diff --git a/Kernel/platform-mtx/floppy.s b/Kernel/platform-mtx/floppy.s new file mode 100644 index 00000000..ac1e4a10 --- /dev/null +++ b/Kernel/platform-mtx/floppy.s @@ -0,0 +1,364 @@ +; +; Core floppy routines for the Memotech SDX (WD17xx) +; Based on the 6809 code +; +; FIXME: better drive spin up wait +; FIXME: double sided media +; FIXME: correct step rates (per drive ?) +; FIXME: precompensation +; +; + .module floppy + + .globl _fd_reset + .globl _fd_operation + .globl _fd_motor_on + .globl _fd_motor_off + +FDCREG .equ 0x10 +FDCTRK .equ 0x11 +FDCSEC .equ 0x12 +FDCDATA .equ 0x13 +FDCCTRL .equ 0x14 +; +; interrupt register reports 0x80 for interrut, 0x40 for drq +; (0x20 is the unrelated reset button) +; + +; +; Structures we use +; +; Command issue +; +CMD .equ 0 +TRACK .equ 1 +SECTOR .equ 2 +DIRECT .equ 3 ; 0 = read 2 = write 1 = status +DATA .equ 4 + + .area _COMMONMEM +; +; Simple routine for pauses +; +nap: dec bc + ld a, b + or c + jr nz, nap + ret + +; +; Wait for the drive controller to become ready +; Preserve HL, DE +; +waitdisk: + ld bc, #0 +waitdisk_l: + in a, (FDCREG) + bit 0, a + ret z + ; + ; Keep poking fdcctrl to avoid a hardware motor timeout + ; + djnz waitdisk_l + dec c + jr nz, waitdisk_l + ld a, #0xD0 ; reset + out (FDCREG), a + ex (sp),hl + ex (sp),hl + ex (sp),hl + ex (sp),hl + in a, (FDCREG) ; read to reset int status + bit 0, a + ret +; +; Set up and perform a disk operation +; +; IX points to the command block +; HL points to the buffer +; DE points to the track reg copy +; +fdsetup: + ld a, (de) + out (FDCTRK), a + cp TRACK(ix) + jr z, fdiosetup + + ; + ; So we can verify + ; + ld a, SECTOR(ix) + out (FDCSEC), a + ; + ; Need to seek the disk + ; + ld a, #0x14 ; seek + out (FDCREG), a + ex (sp),hl + ex (sp),hl + ex (sp),hl + ex (sp),hl + call waitdisk + jr nz, setuptimeout + and #0x18 ; error bits + jr z, fdiosetup + ; seek failed, not good +setuptimeout: ; NE = bad + ld a, #0xff ; we have no idea where we are, force a seek + ld (de), a ; zap track info + ret +; +; Head in the right place +; +fdiosetup: + ld a, TRACK(ix) + ld (de), a ; save track +; cmp #22 ; FIXME +; jr nc, noprecomp +; ld a, (fdcctrl) +; or #0x10 ; Precomp on +; jr precomp1 +;noprecomp: + ld a, (fdcctrl) +;precomp1: + bit 3, SECTOR(ix) ; check if we need side 1 + jr nz, fdio_s1 + res 1, a + jr fdio_setsec +fdio_s1:set 1, a +fdio_setsec: + out (FDCCTRL), a + ld a, SECTOR(ix) + and #7 ; remove side bit + out (FDCSEC), a + in a, (FDCREG) ; Clear any pending status + + ld a, CMD(ix) + + ld de, #0 ; timeout handling + + out (FDCREG), a ; issue the command + ex (sp),hl ; give the FDC a moment to think + ex (sp),hl + ex (sp),hl + ex (sp),hl + ld a, DIRECT(ix) + dec a + ld a, (fdcctrl) + ld d, a ; we need this in a register + ; to meet timing + set 6,d ; halt mode bit + jr z, fdio_in + jr nc, fdio_out +; +; Status registers +; +fdxferdone: + ei +fdxferdone2: + in a, (FDCREG) + and #0x19 ; Error bits + busy + bit 0, a ; Wait for busy to drop, return in a + ret z + ld a, (fdcctrl) + out (FDCCTRL), a + jr fdxferdone2 +; +; Write to the disk - HL points to the target buffer +; +fdio_in: + ld e, #0x16 ; bits to check + ld bc, #FDCDATA ; 256 bytes/sector, c is our port +fdio_inl: + in a, (FDCREG) ; wait for data ready + and e + jr z, fdio_inl + di + ini ; grab and go +fdio_inl2: + in a, (FDCREG) + and e + jr z, fdio_inl2 + ini + jr nz, fdio_inl2 + jr fdxferdone + +; +; Read from the disk - HL points to the target buffer +; +fdio_out: + ld bc, #FDCDATA ; 256 bytes/sector, c is our port + ld e, #0x76 +fdio_outl: + in a, (FDCREG) ; Wait for DRQ (or error) + and e + jr z, fdio_outl + outi ; Stuff byte into FDC while we think + di + in a, (FDCREG) ; No longer busy ?? + bit 0,a + jr nz, fdio_outbyte +fdxferbad: ; Bugger... + ld a, #0xff + ret +fdio_outbyte: + in a, (FDCREG) + and e + jr z, fdio_outbyte + outi + jr nz, fdio_outbyte + jr fdxferdone + + +; +; C glue interface. +; +; Because of the brain dead memory paging we dump the bits into +; kernel space always. The thought of taking an NMI while in the +; user memory and bank flipping to recover is just too odious ! +; + +; +; Reset to track 0, wait for the command then idle +; +; fd_reset(uint8_t *drvptr) +; +_fd_reset: + pop de + pop hl + push hl + push de + ld a, (fdcctrl) + out (FDCCTRL), a + ld a, #1 + out (FDCSEC), a + xor a + out (FDCTRK), a + out (FDCREG), a ; restore + dec a + ld (hl), a ; Zap track pointer + ex (sp),hl ; give the FDC a moment to think + ex (sp),hl + ex (sp),hl + ex (sp),hl + + call waitdisk + cp #0xff + ret z + and #0x10 ; Error bit from the reset + ret nz + ld (hl), a ; Track 0 correctly hit + ret +; +; fd_operation(uint16_t *cmd, uint16_t *drive) +; +; The caller must ensure the drive has been selected and the motor is +; running. +; +_fd_operation: + pop bc ; return address + pop hl ; command + pop de ; drive track ptr + push de + push hl + push bc + push ix + push hl + pop ix + ld l, DATA(ix) + ld h, DATA+1(ix) + call fdsetup ; Set up for a command + ld l, a + ld h, #0 + pop ix + ret +; +; C interface fd_motor_on(uint16_t drivesel) +; +; Selects this drive and turns on the motors. Also pass in the +; choice of density +; +; bit 0: drive select +; bit 1: side select +; bit 2: motor on +; bit 3: motor ready +; bit 4: +; +; +_fd_motor_on: + pop de + pop hl + push hl + push de + ; + ; Select drive B, turn on motor if needed + ; + ld a,(motor_running) ; nothing selected + or a + jr z, notsel + + cp l + jr z, motor_was_on +; +; Select our drive +; +notsel: + ld h, a ; save state as it was + or l + out (FDCCTRL), a + ld (fdcctrl), a + bit 2, h ; FIXME - motor bit + jr nz, motor_was_on + ld bc, #8000 +motorwait: + in a, (FDCCTRL) + bit 3, a + jr nz, motor_good + dec bc + ld a, b + or c + jr nz, motorwait +; +; Timed out +; + ld hl, #-1 + ret +; +; All is actually good ? +; +; If we find the motor is not good try spinning up +; +motor_was_on: + in a, (FDCCTRL) + bit 3,a + jr z, notsel + +motor_good: + ld hl, #0 + ret + +; +; C interface fd_motor_off(void) +; +; Turns off the drive motors, deselects all drives +; +_fd_motor_off: + ld a, (motor_running) + or a + ret z + ; Should we seek to track 0 ? + in a, (FDCCTRL) + res 2,a + out (FDCCTRL), a + xor a + ld (motor_running), a + ret + + .area _COMMONDATA +curdrive: + .db 0xff +motor_running: + .db 0 +fdcctrl: + .db 0 + \ No newline at end of file diff --git a/Kernel/platform-mtx/kernel.def b/Kernel/platform-mtx/kernel.def new file mode 100644 index 00000000..66cb6d40 --- /dev/null +++ b/Kernel/platform-mtx/kernel.def @@ -0,0 +1,12 @@ +; UZI mnemonics for memory addresses etc + +U_DATA .equ 0xC000 ; (this is struct u_data from kernel.h) +U_DATA__TOTALSIZE .equ 0x300 ; 256+256+256 bytes. + +U_DATA_STASH .equ 0xBD00 ; BD00-BFFF + +NMOS_Z80 .equ 0 + +VRAM_CH .equ 3 ; font data 0x1800-1BFF ? + + diff --git a/Kernel/platform-mtx/main.c b/Kernel/platform-mtx/main.c new file mode 100644 index 00000000..9265022b --- /dev/null +++ b/Kernel/platform-mtx/main.c @@ -0,0 +1,41 @@ +#include +#include +#include +#include +#include + +uint16_t ramtop = PROGTOP; +uint16_t vdpport = 0x01 + 256 * 40; /* port and width */ + +void pagemap_init(void) +{ + int i; + /* Ten banks (should check memory size) FIXME */ + for (i = 0x81; i < 0x8A; i++) + pagemap_add(i); +} + +/* 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 */ + irqflags_t irq = di(); +// tty_pollirq(); + irqrestore(irq); +} + +void platform_interrupt(void) +{ + kbd_interrupt(); + timer_interrupt(); +} + +/* Nothing to do for the map of init */ +void map_init(void) +{ +} + +void do_beep(void) +{ +} diff --git a/Kernel/platform-mtx/mtx.s b/Kernel/platform-mtx/mtx.s new file mode 100644 index 00000000..bf73df88 --- /dev/null +++ b/Kernel/platform-mtx/mtx.s @@ -0,0 +1,229 @@ +; +; 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 +; + + + .module mtx + + ; exported symbols + .globl init_early + .globl init_hardware + .globl _program_vectors + .globl _system_tick_counter + .globl platform_interrupt_all + + .globl map_kernel + .globl map_process + .globl map_process_always + .globl map_save + .globl map_restore + + .globl _sil_memcpy + + .globl _kernel_flag + + ; exported debugging tools + .globl _trap_monitor + .globl outchar + + ; imported symbols + .globl _ramsize + .globl _procmem + + .globl unix_syscall_entry + .globl null_handler + .globl nmi_handler + .globl interrupt_handler + + .globl outcharhex + .globl outhl, outde, outbc + .globl outnewline + .globl outstring + .globl outstringhex + + .include "kernel.def" + .include "../kernel.def" + +; ----------------------------------------------------------------------------- +; COMMON MEMORY BANK (0xC000 upwards) +; ----------------------------------------------------------------------------- + .area _COMMONMEM + +_trap_monitor: + di + halt + +_trap_reboot: + di + xor a + out (0),a ; ROM mode, we are in common so survive + rst 0 ; kaboom + +; ----------------------------------------------------------------------------- +; KERNEL MEMORY BANK (below 0xC000, only accessible when the kernel is mapped) +; ----------------------------------------------------------------------------- + .area _CODE + +init_early: + ret + +init_hardware: + ; FIXME: do proper size checker + ; set system RAM size (hardcoded for now) + ld hl, #480 + ld (_ramsize), hl + ld hl, #(480-48) ; 64K for kernel + ld (_procmem), hl + + ; set up interrupt vectors for the kernel (also sets up common memory in page 0x000F which is unused) + ld hl, #0 + push hl + call _program_vectors + pop hl + + ; FIXME: set up interrupt timer on the CTC + ; 08 is channel 0, which is input for vdp + ; 09 is channel 1, output for DART ser 0 } fed 4MHz/13 + ; 0A is channel 2, output for DATA ser 1 } + ; 0B is channel 3, counting CSTTE edges (cpu clocks) at 4MHz + ; 0C-0F are A data, B data, A ctrl, B ctrl + + im 1 ; set CPU interrupt mode + ret + +_sil_memcpy: + push ix + ld ix, #0 + add ix, sp + ld l, 6(ix) ; dptr + ld h, 7(ix) + ld a, 5(ix) ; map + ld e, 8(ix) ; block + ld d, 9(ix) + call map_process_a ; map in the user space we want + ld c, 11(ix) ; port base + out (c), e ; block low + inc c + out (c), d ; block high + inc c + inc c + ld b, #0 + bit 0, 4(ix) ; read ? + jr z, sil_mwrite + inir ; load 256 bytes + inir ; load 256 bytes +sil_copydone: + call map_kernel + pop ix + ret +sil_mwrite: + otir ; write 256 bytes + otir ; write 256 bytes + jr sil_copydone + +;------------------------------------------------------------------------------ +; 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 + + 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 UZI system calls + ld (0x0030), a ; (rst 30h is unix function call vector) + ld hl, #unix_syscall_entry + ld (0x0031), hl + + ; Set vector for jump to NULL + 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 + + ; our platform has a "true" common area, if it did not we would + ; need to copy the "common" code into the common area of the new + ; process. + + ; falls through + + ; put the paging back as it was -- we're in kernel mode so this is predictable +map_kernel: + push af + ld a, #0x80 ; ROM off bank 0 + ; the map port is write only, so keep a local stash + ld (map_save), a + out (0), a + pop af + ret +map_process: + ld a, h + or l + jr z, map_kernel + ld a, (hl) +map_process_a: + ld (map_copy), a + out (0), a + ret +map_process_always: + push af + ld a, (U_DATA__U_PAGE) + ld (map_copy), a + out (0), a + pop af + ret +map_save: + push af + ld a, (map_copy) + ld (map_store), a + pop af + ret +map_restore: + push af + ld a, (map_store) + out (0), a + pop af + ret +map_store: + .db 0 +map_copy: + .db 0 +_kernel_flag: + .db 1 + +; outchar: Wait for UART TX idle, then print the char in A +; destroys: AF +outchar: + out (0x0c), a + ret diff --git a/Kernel/platform-mtx/tricks.s b/Kernel/platform-mtx/tricks.s new file mode 100644 index 00000000..afeb1abc --- /dev/null +++ b/Kernel/platform-mtx/tricks.s @@ -0,0 +1,318 @@ +; +; This is heavily based on the Z80Pack platform code. Only the +; constants have changed. +; + .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 _swapper + + ; imported debug symbols + .globl outstring, outde, outhl, outbc, outnewline, outchar, outcharhex + + .include "kernel.def" + .include "../kernel.def" + + .area _COMMONMEM + +; 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 + + ; Stash the uarea back into process memory + ld hl, (U_DATA__U_PAGE) + ld a, l + out (0), a + ld hl, #U_DATA + ld de, #U_DATA_STASH + ld bc, #U_DATA__TOTALSIZE + ldir + ld a, #0x80 ; kernel + out (0), 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 +swapped: .ascii "_switchin: SWAPPED" + .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 a, #0x80 + out (0), a ; kernel + + push de + ld hl, #P_TAB__P_PAGE_OFFSET + add hl, de ; process ptr + pop de + + ld a, (hl) + + or a + jr nz, not_swapped + + ; + ; We are still on the departing processes stack, which is + ; fine for now. + ; + ld sp, #_swapstack + push hl + push de + call _swapper + pop de + pop hl + ld a, (hl) + +not_swapped: + ; Pages please ! + out (0), a + + ; bear in mind that the stack will be switched now, so we can't use it + ; to carry values over this point + + exx ; thank goodness for exx 8) + ld hl, #U_DATA_STASH + ld de, #U_DATA + ld bc, #U_DATA__TOTALSIZE + ldir + exx + + ld a, #0x80 ; kernel back please + out (0), a + + ; 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 ix, (U_DATA__U_PTAB) + ; next_process->p_status = P_RUNNING + ld P_TAB__P_STATUS_OFFSET(ix), #P_RUNNING + + ; Fix the moved page pointers + ; Just do one byte as that is all we use on this platform + ld a, P_TAB__P_PAGE_OFFSET(ix) + ld (U_DATA__U_PAGE), a + ; 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) + + 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: + 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. + + ; Need to write a new 47.25K bank copy here, then copy the live uarea + ; into the stash of the new process + + ; --------- 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 + ld a, c + call outcharhex + pop af + ld a, (U_DATA__U_PAGE) + + call bankfork ; do the bank to bank copy + + ; Copy done + + ld a, (U_DATA__U_PAGE) ; parent memory + out (0), a ; Switch context to parent + + ; We are going to copy the uarea into the parents uarea stash + ; we must not touch the parent uarea after this point, any + ; changes only affect the child + ld hl, #U_DATA ; copy the udata from common into the + ld de, #U_DATA_STASH ; target process + ld bc, #U_DATA__TOTALSIZE + ldir + ; Return to the kernel mapping + ld a, #0x80 + out (0), a + ; 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 + + ; Make a new process table entry, etc. + ld hl, (fork_proc_ptr) + push hl + call _newproc + pop bc + + ; 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 + +; +; This is related so we will keep it here. Copy the process memory +; for a fork. a is the page base of the parent, c of the child +; +; Assumption - fits into a fixed number of whole 256 byte blocks +; +bankfork: +; ld bc, #(0xC000 - 768) ; 48K minus the uarea stash + + ld b, #0xBD ; C0 x 256 minus 3 sets for the uarea stash + ld hl, #0 ; base of memory to fork (vectors included) +bankfork_1: + push bc ; Save our counter and also child offset + push hl + out (0), a ; switch to parent bank + ld de, #bouncebuffer + ld bc, #256 + ldir ; copy into the bounce buffer + pop de ; recover source of copy to bounce + ; as destination in new bank + pop bc ; recover child page number + push bc + ld b, a ; save the parent bank id + ld a, c ; switch to the child + out (0), a + push bc ; save the bank pointers + ld hl, #bouncebuffer + ld bc, #256 + ldir ; copy into the child + pop bc ; recover the bank pointers + ex de, hl ; destination is now source for next bank + ld a, b ; parent bank is wanted in a + pop bc + djnz bankfork_1 ; rinse, repeat + ret + +; +; For the moment +; +bouncebuffer: + .ds 256 +; +; 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 +; a true common so it's even easier. This can share with the bounce +; buffer used by bankfork as we won't switchin mid way through the +; banked fork() call. +; +_swapstack: diff --git a/Kernel/platform-mtx/uzi.lnk b/Kernel/platform-mtx/uzi.lnk new file mode 100644 index 00000000..45c24177 --- /dev/null +++ b/Kernel/platform-mtx/uzi.lnk @@ -0,0 +1,40 @@ +-mwxuy +-i uzi.ihx +-b _CODE=0x0100 +-b _COMMONMEM=0xC000 +-l z80 +platform-mtx/crt0.rel +platform-mtx/commonmem.rel +platform-mtx/mtx.rel +platform-mtx/main.rel +start.rel +version.rel +lowlevel-z80.rel +usermem_std-z80.rel +platform-mtx/tricks.rel +timer.rel +kdata.rel +usermem.rel +platform-mtx/devfd.rel +platform-mtx/floppy.rel +platform-mtx/devsil.rel +platform-mtx/devices.rel +devio.rel +filesys.rel +process.rel +inode.rel +syscall_exec.rel +syscall_fs.rel +syscall_fs2.rel +syscall_proc.rel +syscall_other.rel +tty.rel +vt.rel +platform-mtx/vdp.rel +mm.rel +bankfixed.rel +swap.rel +devsys.rel +platform-mtx/devlpr.rel +platform-mtx/devtty.rel +-e diff --git a/Kernel/platform-mtx/vdp.s b/Kernel/platform-mtx/vdp.s new file mode 100644 index 00000000..dd7dd3be --- /dev/null +++ b/Kernel/platform-mtx/vdp.s @@ -0,0 +1,16 @@ + .module vdp + + .include "kernel.def" + .include "../kernel.def" + + .include "../dev/vdp1.s" + + + .area _COMMONMEM + +; +; FIXME: should use vdpport, but right now vdpport is in data not +; common space. +; +platform_interrupt_all: + ret