--- /dev/null
+ASRCS = crt0.s tricks.s commonmem.s rc2014.s
+CSRCS = devices.c main.c devtty.c
+DISCARD_CSRCS = discard.c
+DISCARD_DSRCS = ../dev/devide_discard.c ../dev/ds1302_discard.c ../dev/mbr.c
+DSRCS = ../dev/devide.c ../dev/blkdev.c
+DSRCS += ../dev/ds1302.c
+DASRCS = ../dev/ds1302_rc2014.s
+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))
+DAOBJS = $(patsubst ../dev/%.s,%.rel, $(DASRCS))
+NOBJS = $(patsubst ../dev/net/%.c,%.rel, $(NSRCS))
+
+OBJS = $(AOBJS) $(COBJS) $(DOBJS) $(DAOBJS) $(DISCARD_DOBJS) $(DISCARD_COBJS) $(NOBJS)
+
+CROSS_CCOPTS += -I../dev/ -I../dev/net/
+
+CROSS_CC_HIGH = --codeseg COMMONMEM
+
+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 $<
+
+$(DAOBJS): %.rel: ../dev/%.s
+ $(CROSS_AS) $(ASOPTS) $@ $<
+
+$(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 *~ diskstrap fuzix.rom boot loader.inc
+
+image: boot loader
+
+boot: boot.s
+ sdasz80 -o boot.s
+ sdldz80 -i boot.rel
+ makebin -s 4096 boot.ihx boot
+ od -v -w1 -tx1 boot | cut -b 9- | head -4096 | \
+ sed -e 's/^/ .db 0x/' >loader.inc
+
+loader: loader.s loader.inc
+ sdasz80 -o loader.s
+ sdldz80 -i loader.rel
+
+loader.inc: boot.s
--- /dev/null
+Fuzix for the Z80SBC64 and in theory Z80MB64 platforms
+
+Supported Hardware
+
+ RC2014 SBC64 mainboard or MB64 (see notes)
+ DS1302 RTC card (required)
+
+ (CTC is not yet supported but will be a far faster/nicer option once
+ it is. At that point you will need CTC or RTC or both)
+
+ Options
+
+ RC2014 SIO/2 board (or compatible). ACIA is not supported.
+
+ RC2014 Joystick
+
+In Progress
+ CTC at 0x88 for SIO timing and for system clock
+
+ Most other RC2014 cards supported by other platforms should also be
+ possible to add if anyone needs them.
+
+ Suspend to RAM/Resume
+
+Things That Don't Work (yet)
+
+ Flow control
+ SIO speed changing
+
+Notes
+ The Z80MB64 is 22MHz which means there are not yet RTC or CTC for it!
+
+Setting It Up
+
+Put the jumpers into serial download mode and send Z80SBCLD.BIN as per normal
+
+When it prompts 'Z80BC64 Loader 0.2'
+- Send Kernel/platform/loader.ihx
+- Type G B000 (only the G is echoed)
+
+You should see
+
+ Configuring booter...Done
+
+ and then the message
+
+ SBC64 Boot Loader
+ Loading image from disk...done
+
+You can now power off and change the jumper.
+
+At this point it will report a bad image unless you've created a suitable Fuzix
+image on the CF. Fuzix is looking for a standard Fuzix style PC partitioned CF
+card with a filesystem partition (7e) and a swap partition (7f). Make sure the
+partition table is a modern style one (starting partitions at block 2048 not
+block 63).
+
+The kernel image goes at block 2+ on the CF card. With Linux it's a simple matter
+of using dd (carefully)
+
+dd if=Kernel/fuzix.bin of=/dev/sdxx bs=512 seek=2 conv=notrunc
+
+Something similar should work on MacOS. People have reported problems with Cygwin
+dd on windows but I'm not clear why.
+
+To get back to the CP/M image put the jumper back into serial mode and
+follow the download instructions. You will need a different CF card for CP/M as
+unfortunately like RC2014 CP/M in general the supplied CP/M does not honour
+partition tables.
+
+Emulation
+
+Apart from remembering the emulated hard disk has a 1K header all is the same
+
+ ./rc2014 -m z80sbc64 -r sbc64.ram -i sbc64.ide -R
+
+(and to bootstrap initially copy Z80SBCLD.BIN to sbc64.ram)
+
--- /dev/null
+;
+; BOOT and restart image
+;
+; We are entered at power on with bank = 3
+;
+
+resume_tag .equ 0x0084
+
+ .area _BOOT(ABS)
+
+ .org 0x0000
+start:
+ jp init
+
+ .org 0x0080
+init:
+ di
+ ld sp,#0x1000 ; safe spot
+
+ ld hl,#signon
+ call outstr
+
+ ; See if we are loading an image or resuming from memory
+ or a
+ ld hl,(resume_tag)
+ ld de,#0xC0DE
+ sbc hl,de
+ jr nz, disk_load
+ ld a,(0x1003)
+ cp #0xC3
+ jr nz, disk_load
+ ld hl,#resuming
+ call outstr
+ jp 0x1003
+
+signon:
+ .ascii 'SBC64 Boot Loader'
+ .db 13,10,0
+resuming:
+ .ascii 'Resuming from memory'
+ .db 13,10,0
+
+
+disk_load:
+ ld hl,#loading
+ call outstr
+ ; Init the ATA CF
+ ld a,#0xE0
+ out (0x16),a
+ xor a
+ out (0x14),a
+ out (0x15),a
+ ; Set 8bit mode
+ call wait_ready
+ ld a, #1 ; 8bit PIO
+ out (0x11),a
+ ld a, #0xEF ; SET FEATURES (8bit PIO)
+ out (0x17),a
+ call wait_ready
+
+ ; Load the kernel
+ ld d,#1
+ ld bc,#0x10 ; c = data port b = 0
+ ld hl,#0x1000 ; Load 1000-D000 (should be sufficient)
+loader:
+ inc d
+ call load_sector
+ ld a,#0xD0
+ cp h
+ jr nz, loader
+
+ ld a,(0x1003)
+ cp #0xC3
+ jr nz, badimage
+ ld a,(0x1003)
+ cp #0xC3
+ jr nz, badimage
+ ld hl,(0x1006)
+ ld de,#0x10AD
+ or a
+ sbc hl,de
+ jr nz, badimage
+
+ ld hl,#gogogo
+ call outstr
+ jp 0x1000
+
+loading:
+ .asciz 'Loading image from disk...'
+gogogo:
+ .ascii 'done'
+ .db 13,10,0
+
+badimage:
+ ld hl,#badbadbad
+ call outstr
+ halt
+
+badbadbad:
+ .ascii 'Invalid image or CF problem'
+ .db 13,10,0
+
+;
+; Load sector d from disk into HL and advance HL accordingly
+;
+load_sector:
+ ld a,d
+ out (0x13),a ; LBA
+ ld a,#1
+ out (0x12),a ; 1 sector
+ ld a,#0x20
+ out (0x17),a ; command
+ ; Wait
+wait_drq:
+ in a,(0x17)
+ bit 3,a
+ jr z, wait_drq
+ ; Get data, leave HL pointing to next byte, leaves B as 0 again
+ inir
+ inir
+ ret
+wait_ready:
+ in a,(0x17)
+ bit 6,a
+ jr z,wait_ready
+ ret
+
+outstr:
+ ld a,(hl)
+ or a
+ ret z
+ call outchar
+ inc hl
+ jr outstr
+
+;
+; Based on the ROM code but slightly tighter
+; - use ld a,#0 so 0 and 1 bits are same length
+; - don't duplicate excess code in the hi/lo bit paths
+; - use conditional calls to keep 0/1 timing identical
+;
+; FIXME: my math says it's still slightly off timing.
+;
+outchar:
+ push bc
+ ld c,a
+ ld b,#8
+ call lobit
+ ld a,c
+txbit:
+ rrca
+ call c, hibit
+ call nc, lobit
+ djnz txbit
+ pop bc
+hibit:
+ push af
+ ld a,#0xff
+ out (0xf9),a
+ ld a,#7
+bitwait:
+ dec a
+ jp nz,bitwait
+ pop af
+ ret
+lobit:
+ push af
+ ld a,#0
+ out (0xf9),a
+ ld a,#7
+ dec a
+ jp bitwait
--- /dev/null
+;
+; Common is placed at 0xF000 by fuzix.lnk
+;
+
+ .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 */
+#define CONFIG_MULTI
+/* Fixed bank sizes in RAM */
+#define CONFIG_BANK_FIXED
+#define MAP_SIZE 0x8000
+#define MAX_MAPS 2 /* 128K: 2 x 32K user 1 x 60K kernel 4K boot */
+
+/* Permit large I/O requests to bypass cache and go direct to userspace */
+#define CONFIG_LARGE_IO_DIRECT(x) 1
+/* Memory banks */
+#define CONFIG_BANKS 1
+#define TICKSPERSEC 10 /* Ticks per second */
+#define PROGBASE 0x0000 /* also data base */
+#define PROGLOAD 0x0100 /* also data base */
+#define PROGTOP 0x7E00 /* Top of program */
+
+#define PROC_SIZE 32 /* Memory needed per process */
+
+#define SWAPDEV (swap_dev) /* A variable for dynamic, or a device major/minor */
+extern unsigned int swap_dev;
+#define SWAP_SIZE 0x40 /* 32K in blocks (prog + udata) */
+#define SWAPBASE 0x0000 /* start at the base of user mem */
+#define SWAPTOP 0x8000 /* Swap out program */
+#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
+
+/*
+ * 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 2 /* 2 IDE */
+
+/* On-board DS1302, we can read the time of day from it */
+#define CONFIG_RTC
+#define CONFIG_RTC_FULL
+#define CONFIG_NO_CLOCK
+
+/* IDE/CF support */
+#define CONFIG_IDE
+
+/* Device parameters */
+#define NUM_DEV_TTY 3
+
+/* UART0 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
+ .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.
+
+ ; Start with the ROM area CODE-CODE2
+ .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
+ .area _GSINIT ; unused
+ .area _GSFINAL ; unused
+ .area _BUFFERS ; _BUFFERS grows to consume all before it (up to KERNTOP)
+ ; Discard is loaded where process memory wil blow it away
+ .area _DISCARD
+ ; The rest grows upwards from C000 starting with the udata so we can
+ ; swap in one block, ending with the buffers so they can expand up
+ ; note that areas below here may be overwritten by the heap at runtime, so
+ ; put initialisation stuff in here
+ ; These get overwritten and don't matter
+ .area _INITIALIZER ; binman copies this to the right place for us
+ .area _COMMONMEM
+
+ ; exported symbols
+ .globl _suspend
+
+ ; 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 s__BUFFERS
+ .globl l__BUFFERS
+ .globl kstack_top
+
+ .globl interrupt_handler
+ .globl nmi_handler
+ .globl outstring
+
+ .include "kernel.def"
+
+ ; Starts at 0x1000 at the moment
+
+ ; Entered with bank = 3 from the bootstrap logic
+
+resume_sp .equ 0x0080
+resume_tag .equ 0x0084
+
+ .area _CODE
+
+ jp start
+ jp resume
+ .dw 0x10AD
+
+start:
+ ld sp, #kstack_top
+
+ ; move the common memory where it belongs
+ ld hl, #s__DATA
+ ld de, #s__COMMONMEM
+ ld bc, #l__COMMONMEM
+ ldir
+ ; then the discard
+ ; Discard can just be linked in but is next to the buffers
+ ld de, #s__DISCARD
+ ld bc, #l__DISCARD
+ ldir
+
+ ld hl, #s__DATA
+ ld de, #s__DATA + 1
+ ld bc, #l__DATA - 1
+ ld (hl),#0
+ ldir
+
+ ; Zero buffers area
+ ld hl, #s__BUFFERS
+ ld de, #s__BUFFERS + 1
+ ld bc, #l__BUFFERS - 1
+ ld (hl), #0
+ ldir
+
+ call init_hardware
+ call _fuzix_main
+ ; Should never return
+ di
+stop: halt
+ jr stop
+;
+; Helpers for the battery backed memory model
+;
+resume:
+ di
+ ld sp, (resume_sp)
+ pop iy
+ pop ix
+ ld hl, #0
+ ld (resume_tag), hl
+ ret
+
+_suspend:
+ push ix
+ push iy
+ ld (resume_sp), sp
+ ld hl,#0xC0DE
+ ld (resume_tag), hl
+ ld hl, #suspended
+ call outstring
+ di
+ halt
+suspended:
+ .ascii 'Suspended, you may now power off'
+ .db 13,10,0
+
+
+
\ No newline at end of file
--- /dev/null
+#include <kernel.h>
+#include <version.h>
+#include <kdata.h>
+#include <tty.h>
+#include <devsys.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 <input.h>
+#include <devinput.h>
+
+__sfr __at 0x01 js1;
+__sfr __at 0x02 js2;
+
+static uint8_t js_data[2]= {255, 255};
+
+uint8_t read_js(uint8_t *slot, uint8_t n, uint8_t r)
+{
+ uint8_t d = 0;
+ r &= 63;
+ if (r == js_data[n])
+ return 0;
+ js_data[n] = r;
+ if (r & 1)
+ d = STICK_DIGITAL_U;
+ if (r & 2)
+ d |= STICK_DIGITAL_D;
+ if (r & 4)
+ d |= STICK_DIGITAL_L;
+ if (r & 8)
+ d |= STICK_DIGITAL_R;
+ if (r & 16)
+ d |= BUTTON(0);
+ if (r & 32)
+ d |= BUTTON(1);
+ *slot++ = STICK_DIGITAL | (n + 1);
+ *slot = d;
+ return 2;
+}
+
+int platform_input_read(uint8_t *slot)
+{
+ if (read_js(slot, 0, js1))
+ return 2;
+ if (read_js(slot, 1, js2))
+ return 2;
+ return 0;
+}
+
+void platform_input_wait(void)
+{
+ psleep(&js_data);
+}
+
+void poll_input(void)
+{
+ if ((js1 & 63) != js_data[0] ||
+ ((js2 & 63) != js_data[1]))
+ wakeup(&js_data);
+}
+
+int platform_input_write(uint8_t flag)
+{
+ flag;
+ udata.u_error = EINVAL;
+ return -1;
+}
--- /dev/null
+extern void poll_input(void);
--- /dev/null
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <stdbool.h>
+#include <tty.h>
+#include <devtty.h>
+#include <rc2014.h>
+
+__sfr __at 0xf8 cpld_status;
+__sfr __at 0xf9 cpld_data;
+
+static char tbuf1[TTYSIZ];
+static char tbuf2[TTYSIZ];
+static char tbuf3[TTYSIZ];
+
+static uint8_t sleeping;
+
+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},
+ {tbuf3, tbuf3, tbuf3, TTYSIZ, 0, TTYSIZ / 2},
+};
+
+static tcflag_t uart0_mask[4] = {
+ _ISYS,
+ _OSYS,
+ _CSYS,
+ _LSYS
+};
+
+static tcflag_t uart1_mask[4] = {
+ _ISYS,
+ _OSYS,
+ CSIZE|CSTOPB|PARENB|PARODD|_CSYS,
+ _LSYS
+};
+
+static tcflag_t uart2_mask[4] = {
+ _ISYS,
+ /* FIXME: break */
+ _OSYS,
+ /* FIXME CTS/RTS */
+ CSIZE|CBAUD|CSTOPB|PARENB|PARODD|_CSYS,
+ _LSYS,
+};
+
+tcflag_t *termios_mask[NUM_DEV_TTY + 1] = {
+ NULL,
+ uart0_mask,
+ uart1_mask,
+ uart2_mask
+};
+
+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;
+
+ used(flags);
+
+ /* 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)
+{
+ if (minor == 1)
+ return;
+ sio2_setup(minor, flags);
+ sio2_otir(SIO0_BASE + 2 * (minor - 1));
+ /* We need to do CTS/RTS support and baud setting on channel 2
+ yet */
+}
+
+int tty_carrier(uint8_t minor)
+{
+ uint8_t c;
+ if (minor == 1)
+ return 1;
+ else 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))
+ 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[1])) {
+ progress = 1;
+ tty_inproc(1, SIOA_D);
+ }
+ /* Break */
+ if (ca & 2)
+ SIOA_C = 2 << 5;
+ /* Output pending */
+ if ((ca & 4) && (sleeping & 2)) {
+ tty_outproc(1);
+ sleeping &= ~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(1);
+ else
+ tty_carrier_drop(1);
+ }
+ SIOB_C = 0; // read register 0
+ cb = SIOB_C;
+ if ((cb & 1) && !fullq(&ttyinq[2])) {
+ tty_inproc(2, SIOB_D);
+ progress = 1;
+ }
+ if ((cb & 4) && (sleeping & 4)) {
+ tty_outproc(2);
+ sleeping &= ~4;
+ SIOB_C = 5 << 3; // reg 0 CMD 5 - reset transmit interrupt pending
+ }
+ if ((cb ^ old_cb) & 8) {
+ if (cb & 8)
+ tty_carrier_raise(2);
+ else
+ tty_carrier_drop(2);
+ }
+ } while(progress);
+}
+
+void tty_poll_cpld(void)
+{
+ uint8_t ca;
+
+ ca = cpld_status;
+ if (ca & 1)
+ tty_inproc(1, cpld_data);
+}
+
+void tty_putc(uint8_t minor, unsigned char c)
+{
+ if (minor == 1)
+ cpld_bitbang(c);
+ if (minor == 2)
+ SIOA_D = c;
+ else if (minor == 2)
+ SIOB_D = c;
+}
+
+/* We will need this for SIO once we implement flow control signals */
+void tty_sleeping(uint8_t minor)
+{
+ sleeping |= (1 << 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;
+
+ /* Bitbanged so trick the kernel into yielding when appropriate */
+ if (minor == 1)
+ return need_reschedule() ? TTY_READY_SOON: TTY_READY_NOW;
+ 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 == 3) {
+ 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)
+{
+ used(minor);
+}
+
+/* kernel writes to system console -- never sleep! */
+void kputchar(char c)
+{
+ /* Always use the bitbang port - no need for write waits therefore */
+ if (c == '\n')
+ tty_putc(TTYDEV - 512, '\r');
+ tty_putc(TTYDEV - 512, c);
+}
--- /dev/null
+#ifndef __DEVTTY_DOT_H__
+#define __DEVTTY_DOT_H__
+
+void tty_putc(uint8_t minor, unsigned char c);
+void tty_pollirq_sio(void);
+void tty_poll_cpld(void);
+
+extern uint8_t ser_type;
+
+#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)
+{
+}
+
+void pagemap_init(void)
+{
+ /* The high bits do nothing but it's a cheap way to avoid 0x00 */
+ pagemap_add(0x12);
+ pagemap_add(0x10);
+}
+
+/*
+ * 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)
+{
+ ds1302_init();
+#ifdef CONFIG_IDE
+ devide_init();
+#endif
+}
--- /dev/null
+-mwxuy
+-i fuzix.ihx
+-b _CODE=0x1000
+-b _COMMONMEM=0xF400
+-l z80
+platform-rc2014-sbc64/crt0.rel
+platform-rc2014-sbc64/commonmem.rel
+platform-rc2014-sbc64/rc2014.rel
+start.rel
+version.rel
+lowlevel-z80.rel
+platform-rc2014-sbc64/tricks.rel
+platform-rc2014-sbc64/main.rel
+timer.rel
+kdata.rel
+platform-rc2014-sbc64/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
+bankfixed.rel
+tty.rel
+devsys.rel
+usermem.rel
+usermem_std-z80.rel
+platform-rc2014-sbc64/discard.rel
+platform-rc2014-sbc64/devtty.rel
+platform-rc2014-sbc64/mbr.rel
+platform-rc2014-sbc64/blkdev.rel
+platform-rc2014-sbc64/devide.rel
+platform-rc2014-sbc64/devide_discard.rel
+platform-rc2014-sbc64/ds1302.rel
+platform-rc2014-sbc64/ds1302_discard.rel
+platform-rc2014-sbc64/ds1302_rc2014.rel
+-e
--- /dev/null
+; FUZIX mnemonics for memory addresses etc
+
+U_DATA .equ 0xF400 ; (this is struct u_data from kernel.h)
+U_DATA__TOTALSIZE .equ 0x200 ; 256+256 bytes.
+Z80_TYPE .equ 0 ; CMOS
+U_DATA_STASH .equ 0x7E00
+
+Z80_MMU_HOOKS .equ 0
+
+CONFIG_SWAP .equ 1
+
+PROGBASE .equ 0x0000
+PROGLOAD .equ 0x0100
+
+; Mnemonics for I/O ports etc
+
+CONSOLE_RATE .equ 115200
+
+CPU_CLOCK_KHZ .equ 7372
+
+; Z80 CTC ports
+CTC_CH0 .equ 0x88 ; CTC channel 0 and interrupt vector
+CTC_CH1 .equ 0x89 ; CTC channel 1 (periodic interrupts)
+CTC_CH2 .equ 0x8A ; CTC channel 2
+CTC_CH3 .equ 0x8B ; CTC channel 3
--- /dev/null
+
+ .area _BOOT(ABS)
+
+ .org 0xB000
+
+installer:
+ ld a,#0x03
+ out (0x1f),a
+ ld hl,#begin
+ call outstr
+ ld hl,#data
+ ld de,#0x0000
+ ld bc,#0x1000
+ ldir
+ ld hl,#done
+ call outstr
+ rst 0
+
+begin:
+ .asciz 'Configuring booter...'
+done:
+ .ascii 'Done'
+ .db 13,10,0
+
+outstr:
+ ld a,(hl)
+ or a
+ ret z
+ call outchar
+ inc hl
+ jr outstr
+
+;
+; Based on the ROM code but slightly tighter
+; - use ld a,#0 so 0 and 1 bits are same length
+; - don't duplicate excess code in the hi/lo bit paths
+; - use conditional calls to keep 0/1 timing identical
+;
+; FIXME: my math says it's still slightly off timing.
+;
+outchar:
+ push bc
+ ld c,a
+ ld b,#8
+ call lobit
+ ld a,c
+txbit:
+ rrca
+ call c, hibit
+ call nc, lobit
+ djnz txbit
+ pop bc
+hibit:
+ push af
+ ld a,#0xff
+ out (0xf9),a
+ ld a,#7
+bitwait:
+ dec a
+ jp nz,bitwait
+ pop af
+ ret
+lobit:
+ push af
+ ld a,#0
+ out (0xf9),a
+ ld a,#7
+ dec a
+ jp bitwait
+
+data:
+ .include "loader.inc"
--- /dev/null
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <timer.h>
+#include <devtty.h>
+#include <devfd.h>
+#include <rtc.h>
+#include <ds1302.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 = 0x7E00;
+uint8_t ctc = 0;
+
+void platform_discard(void)
+{
+ while (bufpool_end < (struct blkbuf *) ((uint16_t)&udata - 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++;
+ }
+}
+
+static uint8_t idlect;
+
+void platform_idle(void)
+{
+ /* Check the clock. We try and reduce the impact of the clock on
+ latency by not doing it so often. 256 may be too small a divide
+ need t see what 1/10th sec looks like in poll loops */
+ tty_poll_cpld();
+ if (!idlect++)
+ sync_clock();
+}
+
+uint8_t platform_param(unsigned char *p)
+{
+ used(p);
+ return 0;
+}
+
+void platform_interrupt(void)
+{
+ tty_pollirq_sio();
+}
+
+/*
+ * Logic for tickless system. If you have an RTC you can ignore this.
+ */
+
+static uint8_t newticks = 0xFF;
+static uint8_t oldticks;
+
+static uint8_t re_enter;
+
+/*
+ * Hardware specific logic to get the seconds. We really ought to enhance
+ * this to check minutes as well just in case something gets stuck for
+ * ages.
+ */
+static void sync_clock_read(void)
+{
+ uint8_t s;
+ oldticks = newticks;
+ ds1302_read_clock(&s, 1);
+ s = (s & 0x0F) + (((s & 0xF0) >> 4) * 10);
+ newticks = s;
+}
+
+/*
+ * The OS core will invoke this routine when idle (via platform_idle) but
+ * also after a system call and in certain other spots to ensure the clock
+ * is roughly valid. It may be called from interrupts, without interrupts
+ * or even recursively so it must protect itself using the framework
+ * below.
+ *
+ * Having worked out how much time has passed in 1/10ths of a second it
+ * performs that may timer_interrupt events in order to advance the clock.
+ * The core kernel logic ensures that we won't do anything silly from a
+ * jump forward of many seconds.
+ *
+ * We also choose to poll the ttys here so the user has some chance of
+ * getting control back on a messed up process.
+ */
+void sync_clock(void)
+{
+ if (!ctc) {
+ irqflags_t irq = di();
+ int16_t tmp;
+ if (!re_enter++) {
+ sync_clock_read();
+ if (oldticks != 0xFF) {
+ tmp = newticks - oldticks;
+ if (tmp < 0)
+ tmp += 60;
+ tmp *= 10;
+ while(tmp--) {
+ timer_interrupt();
+ }
+ }
+ }
+ re_enter--;
+ irqrestore(irq);
+ }
+}
+
+/*
+ * This method is called if the kernel has changed the system clock. We
+ * don't work out how much work we need to do by using it as a reference
+ * so we don't care.
+ */
+void update_sync_clock(void)
+{
+}
--- /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
+#ifndef __RC2014_SIO_DOT_H__
+#define __RC2014_SIO_DOT_H__
+
+#include "config.h"
+
+#define SIO0_IVT 8
+
+/* Standard RC2014 */
+#define SIO0_BASE 0x80
+__sfr __at (SIO0_BASE + 0) SIOA_C;
+__sfr __at (SIO0_BASE + 1) SIOA_D;
+__sfr __at (SIO0_BASE + 2) SIOB_C;
+__sfr __at (SIO0_BASE + 3) SIOB_D;
+
+extern void sio2_otir(uint8_t port) __z88dk_fastcall;
+extern void cpld_bitbang(uint8_t c) __z88dk_fastcall;
+
+#endif
--- /dev/null
+; 2014-02-19 Sergey Kiselev
+; RC2014 hardware specific code
+
+ .module rc2014
+
+ ; exported symbols
+ .globl init_hardware
+ .globl _program_vectors
+ .globl map_kernel
+ .globl map_process
+ .globl map_process_always
+ .globl map_process_a
+ .globl map_kernel_di
+ .globl map_process_di
+ .globl map_process_always_di
+ .globl map_save_kernel
+ .globl map_restore
+ .globl map_for_swap
+ .globl map_buffers
+ .globl platform_interrupt_all
+ .globl _platform_reboot
+ .globl _platform_monitor
+ .globl _bufpool
+ .globl _int_disabled
+ .globl _cpld_bitbang
+
+ ; imported symbols
+ .globl _ramsize
+ .globl _procmem
+ .globl outhl
+ .globl outnewline
+ .globl interrupt_handler
+ .globl unix_syscall_entry
+ .globl nmi_handler
+
+ ; exported debugging tools
+ .globl outchar
+
+ .include "kernel.def"
+ .include "../kernel.def"
+
+;=========================================================================
+; Constants
+;=========================================================================
+CONSOLE_DIVISOR .equ (1843200 / (16 * CONSOLE_RATE))
+CONSOLE_DIVISOR_HIGH .equ (CONSOLE_DIVISOR >> 8)
+CONSOLE_DIVISOR_LOW .equ (CONSOLE_DIVISOR & 0xFF)
+
+RTS_HIGH .EQU 0xE8
+RTS_LOW .EQU 0xEA
+
+; Base address of SIO/2 chip 0x80
+; For the Scott Baker SIO card adjust the order to match rc2014.h
+SIOA_C .EQU 0x80
+SIOA_D .EQU SIOA_D+1
+SIOB_C .EQU SIOA_D+2
+SIOB_D .EQU SIOA_D+3
+
+ACIA_C .EQU 0x80
+ACIA_D .EQU 0x81
+ACIA_RESET .EQU 0x03
+ACIA_RTS_HIGH_A .EQU 0xD6 ; rts high, xmit interrupt disabled
+ACIA_RTS_LOW_A .EQU 0x96 ; rts low, xmit interrupt disabled
+;ACIA_RTS_LOW_A .EQU 0xB6 ; rts low, xmit interrupt enabled
+
+;=========================================================================
+; Buffers
+;=========================================================================
+ .area _BUFFERS
+ .globl kernel_endmark
+
+_bufpool:
+ .ds (BUFSIZE * 4) ; adjust NBUFS in config.h in line with this
+;
+; So we can check for overflow
+;
+kernel_endmark:
+
+;=========================================================================
+; Initialization code
+;=========================================================================
+ .area _DISCARD
+init_hardware:
+ ld hl,#128
+ ld (_ramsize), hl
+ ld hl,#64
+ ld (_procmem), hl
+
+ ; FIXME: autodetect SIO
+
+ ld hl,#sio_setup
+ ld bc,#0xA00 + SIOA_C ; 10 bytes to SIOA_C
+ otir
+ ld hl,#sio_setup
+ ld bc,#0x0A00 + SIOB_C ; and to SIOB_C
+ otir
+
+serial_up:
+ ; ---------------------------------------------------------------------
+ ; Initialize CTC
+ ;
+ ; Need to do autodetect on this
+ ;
+ ; We must initialize all channels of the CTC. The documentation
+ ; states that the initial CTC state is undefined and we don't want
+ ; random interrupt surprises
+ ; ---------------------------------------------------------------------
+
+ ld a,#0x57 ; counter mode, disable interrupts
+ out (CTC_CH0),a ; set CH0 mode
+ ld a,#0 ; time constant = 256
+ out (CTC_CH0),a ; set CH0 time constant
+ ld a,#0x57 ; counter mode, FIXME C7 enable interrupts
+ out (CTC_CH1),a ; set CH1 mode
+ ld a,#180 ; time constant = 180
+ out (CTC_CH1),a ; set CH1 time constant
+ ld a,#0x57 ; counter mode, disable interrupts
+ out (CTC_CH2),a ; set CH2 mode
+ ld a,#0x57 ; counter mode, disable interrupts
+ out (CTC_CH3),a ; set CH3 mode
+
+ ; Done CTC Stuff
+ ; ---------------------------------------------------------------------
+
+ im 1 ; set Z80 CPU interrupt mode 1
+ ret
+
+sio_setup:
+ .byte 0x00
+ .byte 0x18 ; Reset
+ .byte 0x04
+ .byte 0xC4
+ .byte 0x01
+ .byte 0x18
+ .byte 0x03
+ .byte 0xE1
+ .byte 0x05
+ .byte RTS_LOW
+
+ .area _COMMONMEM
+
+_platform_monitor:
+_platform_reboot:
+ ld a,#0x03
+ out (0x1f),a
+ rst 0
+
+_int_disabled:
+ .db 1
+pagereg:
+ .db 0
+pagesave:
+ .db 0
+
+platform_interrupt_all:
+ ret
+
+; install interrupt vectors
+_program_vectors:
+ di
+ pop de ; temporarily store return address
+ pop hl ; function argument -- base page number
+ push hl ; put stack back as it was
+ push de
+
+ ; At this point the common block has already been copied
+ call map_process
+
+ ; write zeroes across all vectors
+ ld hl,#0
+ ld de,#1
+ ld bc,#0x007f ; program first 0x80 bytes only
+ ld (hl),#0x00
+ ldir
+
+ ; now install the interrupt vector at 0x0038
+ ld a,#0xC3 ; JP instruction
+ ld (0x0038),a
+ ld hl,#interrupt_handler
+ ld (0x0039),hl
+
+ ; set restart vector for UZI system calls
+ ld (0x0030),a ; rst 30h is unix function call vector
+ ld hl,#unix_syscall_entry
+ ld (0x0031),hl
+
+ ; We can't add a NULL handler - it's the restart for power off
+
+ ld (0x0066),a ; Set vector for NMI
+ ld hl,#nmi_handler
+ ld (0x0067),hl
+
+ jr map_kernel
+
+;=========================================================================
+; Memory management
+;=========================================================================
+
+map_process:
+map_process_di:
+ ld a,h
+ or l ; HL == 0?
+ jr z,map_kernel ; HL == 0 - map the kernel
+ ld a,(hl)
+map_for_swap:
+map_process_a:
+ ld (pagereg),a
+ out (0x1f),a
+ ret
+
+map_process_always:
+map_process_always_di:
+ push af
+ ld a,(U_DATA__U_PAGE)
+map_pop_a:
+ ld (pagereg),a
+ out (0x1f),a
+ pop af
+ ret
+
+map_buffers:
+map_kernel:
+map_kernel_di:
+ push af
+ ld a,#3
+ jr map_pop_a
+
+map_restore:
+ push af
+ ld a,(pagesave)
+ jr map_pop_a
+
+map_save_kernel:
+ push af
+ ld a,(pagereg)
+ ld (pagesave),a
+ ld a,#3
+ jr map_pop_a
+
+;
+; A little SIO helper
+;
+ .globl _sio_r
+ .globl _sio2_otir
+
+_sio2_otir:
+ ld b,#0x06
+ ld c,l
+ ld hl,#_sio_r
+ otir
+ ret
+
+; C entry point
+_cpld_bitbang:
+ ld a,l
+; Debug entry point
+;
+; Based on the ROM code but slightly tighter
+; - use ld a,#0 so 0 and 1 bits are same length
+; - don't duplicate excess code in the hi/lo bit paths
+; - use conditional calls to keep 0/1 timing identical
+;
+; FIXME: my math says it's still slightly off timing.
+;
+outchar:
+ push bc
+ ld c,a
+ ld b,#8
+ call lobit
+ ld a,c
+txbit:
+ rrca
+ call c, hibit
+ call nc, lobit
+ djnz txbit
+ pop bc
+hibit:
+ push af
+ ld a,#0xff
+ out (0xf9),a
+ ld a,#7
+bitwait:
+ dec a
+ jp nz,bitwait
+ pop af
+ ret
+lobit:
+ push af
+ ld a,#0
+ out (0xf9),a
+ ld a,#7
+ dec a
+ jp bitwait
+
--- /dev/null
+export CPU = z80
--- /dev/null
+ .include "kernel.def"
+ .include "../kernel.def"
+
+ .include "../lib/z80fixedbank.s"
+