--- /dev/null
+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
--- /dev/null
+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
+
--- /dev/null
+;
+; 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"
--- /dev/null
+#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))
--- /dev/null
+ .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
--- /dev/null
+#include <kernel.h>
+#include <version.h>
+#include <kdata.h>
+#include <tty.h>
+#include <devsys.h>
+#include <vt.h>
+#include <devide.h>
+#include <devsd.h>
+#include <blkdev.h>
+#include <devtty.h>
+
+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
+}
--- /dev/null
+/*
+ * Joysticks off the AY sound chip
+ */
+#include <kernel.h>
+#include <kdata.h>
+#include <input.h>
+#include <devinput.h>
+
+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
--- /dev/null
+extern void queue_input(uint8_t);
+extern void poll_input(void);
--- /dev/null
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <stdbool.h>
+#include <devtty.h>
+#include <keycode.h>
+#include <vt.h>
+#include <tty.h>
+#include <graphics.h>
+#include <input.h>
+#include <devinput.h>
+
+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;
+}
--- /dev/null
+#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
--- /dev/null
+#include <kernel.h>
+#include <timer.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devtty.h>
+#include <blkdev.h>
+
+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
+}
--- /dev/null
+-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
--- /dev/null
+; 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
--- /dev/null
+;
+; 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
+
--- /dev/null
+#include <kernel.h>
+#include <timer.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devtty.h>
+#include <devinput.h>
+
+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
--- /dev/null
+/*
+ * 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
--- /dev/null
+export CROSS_CC_SYS5=--codeseg CODE3
--- /dev/null
+export CPU = z80
--- /dev/null
+;
+; 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
+
--- /dev/null
+ .include "kernel.def"
+ .include "../kernel.def"
+
+ .include "../lib/z80single.s"
+
--- /dev/null
+;
+; 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
+