From c499a8cb1060625dea414369a550c7ef685297d7 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 22 Sep 2017 23:36:49 +0100 Subject: [PATCH] v658c16: intial sketches of the needed platform code Lots to do before this even compiles --- Kernel/platform-v65c816/README | 49 +++++++ Kernel/platform-v65c816/commonmem.s | 38 +++++ Kernel/platform-v65c816/config.h | 43 ++++++ Kernel/platform-v65c816/crt0.s | 112 +++++++++++++++ Kernel/platform-v65c816/devhd.c | 81 +++++++++++ Kernel/platform-v65c816/devhd.h | 9 ++ Kernel/platform-v65c816/device.h | 6 + Kernel/platform-v65c816/devices.c | 39 ++++++ Kernel/platform-v65c816/devtty.c | 77 +++++++++++ Kernel/platform-v65c816/devtty.h | 6 + Kernel/platform-v65c816/kernel.def | 10 ++ Kernel/platform-v65c816/ld65.cfg | 30 ++++ Kernel/platform-v65c816/main.c | 40 ++++++ Kernel/platform-v65c816/target.mk | 1 + Kernel/platform-v65c816/v65.s | 198 +++++++++++++++++++++++++++ Kernel/platform-v65c816/zeropage.inc | 26 ++++ 16 files changed, 765 insertions(+) create mode 100644 Kernel/platform-v65c816/README create mode 100644 Kernel/platform-v65c816/commonmem.s create mode 100644 Kernel/platform-v65c816/config.h create mode 100644 Kernel/platform-v65c816/crt0.s create mode 100644 Kernel/platform-v65c816/devhd.c create mode 100644 Kernel/platform-v65c816/devhd.h create mode 100644 Kernel/platform-v65c816/device.h create mode 100644 Kernel/platform-v65c816/devices.c create mode 100644 Kernel/platform-v65c816/devtty.c create mode 100644 Kernel/platform-v65c816/devtty.h create mode 100644 Kernel/platform-v65c816/kernel.def create mode 100644 Kernel/platform-v65c816/ld65.cfg create mode 100644 Kernel/platform-v65c816/main.c create mode 100644 Kernel/platform-v65c816/target.mk create mode 100644 Kernel/platform-v65c816/v65.s create mode 100644 Kernel/platform-v65c816/zeropage.inc diff --git a/Kernel/platform-v65c816/README b/Kernel/platform-v65c816/README new file mode 100644 index 00000000..e39b00ff --- /dev/null +++ b/Kernel/platform-v65c816/README @@ -0,0 +1,49 @@ +Use a modern cc65 from https://github.com/cc65/cc65 + + +Our memory mapping looks like this + +Bank 0: + 0x0000 Kernel DP + 0x0100 UData + C stack + 0x0200 Bootcode / Replaced with C stack + 0x0300 CPU stack (kernel mode) + 0x0400 Kernel image + 0xF700 7 x 256 byte CPU stacks for processes + 0xFE00 I/O page + 0xFF00 Vectors + +And in user space + + 0x0000 User DP + 0x0100 Program (CPU stack is in bank 0) + 0xFC00 Udata copy (768 bytes) + 0xFF00 Stubs [signal return etc] + +We don't yet allow for a split I/D program using two banks and having 64K +code and 64K data. + +To build: +Set the platform/target +make clean +make + +and you'll get an image file to dd onto the last 64K of your disk image for +the emulator. + +TODO +---- +- Debug initial sketches +- Add stubs and correct stub copier (+ syscall vector) +- Add vectors correctly for the 816 +- Figure out how to set stacks up nicely +- Test signal handling paths +- Fix brk() checking [right now its busted entirely] +- Fix execl() execle() in userspace (so init can be fully tested) +- Add pre-emption logic to the interrupt return path +- Fix fork() to copy the user C stacks in dofork() +- Add swap logic + +Optimisations We Need To Do +-------------------------------------------------------------- +- Only copy the needed memory when forking, not 64K ? diff --git a/Kernel/platform-v65c816/commonmem.s b/Kernel/platform-v65c816/commonmem.s new file mode 100644 index 00000000..1b1692c4 --- /dev/null +++ b/Kernel/platform-v65c816/commonmem.s @@ -0,0 +1,38 @@ +; +; We keep our common area right down low, with the ZP and stack +; +; + ; exported symbols + .export _ub + .export _udata + .export kstack_top + .export istack_top + .export istack_switched_sp + .export CTemp + + .segment "COMMONDATA" + .include "zeropage.inc" + +; +; In 6502 land these are the C stacks, we will need to handle the +; hardware stack separately, and also to save sp,sp+1 etc on irqs +; +; Declared as BSS so no non zero bytes here please +; +_ub: ; first 512 bytes: starts with struct u_block, with the kernel stack working down from above +_udata: +kstack_base: + .res 512,0 +kstack_top: +FIXME: C stack of 512 - udata, 65C816 stack follows + +; +; We have a single istack so we can stuff that anywhere we like +; + .bss + +istack_base: + .res 254,0 +istack_top: +FIXME: interrupt CPU stack (64 ?) +istack_switched_sp: .word 0 diff --git a/Kernel/platform-v65c816/config.h b/Kernel/platform-v65c816/config.h new file mode 100644 index 00000000..e359fb04 --- /dev/null +++ b/Kernel/platform-v65c816/config.h @@ -0,0 +1,43 @@ +/* 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 +/* Acct syscall support */ +#undef CONFIG_ACCT +/* Multiple processes in memory at once */ +#define CONFIG_MULTI +/* Use fixed banks for now. It's simplest and we've got so much memory ! */ +#define CONFIG_BANKS 1 + +#define CONFIG_CALL_R2L /* Runtime stacks arguments backwards */ + +/* + * We have 512K of RAM and have to allocate it in banks due to the CPU + * bank granularity. That gives us 7 processes plus kernel and more + * if we add swap. + */ +#define CONFIG_BANK_65C816 +#define MAX_MAPS 7 +#define MAP_SIZE 0xFC00 /* 0-FBFF */ + +#define TICKSPERSEC 10 /* Ticks per second */ +#define MAPBASE 0x0000 /* We map from 0 */ +#define PROGBASE 0x0100 /* also data base */ +#define PROGLOAD 0x0100 +#define PROGTOP 0xFC00 /* Top of program. If we fixed a few things we + could go to FE00 */ + +#define BOOT_TTY 513 /* Set this to default device for stdio, stderr */ + +/* We need a tidier way to do this from the loader */ +#define CMDLINE NULL /* Location of root dev name */ + +/* Device parameters */ +#define NUM_DEV_TTY 1 +#define TTYDEV BOOT_TTY /* Device used by kernel for messages, panics */ +#define NBUFS 8 /* Number of block buffers */ +#define NMOUNTS 2 /* Number of mounts at a time */ + +#define platform_discard() /* for now - wants fixing */ diff --git a/Kernel/platform-v65c816/crt0.s b/Kernel/platform-v65c816/crt0.s new file mode 100644 index 00000000..5776ea89 --- /dev/null +++ b/Kernel/platform-v65c816/crt0.s @@ -0,0 +1,112 @@ + ; imported symbols + .import init_early + .import init_hardware + .import _fuzix_main + .import kstack_top + .import vector + .import nmi_handler + + .import __BSS_RUN__, __BSS_SIZE__ + .importzp ptr1, ptr2, tmp1 + + ; startup code @0 + .include "zeropage.inc" + +; +; So we end up first in the image +; + .segment "START" + .byte 65 + .byte 81 + + .a8 + .i8 + .p816 + +entry: +; +; We are entered at $0202 just after the required magic number +; +; We get run from bank 0, our I/O writes would otherwise need to be +; 24bit +; + sep #$30 ; ensure we are in 8bit mode + lda #'F' + sta $FE20 ; signal our arrival + + sei ; interrupts off + cld ; decimal off + + rep #$10 + .i16 + ldx #kstack + txs ; Stack (6502 not C) + + lda #'u' + sta $FE20 + + ldx #kstack_top ; C stack + sta sp + + ldx #__BSS_RUN__ + + lda #'z' + sta $FE20 + + txy + iny + + ; Wipe the BSS + + rep #$20 + .a16 + lda #__BSS_SIZE-2 ; must be >=2 bytes or else + clz 0,x + mvn 0,0 + + + sep #$30 + .a8 + .i8 + + lda #'i' + sta $FE20 + + lda #'x' + sta $FE20 + + jsr init_early + lda #'.' + sta $FE20 + jsr init_hardware + lda #13 + sta $FE20 + lda #10 + sta $FE20 + jmp code + +; The above gets blasted into udata space + .code + +code: + rep #$30 + .a8 + .i8 + ldx #$U_DATA + ldy #$U_DATA+1 + lda #$UDATA_TOTALSIZE-2 + clz 0,x + mvn 0,0 + + sep #$30 + .a8 + .i8 + + jsr _fuzix_main ; Should never return + sei ; Spin +stop: jmp stop + + .segment "VECTORS" + .addr vector + .addr $0202 ; does it matter ??? + .addr nmi_handler diff --git a/Kernel/platform-v65c816/devhd.c b/Kernel/platform-v65c816/devhd.c new file mode 100644 index 00000000..51b57c50 --- /dev/null +++ b/Kernel/platform-v65c816/devhd.c @@ -0,0 +1,81 @@ +/* + * ROMdisc hack for testing + */ + +#include +#include +#include +#include + +extern uint8_t hd_map; + +extern void hd_read_data(uint16_t addr); +extern void hd_write_data(uint16_t addr); + +volatile uint8_t *disknum = (volatile uint8_t *)0xFE30; +volatile uint8_t *diskcylh = (volatile uint8_t *)0xFE31; +volatile uint8_t *diskcyll = (volatile uint8_t *)0xFE32; +volatile uint8_t *diskcmd = (volatile uint8_t *)0xFE33; +volatile uint8_t *diskstat = (volatile uint8_t *)0xFE35; + +static int hd_transfer(uint8_t minor, bool is_read, uint8_t rawflag) +{ + uint16_t dptr, nb; + irqflags_t irq; + uint8_t err; + + /* FIXME: add swap */ + if(rawflag == 1 && d_blkoff(9)) + return -1; + + /* For swap it'll be the swap bank passed */ + hd_map = rawflag ? udata.u_page : KERNEL_BANK; + + dptr = (uint16_t)udata.u_dptr; + nb = udata.u_nblock; + + while (udata.u_nblock--) { + *disknum = minor; + *diskcylh = udata.u_block >> 8; + *diskcyll = udata.u_block; + *diskcmd = 1; + if ((err = *diskstat) != 0) { + kprintf("hd%d: disk error %x\n", err); + udata.u_error = EIO; + return -1; + } + /* We shouldn't need the di any more */ + irq = di(); + if (is_read) + hd_read_data(dptr); + else + hd_write_data(dptr); + irqrestore(irq); + udata.u_block++; + dptr += 512; + } + return nb; +} + +int hd_open(uint8_t minor, uint16_t flag) +{ + used(flag); + if(minor != 0) { + udata.u_error = ENODEV; + return -1; + } + return 0; +} + +int hd_read(uint8_t minor, uint8_t rawflag, uint8_t flag) +{ + used(flag); + return hd_transfer(minor, true, rawflag); +} + +int hd_write(uint8_t minor, uint8_t rawflag, uint8_t flag) +{ + used(flag); + return hd_transfer(minor, false, rawflag); +} + diff --git a/Kernel/platform-v65c816/devhd.h b/Kernel/platform-v65c816/devhd.h new file mode 100644 index 00000000..5b99f00f --- /dev/null +++ b/Kernel/platform-v65c816/devhd.h @@ -0,0 +1,9 @@ +#ifndef __DEVHD_DOT_H__ +#define __DEVHD_DOT_H__ + +/* public interface */ +int hd_read(uint8_t minor, uint8_t rawflag, uint8_t flag); +int hd_write(uint8_t minor, uint8_t rawflag, uint8_t flag); +int hd_open(uint8_t minor, uint16_t flag); + +#endif /* __DEVHD_DOT_H__ */ diff --git a/Kernel/platform-v65c816/device.h b/Kernel/platform-v65c816/device.h new file mode 100644 index 00000000..6f4c1e26 --- /dev/null +++ b/Kernel/platform-v65c816/device.h @@ -0,0 +1,6 @@ +#ifndef __DEVICE_DOT_H__ +#define __DEVICE_DOT_H__ + +extern void mod_control(uint8_t set, uint8_t clr); + +#endif /* __DEVICE_DOT_H__ */ diff --git a/Kernel/platform-v65c816/devices.c b/Kernel/platform-v65c816/devices.c new file mode 100644 index 00000000..8f2563d7 --- /dev/null +++ b/Kernel/platform-v65c816/devices.c @@ -0,0 +1,39 @@ +#include +#include +#include +#include +#include +#include +#include + +struct devsw dev_tab[] = /* The device driver switch table */ +{ +// minor open close read write ioctl +// ----------------------------------------------------------------- + /* 0: /dev/fd Floppy disc block devices */ + { hd_open, no_close, hd_read, hd_write, no_ioctl }, + /* 1: /dev/hd Hard disc block devices (absent) */ + { nxio_open, no_close, no_rdwr, no_rdwr, no_ioctl }, + /* 2: /dev/tty TTY devices */ + { tty_open, tty_close, tty_read, tty_write, tty_ioctl }, + /* 3: /dev/lpr Printer devices */ + { no_open, no_close, no_rdwr, no_rdwr, no_ioctl }, + /* 4: /dev/mem etc System devices (one offs) */ + { no_open, no_close, sys_read, sys_write, sys_ioctl }, + /* Pack to 7 with nxio if adding private devices and start at 8 */ +}; + +bool validdev(uint16_t dev) +{ + /* This is a bit uglier than needed but the right hand side is + a constant this way */ + if(dev > ((sizeof(dev_tab)/sizeof(struct devsw)) << 8) - 1) + return false; + else + return true; +} + +void device_init(void) +{ +} + diff --git a/Kernel/platform-v65c816/devtty.c b/Kernel/platform-v65c816/devtty.c new file mode 100644 index 00000000..9895ea32 --- /dev/null +++ b/Kernel/platform-v65c816/devtty.c @@ -0,0 +1,77 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +static volatile uint8_t *uart = (volatile uint8_t *)0xFE20; +static volatile uint8_t *timer = (volatile uint8_t *)0xFE10; + +static char tbuf1[TTYSIZ]; +PTY_BUFFERS; + +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}, + PTY_QUEUES +}; + +/* tty1 is the screen tty2 is the serial port */ + +/* Output for the system console (kprintf etc) */ +void kputchar(uint8_t c) +{ + if (c == '\n') + tty_putc(1, '\r'); + tty_putc(1, c); +} + +ttyready_t tty_writeready(uint8_t minor) +{ + return TTY_READY_NOW; +} + +void tty_putc(uint8_t minor, unsigned char c) +{ + minor; + uart[0] = c; +} + +void tty_setup(uint8_t minor) +{ + minor; +} + +void tty_sleeping(uint8_t minor) +{ + minor; +} + +/* For the moment */ +int tty_carrier(uint8_t minor) +{ + minor; + return 1; +} + +void tty_poll(void) +{ + uint8_t x; + + x = uart[1] & 1; + if (x) { + x = uart[0]; + tty_inproc(1, x); + } +} + +void platform_interrupt(void) +{ + uint8_t t = *timer; + tty_poll(); + while(t--) + timer_interrupt(); +} diff --git a/Kernel/platform-v65c816/devtty.h b/Kernel/platform-v65c816/devtty.h new file mode 100644 index 00000000..da0afba5 --- /dev/null +++ b/Kernel/platform-v65c816/devtty.h @@ -0,0 +1,6 @@ +#ifndef __DEVTTY_DOT_H__ +#define __DEVTTY_DOT_H__ + +extern void tty_poll(void); + +#endif diff --git a/Kernel/platform-v65c816/kernel.def b/Kernel/platform-v65c816/kernel.def new file mode 100644 index 00000000..432367aa --- /dev/null +++ b/Kernel/platform-v65c816/kernel.def @@ -0,0 +1,10 @@ +; UZI mnemonics for memory addresses etc + +; (this is struct u_data from kernel.h) +U_DATA .set $0100 ; stomps over bootstrap +; 256+256+256 bytes. (U, kstack copy, k C stack copy) +U_DATA__TOTALSIZE .set $300 +U_DATA_STASH .set $FC00 ; leaves FFxx for vectors and stubs + +PROGLOAD .set $0200 +ZPBASE .set $0 diff --git a/Kernel/platform-v65c816/ld65.cfg b/Kernel/platform-v65c816/ld65.cfg new file mode 100644 index 00000000..0db09c20 --- /dev/null +++ b/Kernel/platform-v65c816/ld65.cfg @@ -0,0 +1,30 @@ +MEMORY { + RAMZ: start = $0000, size = $0100, type = rw, fill = yes; + STACK: start = $0100, size = $0100, type = rw, fill = yes; + BOOT: start = $0200, size = $0200, type = rw, fill = yes; + MAIN: start = $0400, size = $F300, type = rw, fill = yes; + USTACKS:start = $F700, size = $0700, type = rw, fill = yes; + IO: start = $FE00, size = $0100, type = rw, fill = yes; + VECTOR: start = $FFF0, size = $0010, type = rw, fill = yes; +} + +SEGMENTS { + ZEROPAGE: load = RAMZ, type = zp, define = yes; + COMMONDATA: load = MAIN, type = bss; + CODE: load = MAIN, type = ro, define = yes; + RODATA: load = MAIN, type = ro; + + START: load = BOOT, type = ro; + + DATA: load = MAIN, type = rw, define = yes; + BSS: load = MAIN, type = bss, define = yes; + + DISCARD: load = MAIN, type = ro; + DISCARDDATA: load = MAIN, type = ro; + + VECTORS: load = VECTOR, type = ro; +} + +FILES { + %O: format = bin; +} diff --git a/Kernel/platform-v65c816/main.c b/Kernel/platform-v65c816/main.c new file mode 100644 index 00000000..4b0e7c36 --- /dev/null +++ b/Kernel/platform-v65c816/main.c @@ -0,0 +1,40 @@ +#include +#include +#include +#include +#include + +uint8_t kernel_flag = 1; + +void platform_idle(void) +{ + irqflags_t flags = di(); + tty_poll(); + irqrestore(flags); +} + +void do_beep(void) +{ +} + +/* + * Map handling: We have flexible paging. Each map table consists of a set of pages + * with the last page repeated to fill any holes. + */ + +void pagemap_init(void) +{ + int i; + /* Bank 0 is the kernel */ + for (i = 15 ; i > 0; i--) + pagemap_add(i * 8); +} + +void map_init(void) +{ +} + +uint8_t platform_param(char *p) +{ + return 0; +} diff --git a/Kernel/platform-v65c816/target.mk b/Kernel/platform-v65c816/target.mk new file mode 100644 index 00000000..677f44e4 --- /dev/null +++ b/Kernel/platform-v65c816/target.mk @@ -0,0 +1 @@ +export CPU = 658C16 diff --git a/Kernel/platform-v65c816/v65.s b/Kernel/platform-v65c816/v65.s new file mode 100644 index 00000000..3384b3c4 --- /dev/null +++ b/Kernel/platform-v65c816/v65.s @@ -0,0 +1,198 @@ +; +; v65 platform functions +; + + .export init_early + .export init_hardware + .export _program_vectors + + ; exported debugging tools + .export _trap_monitor + .export _trap_reboot + .export outchar + .export ___hard_di + .export ___hard_ei + .export ___hard_irqrestore + .export vector + + .import _ramsize + .import _procmem + .import nmi_handler + .import unix_syscall_entry + .import kstack_top + .import istack_switched_sp + .import istack_top + .import _unix_syscall + .import _platform_interrupt + .import _kernel_flag + .import pushax + + .import outcharhex + .import outxa + .import incaxy + + .import _create_init_common + + .include "kernel.def" + .include "../kernel816.def" + .include "zeropage.inc" + +; +; syscall is jsr [$00fe] +; +syscall = $FE + + .code + +_trap_monitor: + jmp _trap_monitor + +_trap_reboot: + lda #$A5 + sta $FE40 ; Off + jmp _trap_reboot ; FIXME: original ROM map and jmp + +___hard_di: + php + sei ; Save old state in return to C + pla ; Old status + rts + +___hard_ei: + cli ; on 6502 cli enables IRQs!!! + rts + +___hard_irqrestore: + and #4 ; IRQ flag + beq irq_on + cli + rts +irq_on: + sei + rts + +init_early: + ; copy the stubs from bank 0 to all banks so we can keep the + jsr _create_init_common + rts + +init_hardware: + ; set system RAM size for test purposes + rep #$10 + .i16 + ldx #8 + stx _ramsize + ldx #512-64 + stx _procmem + ; TODO - correct vectors for the 816 + ldx #vector + stx $FFFE + ldx #