--- /dev/null
+ASRCS = crt0.s z180.s commonmem.s yaz180.s monitor.s
+CSRCS += devices.c main.c devtty.c ppide.c
+DISCARD_CSRCS = discard.c
+DISCARD_DSRCS = ../dev/devide_discard.c
+DSRCS = ../dev/devide.c ../dev/mbr.c ../dev/blkdev.c
+DASRCS = ../dev/devrd_z180_hw.s
+
+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))
+
+OBJS = $(AOBJS) $(COBJS) $(DOBJS) $(DISCARD_DOBJS) $(DISCARD_COBJS) $(DAOBJS)
+
+CROSS_CCOPTS += -I../dev/
+
+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 $<
+
+clean:
+ rm -f $(OBJS) $(JUNK) core *~ fuzix.com makecpmloader diskboot.bin
+
+z180.rel: z180.s kernel.def ../cpu-z180/z180.s
+
+image:
+ ../cpm-loader/makecpmloader ../cpm-loader/cpmload.bin ../fuzix.bin 0x88 fuzix.com
+ ../cpm-loader/makecpmloader ../cpm-loader/fuzixload.bin ../fuzix.bin 0x88 fuzix
--- /dev/null
+TODO
+- Verify the Z80_IO_BASE setting is correct
+- Verify the memory bases are right and it boots
+- Worry about the fact the PPIDE port arrangement is different
+- Maybe - add SD support if the CSIO pins are exposed
+
+This is Fuzix for the YAZ180 based upon the Z180 code by Will Sowerbutts
+<will@sowerbutts.com>
+
+Supported hardware:
+ - PPIDE interface (TODO)
+ - SD interface
+ - RS232 serial port (ASCI channel 0, tty1)
+ - RS232 serial port (ASCI channel 1, tty2)
+
+The file "Kernel/platform-yaz180/fuzix.com" is a CP/M executable which
+will load and boot the Fuzix kernel from within CP/M.
+
+When booting the system from CP/M you can specify the root filesystem device on
+the command line after the command name or unit number.
+
+For example, with root filesystem on /dev/hdb1 (minor #17) at the CP/M command
+prompt:
+
+ A> FUZIX hdb1
+or A> FUZIX 17
+
--- /dev/null
+ .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
+/* Single tasking */
+#undef CONFIG_SINGLETASK
+/* CP/M emulation */
+#undef CONFIG_CPM_EMU
+/* Fixed banking: 8 x 64K banks, top 4KB is shared with kernel, 60KB-62KB is user memory */
+#define CONFIG_BANK_FIXED
+/* Permit large I/O requests to bypass cache and go direct to userspace */
+#define CONFIG_LARGE_IO_DIRECT(x) 1
+/* 8 60K banks, 1 is kernel */
+#define MAX_MAPS 8
+#define MAP_SIZE PROGTOP /* WRS: I feel this should be 60KB, but setting it so breaks pagemap_realloc() when exec calls it */
+
+/* Banks as reported to user space */
+#define CONFIG_BANKS 1
+
+#define TICKSPERSEC 40U /* Ticks per second */
+#define PROGBASE 0x0000 /* also data base */
+#define PROGLOAD 0x0100 /* also data base */
+#define PROGTOP 0xF800 /* Top of program, base of U_DATA copy */
+#define KERNTOP 0xF000 /* Kernel has lower 60KB */
+#define PROC_SIZE 64 /* Memory needed per process */
+
+/* We need a tidier way to do this from the loader */
+#define CMDLINE (0x0081) /* 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 yaz180.s */
+#define NMOUNTS 4 /* Number of mounts at a time */
+
+/* Hardware parameters */
+#define Z180_IO_BASE 0x00
+
+#define MAX_BLKDEV 2 /* 2 IDE drives */
+
+#define CONFIG_IDE
+#define CONFIG_PPIDE
+
+#define NUM_DEV_TTY 2
+/* ASCI0 as the console */
+#define TTYDEV (512+1) /* System console (used by kernel, init) */
+
+#define platform_copyright()
--- /dev/null
+; 2013-12-18 William R Sowerbutts
+
+ .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 _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
+ .area _GSINIT
+ .area _GSFINAL
+ .area _DISCARD
+ .area _COMMONMEM
+
+ ; imported symbols
+ .globl _fuzix_main
+ .globl init_early
+ .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
+
+ ; startup code
+ .area _CODE
+init:
+ di
+ ld sp, #kstack_top
+
+ ; move the common memory where it belongs
+ ld hl, #s__DATA
+ 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
+
+ ; Configure memory map
+ call init_early
+
+ ; 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 <devtty.h>
+#include <devide.h>
+#include <devsd.h>
+#include <blkdev.h>
+
+struct devsw dev_tab[] = /* The device driver switch table */
+{
+/* open close read write ioctl */
+ { blkdev_open, no_close, blkdev_read, blkdev_write, blkdev_ioctl }, /* 0: /dev/hd -- standard block device interface */
+ { no_open, no_close, no_rdwr, no_rdwr, no_ioctl }, /* 1: /dev/fd -- floppy disks */
+ { tty_open, tty_close, tty_read, tty_write, tty_ioctl }, /* 2: /dev/tty -- serial ports */
+ { no_open, no_close, no_rdwr, no_rdwr, no_ioctl }, /* 3: /dev/lp -- printer ports */
+ { no_open, no_close, sys_read, sys_write, sys_ioctl }, /* 4: /dev/mem etc System devices (one offs) */
+};
+
+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)
+{
+ devide_init();
+}
--- /dev/null
+/*-----------------------------------------------------------------------*/
+/* N8VEM Mark IV Z180 CSI/O SPI SD driver */
+/* 2014-12-27 Will Sowerbutts */
+/* 2014-12-29 Optimised for size/speed */
+/*-----------------------------------------------------------------------*/
+
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <timer.h>
+#include <stdbool.h>
+#include "config.h"
+#include <z180.h>
+#include <blkdev.h>
+
+#define CSIO_CNTR_TE (1<<4) /* transmit enable */
+#define CSIO_CNTR_RE (1<<5) /* receive enable */
+#define CSIO_CNTR_END_FLAG (1<<7) /* operation completed flag */
+
+#define MARK4_SD_CS (1<<2) /* chip select */
+#define MARK4_SD_WRITE_PROTECT (1<<4) /* write protect */
+#define MARK4_SD_CARD_DETECT (1<<5) /* card detect */
+#define MARK4_SD_INT_ENABLE (1<<6) /* interrupt enable */
+#define MARK4_SD_INT_PENDING (1<<7) /* interrupt enable */
+
+__sfr __at (MARK4_IO_BASE + 0x09) MARK4_SD;
+
+/* the CSI/O and SD card send the bits of each byte in opposite orders, so we need to flip them over */
+static uint8_t reverse_byte(uint8_t byte) __naked
+{
+ /* code by John Metcalf, from http://www.retroprogramming.com/2014/01/fast-z80-bit-reversal.html */
+ __asm
+ ld hl, #2
+ add hl, sp
+ ld a, (hl)
+reverse_byte_a:
+ ; reverse bits in A
+ ld l,a ; a = 76543210
+ rlca
+ rlca ; a = 54321076
+ xor l
+ and #0xAA
+ xor l ; a = 56341270
+ ld l,a
+ rlca
+ rlca
+ rlca ; a = 41270563
+ rrc l ; l = 05634127
+ xor l
+ and #0x66
+ xor l ; a = 01234567
+ ld l, a ; return value in L
+ ret
+ __endasm;
+ byte; /* squelch compiler warning */
+}
+
+void sd_spi_clock(bool go_fast)
+{
+ unsigned char c;
+
+ c = CSIO_CNTR & 0xf8; /* clear low three bits, gives fastest rate (clk/20) */
+ if(!go_fast)
+ c = c | 0x03; /* set low two bits, clk/160 (can go down to clk/1280, see data sheet) */
+ CSIO_CNTR = c;
+}
+
+void sd_spi_raise_cs(void)
+{
+ /* wait for idle */
+ while(CSIO_CNTR & (CSIO_CNTR_TE | CSIO_CNTR_RE));
+ MARK4_SD = MARK4_SD & (~MARK4_SD_CS);
+}
+
+void sd_spi_lower_cs(void)
+{
+ /* wait for idle */
+ while(CSIO_CNTR & (CSIO_CNTR_TE | CSIO_CNTR_RE));
+ MARK4_SD = MARK4_SD | MARK4_SD_CS;
+}
+
+void sd_spi_transmit_byte(unsigned char byte)
+{
+ unsigned char c;
+
+ /* reverse the bits before we busywait */
+ byte = reverse_byte(byte);
+
+ /* wait for any current transmit operation to complete */
+ do{
+ c = CSIO_CNTR;
+ }while(c & CSIO_CNTR_TE);
+
+ /* write the byte and enable transmitter */
+ CSIO_TRDR = byte;
+ CSIO_CNTR = c | CSIO_CNTR_TE;
+}
+
+uint8_t sd_spi_receive_byte(void)
+{
+ unsigned char c;
+
+ /* wait for any current transmit or receive operation to complete */
+ do{
+ c = CSIO_CNTR;
+ }while(c & (CSIO_CNTR_TE | CSIO_CNTR_RE));
+
+ /* enable receive operation */
+ CSIO_CNTR = c | CSIO_CNTR_RE;
+
+ /* wait for receive to complete */
+ while(CSIO_CNTR & CSIO_CNTR_RE);
+
+ /* read byte */
+ return reverse_byte(CSIO_TRDR);
+}
+
+/****************************************************************************/
+/* The innermost part of the transfer routines has to live in common memory */
+/* since it must be able to bank switch to the user memory bank. */
+/****************************************************************************/
+COMMON_MEMORY
+
+/* WRS: measured byte transfer time as approx 5.66us with Z180 @ 36.864MHz,
+ three times faster. Main change is to start the next receive operation
+ as soon as possible and overlap the loop housekeeping with the receive. */
+bool sd_spi_receive_sector(void) __naked
+{
+ __asm
+waitrx:
+ in0 a, (_CSIO_CNTR) ; wait for any current transmit or receive operation to complete
+ tst a, #0x30
+ jr nz, waitrx
+ set 5, a ; set CSIO_CNTR_RE, enable receive operation for first byte
+ out0 (_CSIO_CNTR), a
+ ld h, a ; stash value for reuse later
+
+ ; load parameters
+ ld a, (_blk_op+BLKPARAM_IS_USER_OFFSET) ; blkparam.is_user
+ ld de, (_blk_op+BLKPARAM_ADDR_OFFSET) ; blkparam.addr
+ ld bc, #512 ; sector size
+ or a
+ push af ; stash is_user flag now in Z bit (we cannot load it again after we remap)
+ call nz, map_process_always ; map user process
+rxnextbyte:
+ dec bc ; length--
+ ld a, b
+ or c
+ jr nz, waitrx2
+ res 5, h ; final byte: clear CSIO_CNTR_RE bit in H
+waitrx2:
+ ld l, c ; store C temporarily
+ ld c, #_CSIO_CNTR ; load IO port address
+waitrx3:
+ tstio #0x20 ; test bits in IO port (C)
+ jr nz, waitrx3 ; wait for receive to complete
+ in0 a, (_CSIO_TRDR) ; load received byte
+ out0 (_CSIO_CNTR), h ; start next receive (or NOP, if this is the final byte)
+ ld c, l ; restore C
+ ; reverse bits in A
+ ld l,a ; a = 76543210
+ rlca
+ rlca ; a = 54321076
+ xor l
+ and #0xAA
+ xor l ; a = 56341270
+ ld l,a
+ rlca
+ rlca
+ rlca ; a = 41270563
+ rrc l ; l = 05634127
+ xor l
+ and #0x66
+ xor l ; a = 01234567
+ ld (de), a ; store reversed byte value
+ inc de ; ptr++
+ bit 5, h
+ jr nz, rxnextbyte ; go again if not yet done
+ jr transferdone ; we are done
+ __endasm;
+}
+
+bool sd_spi_transmit_sector(void) __naked
+{
+ __asm
+ ; load parameters
+ ld a, (_blk_op+BLKPARAM_IS_USER_OFFSET) ; blkparam.is_user
+ ld de, (_blk_op+BLKPARAM_ADDR_OFFSET) ; blkparam.addr
+ ld hl, #512 ; sector size
+ or a
+ push af ; stash is_user flag now in Z bit (we cannot load it again after we remap)
+ call nz, map_process_always ; map user process
+gotransmit:
+ in0 a, (_CSIO_CNTR)
+ and #0xDF ; mask off RE bit
+ or #0x10 ; set TE bit
+ ld b, a ; B now contains CNTR register value to start transmission
+txnextbyte:
+ ld a, (de)
+ ; reverse bits in A
+ ld c,a
+ rlca
+ rlca
+ xor c
+ and #0xAA
+ xor c
+ ld c,a
+ rlca
+ rlca
+ rlca
+ rrc c
+ xor c
+ and #0x66
+ xor c
+ ld c, #_CSIO_CNTR ; load IO port address
+waittx:
+ tstio #0x10 ; test bits in IO port (C)
+ jr nz, waittx ; wait for transmit to complete
+ out0 (_CSIO_TRDR), a ; write byte to transmit
+ out0 (_CSIO_CNTR), b ; start transmit
+ inc de ; ptr++
+ dec hl ; length--
+ ld a, h
+ or l
+ jr nz, txnextbyte ; length != 0, go again
+transferdone: ; note this code is shared with sd_spi_receive_block
+ ld l, #1 ; return true
+ pop af ; recover is_user bit in Z flag
+ ret z ; return if kernel still mapped
+ jp map_kernel ; else map kernel and return
+ __endasm;
+}
--- /dev/null
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <stdbool.h>
+#include <tty.h>
+#include <devtty.h>
+#include <z180.h>
+
+static char tbuf1[TTYSIZ];
+static 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 },
+};
+
+static tcflag_t console_mask[4] = {
+ _ISYS,
+ _OSYS,
+ _CSYS,
+ _LSYS
+};
+
+/* TODO: stty support for the Z180 ports */
+tcflag_t *termios_mask[NUM_DEV_TTY + 1] = {
+ NULL,
+ console_mask,
+ console_mask,
+};
+
+void tty_setup(uint8_t minor, uint8_t flags)
+{
+ minor;
+}
+
+/* For the moment */
+int tty_carrier(uint8_t minor)
+{
+ minor;
+ return 1;
+}
+
+void tty_pollirq_asci0(void)
+{
+ while(ASCI_STAT0 & 0x80)
+ tty_inproc(1, ASCI_RDR0);
+}
+
+void tty_pollirq_asci1(void)
+{
+ while(ASCI_STAT1 & 0x80)
+ tty_inproc(2, ASCI_RDR1);
+}
+
+void tty_putc(uint8_t minor, unsigned char c)
+{
+ switch(minor){
+ case 1:
+ while(!(ASCI_STAT0 & 2));
+ ASCI_TDR0 = c;
+ break;
+ case 2:
+ while(!(ASCI_STAT1 & 2));
+ ASCI_TDR1 = c;
+ break;
+ }
+}
+
+void tty_sleeping(uint8_t minor)
+{
+ minor;
+}
+
+void tty_data_consumed(uint8_t minor)
+{
+}
+
+ttyready_t tty_writeready(uint8_t minor)
+{
+ minor;
+ return TTY_READY_NOW;
+}
+
+/* kernel writes to system console -- never sleep! */
+void kputchar(char c)
+{
+ tty_putc(TTYDEV & 0xFF, c);
+ if(c == '\n')
+ tty_putc(TTYDEV & 0xFF, '\r');
+}
--- /dev/null
+#ifndef __DEVTTY_DOT_H__
+#define __DEVTTY_DOT_H__
+void tty_pollirq_asci0(void);
+void tty_pollirq_asci1(void);
+
+#ifdef CONFIG_PROPIO2
+void tty_poll_propio2(void);
+#endif
+#endif
--- /dev/null
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devtty.h>
+#include "config.h"
+#include <z180.h>
+
+void init_hardware_c(void)
+{
+ ramsize = 912;
+ procmem = 848;
+ /* zero out the initial bufpool */
+ memset(bufpool, 0, (char*)bufpool_end - (char*)bufpool);
+}
+
+void pagemap_init(void)
+{
+ int i;
+
+ /* YAZ180 has RAM from 0C000 to EFFFF
+ * First 64K is used by the kernel.
+ * Each process gets the full 64K for now.
+ * Page size is 4KB.
+ * We don't do anything right now with C000-FFFF so that is
+ * a good place to load any additional tools
+ */
+ for(i = 0x20; i < 0xF0; i+=0x10)
+ pagemap_add(i);
+}
+
+void map_init(void)
+{
+ /* clone udata and stack into a regular process bank, return with common memory
+ for the new process loaded */
+ copy_and_map_process(&init_process->p_page);
+ /* kernel bank udata (0x300 bytes) is never used again -- could be reused? */
+}
+
+uint8_t platform_param(char *p)
+{
+ used(p);
+ return 0;
+}
--- /dev/null
+; 2015-01-21 Will Sowerbutts <will@sowerbutts.com>
+;
+; Boot sector for N8VEM Mark IV SBC with UNA BIOS, based on
+; my UNA CP/M boot sector (2014-07-11)
+
+ .module diskboot
+
+
+; we are loaded at 0x8000
+himem = 0xFA00 ; our location in memory
+buffer = 0xF800 ; disk buffer (512 bytes)
+stacktop = 0xFE00 ; top of stack (512 bytes)
+
+; UNA BIOS constants
+UNABIOS_STUB_ENTRY = 0xFFFD ; main UNA entry vector
+UNABIOS_BOOTHISTORY = 0xFC ; C register (subfunction in B)
+UNABIOS_BOOT_GET = 0x00 ; B register (BOOTHISTORY subfunction)
+UNABIOS_GETINFO = 0xFA ; C regsister (subfunction in B)
+UNABIOS_GET_USER_PAGES = 0x05 ; B register (GETINFO subfunction)
+UNABIOS_BANKEDMEM = 0xFB ; C register (subfunction in B)
+UNABIOS_BANK_GET = 0x00 ; B register (BANKEDMEM subfunction)
+UNABIOS_BANK_SET = 0x01 ; B register (BANKEDMEM subfunction)
+UNABIOS_GET_HMA = 0xF1 ; C register (subfunction in B)
+UNABIOS_BLOCK_SETLBA = 0x41 ; C register (unit number in B, 28-bit LBA in DEHL)
+UNABIOS_BLOCK_READ = 0x42 ; C register (unit number in B, buffer address in DE, sector count in L)
+UNABIOS_OUTPUT_WRITE = 0x12 ; C register (unit number in B)
+
+ .area _LOADER (ABS)
+ .org himem
+start:
+ ; UNA BIOS loads us from disk sector 0 at 0x8000
+ jr gocopy ; we must start with a JP or JR instruction.
+ .ds 0x40 - (.-start) ; must leave room for floppy or partition superblock information
+
+ ; Copy us up into high memory
+gocopy: ld hl, #0x8000
+ ld de, #himem
+ ld bc, #512
+ ldir
+ jp go
+
+ ; Executes in high memory
+go: ld sp, #stacktop ; set inital stack
+ ; write a character
+ ld e, #0x5B ; '['
+ call printchar
+
+ ; determine the boot unit
+ ld bc, #(UNABIOS_BOOT_GET << 8 | UNABIOS_BOOTHISTORY)
+ call #UNABIOS_STUB_ENTRY
+ ld a, l
+ ld (unit), a ; save boot unit
+
+ ; get the page number for the user memory bank
+ ld bc, #(UNABIOS_GET_USER_PAGES << 8 | UNABIOS_GETINFO)
+ call #UNABIOS_STUB_ENTRY
+ ; returns EXEC_PAGE value in DE
+
+ ; map in user memory bank
+ ld bc, #(UNABIOS_BANK_SET << 8 | UNABIOS_BANKEDMEM)
+ call #UNABIOS_STUB_ENTRY
+
+ ; write unabios vector in user memory
+ ld hl, #UNABIOS_STUB_ENTRY
+ ld de, #0x0008
+ ld bc, #3
+ ldir
+
+ ; wipe BDOS entry vector
+ ld a, #0x76 ; halt instruction
+ ld (0x0005), a ; this is used as a marker to detect cold boot versus warm reload
+
+ ; wipe persistent memory pointer (persist_ptr, immediately below UNA UBIOS stub / HMA)
+ ld c, #UNABIOS_GET_HMA ; get pointer to lowest byte used by UNA BIOS stub
+ call #UNABIOS_STUB_ENTRY ; returns lowest used byte in HL.
+ xor a ; zero out the two bytes below that.
+ dec hl
+ ld (hl), a
+ dec hl
+ ld (hl), a
+
+ ld a, (firstblock)
+ ld (block), a
+
+nextblock:
+ ; print a = character only every other block
+ ld a, (block)
+ and #1
+ jr z, setlba
+ ld e, #0x3D ; '='
+ call printchar
+
+setlba: ; set LBA
+ xor a
+ ld d, a
+ ld e, a
+ ld h, a
+ ld a, (block)
+ ld l, a
+ inc a ; setup for next block now
+ ld (block), a
+ ld c, #UNABIOS_BLOCK_SETLBA
+ ld a, (unit)
+ ld b, a
+ call #UNABIOS_STUB_ENTRY
+ jr nz, error
+
+ ; read block into buffer
+ ld c, #UNABIOS_BLOCK_READ
+ ld a, (unit)
+ ld b, a
+ ld l, #1
+ ld de, #buffer
+ call #UNABIOS_STUB_ENTRY
+ jr nz, error
+
+ ; copy block into low memory
+ ld hl, #buffer
+ ld de, (copyaddr)
+ ld bc, #512
+ ldir
+
+ ld (copyaddr), de
+ ld a, (firstblock)
+ ld d, a
+ ld a, (count)
+ ld e, a
+ ld a, (block)
+ sub d
+ cp e
+ jr nz, nextblock
+
+ ld e, #0x5D ; ']'
+ call printchar
+ ld e, #0x0D
+ call printchar
+ ld e, #0x0A
+ call printchar
+
+ ; we're loaded. let's go.
+ ld hl, (entryaddr)
+ jp (hl)
+
+
+; print a hex byte in A
+byt_out:
+ push af ; save low nibble
+ rrca ; move high nibble into position
+ rrca ; **
+ rrca
+ rrca
+ call nib_out ; put out the high nibble
+ pop af ; fall into nib_out to put out low nibble
+; print a hex-nibble in A
+nib_out:
+ and #0x0F ; mask the nibble
+ add #0 ; clear the AUX carry bit
+ daa ; decimal adjust the A
+ add #0xF0 ; move hi-nib into carry, hi-nib is 0 or F
+ adc #0x40 ; form ascii character
+ ld e, a
+ ; fall through into printchar
+printchar:
+ ld bc, #UNABIOS_OUTPUT_WRITE
+ jp UNABIOS_STUB_ENTRY
+
+error:
+ ; print the error
+ ld a, c
+ call byt_out
+ ld e, a
+ call printchar
+
+ ; sad face :(
+ ld e, #0x20 ; space
+ call printchar
+ ld e, #0x3A ; ':'
+ call printchar
+ ld e, #0x28 ; '('
+ call printchar
+
+ ; park the vehicle
+ halt
+
+block: .ds 1
+unit: .ds 1
+firstblock: .db 2 ; start loading at sector 2
+count: .db 124 ; max sectors we can load before we overwrite ourselves (62KB)
+copyaddr: .dw 0x0088 ; load address
+entryaddr: .dw 0x0088 ; entry address
+
+ .ds 0x1BE - ( . -start) ; pad to start of partition tables
+ .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; partition 1
+ .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; partition 2
+ .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; partition 3
+ .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; partition 4
+ .dw 0xAA55 ; DOS boot signature
--- /dev/null
+-mwxuy
+-i fuzix.ihx
+-b _CODE=0x0088
+-b _COMMONMEM=0xF800
+-b _DISCARD=0xE000
+-l z180
+platform-yaz180/crt0.rel
+platform-yaz180/commonmem.rel
+platform-yaz180/z180.rel
+platform-yaz180/yaz180.rel
+platform-yaz180/main.rel
+start.rel
+version.rel
+lowlevel-z180.rel
+usermem_std-z180.rel
+timer.rel
+kdata.rel
+usermem.rel
+platform-yaz180/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
+mm.rel
+bankfixed.rel
+swap.rel
+devsys.rel
+platform-yaz180/discard.rel
+platform-yaz180/devtty.rel
+platform-yaz180/devide.rel
+platform-yaz180/devide_discard.rel
+platform-yaz180/ppide.rel
+platform-yaz180/mbr.rel
+platform-yaz180/blkdev.rel
+platform-yaz180/monitor.rel
+-e
--- /dev/null
+; UZI mnemonics for memory addresses etc
+
+; Move down to 0xF600 to fit the monitor in
+U_DATA .equ 0xF800 ; (this is struct u_data from kernel.h)
+U_DATA__TOTALSIZE .equ 0x200 ; 256+256 bytes.
+Z80_TYPE .equ 2
+
+OS_BANK .equ 0x00 ; value from include/kernel.h
+
+; N8VEM Mark IV mnemonics
+FIRST_RAM_BANK .equ 0x10 ; 10000 (actually C000-FFFF is avaiable)
+Z180_IO_BASE .equ 0x00
+
+; No standard clock speed for the Mark IV board, but this is a common choice.
+USE_FANCY_MONITOR .equ 1 ; disabling this saves around approx 0.5KB
+CPU_CLOCK_KHZ .equ 36864 ; 18.432MHz * 2
+Z180_TIMER_SCALE .equ 20 ; CPU clocks per timer tick
+TICKSPERSEC .equ 40 ; timer interrupt rate (Hz)
+
+PROGBASE .equ 0x0000
+PROGLOAD .equ 0x0100
--- /dev/null
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devtty.h>
+#include "config.h"
+#include <z180.h>
+
+uint16_t ramtop = PROGTOP;
+extern unsigned char irqvector;
+
+struct blkbuf *bufpool_end = bufpool + NBUFS; /* minimal for boot -- expanded after we're done with _DISCARD */
+
+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++;
+ }
+}
+
+void z180_timer_interrupt(void)
+{
+ unsigned char a;
+
+ /* we have to read both of these registers in order to reset the timer */
+ a = TIME_TMDR0L;
+ a = TIME_TCR;
+ timer_interrupt();
+}
+
+void platform_idle(void)
+{
+ /* Let's go to sleep while we wait for something to interrupt us;
+ * Makes the Mark IV's run LED go red, which amuses me greatly. */
+ __asm
+ halt
+ __endasm;
+}
+
+void platform_interrupt(void)
+{
+ switch(irqvector){
+ case Z180_INT_TIMER0:
+ z180_timer_interrupt();
+ return;
+ case Z180_INT_ASCI0:
+ tty_pollirq_asci0();
+ return;
+ case Z180_INT_ASCI1:
+ tty_pollirq_asci1();
+ return;
+ default:
+ return;
+ }
+}
--- /dev/null
+; 2015-01-17 William R Sowerbutts
+
+ .module monitor
+ .include "kernel.def"
+ .globl _platform_monitor
+ .globl _platform_reboot
+ .globl map_kernel
+
+; -----------------------------------------------------------------------------
+.ifne USE_FANCY_MONITOR ; -----------------------------------------------------
+ .area _CODE ; actual monitor lives in kernel bank
+ .include "../lib/monitor-z80.s"
+
+ .area _COMMONMEM ; just a stub goes in common memory
+_platform_monitor:
+ di
+ call map_kernel
+ jp monitor_entry
+
+
+; -----------------------------------------------------------------------------
+.else ; MICRO MONITOR ---------------------------------------------------------
+ .globl outchar
+ .globl outnewline
+ .globl outhl
+
+ .area _COMMONMEM
+_platform_monitor: di
+ call outnewline
+ ; just dump a few words from the stack
+ ld b, #50
+stacknext: pop hl
+ call outhl
+ ld a, #' '
+ call outchar
+ djnz stacknext
+ halt
+.endif
+
+_platform_reboot: ; TODO
+ jr _platform_monitor
--- /dev/null
+#ifdef CONFIG_PPIDE
+#define PPIDE_BASE 0x60 /* Base address of 8255A */
+#define IDE_REG_INDIRECT /* IDE registers are not directly connected to the CPU bus */
+
+/* IDE control signal to 8255 port C mapping */
+#define PPIDE_A0_LINE 0x01 // Direct from 8255 to IDE interface
+#define PPIDE_A1_LINE 0x02 // Direct from 8255 to IDE interface
+#define PPIDE_A2_LINE 0x04 // Direct from 8255 to IDE interface
+#define PPIDE_CS0_LINE 0x08 // Inverter between 8255 and IDE interface
+#define PPIDE_CS1_LINE 0x10 // Inverter between 8255 and IDE interface
+#define PPIDE_WR_LINE 0x20 // Inverter between 8255 and IDE interface
+#define PPIDE_WR_BIT 5 // (1 << PPIDE_WR_BIT) = PPIDE_WR_LINE
+#define PPIDE_RD_LINE 0x40 // Inverter between 8255 and IDE interface
+#define PPIDE_RD_BIT 6 // (1 << PPIDE_RD_BIT) = PPIDE_RD_LINE
+#define PPIDE_RST_LINE 0x80 // Inverter between 8255 and IDE interface
+
+/* 8255 configuration */
+#define PPIDE_PPI_BUS_READ 0x92
+#define PPIDE_PPI_BUS_WRITE 0x80
+
+/* IDE register addresses */
+#define ide_reg_data (PPIDE_CS0_LINE)
+#define ide_reg_error (PPIDE_CS0_LINE | PPIDE_A0_LINE)
+#define ide_reg_features (PPIDE_CS0_LINE | PPIDE_A0_LINE)
+#define ide_reg_sec_count (PPIDE_CS0_LINE | PPIDE_A1_LINE)
+#define ide_reg_lba_0 (PPIDE_CS0_LINE | PPIDE_A1_LINE | PPIDE_A0_LINE)
+#define ide_reg_lba_1 (PPIDE_CS0_LINE | PPIDE_A2_LINE)
+#define ide_reg_lba_2 (PPIDE_CS0_LINE | PPIDE_A2_LINE | PPIDE_A0_LINE)
+#define ide_reg_lba_3 (PPIDE_CS0_LINE | PPIDE_A2_LINE | PPIDE_A1_LINE)
+#define ide_reg_devhead (PPIDE_CS0_LINE | PPIDE_A2_LINE | PPIDE_A1_LINE)
+#define ide_reg_command (PPIDE_CS0_LINE | PPIDE_A2_LINE | PPIDE_A1_LINE | PPIDE_A0_LINE)
+#define ide_reg_status (PPIDE_CS0_LINE | PPIDE_A2_LINE | PPIDE_A1_LINE | PPIDE_A0_LINE)
+#define ide_reg_altstatus (PPIDE_CS1_LINE | PPIDE_A2_LINE | PPIDE_A1_LINE)
+#define ide_reg_control (PPIDE_CS1_LINE | PPIDE_A2_LINE | PPIDE_A1_LINE | PPIDE_A0_LINE)
+#endif /* CONFIG_PPIDE */
+
+#define ide_select(x)
+#define ide_deselect()
--- /dev/null
+/*
+ * FIXME: this is wrong for the YAZ180 as the bit mappings are
+ * different.
+ */
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <stdbool.h>
+#include <timer.h>
+#include <devide.h>
+#include <blkdev.h>
+
+#ifdef CONFIG_PPIDE
+
+__sfr __at (PPIDE_BASE + 0x00) ppi_port_a; /* IDE bus LSB */
+__sfr __at (PPIDE_BASE + 0x01) ppi_port_b; /* IDE bus MSB */
+__sfr __at (PPIDE_BASE + 0x02) ppi_port_c; /* IDE bus control signals */
+__sfr __at (PPIDE_BASE + 0x03) ppi_control; /* 8255 command register */
+
+void ppide_init(void)
+{
+ ppi_control = PPIDE_PPI_BUS_READ;
+ ppi_port_c = ide_reg_status;
+}
+
+uint8_t devide_readb(uint8_t regaddr)
+{
+ uint8_t r;
+
+ /* note: ppi_control should contain PPIDE_PPI_BUS_READ already */
+ ppi_port_c = regaddr;
+ ppi_port_c = regaddr | PPIDE_RD_LINE; /* begin /RD pulse */
+ r = ppi_port_a;
+ ppi_port_c = regaddr; /* end /RD pulse */
+ return r;
+}
+
+void devide_writeb(uint8_t regaddr, uint8_t value)
+{
+ ppi_control = PPIDE_PPI_BUS_WRITE;
+ ppi_port_c = regaddr;
+ ppi_port_a = value;
+ ppi_port_b = 0;
+ ppi_port_c = regaddr | PPIDE_WR_LINE;
+ /* FIXME: check timing */
+ ppi_port_c = regaddr;
+ ppi_control = PPIDE_PPI_BUS_READ;
+}
+
+/****************************************************************************/
+/* The innermost part of the transfer routines has to live in common memory */
+/* since it must be able to bank switch to the user memory bank. */
+/****************************************************************************/
+COMMON_MEMORY
+
+void devide_read_data(void) __naked
+{
+ __asm
+ ld a, #ide_reg_data
+ ld c, #PPIDE_BASE+2 ; select control lines
+ out (c), a ; select IDE data register
+ ld hl, (_blk_op+BLKPARAM_ADDR_OFFSET) ; blkparam.addr
+ ld d, #ide_reg_data ; register address
+ ld e, #ide_reg_data | PPIDE_RD_LINE ; register address with /RD asserted
+ ld b, #0 ; setup count
+ ld a, (_blk_op+BLKPARAM_IS_USER_OFFSET) ; blkparam.is_user
+ or a ; test is_user
+ push af ; save flags
+ ld a, #PPIDE_BASE+0 ; I will be needing this later
+ call nz, map_process_always ; map user memory first if required
+goread: ; now we do the transfer
+ out (c), e ; assert /RD
+ ld c, a ; PPIDE_BASE
+ ini ; read byte from LSB
+ inc c ; up to MSB
+ ini ; read byte from MSB
+ inc c ; control lines
+ out (c), d ; de-assert /RD
+ inc b ; (delay) counteract second ini instruction
+ jr nz, goread ; (delay) next word
+ ; read completed
+ pop af ; recover is_user test result
+ ret z ; done if kernel memory transfer
+ jp map_kernel ; else map kernel then return
+ __endasm;
+}
+
+void devide_write_data(void) __naked
+{
+ __asm
+ ld c, #PPIDE_BASE+2 ; select control lines
+ ld a, #ide_reg_data
+ out (c), a ; select data register
+ ld a, #PPIDE_PPI_BUS_WRITE
+ inc c ; up to 8255A command register
+ out (c), a ; 8255A ports A, B to output mode
+ dec c ; back down to the control lines
+ ld hl, (_blk_op+BLKPARAM_ADDR_OFFSET) ; blkparam.addr
+ ld d, #ide_reg_data ; register address
+ ld e, #ide_reg_data | PPIDE_WR_LINE ; register address with /WR asserted
+ ld b, #0 ; setup count
+ ld a, (_blk_op+BLKPARAM_IS_USER_OFFSET) ; blkparam.is_user
+ or a ; test is_user
+ push af ; save flags
+ ld a, #PPIDE_BASE+0 ; I will be needing this later
+ call nz, map_process_always ; map user memory first if required
+gowrite: ; now we do the transfer
+ out (c), d ; de-assert /WR
+ ld c, a ; PPIDE_BASE
+ outi ; write byte to LSB
+ inc c ; up to MSB
+ outi ; write byte to MSB
+ inc c ; up to control lines
+ out (c), e ; assert /WR
+ inc b ; (delay) offset to counteract second outi instruction
+ jr nz, gowrite ; (delay) next word
+ ; write completed
+ out (c), d ; de-assert /WR
+ ld a, #PPIDE_PPI_BUS_READ
+ inc c ; up to 8255A command register
+ out (c), a ; 8255A ports A, B to read mode
+ pop af ; recover is_user test result
+ ret z ; done if kernel memory transfer
+ jp map_kernel ; else map kernel then return
+ __endasm;
+}
+
+#endif
--- /dev/null
+export CPU = z180
+export USERCPU = z80
--- /dev/null
+; 2014-12-16 William R Sowerbutts
+; N8VEM Mark IV SBC hardware specific code
+
+ .module mark4
+ .z180
+
+ ; exported symbols
+ .globl init_early
+ .globl init_hardware
+ .globl inchar
+ .globl outchar
+ .globl platform_interrupt_all
+ .globl _bufpool
+
+ ; imported symbols
+ .globl z180_init_hardware
+ .globl z180_init_early
+ .globl outhl
+ .globl outnewline
+
+ .include "kernel.def"
+ .include "../cpu-z180/z180.def"
+ .include "../kernel.def"
+
+; -----------------------------------------------------------------------------
+; Buffers
+; -----------------------------------------------------------------------------
+ .area _BUFFERS
+_bufpool:
+ .ds (BUFSIZE * 4) ; adjust NBUFS in config.h in line with this
+
+; -----------------------------------------------------------------------------
+; Initialisation code
+; -----------------------------------------------------------------------------
+ .area _DISCARD
+
+init_early:
+ jp z180_init_early
+
+init_hardware:
+ ; enable ASCI interrupts
+ in0 a, (ASCI_STAT0)
+ or #0x08 ; enable ASCI0 receive interrupts
+ out0 (ASCI_STAT0), a
+ in0 a, (ASCI_ASEXT0)
+ and #0x7f ; disable RDRF interrupt inhibit
+ out0 (ASCI_ASEXT0), a
+ in0 a, (ASCI_STAT1)
+ or #0x08 ; enable ASCI1 receive interrupts
+ out0 (ASCI_STAT1), a
+ in0 a, (ASCI_ASEXT1)
+ and #0x7f ; disable RDRF interrupt inhibit
+ out0 (ASCI_ASEXT1), a
+
+ jp z180_init_hardware
+
+; -----------------------------------------------------------------------------
+; COMMON MEMORY BANK
+; -----------------------------------------------------------------------------
+ .area _COMMONMEM
+
+; outchar: Wait for UART TX idle, then print the char in A
+; destroys: AF
+outchar:
+ push bc
+ ld b, a
+ ; wait for transmitter to be idle
+ocloop: in0 a, (ASCI_STAT0)
+ bit 1, a ; and 0x02
+ jr z, ocloop ; loop while busy
+ ; now output the char to serial port
+ ld a, b
+ out0 (ASCI_TDR0), a
+ pop bc
+ ret
+
+; inchar: Wait for character on UART, return in A
+; destroys: AF
+inchar:
+ in0 a, (ASCI_STAT0)
+ rlca
+ jr nc, inchar
+ in0 a, (ASCI_RDR0)
+ ret
+
+platform_interrupt_all:
+ ret
--- /dev/null
+.include "../cpu-z180/z180.s"