-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"
--- /dev/null
+
+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
--- /dev/null
+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.
+
--- /dev/null
+;
+; 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
--- /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
+/* 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 */
--- /dev/null
+ ; 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 ; C stack
+ sta sp
+ 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
--- /dev/null
+#ifndef __DEVICE_DOT_H__
+#define __DEVICE_DOT_H__
+
+extern void mod_control(uint8_t set, uint8_t clr);
+
+#endif /* __DEVICE_DOT_H__ */
--- /dev/null
+#include <kernel.h>
+#include <version.h>
+#include <kdata.h>
+#include <devrd.h>
+#include <devsys.h>
+#include <tty.h>
+#include <devtty.h>
+
+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)
+{
+}
+
--- /dev/null
+/*
+ * NC100 RD PCMCIA driver
+ *
+ */
+
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devrd.h>
+
+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);
+}
+
--- /dev/null
+#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__ */
+
--- /dev/null
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <stdbool.h>
+#include <devtty.h>
+#include <device.h>
+#include <vt.h>
+#include <tty.h>
+
+#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;
--- /dev/null
+#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
--- /dev/null
+; 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
+
--- /dev/null
+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;
+}
--- /dev/null
+#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;
+}
+
--- /dev/null
+#include <kernel.h>
+#include <timer.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devtty.h>
+
+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)
+{
+}
--- /dev/null
+;
+; 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 $FFFE
+ lda #>vector
+ sta $FFFF
+ lda #<nmi_handler
+ sta $FFFA
+ 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
+ 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
+ ldx #>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
+ 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
+ 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
+ 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
--- /dev/null
+;
+; 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
+
+
--- /dev/null
+;
+; 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
+