--- /dev/null
+ASRCS = crt0.s tricks.s commonmem.s linc80.s
+CSRCS = devices.c main.c devtty.c
+DISCARD_CSRCS = discard.c
+DISCARD_DSRCS = ../dev/devide_discard.c
+DSRCS = ../dev/devide.c ../dev/mbr.c ../dev/blkdev.c
+NSRCS =
+
+AOBJS = $(ASRCS:.s=.rel)
+COBJS = $(CSRCS:.c=.rel)
+DISCARD_COBJS = $(DISCARD_CSRCS:.c=.rel)
+DISCARD_DOBJS = $(patsubst ../dev/%.c,%.rel, $(DISCARD_DSRCS))
+DOBJS = $(patsubst ../dev/%.c,%.rel, $(DSRCS))
+
+OBJS = $(AOBJS) $(COBJS) $(DOBJS) $(DISCARD_DOBJS) $(DISCARD_COBJS) $(NOBJS)
+
+CROSS_CCOPTS += -I../dev/ -I../dev/net/
+
+JUNK = *.rel *.lst *.asm *.sym *.rst *.map *.ihx *.bin
+
+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 $<
+
+$(DISCARD_COBJS): %.rel: %.c
+ $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_SEGDISC) -c $<
+
+$(DISCARD_DOBJS): %.rel: ../dev/%.c
+ $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_SEGDISC) -c $<
+
+$(NOBJS): %.rel: ../dev/net/%.c
+ $(CROSS_CC) $(CROSS_CCOPTS) -c $<
+
+clean:
+ rm -f $(OBJS) $(JUNK) core *~ fuzix.com loader.tmp
+
+image: loader.bin
+ dd if=../fuzix.bin of=fuzix.com bs=256 skip=1 count=248
+
+loader.bin: loader.s
+ sdasz80 -o loader.s
+ sdldz80 -i loader.rel
+ makebin -s 65536 loader.ihx loader.tmp
+ dd if=loader.tmp bs=256 skip=208 of=loader.bin
--- /dev/null
+LiNC80 Experimental Port
+
+This port supports the following configurations
+
+ LiNC80 with at least one extra 16K bank of RAM as bank 1
+ (additional banks will not be used at this point)
+
+ IDE CF card configured with CP/M to load Fuzix (pending a better
+ loader). Partition table 65536 blocks into the media with at
+ least a root and swap partition present.
+
+ Options:
+ No LiNC80 or RC2014 add in cards are currently supported
+
+ Planned:
+ A different build that supports multiple banks of 16K or
+ with a simple board mod 32K banks
+ Maybe sound card when we get to the Fuzix sound support
+
+
+Memory map:
+
+Kernel
+
+0000-7FFF Common and kernel
+8000-BFFF Kernel (banked and in bank 0)
+C000-FFFF User
+
+User
+
+0000-7FFF Common and kernel
+8000-BFFF User (banked and in bank 1)
+C000-FFFF User
+
+TO DO
+
+Write a proper bootloader that can use partition tables but will trick the
+CPM loader into doing the right thing.
+
+Version that supports multiple 16K banks and multiple processes in memory
+ZX style. Also code to probe for and use the 32K hack which is far nicer.
--- /dev/null
+;
+; Standard common. Nothing special here except to remember that writes
+; to common space won't write through all banks
+;
+ .module commonmem
+
+ .area _COMMONMEM
+
+ .include "../cpu-z80/std-commonmem.s"
+
--- /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) */
+#undef CONFIG_PROFIL
+/* Multiple processes in memory at once */
+#undef CONFIG_MULTI
+/* Swap based one process in RAM */
+#define CONFIG_SWAP_ONLY
+#define CONFIG_PARENT_FIRST
+#define MAXTICKS 20
+/* Permit large I/O requests to bypass cache and go direct to userspace */
+#define CONFIG_LARGE_IO_DIRECT
+/* One memory bank */
+#define CONFIG_BANKS 1
+#define TICKSPERSEC 10 /* Ticks per second */
+#define PROGBASE 0x8000 /* also data base */
+#define PROGLOAD 0x8000 /* also data base */
+#define PROGTOP 0xFFFF /* Top of program */
+#define KERNTOP 0xC000 /* Grow buffers to 0xC000 */
+
+#define PROC_SIZE 32 /* Memory needed per process (inc udata) */
+
+#define SWAPDEV (swap_dev) /* A variable for dynamic, or a device major/minor */
+extern unsigned int swap_dev;
+#define SWAP_SIZE 0x41 /* 32.5K in blocks (prog + udata) */
+#define SWAPBASE 0x8000 /* start at the base of user mem */
+#define SWAPTOP 0x10000UL /* Swap out program */
+#define CONFIG_SPLIT_UDATA /* Adjacent addresses but different bank! */
+#define UDATA_BLKS 1 /* One block of udata */
+#define UDATA_SIZE 512 /* 512 bytes of udata */
+#define MAX_SWAPS 16 /* We will size if from the partition */
+/* Swap will be set up when a suitably labelled partition is seen */
+#define CONFIG_DYNAMIC_SWAP
+
+/* Until we have a bootloader properly done */
+#define CONFIG_MBR_OFFSET 65536
+/*
+ * When the kernel swaps something it needs to map the right page into
+ * memory using map_for_swap and then turn the user address into a
+ * physical address. For a simple banked setup there is no conversion
+ * needed so identity map it.
+ */
+#define swap_map(x) ((uint8_t *)(x))
+
+/* We need a tidier way to do this from the loader */
+#define CMDLINE NULL /* Location of root dev name */
+#define BOOTDEVICENAMES "hd#"
+
+#define CONFIG_DYNAMIC_BUFPOOL /* we expand bufpool to overwrite the _DISCARD segment at boot */
+#define NBUFS 4 /* Number of block buffers, keep in line with space reserved in zeta-v2.s */
+#define NMOUNTS 2 /* Number of mounts at a time */
+
+#define MAX_BLKDEV 1 /* 1 IDE for now */
+
+/* IDE/CF support */
+#define CONFIG_IDE
+
+/* Device parameters */
+#define NUM_DEV_TTY 2
+
+/* SIO port B as the console */
+#define BOOT_TTY (512 + 1)
+#define TTY_INIT_BAUD B115200 /* Hardwired generally */
+
+#define TTYDEV BOOT_TTY /* Device used by kernel for messages, panics */
+
+#define platform_copyright()
--- /dev/null
+; 2015-02-20 Sergey Kiselev
+; 2013-12-18 William R Sowerbutts
+
+ .module crt0
+
+ ; Ordering of segments for the linker.
+ .area _CODE
+ .area _HOME ; compiler stores __mullong etc in here if you use them
+ .area _CODE2
+ .area _CONST
+ .area _INITIALIZED
+ .area _DATA
+ .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 _BUFFERS ; _BUFFERS grows to consume all before it (up to KERNTOP)
+ .area _INITIALIZER ; binman copies this to the right place for us
+ .area _GSINIT ; unused
+ .area _GSFINAL ; unused
+ .area _DISCARD
+ .area _COMMONMEM
+ .area _PAGE0 ; unused but stops binman changing us
+
+ ; exported symbols
+ .globl init
+
+ ; imported symbols
+ .globl _fuzix_main
+ .globl init_hardware
+ .globl s__INITIALIZER
+ .globl s__COMMONMEM
+ .globl l__COMMONMEM
+ .globl s__DISCARD
+ .globl l__DISCARD
+ .globl s__DATA
+ .globl l__DATA
+ .globl kstack_top
+
+ .include "kernel.def"
+
+ .area _COMMONMEM
+
+start:
+ jp init
+
+ .area _CODE
+
+init:
+ di
+ ; switch to stack in high memory
+ ld sp, #kstack_top
+
+ 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
+
+ ; fuzix_main() shouldn't return, but if it does...
+ di
+stop: halt
+ jr stop
--- /dev/null
+#include <kernel.h>
+#include <version.h>
+#include <kdata.h>
+#include <tty.h>
+#include <devsys.h>
+#include <devfd.h>
+#include <devrd.h>
+#include <devtty.h>
+#include <blkdev.h>
+#include <ds1302.h>
+
+struct devsw dev_tab[] = /* The device driver switch table */
+{
+/* open close read write ioctl */
+ /* 0: /dev/hd - block device interface */
+#ifdef CONFIG_IDE
+ { blkdev_open, no_close, blkdev_read, blkdev_write, blkdev_ioctl},
+#else
+ { no_open, no_close, no_rdwr, no_rdwr, no_ioctl},
+#endif
+ /* 1: /dev/fd - Floppy disk block devices */
+ { no_open, no_close, no_rdwr, no_rdwr, no_ioctl},
+ /* 2: /dev/tty -- serial ports */
+ { tty_open, tty_close, tty_read, tty_write, tty_ioctl},
+ /* 3: RAM disk */
+ { 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},
+};
+
+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;
+}
--- /dev/null
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <stdbool.h>
+#include <tty.h>
+#include <devtty.h>
+
+static char tbuf1[TTYSIZ];
+static char tbuf2[TTYSIZ];
+
+static tcflag_t uart_mask[4] = {
+ _ISYS,
+ _OSYS,
+ CSIZE|CSTOPB|CBAUD|PARENB|PARODD|_CSYS,
+ _LSYS
+};
+
+tcflag_t *termios_mask[NUM_DEV_TTY + 1] = {
+ NULL,
+ uart_mask,
+ uart_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},
+ {tbuf2, tbuf2, tbuf2, TTYSIZ, 0, TTYSIZ / 2},
+};
+
+uint8_t sio_r[] = {
+ 0x03, 0xC1,
+ 0x04, 0xC4,
+ 0x05, 0xEA
+};
+
+static void sio2_setup(uint8_t minor, uint8_t flags)
+{
+ struct termios *t = &ttydata[minor].termios;
+ uint8_t r;
+ /* Set bits per character */
+ sio_r[1] = 0x01 | ((t->c_cflag & CSIZE) << 2);
+ r = 0xC4;
+ if (t->c_cflag & CSTOPB)
+ r |= 0x08;
+ if (t->c_cflag & PARENB)
+ r |= 0x01;
+ if (t->c_cflag & PARODD)
+ r |= 0x02;
+ sio_r[3] = r;
+ sio_r[5] = 0x8A | ((t->c_cflag & CSIZE) << 1);
+}
+
+void tty_setup(uint8_t minor, uint8_t flags)
+{
+ sio2_setup(minor, flags);
+ sio2_otir(SIO0_BASE + 4 - minor); /* minor is 1 or 2 */
+ /* We need to do CTS/RTS support and baud setting yet */
+}
+
+int tty_carrier(uint8_t minor)
+{
+ uint8_t c;
+ if (minor == 2) {
+ SIOA_C = 0;
+ c = SIOA_C;
+ } else {
+ SIOB_C = 0;
+ c = SIOB_C;
+ }
+ if (c & 0x8)
+ return 1;
+ return 0;
+}
+
+void tty_pollirq_sio(void)
+{
+ static uint8_t old_ca, old_cb;
+ uint8_t ca, cb;
+ uint8_t progress;
+
+ /* Check for an interrupt */
+ SIOA_C = 0;
+// if (!(SIOA_C & 2))
+//FIXME return;
+
+ /* FIXME: need to process error/event interrupts as we can get
+ spurious characters or lines on an unused SIO floating */
+ do {
+ progress = 0;
+ SIOA_C = 0; // read register 0
+ ca = SIOA_C;
+ /* Input pending */
+ if ((ca & 1) && !fullq(&ttyinq[2])) {
+ progress = 1;
+ tty_inproc(2, SIOA_D);
+ }
+ /* Break */
+ if (ca & 2)
+ SIOA_C = 2 << 5;
+ /* Output pending */
+ if (ca & 4) {
+ tty_outproc(2);
+ SIOA_C = 5 << 3; // reg 0 CMD 5 - reset transmit interrupt pending
+ }
+ /* Carrier changed */
+ if ((ca ^ old_ca) & 8) {
+ if (ca & 8)
+ tty_carrier_raise(2);
+ else
+ tty_carrier_drop(2);
+ }
+ SIOB_C = 0; // read register 0
+ cb = SIOB_C;
+ if ((cb & 1) && !fullq(&ttyinq[1])) {
+ tty_inproc(1, SIOB_D);
+ progress = 1;
+ }
+ if (cb & 4) {
+ tty_outproc(1);
+ SIOB_C = 5 << 3; // reg 0 CMD 5 - reset transmit interrupt pending
+ }
+ if ((cb ^ old_cb) & 8) {
+ if (cb & 8)
+ tty_carrier_raise(1);
+ else
+ tty_carrier_drop(1);
+ }
+ } while(progress);
+}
+
+void tty_putc(uint8_t minor, unsigned char c)
+{
+ if (minor == 2) {
+ SIOA_D = c;
+ } else if (minor == 1)
+ SIOB_D = c;
+}
+
+/* We will need this for SIO once we implement flow control signals */
+void tty_sleeping(uint8_t minor)
+{
+}
+
+/* Be careful here. We need to peek at RR but we must be sure nobody else
+ interrupts as we do this. Really we want to switch to irq driven tx ints
+ on this platform I think. Need to time it and see
+
+ An asm common level tty driver might be a better idea
+
+ Need to review this we should be ok as the IRQ handler always leaves
+ us pointing at RR0 */
+
+ttyready_t tty_writeready(uint8_t minor)
+{
+ irqflags_t irq;
+ uint8_t c;
+
+ irq = di();
+ if (minor == 2) {
+ SIOA_C = 0; /* read register 0 */
+ c = SIOA_C;
+ irqrestore(irq);
+ if (c & 0x04) /* THRE? */
+ return TTY_READY_NOW;
+ return TTY_READY_SOON;
+ } else if (minor == 1) {
+ SIOB_C = 0; /* read register 0 */
+ c = SIOB_C;
+ irqrestore(irq);
+ if (c & 0x04) /* THRE? */
+ return TTY_READY_NOW;
+ return TTY_READY_SOON;
+ }
+ irqrestore(irq);
+ return TTY_READY_NOW;
+}
+
+void tty_data_consumed(uint8_t minor)
+{
+}
+
+/* kernel writes to system console -- never sleep! */
+void kputchar(char c)
+{
+ tty_putc(TTYDEV - 512, c);
+ if (c == '\n')
+ tty_putc(TTYDEV - 512, '\r');
+}
--- /dev/null
+#ifndef __DEVTTY_DOT_H__
+#define __DEVTTY_DOT_H__
+
+#define SIO0_BASE 0x00
+__sfr __at (SIO0_BASE + 0) SIOA_D;
+__sfr __at (SIO0_BASE + 1) SIOB_D;
+__sfr __at (SIO0_BASE + 2) SIOA_C;
+__sfr __at (SIO0_BASE + 3) SIOB_C;
+
+extern void sio2_otir(uint8_t port) __z88dk_fastcall;
+
+void tty_putc(uint8_t minor, unsigned char c);
+void tty_pollirq_sio(void);
+
+#endif
--- /dev/null
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devtty.h>
+#include <ds1302.h>
+#include <devide.h>
+#include <blkdev.h>
+#include "config.h"
+
+void map_init(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;
+ while(n)
+ swapmap_init(n--);
+}
+
+void device_init(void)
+{
+#ifdef CONFIG_IDE
+ devide_init();
+#endif
+}
--- /dev/null
+-mwxuy
+-i fuzix.ihx
+-b _COMMONMEM=0x0100
+-b _CODE=0x0B00
+-l z80
+platform-linc80/crt0.rel
+platform-linc80/commonmem.rel
+platform-linc80/linc80.rel
+start.rel
+version.rel
+lowlevel-z80.rel
+platform-linc80/tricks.rel
+platform-linc80/main.rel
+timer.rel
+kdata.rel
+platform-linc80/devices.rel
+devio.rel
+filesys.rel
+process.rel
+inode.rel
+syscall_exec16.rel
+syscall_fs.rel
+syscall_proc.rel
+syscall_fs2.rel
+syscall_fs3.rel
+syscall_other.rel
+mm.rel
+swap.rel
+simple.rel
+tty.rel
+devsys.rel
+usermem.rel
+usermem_std-z80.rel
+platform-linc80/discard.rel
+platform-linc80/devtty.rel
+platform-linc80/mbr.rel
+platform-linc80/blkdev.rel
+platform-linc80/devide.rel
+platform-linc80/devide_discard.rel
+-e
--- /dev/null
+; FUZIX mnemonics for memory addresses etc
+
+U_DATA .equ 0x0103 ; (this is struct u_data from kernel.h)
+U_DATA__TOTALSIZE .equ 0x0200 ; 256+256+256 bytes.
+Z80_TYPE .equ 0 ; CMOS
+
+Z80_MMU_HOOKS .equ 0
+
+CONFIG_SWAP .equ 1
+
+PROGBASE .equ 0x8000
+PROGLOAD .equ 0x8000
+
+; Mnemonics for I/O ports etc
+
+CONSOLE_RATE .equ 115200
+
+CPU_CLOCK_KHZ .equ 7372
+
+SIOA_D .EQU 0x00
+SIOB_D .EQU 0x01
+SIOA_C .EQU 0x02
+SIOB_C .EQU 0x03
+
+; Z80 CTC ports
+CTC_CH0 .equ 0x08 ; CTC channel 0 and interrupt vector
+CTC_CH1 .equ 0x09 ; CTC channel 1
+CTC_CH2 .equ 0x0A ; CTC channel 2
+CTC_CH3 .equ 0x0B ; CTC channel 3
+
+NBUFS .equ 4
+
--- /dev/null
+;
+; Linc80 Initial Support
+;
+
+ .module linc80
+
+ ; exported symbols
+ .globl init_hardware
+ .globl interrupt_handler
+ .globl _program_vectors
+ .globl _kernel_flag
+ .globl map_kernel
+ .globl map_buffers
+ .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_for_swap
+ .globl _platform_reboot
+ .globl _int_disabled
+ .globl platform_interrupt_all
+ .globl _need_resched
+
+ ; exported debugging tools
+ .globl _platform_monitor
+ .globl outchar
+
+ ; imported symbols
+ .globl _ramsize
+ .globl _procmem
+ .globl istack_top
+ .globl istack_switched_sp
+ .globl kstack_top
+ .globl unix_syscall_entry
+ .globl null_handler
+ .globl nmi_handler
+ .globl outcharhex
+
+ .globl s__COMMONMEM
+ .globl l__COMMONMEM
+
+ .include "kernel.def"
+ .include "../kernel.def"
+
+
+;
+; 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
+
+ .area _COMMONMEM
+
+_platform_monitor:
+ ; Reboot ends up back in the monitor
+_platform_reboot:
+ xor a
+ out (0x38), a ; ROM appears low
+ rst 0 ; bang
+
+_int_disabled:
+ .db 1
+
+map_buffers:
+map_kernel:
+map_kernel_di:
+ push af
+ ld a,#1
+map_a:
+ ld (mapreg),a
+ out (0x38),a
+ pop af
+ ret
+map_process:
+ ld a,h
+ or l
+ jr z, map_kernel
+map_process_always:
+map_process_always_di:
+map_for_swap:
+ push af
+ ld a,#3
+ jr map_a
+map_save_kernel:
+ push af
+ ld a,(mapreg)
+ ld (mapsave),a
+ ld a,#1
+ jr map_a
+map_restore:
+ push af
+ ld a,(mapsave)
+ jr map_a
+
+_program_early_vectors:
+ ; 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
+
+_program_vectors:
+platform_interrupt_all:
+ ret
+
+ .globl spurious ; so we can debug trap on it
+
+spurious:
+ reti
+
+mapreg:
+ .db 0
+mapsave:
+ .db 0
+
+_need_resched:
+ .db 0
+
+
+
+; -----------------------------------------------------------------------------
+; All of discard gets reclaimed when init is run
+;
+; Discard must be above 0x8000 as we need some of it when the ROM
+; is paged in during init_hardware
+; -----------------------------------------------------------------------------
+ .area _DISCARD
+
+init_hardware:
+ call _program_early_vectors
+ ; IM2 vector for the CTC
+ ld hl, #spurious
+ ld (0x80),hl ; CTC vectors
+ ld (0x82),hl
+ ld (0x84),hl
+ ld hl, #interrupt_handler ; Standard tick handler
+ ld (0x86),hl
+
+ ld hl,#spurious ; For now
+ ld (0x88),hl ; PIO A
+ ld (0x8A),hl ; PIO B
+
+ ld hl,#spurious ; For now
+ ld (0x90),hl ; SIO B TX empty
+ ld (0x92),hl ; SIO B External status
+ ld (0x94),hl ; SIO B Receive
+ ld (0x96),hl ; SIO B Special
+ ld (0x98),hl ; SIO A TX empty
+ ld (0x9A),hl ; SIO A External status
+ ld (0x9C),hl ; SIO A Received
+ ld (0x9E),hl ; SIO A Special
+ ld hl, #80
+ ld (_ramsize), hl
+ ld hl,#32
+ ld (_procmem), hl
+
+ ld hl,#sio_setup
+ ld bc,#0xA00 + SIOA_C ; 10 bytes to SIOA_C
+ otir
+ ld hl,#sio_setup
+ ld bc,#0x0C00 + SIOB_C ; and to SIOB_C with vector
+ otir
+
+ ;
+ ; Now program up the CTC
+ ; CTC 0 and CTC 1 are set up for the serial and we should
+ ; not touch them. We configure up 2 and 3
+ ;
+ ld a,#0x80
+ out (CTC_CH0),a ; set the CTC vector
+
+ ld a,#0x25 ; timer, 256 prescale, irq off
+ out (CTC_CH2),a
+ ld a,#180 ; counter base (160 per second)
+ out (CTC_CH2),a
+ ld a,#0xF5 ; counter, irq on
+ out (CTC_CH3),a
+ ld a,#16
+ out (CTC_CH3),a ; 160 per sec down to 10 per sec
+
+ xor a
+ ld i,a ; Use upper half of rst vector page
+ im 2 ; set CPU interrupt
+
+ ret
+
+RTS_LOW .EQU 0xEA
+
+sio_setup:
+ .byte 0x00
+ .byte 0x18 ; Reset
+ .byte 0x04
+ .byte 0xC4
+ .byte 0x01
+ .byte 0x18
+ .byte 0x03
+ .byte 0xE1
+ .byte 0x05
+ .byte RTS_LOW
+ .byte 0x02 ; IRQ vector (B only)
+ .byte 0x90
+
+ .area _CODE
+
+_kernel_flag:
+ .db 1 ; We start in kernel mode
+
+
+;
+; A little SIO helper
+;
+ .globl _sio_r
+ .globl _sio2_otir
+
+_sio2_otir:
+ ld b,#0x06
+ ld c,l
+ ld hl,#_sio_r
+ otir
+ ret
+;
+; outchar: Wait for UART TX idle, then print the char in A
+; destroys: AF
+;
+; We use the A port for debug as the console is usually on B
+;
+outchar:
+ push af
+ ; wait for transmitter to be idle
+ocloop_sio:
+ xor a ; read register 0
+ out (SIOA_C), a
+ in a,(SIOA_C) ; read Line Status Register
+ and #0x04 ; get THRE bit
+ jr z,ocloop_sio
+ ; now output the char to serial port
+ pop af
+ out (SIOA_D),a
+ ret
+
--- /dev/null
+;
+; The CP/M command blindly loads the first 24 blocks moves them to the
+; top 12K and then runs whatever is indicated at 0xFFFE/FFFF
+;
+
+ .area VECTOR(ABS)
+
+ .org 0xFFFE
+ .word start
+
+ .area LOADER(ABS)
+
+ .org 0xD000
+
+DATA .equ 0x10
+ERROR .equ 0x11
+FEATURES .equ 0x11
+COUNT .equ 0x12
+LBA_0 .equ 0x13
+LBA_1 .equ 0x14
+LBA_2 .equ 0x15
+LBA_3 .equ 0x16
+STATUS .equ 0x17
+CMD .equ 0x17
+
+ERR .equ 0
+DRQ .equ 3
+READY .equ 6
+BUSY .equ 7
+
+ATA_READ .equ 0x20
+
+SIOB_C .equ 3
+SIOB_D .equ 1
+
+ .ds 10240 ; boot sector and more for loader space
+
+start:
+ ; A modern partition setup has lots of room for boot space, so we
+ ; just load the blocks after the loader (24-147). We can't overlap
+ ; because of the FFFE/FFFF thing.
+
+ ld sp, #0xFE00
+ ld hl,#hello
+ call serstr
+
+ call ide_ready
+ ld a,#0xE0
+ out (LBA_3),a
+ call ide_ready
+ xor a
+ out (LBA_2),a
+ out (LBA_1),a
+
+ ld de,#0x7C18 ; sectors 24-119
+ ld hl,#0x0100 ; load address
+load_loop:
+ call ide_ready
+ ld a,e
+ out (LBA_0),a
+ ld a,#1
+ out (COUNT),a
+ ld a,#ATA_READ
+ out (CMD),a
+ nop
+ call ide_wait_drq
+ ld bc,#DATA
+ inir
+ inir
+ ld a,#'.'
+ call serout
+ inc e
+ dec d
+ jr nz, load_loop
+ ld hl,#gogogo
+ call serstr
+ jp 0x0100
+
+ide_ready:
+ in a,(STATUS)
+ bit BUSY,a
+ jr nz, ide_ready
+ bit READY,a
+ jr z, ide_ready
+ ret
+ide_wait_drq:
+ in a,(STATUS)
+ bit DRQ,a
+ jr z,ide_wait_drq
+ ret
+
+
+serout:
+ push af
+ ; wait for transmitter to be idle
+ocloop_sio:
+ xor a ; read register 0
+ out (SIOB_C), a
+ in a,(SIOB_C) ; read Line Status Register
+ and #0x04 ; get THRE bit
+ jr z,ocloop_sio
+ ; now output the char to serial port
+ pop af
+ out (SIOB_D),a
+ ret
+
+serstr:
+ ld a,(hl)
+ or a
+ ret z
+ inc hl
+ call serout
+ jr serstr
+
+hello:
+ .asciz 'LiNC80 FUZIX LOADER 0.1\n\n'
+gogogo:
+ .asciz '\nExecuting FUZIX...\n'
--- /dev/null
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <timer.h>
+#include <devtty.h>
+
+extern unsigned char irqvector;
+struct blkbuf *bufpool_end = bufpool + NBUFS; /* minimal for boot -- expanded after we're done with _DISCARD */
+uint16_t swap_dev = 0xFFFF;
+uint16_t ramtop = 0xFFFF;
+
+void platform_discard(void)
+{
+ while (bufpool_end < (struct blkbuf *) (KERNTOP - sizeof(struct blkbuf))) {
+ memset(bufpool_end, 0, sizeof(struct blkbuf));
+#if BF_FREE != 0
+ bufpool_end->bf_busy = BF_FREE; /* redundant when BF_FREE == 0 */
+#endif
+ bufpool_end->bf_dev = NO_DEVICE;
+ bufpool_end++;
+ }
+ kprintf("Buffers available: %d\n", bufpool_end - bufpool);
+}
+
+static uint8_t idlect;
+
+void platform_idle(void)
+{
+ __asm
+ halt
+ __endasm;
+}
+
+uint8_t platform_param(unsigned char *p)
+{
+ used(p);
+ return 0;
+}
+
+void platform_interrupt(void)
+{
+ tty_pollirq_sio(); /* For now as we don't have nice
+ tty set up yet */
+ timer_interrupt();
+}
+
--- /dev/null
+#define ide_select(x)
+#define ide_deselect()
+
+/* 8bit, no altstatus/control */
+#define IDE_8BIT_ONLY
+#define IDE_REG_CS1_BASE 0x10
--- /dev/null
+export CPU = z80
--- /dev/null
+ .include "kernel.def"
+ .include "../kernel.def"
+
+ .include "../lib/z80single.s"
+