From f79b9d8fac036145cb01381fd0c86ead3cf28dfe Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Sat, 10 Jan 2015 00:43:20 +0000 Subject: [PATCH] tgl6502: initial bring up tree elements for the TGL6502 platform There is a lot left to fill in on the 6502 tree. There are also some very weird bugs right now such as kprintf working/not working depending upon subtle changes to code sizes elsewhere. It's hard at this point to tell if its emulator bugs, something weird in the setup code, compiler etc. All part of the fun. --- Kernel/Makefile | 10 +- Kernel/platform-tgl6502/Makefile | 32 ++ Kernel/platform-tgl6502/README | 34 ++ Kernel/platform-tgl6502/commonmem.s | 30 ++ Kernel/platform-tgl6502/config.h | 42 +++ Kernel/platform-tgl6502/crt0.s | 175 +++++++++++ Kernel/platform-tgl6502/device.h | 6 + Kernel/platform-tgl6502/devices.c | 39 +++ Kernel/platform-tgl6502/devrd.c | 69 ++++ Kernel/platform-tgl6502/devrd.h | 13 + Kernel/platform-tgl6502/devtty.c | 62 ++++ Kernel/platform-tgl6502/devtty.h | 7 + Kernel/platform-tgl6502/kernel.def | 7 + Kernel/platform-tgl6502/ld65.cfg | 22 ++ Kernel/platform-tgl6502/libc.c | 17 + Kernel/platform-tgl6502/main.c | 32 ++ Kernel/platform-tgl6502/tgl6502.s | 452 +++++++++++++++++++++++++++ Kernel/platform-tgl6502/tricks.s | 194 ++++++++++++ Kernel/platform-tgl6502/zeropage.inc | 26 ++ 19 files changed, 1264 insertions(+), 5 deletions(-) create mode 100644 Kernel/platform-tgl6502/Makefile create mode 100644 Kernel/platform-tgl6502/README create mode 100644 Kernel/platform-tgl6502/commonmem.s create mode 100644 Kernel/platform-tgl6502/config.h create mode 100644 Kernel/platform-tgl6502/crt0.s create mode 100644 Kernel/platform-tgl6502/device.h create mode 100644 Kernel/platform-tgl6502/devices.c create mode 100644 Kernel/platform-tgl6502/devrd.c create mode 100644 Kernel/platform-tgl6502/devrd.h create mode 100644 Kernel/platform-tgl6502/devtty.c create mode 100644 Kernel/platform-tgl6502/devtty.h create mode 100644 Kernel/platform-tgl6502/kernel.def create mode 100644 Kernel/platform-tgl6502/ld65.cfg create mode 100644 Kernel/platform-tgl6502/libc.c create mode 100644 Kernel/platform-tgl6502/main.c create mode 100644 Kernel/platform-tgl6502/tgl6502.s create mode 100644 Kernel/platform-tgl6502/tricks.s create mode 100644 Kernel/platform-tgl6502/zeropage.inc diff --git a/Kernel/Makefile b/Kernel/Makefile index a01832c4..0fa31c5d 100644 --- a/Kernel/Makefile +++ b/Kernel/Makefile @@ -1,11 +1,11 @@ -TARGET_LIST = platform-nc100 platform-micropack platform-pcw8256 platform-socz80 platform-zx128 platform-trs80 platform-z80pack platform-z80pack-lite platform-z80pack32 platform-dragon +TARGET_LIST = platform-nc100 platform-micropack platform-pcw8256 platform-socz80 platform-zx128 platform-trs80 platform-z80pack platform-z80pack-lite platform-z80pack32 platform-dragon platform-tgl6502 -export TARGET= trs80 -export CPU = z80 +#export TARGET= trs80 +#export CPU = z80 #export TARGET = dragon #export CPU = 6809 -#export TARGET = 6502test -#export CPU = 6502 +export TARGET = tgl6502 +export CPU = 6502 export VERSION = "0.1" export SUBVERSION = "ac1" diff --git a/Kernel/platform-tgl6502/Makefile b/Kernel/platform-tgl6502/Makefile new file mode 100644 index 00000000..b415860a --- /dev/null +++ b/Kernel/platform-tgl6502/Makefile @@ -0,0 +1,32 @@ + +CSRCS = devtty.c devrd.c +CSRCS += devices.c main.c libc.c + +ASRCS = tgl6502.s crt0.s +ASRCS += tricks.s commonmem.s + +COBJS = $(CSRCS:.c=$(BINEXT)) +AOBJS = $(ASRCS:.s=$(BINEXT)) +OBJS = $(COBJS) $(AOBJS) + +JUNK = $(CSRCS:.c=.o) $(CSRCS:.c=.s) $(ASRCS:.s=.o) + +all: $(OBJS) + +$(COBJS): %$(BINEXT): %.c + $(CROSS_CC) $(CROSS_CCOPTS) $< + +$(AOBJS): %$(BINEXT): %.s + $(CROSS_AS) $(ASOPTS) $< -o $*$(BINEXT) + +clean: + rm -f $(OBJS) $(JUNK) core *~ + +image: + $(CROSS_LD) -o ../fuzix.bin --mapfile ../fuzix.map -C ld65.cfg crt0.o commonmem.o \ + tgl6502.o ../start.o ../version.o ../lowlevel-6502.o \ + tricks.o main.o ../timer.o ../kdata.o devrd.o devices.o \ + ../devio.o ../filesys.o ../process.o ../inode.o ../syscall_fs.o \ + ../syscall_proc.o ../syscall_other.o ../mm.o ../swap.o ../bankfixed.o \ + ../tty.o ../devsys.o ../syscall_fs2.o ../syscall_exec.o \ + ../usermem.o ../usermem_std-6502.o devtty.o libc.o diff --git a/Kernel/platform-tgl6502/README b/Kernel/platform-tgl6502/README new file mode 100644 index 00000000..485d34dc --- /dev/null +++ b/Kernel/platform-tgl6502/README @@ -0,0 +1,34 @@ +Initial 6502 experimentation for the tgl6502 - as an experimental target +to play with 6502isms easily + +Our memory mapping looks like this + + 0x0000 ZP + 0x0100 6502 Stack (per proc) + 0x0200 C stack (per proc) + 0x0400 I stack (per proc) + 0x0500 UData per proc + 0x0600+ Common copy + + 0x2000 Kernel data (8K) + 0x4000 Kernel data (48K) + +This ensures we can do all our stack flips in one operation when we switch +process in switchin. + + + + +Lots not yet done: + +tricks.s is basically stubs for the 6502 code +signal checks are not being done on the syscall path (or irq path) + +We hackishly chop up and share the 6502 256 byte system stack. Probably we +should just check for overflows and kill, or perhaps copy stacks in/out if +it would otherwise run out ? + + +Memory set up for now is banking, because we'll need swap and bank16k+swap +still needs significant work on the I/O side of things. + diff --git a/Kernel/platform-tgl6502/commonmem.s b/Kernel/platform-tgl6502/commonmem.s new file mode 100644 index 00000000..a061d8ab --- /dev/null +++ b/Kernel/platform-tgl6502/commonmem.s @@ -0,0 +1,30 @@ +; +; 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 + + .segment "COMMONDATA" + +; +; 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: + + ; next 256 bytes: 253 byte interrupt stack, then 3 byte saved stack pointer +istack_base: + .res 254,0 +istack_top: +istack_switched_sp: .word 0 diff --git a/Kernel/platform-tgl6502/config.h b/Kernel/platform-tgl6502/config.h new file mode 100644 index 00000000..a2a93e30 --- /dev/null +++ b/Kernel/platform-tgl6502/config.h @@ -0,0 +1,42 @@ +/* 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 +/* Single tasking - for now while we get it booting */ +#undef CONFIG_SINGLETASK +#define CONFIG_BANKS 2 + +/* For now used BANK_FIXED as we don't yet have sane swap with 16K maps */ +#define CONFIG_BANK_FIXED +#define MAX_MAPS 2 +#define MAP_SIZE 0xC000 + +/* And swapping */ +#define SWAPDEV 257 /* FIXME */ +#define SWAP_SIZE 0x60 /* 48K in blocks */ +#define SWAPBASE 0x0000 /* We swap the lot in one, include the */ +#define SWAPTOP 0xC000 /* vectors so its a round number of sectors */ +/* FIXME: we need to swap the udata separately */ +#define MAX_SWAPS 32 + +#define TICKSPERSEC 10 /* Ticks per second */ +#define PROGBASE 0x0200 /* also data base */ +#define PROGLOAD 0x0200 +#define PROGTOP 0xC000 /* Top of program */ + +#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 */ diff --git a/Kernel/platform-tgl6502/crt0.s b/Kernel/platform-tgl6502/crt0.s new file mode 100644 index 00000000..04a569bf --- /dev/null +++ b/Kernel/platform-tgl6502/crt0.s @@ -0,0 +1,175 @@ + ; exported symbols + .export start + + ; imported symbols + .import init_early + .import init_hardware + .import _fuzix_main + .import kstack_top + .import vector + .import nmi_handler + + .import __BSS_RUN__, __BSS_SIZE__ + .import __DATA_LOAD__, __DATA_RUN__, __DATA_SIZE__ + .import __COMMONMEM_LOAD__, __COMMONMEM_RUN__, __COMMONMEM_SIZE__ + .importzp ptr1, ptr2, tmp1 + + + ; startup code @0 + .code + .include "zeropage.inc" + +; +; We are entered in ROM 8K bank $40, at virtual address $C000 +; + lda #'F' + sta $FF03 ; signal our arrival + + sei ; interrupts off + cld ; decimal off + ldx #$00 + txs ; Stack (6502 not C) + +; +; We are in the wrong place at the wrong time +; +; Map our page at $4000 as well +; + ldx #$40 ; our first 8K + stx $FF8C ; at ROM 0x4000 +; +; And land in the right place... +; + jmp start +start: ; Map ROM at 0x4000-0xFFFF + lda #'u' + sta $FF03 + inx ; ROM bank 1 is a magic hack we + inx ; must skip over + stx $FF8D + inx + stx $FF8E + inx + stx $FF8F + inx + stx $FF90 + inx + stx $FF91 + + lda #kstack_top + sta sp+1 + + lda #<__BSS_RUN__ + sta ptr1 + lda #>__BSS_RUN__ + sta ptr1+1 + lda #0 + tay + + lda #'z' + sta $FF03 + + ldx #>__BSS_SIZE__ + beq bss_wipe_tail +bss_wiper_1: sta (ptr1),y + iny + bne bss_wiper_1 + inc ptr1+1 + dex + bne bss_wiper_1 + +bss_wipe_tail: + cpy #<__BSS_SIZE__ + beq gogogo + sta (ptr1),y + iny + bne bss_wipe_tail +gogogo: + lda #'i' + sta $FF03 + ; But not just yet on the tgl6502 - need to sort the ROM + ; to RAM copy of the data out + ; + ; This code comes from the TGL support library + ; Ullrich von Bassewitz 1998-12-07 + ; + ; Give me LDIR any day of the week + lda #<__DATA_LOAD__ ; Source pointer + sta ptr1 + lda #>__DATA_LOAD__ + sta ptr1+1 + + lda #<__DATA_RUN__ ; Target pointer + sta ptr2 + lda #>__DATA_RUN__ + sta ptr2+1 + + ldx #<~__DATA_SIZE__ + lda #>~__DATA_SIZE__ ; Use -(__DATASIZE__+1) + sta tmp1 + + jsr copyloop + + lda #<__COMMONMEM_LOAD__ ; Source pointer + sta ptr1 + lda #>__COMMONMEM_LOAD__ + sta ptr1+1 + + lda #<__COMMONMEM_RUN__ ; Target pointer + sta ptr2 + lda #>__COMMONMEM_RUN__ + sta ptr2+1 + + ldx #<~__COMMONMEM_SIZE__ + lda #>~__COMMONMEM_SIZE__ ; Use -(__DATASIZE__+1) + sta tmp1 + + jsr copyloop + + + lda #'x' + sta $FF03 + + jsr init_early + lda #'.' + sta $FF03 + jsr init_hardware + lda #13 + sta $FF03 + lda #10 + sta $FF03 + jsr _fuzix_main ; Should never return + sei ; Spin +stop: jmp stop + + +copyloop: + ldy #$00 + +; Copy loop + +@L1: inx + beq @L3 + +@L2: lda (ptr1),y + sta (ptr2),y + iny + bne @L1 + inc ptr1+1 + inc ptr2+1 ; Bump pointers + bne @L1 ; Branch always (hopefully) + +; Bump the high counter byte + +@L3: inc tmp1 + bne @L2 + rts + +; Done + + .segment "VECTORS" + .addr vector + .addr $C000 ; our ROM mapping + .addr nmi_handler diff --git a/Kernel/platform-tgl6502/device.h b/Kernel/platform-tgl6502/device.h new file mode 100644 index 00000000..6f4c1e26 --- /dev/null +++ b/Kernel/platform-tgl6502/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-tgl6502/devices.c b/Kernel/platform-tgl6502/devices.c new file mode 100644 index 00000000..614690bf --- /dev/null +++ b/Kernel/platform-tgl6502/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 */ + { rd_open, no_close, rd_read, rd_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) + 255) + return false; + else + return true; +} + +void device_init(void) +{ +} + diff --git a/Kernel/platform-tgl6502/devrd.c b/Kernel/platform-tgl6502/devrd.c new file mode 100644 index 00000000..ddbf8b3c --- /dev/null +++ b/Kernel/platform-tgl6502/devrd.c @@ -0,0 +1,69 @@ +/* + * NC100 RD PCMCIA driver + * + */ + +#include +#include +#include +#include + +static int rd_transfer(bool is_read, uint8_t rawflag) +{ + blkno_t block; + int block_xfer; + uint16_t dptr; + int dlen; + int ct = 0; + int map; + + /* FIXME: raw is broken unless nicely aligned */ + if(rawflag) { + dlen = udata.u_count; + dptr = (uint16_t)udata.u_base; + if (dptr & 0x1FF) { + udata.u_error = EIO; + return -1; + } + block = udata.u_offset >> 9; + block_xfer = dlen >> 9; + map = 1; + } else { /* rawflag == 0 */ + dlen = 512; + dptr = (uint16_t)udata.u_buf->bf_data; + block = udata.u_buf->bf_blk; + block_xfer = 1; + map = 0; + } + block += 2*320; /* ramdisc starts at 320K in */ + + while (ct < block_xfer) { +/* rd_memcpy(is_read, map, dptr, block); */ + block++; + ct++; + } + return ct; +} + +int rd_open(uint8_t minor, uint16_t flag) +{ + flag; + if(minor != 0) { + udata.u_error = ENODEV; + return -1; + } + return 0; +} + +int rd_read(uint8_t minor, uint8_t rawflag, uint8_t flag) +{ + flag;minor; + return rd_transfer(true, rawflag); +} + +int rd_write(uint8_t minor, uint8_t rawflag, uint8_t flag) +{ + flag;minor; + return rd_transfer(false, rawflag); +} + diff --git a/Kernel/platform-tgl6502/devrd.h b/Kernel/platform-tgl6502/devrd.h new file mode 100644 index 00000000..6320b269 --- /dev/null +++ b/Kernel/platform-tgl6502/devrd.h @@ -0,0 +1,13 @@ +#ifndef __DEVRD_DOT_H__ +#define __DEVRD_DOT_H__ + +/* public interface */ +int rd_read(uint8_t minor, uint8_t rawflag, uint8_t flag); +int rd_write(uint8_t minor, uint8_t rawflag, uint8_t flag); +int rd_open(uint8_t minor, uint16_t flag); + +/* asm banking helper */ +void rd_memcpy(uint8_t isread, uint8_t map, uint16_t dptr, uint16_t block); + +#endif /* __DEVRD_DOT_H__ */ + diff --git a/Kernel/platform-tgl6502/devtty.c b/Kernel/platform-tgl6502/devtty.c new file mode 100644 index 00000000..a560af0d --- /dev/null +++ b/Kernel/platform-tgl6502/devtty.c @@ -0,0 +1,62 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#undef DEBUG /* UNdefine to delete debug code sequences */ + +uint8_t *uart = (uint8_t *)0xFF00; + +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); +} + +bool tty_writeready(uint8_t minor) +{ + return 1; +} + +void tty_putc(uint8_t minor, unsigned char c) +{ + minor; + uart[3] = c; +} + +void tty_setup(uint8_t minor) +{ + minor; +} + +/* For the moment */ +int tty_carrier(uint8_t minor) +{ + minor; + return 1; +} + +void platform_interrupt(void) +{ + timer_interrupt(); +} + +/* This is used by the vt asm code, but needs to live at the top of the kernel */ +uint16_t cursorpos; diff --git a/Kernel/platform-tgl6502/devtty.h b/Kernel/platform-tgl6502/devtty.h new file mode 100644 index 00000000..948cc298 --- /dev/null +++ b/Kernel/platform-tgl6502/devtty.h @@ -0,0 +1,7 @@ +#ifndef __DEVTTY_DOT_H__ +#define __DEVTTY_DOT_H__ + +extern int nc100_tty_open(uint8_t minor, uint16_t flag); +extern int nc100_tty_close(uint8_t minor); +extern void nc100_tty_init(void); +#endif diff --git a/Kernel/platform-tgl6502/kernel.def b/Kernel/platform-tgl6502/kernel.def new file mode 100644 index 00000000..8d4734e0 --- /dev/null +++ b/Kernel/platform-tgl6502/kernel.def @@ -0,0 +1,7 @@ +; UZI mnemonics for memory addresses etc + +; (this is struct u_data from kernel.h) +U_DATA .set $0200 +; 256+256+256 bytes. +U_DATA__TOTALSIZE .set $300 + diff --git a/Kernel/platform-tgl6502/ld65.cfg b/Kernel/platform-tgl6502/ld65.cfg new file mode 100644 index 00000000..527be4b5 --- /dev/null +++ b/Kernel/platform-tgl6502/ld65.cfg @@ -0,0 +1,22 @@ +MEMORY { + RAMZ: start = $0000, size = $0100, type = rw, define = yes; + RAM0: start = $0200, size = $1E00, type = rw, define = yes; + RAM1: start = $2000, size = $2000, type = rw, define = yes; + ROM0: start = $4000, size = $C000, fill = yes; +} + +SEGMENTS { + ZEROPAGE: load = RAMZ, type = zp; + CODE: load = ROM0, type = ro; + RODATA: load = ROM0, type = ro; + DATA: load = ROM0, run = RAM1, type = rw, define = yes; + BSS: load = RAM1, type = bss, define=yes; + COMMONDATA: load = RAM0, type= bss; + COMMONMEM: load = ROM0, run = RAM0, type = rw, define = yes; + STUBS: load = ROM0, run = RAM0, type = ro; + VECTORS: load = ROM0, type = ro, start = $FFFA; +} + +FILES { + %O: format = bin; +} diff --git a/Kernel/platform-tgl6502/libc.c b/Kernel/platform-tgl6502/libc.c new file mode 100644 index 00000000..8a972835 --- /dev/null +++ b/Kernel/platform-tgl6502/libc.c @@ -0,0 +1,17 @@ +#include "cpu.h" + +void *memcpy(void *d, void *s, size_t sz) +{ + unsigned char *dp, *sp; + while(sz--) + *dp++=*sp++; + return d; +} + +size_t strlen(const char *p) +{ + const char *e = p; + while(*e++); + return e-p-1; +} + diff --git a/Kernel/platform-tgl6502/main.c b/Kernel/platform-tgl6502/main.c new file mode 100644 index 00000000..fe90dedf --- /dev/null +++ b/Kernel/platform-tgl6502/main.c @@ -0,0 +1,32 @@ +#include +#include +#include +#include +#include + +uint8_t kernel_flag = 0; + +void platform_idle(void) +{ +} + +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) +{ + /* We treat RAM as 2 48K banks + 16K of kernel data */ + /* 0-3 kernel, 4-9 Bank 0, 10-15 bank 1 */ + pagemap_add(4); + pagemap_add(10); +} + +void map_init(void) +{ +} diff --git a/Kernel/platform-tgl6502/tgl6502.s b/Kernel/platform-tgl6502/tgl6502.s new file mode 100644 index 00000000..1e72ecce --- /dev/null +++ b/Kernel/platform-tgl6502/tgl6502.s @@ -0,0 +1,452 @@ +; +; 6502 Build testing +; + + .export init_early + .export init_hardware + .export _program_vectors + .export map_kernel + .export map_process + .export map_process_always + .export map_save + .export map_restore + + .export _unix_syscall_i + .export _platform_interrupt_i + .export platform_doexec + + ; exported debugging tools + .export _trap_monitor + .export outchar + .export _di + .export _ei + .export _irqrestore + .export nmi_trap + .export vector + + .import interrupt_handler + .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 + + .include "kernel.def" + .include "../kernel02.def" + .include "zeropage.inc" + +; +; syscall is jsr [$00fe] +; +syscall = $FE +; ----------------------------------------------------------------------------- +; COMMON MEMORY BANK (0x0200 upwards after the common data blocks) +; ----------------------------------------------------------------------------- + .segment "COMMONMEM" + +nmi_trap: +_trap_monitor: + sei + jmp _trap_monitor + +_trap_reboot: + jmp _trap_reboot ; FIXME: original ROM map and jmp + +_di: + php + sei ; Save old state in return to C + pla ; Old status + rts +_ei: + cli ; on 6502 cli enables IRQs!!! + rts + +_irqrestore: + and #4 ; IRQ flag + beq irq_on + cli + rts +irq_on: + sei + rts + +; ----------------------------------------------------------------------------- +; KERNEL MEMORY BANK (only accessible when the kernel is mapped) +; ----------------------------------------------------------------------------- + .code + +init_early: + rts + +init_hardware: + ; set system RAM size for test purposes + lda #0 + sta _ramsize+1 + sta _procmem+1 + lda #128 + sta _ramsize + lda #120 + sta _procmem + + jsr program_vectors_k + + rts + + +;------------------------------------------------------------------------------ +; COMMON MEMORY PROCEDURES FOLLOW + + .segment "COMMONMEM" + +_program_vectors: + ; we are called, with interrupts disabled, by both newproc() and crt0 + ; will exit with interrupts off + sei + ; + ; Fixme: block copy stubs segment as well if 6509. + ; + + ; our C caller will invoke us with the pointer in x,a + ; just pass it on + jsr map_process +program_vectors_k: + lda #vector + sta $FFFF + lda #nmi_handler + sta $FFFB + ; However tempting it may be to use BRK for system calls we + ; can't do this on an NMOS 6502 because the chip has brain + ; dead IRQ handling buts that could simply "lose" the syscall! + lda #syscall_entry + sta syscall+1 + jsr map_kernel + rts + +; +; On a fully switching system with far copies like the 6509 this is +; all basically a no-op +; +; On a banked setup the semantics are: +; +; map_process_always() +; Map the current process (ie the one with the live uarea) +; +; map_kernel() +; Map the kernel +; +; map_process(pageptr [in X,A]) +; if pageptr = 0 then map_kernel +; else map_process using the pageptr +; +; map_save +; save the current mapping +; +; map_restore +; restore the saved mapping +; +; save/restore are used so that the kernel can play with its internal +; banking/mappings without having to leave interrupts off all the time +; +map_process_always: + pha + lda #U_DATA__U_PAGE + jsr map_process_2 + pla + rts +; +; X,A points to the map table of this process +; +map_process: + cmp #0 + bne map_process_2 + cpx #0 + bne map_process_2 +; +; Map in the kernel below the current common, all registers preserved +; the kernel lives in 40/42/43/.... (41 has the reset vectors in so +; we avoid it. Later we'll be clever and stuff _DISCARD and the copy +; blocks there or something (that would also let us put RODATA in +; common area just to balance out memory usages). +; +map_kernel: + pha + ; Common is left untouched as is ZP and S + lda #$01 ; Kernel RAM at 0x2000-0x3FFF + sta $FF8B ; + ldx #$40 ; Kernel ROM at 0x4000-0xFFFF + stx $FF8C + inx ; Skip second bank + inx + stx $FF8D + inx + stx $FF8E + inx + stx $FF8F + inx + stx $FF90 + inx + stx $FF91 + pla + rts + +; X,A holds the map table of this process +map_process_2: + sta ptr1 + tya + pha + sty ptr1+1 + ldy #0 + lda (ptr1),y ; 4 bytes if needed + jsr restore_bits + pla + tay + rts + + +; +; Restore mapping. This may not be sufficient. We may need to do a +; careful 6 byte save/restore FIXME +; +map_restore: + pha + txa + pha + ldx saved_map + jsr restore_bits + pla + tax + pla + rts + +; +; Restore all but the zero page and the top of memory map for this +; process. The ZP means 0-1FFF are not mapped the way the core +; kernel expects. We need to handle that in our user copiers +; +restore_bits: + inx ; We don't want to play with the ZP + stx $FF8B ; 2000 + inx + stx $FF8C ; 4000 + inx + stx $FF8D ; 6000 + inx + stx $FF8E ; 8000 + inx + stx $FF8F ; A000 + inx + stx $FF90 ; C000 + ; E000 we don't have enough RAM for until + ; we go to proper banking + rts + +; Save the current mapping. +; +; FIXME: need to copy the 8 byte area +; +map_save: + pha + sta saved_map + pla + rts + +saved_map: .byte 0 + +; outchar: Wait for UART TX idle, then print the char in a without +; corrupting other registers + +outchar: + pha +outcharw: + lda $FF01 + and #4 + beq outcharw + pla + sta $FF03 + rts + +; +; Code that will live in each bank at the same address and is copied +; there on 6509 type setups. On 6502 it may well be linked once in +; common space +; + .segment "STUBS" +; +; Interrupt vector logic. Keep this in platform for the 6502 so that +; we can use the shorter one for the CMOS chip +; +vector: + pha + txa + pha + tya + pha + cld +; +; Save the old stack ptr +; + lda sp ; put the C stack + pha ; on the 6502 stack + lda sp+1 + pha + tsx ; and save the 6502 stack ptr + stx istack_switched_sp ; in uarea/stacks + +; +; Hope the user hasn't gone over 192 bytes of 6502 stack ! +; + ldx #$40 ; guess at reserving some istack + txs ; our istack +; +; Configure the C stack to the i stack +; + lda #istack_top + sta sp+1 + jsr interrupt_handler +; +; Reload the previous value into the stack ptr +; + ldx istack_switched_sp + txs ; recover 6502 stack + pla ; recover C stack + sta sp+1 ; from 6502 stack + pla + sta sp+1 +irqout: + pla + tya + pla + txa + pla + rti + + +; X, A holds the syscall block +; Y holds the call code +; We assume the kernel is in bank 0 +; +syscall_entry: + sei + sty U_DATA__U_CALLNO + pha + txa + pha + sta ptr1 + stx ptr1+1 + lda #U_DATA__U_ARGN + sta ptr2+1 + + ldy #0 + +copy_args: lda (ptr1),y ; copy the arguments from current bank + sta (ptr2),y ; will write into bank 1 + iny + cpy #8 + bne copy_args + ; + ; Now we need to bank and stack switch + ; + lda sp + pha + lda sp+1 + pha + tsx + stx U_DATA__U_SP +; +; We try and divide our previous stack resource up between user +; and kernel. It's not clear if we should do this, copy the stack +; or do something clever I've not thought of yet. Possibly we should +; see if there is enough stack and if not copy and screw about ? +; + ldx #$80 + txs ; Switch to the working stack +; +; Set up the C stack +; + lda #kstack_top + sta sp+1 + + cli +; +; Caution: We may enter here and context switch and another task +; exit via its own syscall returning in its own memory context. +; +; Don't assume anything we stored statically *except* the uarea +; will be different. The uarea is banked in and out (or copied in +; more awkward systems). +; + jsr unix_syscall_entry + + sei +; +; Correct the system stack +; + ldx U_DATA__U_SP + txs +; +; From that recover the C stack and the syscall buf ptr +; + pla + sta sp+1 + pla + sta sp + pla + sta ptr1+1 + pla + sta ptr1+1 +; +; Copy the return data over +; + ldy #8 ; write them after the argument block + lda U_DATA__U_ERROR + + sta (ptr1), y + iny + lda U_DATA__U_ERROR+1 + sta (ptr1),y + iny + lda U_DATA__U_RETVAL + sta (ptr1),y + iny + lda U_DATA__U_RETVAL+1 + sta (ptr1), y +; +; FIXME: do signal dispatch - this will need C stack fixing, and +; basically signal dispatch is __interrupt. +; + + rts + + +platform_doexec: + jmp $2000 ; FIXME: should jump to argument really + +; +; Straight jumps no funny banking issues +; +_unix_syscall_i: + jmp _unix_syscall +_platform_interrupt_i: + jmp _platform_interrupt + + .segment "ZEROPAGE" + +zp_intvec: .byte 0 diff --git a/Kernel/platform-tgl6502/tricks.s b/Kernel/platform-tgl6502/tricks.s new file mode 100644 index 00000000..a43fff23 --- /dev/null +++ b/Kernel/platform-tgl6502/tricks.s @@ -0,0 +1,194 @@ +; +; 6502 version +; + .export _switchout + .export _switchin + .export _dofork + .export _ramtop + + .import _chksigs + .import _trap_monitor + + .include "kernel.def" + .include "../kernel02.def" + + .segment "COMMONMEM" + +; ramtop must be in common for single process swapping cases +; and its a constant for the others from before init forks so it'll be fine +; here +_ramtop: + .word 0 + +; Switchout switches out the current process, finds another that is READY, +; possibly the same process, and switches it in. When a process is +; restarted after calling switchout, it thinks it has just returned +; from switchout(). +; +; FIXME: make sure we optimise the switch to self case higher up the stack! +; +; This function can have no arguments or auto variables. +_switchout: + sei + + jsr _chksigs +; +; ; save machine state +; ldd #0 ; return code set here is ignored, but _switchin can +; ; return from either _switchout OR _dofork, so they must both write +; ; U_DATA__U_SP with the following on the stack: +; pshs d +; sts U_DATA__U_SP +; +; ; set inint to false +; lda #0 +; sta _inint +; +; ; find another process to run (may select this one again) returns it +; ; in X +; jsr _getproc + jsr _switchin + ; we should never get here + jsr _trap_monitor + +badswitchmsg: .asciiz "_switchin: FAIL\r\n" + +; new process pointer is in X +_switchin: +; orcc #0x10 ; irq off +; +; ldy P_TAB__P_PAGE_OFFSET+3,x +; ; FIXME: can we skip the usermaps here ? +; stx 0xffa6 ; map the process uarea we want +; adda #1 +; stx 0xffa7 +; stx 0xffaf ; and include the kernel mapping +; + ; ------- No stack ------- + ; check u_data->u_ptab matches what we wanted +; cmpx U_DATA__U_PTAB +; bne switchinfail +; + ; wants optimising up a bit +; lda #P_RUNNING +; sta P_TAB__P_STATUS_OFFSET,x + +; lda #0 +; sta _runticks + + ; restore machine state -- note we may be returning from either + ; _switchout or _dofork +; lds U_DATA__U_SP + +; puls x ; return code + + ; enable interrupts, if the ISR isn't already running +; lda _inint +; beq swtchdone ; in ISR, leave interrupts off +; andcc #0xef +;swtchdone: +; rts + +switchinfail: +; jsr outx +; ldx #badswitchmsg +; jsr outstring +; ; something went wrong and we didn't switch in what we asked for +; jmp _trap_monitor + +fork_proc_ptr: .word 0 ; (C type is struct p_tab *) -- address of child process p_tab entry + +; +; Called from _fork. We are in a syscall, the uarea is live as the +; parent uarea. The kernel is the mapped object. +; +_dofork: +; ; always disconnect the vehicle battery before performing maintenance +; orcc #0x10 ; should already be the case ... belt and braces. + + ; new process in X, get parent pid into y + +; stx fork_proc_ptr +; ldy P_TAB__P_PID_OFFSET,x + + ; Save the stack pointer and critical registers. + ; When this process (the parent) is switched back in, it will be as if + ; it returns with the value of the child's pid. +; pshs y ; y has p->p_pid from above, the return value in the parent + + ; save kernel stack pointer -- when it comes back in the parent we'll be in + ; _switchin which will immediately return (appearing to be _dofork() + ; returning) and with HL (ie return code) containing the child PID. + ; Hurray. + ; sts U_DATA__U_SP + + ; now we're in a safe state for _switchin to return in the parent + ; process. + + ; --------- we switch stack copies in this call ----------- +; jsr fork_copy ; copy 0x000 to udata.u_top and the + ; uarea and return on the childs + ; common + ; We are now in the kernel child context + + ; now the copy operation is complete we can get rid of the stuff + ; _switchin will be expecting from our copy of the stack. +; puls y + +; ldx fork_proc_ptr +; jsr _newproc + + ; any calls to map process will now map the childs memory + + ; runticks = 0; +; clr _runticks + ; in the child process, fork() returns zero. + ; + ; And we exit, with the kernel mapped, the child now being deemed + ; to be the live uarea. The parent is frozen in time and space as + ; if it had done a switchout(). +; rts + +fork_copy: +; ldd U_DATA__U_TOP +; addd #0x0fff ; + 0x1000 (-1 for the rounding to follow) +; lsra +; lsra +; lsra +; lsra +; lsra ; bits 2/1 for 8K pages +; anda #6 ; lose bit 0 +; adda #2 ; and round up to the next bank (but in 8K terms) +; +; ldx fork_proc_ptr +; ldy P_TAB__P_PAGE_OFFSET,x +; ; y now points to the child page pointers +; ldx U_DATA__U_PAGE +; ; and x to the parent +;fork_next: +; ld a,(hl) +; out (0x11), a ; 0x4000 map the child +; ld c, a +; inc hl +; ld a, (de) +; out (0x12), a ; 0x8000 maps the parent +; inc de +; exx +; ld hl, #0x8000 ; copy the bank +; ld de, #0x4000 +; ld bc, #0x4000 ; we copy the whole bank, we could optimise +; ; further +; ldir +; exx +; call map_kernel ; put the maps back so we can look in p_tab +; FIXME: can't map_kernel here - we've been playing with the maps, fix +; directly +; suba #1 +; bne fork_next + +; ld a, c +; out (0x13), a ; our last bank repeats up to common + ; --- we are now on the stack copy, parent stack is locked away --- +; rts ; this stack is copied so safe to return on + + diff --git a/Kernel/platform-tgl6502/zeropage.inc b/Kernel/platform-tgl6502/zeropage.inc new file mode 100644 index 00000000..1ba03586 --- /dev/null +++ b/Kernel/platform-tgl6502/zeropage.inc @@ -0,0 +1,26 @@ +; +; zeropage.inc +; +; (C) Copyright 2002-2012, Ullrich von Bassewitz (uz@cc65.org) +; + +; Assembler include file that imports the runtime zero page locations used +; by the compiler, ready for usage in asm code. + + + .globalzp sp, sreg, regsave + .globalzp ptr1, ptr2, ptr3, ptr4 + .globalzp tmp1, tmp2, tmp3, tmp4 + .globalzp regbank + +; The size of the register bank +regbanksize = 6 + +; The total amount of zero page space used +zpspace = 26 + +; The amount of space that needs to be saved by an interrupt handler that +; calls C code (does not include the register bank, which is saved by the +; generated C code if required). +zpsavespace = zpspace - regbanksize + -- 2.34.1