From: Alan Cox Date: Mon, 7 Jan 2019 01:26:20 +0000 (+0000) Subject: linc80: initial port X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=f6a3975865b96a9e2fff04a66407e07aabf33020;p=FUZIX.git linc80: initial port Lots of work to do on the IM2 side - serial handlers etc rather than polling on the timer as an icky hack to get started --- diff --git a/Kernel/platform-linc80/Makefile b/Kernel/platform-linc80/Makefile new file mode 100644 index 00000000..6b5c5849 --- /dev/null +++ b/Kernel/platform-linc80/Makefile @@ -0,0 +1,50 @@ +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 diff --git a/Kernel/platform-linc80/README b/Kernel/platform-linc80/README new file mode 100644 index 00000000..77da6e06 --- /dev/null +++ b/Kernel/platform-linc80/README @@ -0,0 +1,41 @@ +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. diff --git a/Kernel/platform-linc80/commonmem.s b/Kernel/platform-linc80/commonmem.s new file mode 100644 index 00000000..355bd53a --- /dev/null +++ b/Kernel/platform-linc80/commonmem.s @@ -0,0 +1,10 @@ +; +; 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" + diff --git a/Kernel/platform-linc80/config.h b/Kernel/platform-linc80/config.h new file mode 100644 index 00000000..fa23cee1 --- /dev/null +++ b/Kernel/platform-linc80/config.h @@ -0,0 +1,69 @@ +/* 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() diff --git a/Kernel/platform-linc80/crt0.s b/Kernel/platform-linc80/crt0.s new file mode 100644 index 00000000..2d2b7491 --- /dev/null +++ b/Kernel/platform-linc80/crt0.s @@ -0,0 +1,70 @@ +; 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 diff --git a/Kernel/platform-linc80/devices.c b/Kernel/platform-linc80/devices.c new file mode 100644 index 00000000..1a52d3e6 --- /dev/null +++ b/Kernel/platform-linc80/devices.c @@ -0,0 +1,39 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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; +} diff --git a/Kernel/platform-linc80/devtty.c b/Kernel/platform-linc80/devtty.c new file mode 100644 index 00000000..ea1342c1 --- /dev/null +++ b/Kernel/platform-linc80/devtty.c @@ -0,0 +1,188 @@ +#include +#include +#include +#include +#include +#include + +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'); +} diff --git a/Kernel/platform-linc80/devtty.h b/Kernel/platform-linc80/devtty.h new file mode 100644 index 00000000..0857f805 --- /dev/null +++ b/Kernel/platform-linc80/devtty.h @@ -0,0 +1,15 @@ +#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 diff --git a/Kernel/platform-linc80/discard.c b/Kernel/platform-linc80/discard.c new file mode 100644 index 00000000..3b5281fe --- /dev/null +++ b/Kernel/platform-linc80/discard.c @@ -0,0 +1,40 @@ +#include +#include +#include +#include +#include +#include +#include +#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 +} diff --git a/Kernel/platform-linc80/fuzix.lnk b/Kernel/platform-linc80/fuzix.lnk new file mode 100644 index 00000000..4c22ca57 --- /dev/null +++ b/Kernel/platform-linc80/fuzix.lnk @@ -0,0 +1,40 @@ +-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 diff --git a/Kernel/platform-linc80/kernel.def b/Kernel/platform-linc80/kernel.def new file mode 100644 index 00000000..c4764f7a --- /dev/null +++ b/Kernel/platform-linc80/kernel.def @@ -0,0 +1,32 @@ +; 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 + diff --git a/Kernel/platform-linc80/linc80.s b/Kernel/platform-linc80/linc80.s new file mode 100644 index 00000000..8e796346 --- /dev/null +++ b/Kernel/platform-linc80/linc80.s @@ -0,0 +1,267 @@ +; +; 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 + diff --git a/Kernel/platform-linc80/loader.s b/Kernel/platform-linc80/loader.s new file mode 100644 index 00000000..686ec30b --- /dev/null +++ b/Kernel/platform-linc80/loader.s @@ -0,0 +1,118 @@ +; +; 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' diff --git a/Kernel/platform-linc80/main.c b/Kernel/platform-linc80/main.c new file mode 100644 index 00000000..2f88a938 --- /dev/null +++ b/Kernel/platform-linc80/main.c @@ -0,0 +1,46 @@ +#include +#include +#include +#include +#include + +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(); +} + diff --git a/Kernel/platform-linc80/platform_ide.h b/Kernel/platform-linc80/platform_ide.h new file mode 100644 index 00000000..233ca468 --- /dev/null +++ b/Kernel/platform-linc80/platform_ide.h @@ -0,0 +1,6 @@ +#define ide_select(x) +#define ide_deselect() + +/* 8bit, no altstatus/control */ +#define IDE_8BIT_ONLY +#define IDE_REG_CS1_BASE 0x10 diff --git a/Kernel/platform-linc80/target.mk b/Kernel/platform-linc80/target.mk new file mode 100644 index 00000000..3bffcde0 --- /dev/null +++ b/Kernel/platform-linc80/target.mk @@ -0,0 +1 @@ +export CPU = z80 diff --git a/Kernel/platform-linc80/tricks.s b/Kernel/platform-linc80/tricks.s new file mode 100644 index 00000000..0113d75b --- /dev/null +++ b/Kernel/platform-linc80/tricks.s @@ -0,0 +1,5 @@ + .include "kernel.def" + .include "../kernel.def" + + .include "../lib/z80single.s" +