+++ /dev/null
-
-CSRCS = devtty.c devrd.c
-CSRCS += devices.c main.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) $(CROSS_CC_SEG1) $<
-
-$(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 ../bank16k_low.o \
- ../tty.o ../devsys.o ../syscall_fs2.o ../syscall_fs3.o ../syscall_exec16.o \
- ../usermem.o ../usermem_std-6502.o devtty.o
+++ /dev/null
-Initial 6502 experimentation for the tgl6502 - as an experimental target
-to play with 6502isms easily
-
-See:
-http://thegaragelab.com/programming-the-tgl-6502/
-
-Use a modern cc65 from https://github.com/cc65/cc65
-
-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 actual data per proc
- 0x0600+ Common copy and compiler runtime
-
- 0x2000 Kernel data (8K)
- 0x4000 Kernel code (48K)
-
-This ensures we can do all our stack flips in one operation when we switch
-process in switchin.
-
-
-
-
-Lots not yet done:
-
-signal checks are not being done on the syscall path (or irq path)
-
-Checking on the 6502 stack. Probably we should just check for overflows and
-kill, or perhaps copy stacks in/out IFF it would otherwise run out (as
-Apple ProDOS seems to)
-
-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.
-
-Lots of memory to save in kernel space by making the common and data copies
-come from a bank we then switch out, along perhaps with the const data from
-what would be discard areas on the Z80.
-
-
-To build:
-Set the platform/target
-make clean
-make
-tools/tglsplice
-
-and you'll get a 6502.rom
-
-If you have a filesystem tgl_rootfs of 64K it will add this into the ROM
-image at the top. (Note this may move in future as the top block may become
-reserved for the tgl code).
-
-If you have a monitor then put it in binary form in tgl_monitor and it'll
-be merged with the image. The monitor will be mapped at 0xE000 and entered
-at that address. It must fit in the 8K minus the vectors. On entry there
-isn't really any RAM free as such but 1F00-1FFF is probably a fairly safe
-place to store workspace without trashing the Fuzix image.
-
-TODO
-----
-- Signal handling paths
-- Fix brk() checking
-- Interrupts
-- Real I/O device
-- Fix up all the C library stubs that use time_t. The kernel uses 64bits
- but the user code is packing them to 4 bytes. Needs some kind of define
- to pad up the structs that matter. 6809 will need the same but
- other-endian.
-
-Fairly Essential Optimsations To Do For A Box This Slow on RAM
---------------------------------------------------------------
-
-- Fast copy via spi buffer hack
-- Use bank mode not 48K fixed so we can get more processes in (we don't
- have user overlapping common so swap can be done eventually too)
-- Only copy the needed memory when forking, not 48K (in theory we are copying
- low->brk, sp->top, S->top of page, and Z)
-- execve direct read to usermem (core change)
-- vfork()
-- usermem functions that use banking tricks
-- map_save/restore copy/restore entries for kernel mode so we can take an
- interrupt when we are pulling banking tricks
-
-General 650x Questions
-----------------------
-
-- What would it take to make ld65 generate banked binaries for 6502 boxes.
- The C argument stack is separate from the call/return stack so the usual
- horrible argument magic is avoided. It would just need stubs for inter
- bank calling added by the linker somehow, along with allowing multiple
- memory regions at the same address with different output files
-
-- Would using a relocatable binary format make more sense given how varied
- 6502 maps are. cc65 can already generate a quite usable format.
-
-- Is it worth having standardised usermem_ helpers and entry/exit code for 6509
-
+++ /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
- .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:
-
- ; 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
-;
-; Finally we tack the ZP save area for interrupts on the end
-;
-; Swap space for the the C temporaries (FIXME - we stash sp twice right now)
-;
-CTemp:
- .res 2 ; sp
- .res 2 ; sreg
- .res (zpsavespace-4) ; Other stuff
+++ /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
-
-#define CONFIG_CALL_R2L /* Runtime stacks arguments backwards */
-
-/*
- * The banking is really 8K banks but we run with them in pairs
- * We've got 128K - 8 banks of 16K, of which the kernel eats one for data
- * (Kernel code is in the ROM banks which are separate)
- */
-#define CONFIG_BANK16_LOW
-#define MAX_MAPS 7
-
-#if 0
-/* And swapping */
-#define SWAPDEV 257 /* FIXME */
-#define SWAP_SIZE 0x70 /* 56K in blocks */
-#define SWAPBASE 0x0000 /* We swap the lot in one, include the */
-#define SWAPTOP 0xE000 /* vectors so its a round number of sectors */
-/* FIXME: we need to swap the udata separately */
-#define MAX_SWAPS 32
-/* TODO */
-#endif
-
-#define TICKSPERSEC 10 /* Ticks per second */
-#define MAPBASE 0x0000 /* We map from 0 */
-#define PROGBASE 0x2000 /* also data base */
-#define PROGLOAD 0x2000
-#define PROGTOP 0xC000 /* Top of program (for debug for now, can go to FFF9) */
-
-#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()
+++ /dev/null
- ; exported symbols
- .export start
- .export copycommon
-
- ; 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 __CODE_LOAD__, __CODE_RUN__, __CODE_SIZE__
- .import __DATA_LOAD__, __DATA_RUN__, __DATA_SIZE__
- .import __COMMONMEM_LOAD__, __COMMONMEM_RUN__, __COMMONMEM_SIZE__
- .import __STUBS_LOAD__, __STUBS_RUN__, __STUBS_SIZE__
- .importzp ptr1, ptr2, tmp1
-
- ; startup code @0
- .include "zeropage.inc"
-
-;
-; So we end up first in the ROM
-;
- .segment "START"
-;
-; 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 #$FF
- 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 #$02
- sta $FF8A ; Common for init at 0x0000
- lda #$01 ; Kernel data at 0x2000
- sta $FF8B
-
- 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 #'z'
- sta $FF03
-
- lda #0
- tay
- 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 -(__DATA_SIZE__+1)
- sta tmp1
-
- jsr copyloop
-
- lda #<__CODE_LOAD__ ; Source pointer
- sta ptr1
- lda #>__CODE_LOAD__
- sta ptr1+1
-
- lda #<__CODE_RUN__ ; Target pointer
- sta ptr2
- lda #>__CODE_RUN__
- sta ptr2+1
-
- ldx #<~__CODE_SIZE__
- lda #>~__CODE_SIZE__ ; Use -(__CODE_SIZE__+1)
- sta tmp1
-
- jsr copyloop
- lda #<__STUBS_LOAD__ ; Source pointer
- sta ptr1
- lda #>__STUBS_LOAD__
- sta ptr1+1
-
- lda #<__STUBS_RUN__ ; Target pointer
- sta ptr2
- lda #>__STUBS_RUN__
- sta ptr2+1
-
- ldx #<~__STUBS_SIZE__
- lda #>~__STUBS_SIZE__ ; Use -(__STUBS_SIZE__+1)
- sta tmp1
-
- jsr copyloop
-
-
-
- jsr copycommon
-
- 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
-
-
-;
-; This may also used be useful at runtime so split it off as a helper
-; We can revisit and unsplit it if not.
-;
-copycommon:
- pha
- txa
- pha
- 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
- pla
- tax
- pla
- rts
-
- .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) - 1)
- return false;
- else
- return true;
-}
-
-void device_init(void)
-{
-}
-
+++ /dev/null
-/*
- * ROMdisc hack for testing
- */
-
-#include <kernel.h>
-#include <kdata.h>
-#include <printf.h>
-#include <devrd.h>
-
-extern uint16_t romd_roff;
-extern uint8_t romd_rmap;
-extern uint8_t romd_bank;
-extern uint8_t romd_mapu;
-
-extern void __fastcall__ rd_copyin(uint16_t addr);
-
-
-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;
- irqflags_t irq;
-
- if(rawflag) {
- dlen = udata.u_count;
- dptr = (uint16_t)udata.u_base;
- /* Must be block aligned but otherwise we are happy */
- if (((uint16_t)udata.u_offset|dlen) & BLKMASK) {
- udata.u_error = EIO;
- return -1;
- }
- block = udata.u_offset >> 9;
- block_xfer = dlen >> 9;
- romd_mapu = 1;
- } else { /* rawflag == 0 */
- dlen = 512;
- dptr = (uint16_t)udata.u_buf->bf_data;
- block = udata.u_buf->bf_blk;
- block_xfer = 1;
- romd_mapu = 0;
- }
-
- while (ct < block_xfer) {
- /* Offset of block within an 8K bank (high byte) */
- romd_roff = (block << 9) & 0x1FFF ;
- /* 8K block we need to select */
- romd_rmap = 0x48 + (block >> 4);
- /* Map it over a page we are not copying into */
- if (dptr >= 0xC000) {
- romd_roff += 0xA000;
- romd_bank = 0;
- } else {
- romd_roff += 0xC000;
- romd_bank = 1;
- }
- irq = di();
-// kprintf("RD: map %d, roff %x bank %d dptr %x\n",
-// romd_rmap, romd_roff, romd_bank, dptr);
- if (is_read) {
- rd_copyin(dptr);
- }
- irqrestore(irq);
- block++;
- ct++;
- dptr+=512;
- }
- return ct;
-}
-
-int rd_open(uint8_t minor, uint16_t flag)
-{
- if(minor != 0) {
- udata.u_error = ENODEV;
- return -1;
- }
- return 0;
-}
-
-int rd_read(uint8_t minor, uint8_t rawflag, uint8_t flag)
-{
- return rd_transfer(true, rawflag);
-}
-
-int rd_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
-{
- 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 */
-
-static volatile uint8_t *uart = (volatile 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);
-}
-
-ttyready_t tty_writeready(uint8_t minor)
-{
- return TTY_READY_NOW;
-}
-
-void tty_putc(uint8_t minor, unsigned char c)
-{
- minor;
- uart[3] = 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_data_consumed(uint8_t minor)
-{
-}
-
-void tty_poll(void)
-{
- uint8_t x;
-
- x = uart[1] & 4;
- if (x) {
- x = uart[2];
- tty_inproc(1, x);
- }
-}
-
-void platform_interrupt(void)
-{
- tty_poll();
- 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 void tty_poll(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 $200
-
-PROGLOAD .set $2000
-ZPBASE .set $0
+++ /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 = $A000, fill = yes;
- ROM1: start = $E000, size = $2000, fill = yes;
-}
-
-SEGMENTS {
- ZEROPAGE: load = RAMZ, type = zp, define = yes;
- START: load = ROM0, type = ro;
- RODATA: load = ROM0, type = ro;
- DISCARD: load = ROM1, type = ro;
- DISCARDDATA: load = ROM1, 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 = ROM1, run = RAM0, type = rw, define = yes;
- CODE: load = ROM1, run = RAM0, type = ro, define = yes;
- SEG1: load = ROM0, type = ro;
- SEG2: load = ROM0, type = ro;
- SEG3: load = ROM0, type = ro;
- SYS1: load = ROM0, type = ro;
- SYS2: load = ROM0, type = ro;
- SYS3: load = ROM0, type = ro;
- SYS4: load = ROM0, type = ro;
- SYS5: load = ROM0, type = ro;
- STUBS: load = ROM1, run = RAM0, type = ro, define = yes;
- VECTORS: load = ROM1, type = ro, start = $FFFA;
-}
-
-FILES {
- %O: format = bin;
-}
+++ /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)
-{
- 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)
-{
- /* Really 8K banks 0,1,2,... but we pair them up so we have */
- /* 8 x 16 banks numbered 0,2,4,.... , 0 is the kernel, init starts in 2 */
- pagemap_add(14);
- pagemap_add(12);
- pagemap_add(10);
- pagemap_add(8);
- pagemap_add(6);
- pagemap_add(4);
- pagemap_add(2);
-}
-
-void map_init(void)
-{
- udata.u_page = 0x0202;
- udata.u_page2 = 0x0202;
-}
-
-uint8_t platform_param(char *p)
-{
- return 0;
-}
+++ /dev/null
-export CPU = 6502
+++ /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 _platform_monitor
- .export _platform_reboot
- .export outchar
- .export ___hard_di
- .export ___hard_ei
- .export ___hard_irqrestore
- .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
- .import stash_zp
- .import pushax
-
- .import outcharhex
- .import outxa
- .import incaxy
-
- .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"
-
-_platform_monitor:
-;
-; Put the ROM back as it was at entry including the second 8K bank we
-; only use for vectors, then jump to $E000 which should enter whatever
-; monitor was put there.
-;
- sei
- ldx #$40
- stx $FF90 ; $C000
- inx
- stx $FF91 ; $E000
- jmp $E000
-
-_platform_reboot:
- jmp _platform_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
-
-; -----------------------------------------------------------------------------
-; 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
- ;
- ; our C caller will invoke us with the pointer in x,a
- ; just pass it on
- jsr map_process
-program_vectors_k:
-;
-; These are in common ROM space in our case
-;
-; 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 bits 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
-;
-; ptr1 and tmp1 may be destroyed by these methods, but no other
-; temporaries.
-;
-map_process_always:
- pha
- txa
- pha
- lda #<U_DATA__U_PAGE
- ldx #>U_DATA__U_PAGE
- jsr map_process_2
- pla
- tax
- 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
- txa
- 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
- tax
- pla
- rts
-
-; X,A holds the map table of this process
-map_process_2:
- sta ptr1
- stx ptr1+1
- tya
- pha
- ldy #0
- lda (ptr1),y ; 4 bytes if needed
- clc
- adc #1
- sta $FF8B ; 0x2000 takes on the upper half of the map
- ldy #1
- ldx #0
-map_proc_l:
- lda (ptr1),y ; do pages 1-3 as maps 2-7
- sta $FF8C,x
- inx
- clc
- adc #1
- sta $FF8C,x
- inx
- iny
- cpy #4
- bne map_proc_l
- 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
- tya
- pha
- ldx saved_map ; First bank we skip half of
- inx
- stx $FF8B ; 0x2000 takes on the upper half of the map
- ldy #1
- ldx #0
-restore_n:
- lda saved_map,y ; do pages 1-3 as maps 2-7
- sta $FF8C,x
- inx
- clc
- adc #1
- sta $FF8C,x
- inx
- iny
- cpy #4
- bne restore_n
- pla
- tay
- 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.
-; May not be sufficient if we want IRQs on while doing page tricks
-;
-map_save:
- pha
- tya
- pha
- ldy #0
-map_save_l: ; save the four entries
- lda U_DATA__U_PAGE,y
- sta saved_map,y
- iny
- cpy #4
- bne map_save_l
- pla
- tay
- pla
- rts
-
-saved_map: .byte 0, 0, 0, 0
-
-; outchar: Wait for UART TX idle, then print the char in a without
-; corrupting other registers
-
-outchar:
- 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
-;
-; Q: do we want to spot brk() instructions and signal them ?
-;
-;
-; Save the old stack ptr
-;
- jsr stash_zp ; Save zero page bits
- tsx ; and save the 6502 stack ptr
- stx istack_switched_sp ; in uarea/stacks
-;
-; Hope the user hasn't used all the CPU stack
-;
-; FIXME: we should check here if S is too low and if so set it high
-; and deliver SIGKILL
-;
-; 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
- jsr stash_zp ; restore zero page bits
-;
-; Signal handling on 6502 is foul as the C stack may be inconsistent
-; during an IRQ. We push a new complete rti frame below the official
-; one, along with a vector and the signal number. The glue in the
-; app is expected to switch to a signal stack or similar, pop the
-; values, invoke the signal handler and then return.
-;
-; FIXME: at the moment the irqout path will not check for multiple
-; signals so the next one gets delivered next irq.
-;
-;
- lda U_DATA__U_CURSIG
- beq irqout
- tay
- tsx
- txa
- sec
- sbc #6 ; move down past the existing rti
- tax
- txs
- lda #>irqout
- pha
- lda #<irqout
- pha ; stack a return vector
- tya
- pha ; stack signal number
- ldx #0
- stx U_DATA__U_CURSIG
- asl a
- tay
- lda U_DATA__U_SIGVEC,y ; Our vector (low)
- pha ; stack half of vector
- lda U_DATA__U_SIGVEC+1,y ; High half
- pha ; stack rest of vector
- txa
- sta U_DATA__U_SIGVEC,y ; Wipe the vector
- sta U_DATA__U_SIGVEC+1,y
- lda #<PROGLOAD + 20
- pha
- lda #>PROGLOAD + 20
- lda #0
- pha ; dummy flags, with irq enable
- rti ; return on the fake frame
- ; if the handler returns
- ; rather than doing a longjmp
- ; we'll end up at irqout and pop the
- ; real frame
-irqout:
- pla
- tay
- pla
- tax
- pla
- rti
-;
-; sp/sp+1 are the C stack of the userspace
-; with the syscall number in X
-; Y indicates the number of bytes of argument
-;
-syscall_entry:
- php
- sei
- cld
-
- stx U_DATA__U_CALLNO
-
- ; No arguments - skip all the copying and stack bits
- cpy #0
- beq noargs
-
- ; Remove the arguments. This is fine as by the time we go back
- ; to the user stack we'll have finished with them
- lda sp
- sta ptr1
- ldx sp+1
- stx ptr1+1
- jsr incaxy
- sta sp
- stx sp+1
-
- ;
- ; We copy the arguments but need to deal with the compiler
- ; stacking in the reverse order. At this point ptr1 points
- ; to the last byte of the arguments (first argument). We go
- ; down the stack copying words up the argument list.
- ;
- ldx #0
-copy_args:
- dey
- lda (ptr1),y ; copy the arguments over
- sta U_DATA__U_ARGN+1,x
- dey
- lda (ptr1),y
- sta U_DATA__U_ARGN,x
- inx
- inx
- cpy #0
- bne copy_args
-noargs:
- ;
- ; Now we need to stack switch. Save the adjusted stack we want
- ; for return
- ;
- lda sp
- pha
- lda sp+1
- pha
- tsx
- stx U_DATA__U_SYSCALL_SP
-;
-; We save a copy of the high byte of sp here as we may need it to get
-; the brk() syscall right.
-;
- sta U_DATA__U_SYSCALL_SP + 1
-;
-;
-; FIXME: we should check here if there is enough 6502 stack left
-; and if so either copy and switch stacks or kill the process
-;
-; 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_SYSCALL_SP
- txs
-;
-; From that recover the C stack and the syscall buf ptr
-;
- pla
- sta sp+1
- pla
- sta sp
- lda U_DATA__U_CURSIG
- beq syscout
- tay
-
- tsx ; Move past existing return stack
- dex
- dex
- dex
- txs
-
- ;
- ; The signal handler might make syscalls so we need to get
- ; our return saved and return the right value!
- ;
- lda U_DATA__U_ERROR
- pha
- lda U_DATA__U_RETVAL
- pha
- lda U_DATA__U_RETVAL+1
- pha
- lda #>sigret ; Return address
- pha
- lda #<sigret
- pha
-
- tya
- pha ; signal
- ldx #0
- stx U_DATA__U_CURSIG
- asl a
- tay
- lda U_DATA__U_SIGVEC,y ; Our vector
- pha
- lda U_DATA__U_SIGVEC+1,y
- pha
- txa
- sta U_DATA__U_SIGVEC,y ; Wipe the vector
- sta U_DATA__U_SIGVEC+1,y
-
- ; Invoke the helper with signal and vector stacked
- ; it will then return to syscout and recover the original
- ; frame. If the handler made syscalls then
- jmp (PROGLOAD + 20)
-
- ;
- ; FIXME: should loop for more signals if appropriate
- ;
-sigret:
- pla ; Unstack the syscall return pieces
- tax
- pla
- tay
- pla
- plp ; from original stack frame
- rts
-
-syscout:
-; We may be in decimal mode beyond this line.. take care
-;
- plp
-
-; Copy the return data over
-;
- ldy U_DATA__U_RETVAL
- ldx U_DATA__U_RETVAL+1
-; Also sets Z for us
- lda U_DATA__U_ERROR
-
- rts
-
-platform_doexec:
-;
-; Start address of executable
-;
- stx ptr1+1
- sta ptr1
-
-;
-; Set up the C stack
-;
- lda U_DATA__U_ISP
- sta sp
- ldx U_DATA__U_ISP+1
- stx sp+1
-
-;
-; Set up the 6502 stack
-;
- ldx #$ff
- txs
- ldx #>PROGLOAD ; For the relocation engine
- lda #ZPBASE
- jmp (ptr1) ; Enter user application
-
-;
-; Straight jumps no funny banking issues
-;
-_unix_syscall_i:
- jmp _unix_syscall
-_platform_interrupt_i:
- jmp _platform_interrupt
-
-
-;
-; ROM disc copier (needs to be in common), call with ints off
-;
-; AX = ptr, length always 512, src and page in globals
-;
-; Uses ptr3/4 as 1/2 are reserved for the mappers
-;
-
- .export _romd_bank, _romd_roff, _romd_rmap, _romd_mapu
- .export _rd_copyin
-
-_rd_copyin:
- sta ptr3
- stx ptr3+1 ; Save the target
-
- ;
- ; We must flip banks before we play mmu pokery, or it will
- ; undo all our work. This means our variables must be commondata
- ;
- lda _romd_mapu
- beq rd_kmap
- jsr map_process_always
-rd_kmap:
- ldy _romd_bank ; 0 = A0, 1 = C0, pick based on target
- lda $FF8F,y ;
- pha ; Save the old mapping
- lda _romd_rmap
- sta $FF8F,y
- lda _romd_roff
- sta ptr4
- lda _romd_roff+1
- sta ptr4+1
- ldy #0
- ldx #2
-rd_cl: lda (ptr4),y
- sta (ptr3),y
- iny
- bne rd_cl
- inc ptr3+1
- inc ptr4+1
- dex
- bne rd_cl
- pla
- ldx rd_kmap
- bne rd_mapback
- ldy _romd_bank
- sta $FF8F,y
- rts
-rd_mapback:
- jsr map_kernel
- rts
-
- .segment "COMMONDATA"
-
-_romd_roff:
- .res 2
-_romd_rmap:
- .res 1
-_romd_bank:
- .res 1
-_romd_mapu:
- .res 1
+++ /dev/null
-;
-; 6502 version
-;
- .export _switchout
- .export _switchin
- .export _dofork
- .export _ramtop
-
- .import _chksigs
- .import _platform_monitor
-
- .import map_kernel
-
- .import _newproc
- .import _getproc
- .import _runticks
- .import _inint
- .import outstring
- .import outxa
- .import outcharhex
-
- .include "kernel.def"
- .include "../kernel02.def"
- .include "zeropage.inc"
-
- .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
-;
-; Put the C stack on the CPU stack, and store that in U_SP
-;
- lda #0 ; return code
- pha
- pha
- lda sp ; C stack
- pha
- lda sp+1
- pha
- tsx
- stx U_DATA__U_SP ; Save it
-
- ; set inint to false
- lda #0
- sta _inint
-
- ; find another process to run (may select this one again) returns it
- ; in x,a
- jsr _getproc
- jsr _switchin
- ; we should never get here
- jsr _platform_monitor
-
-badswitchmsg: .byte "_switchin: FAIL"
- .byte 13, 10, 0
-
-;
-; On entry x,a holds the process to switch in
-;
-_switchin:
- sei
- sta ptr1
- stx ptr1+1
- ; Take a second saved set as we are going to swap stacks and ZP
- ; with a CPU that hasn't got sufficient registers to keep it on
- ; CPU
- sta switch_proc_ptr
- stx switch_proc_ptr+1
-; jsr outxa
- ldy #P_TAB__P_PAGE_OFFSET
- lda (ptr1),y
-; pha
-; jsr outcharhex
-; pla
- sta $FF8A ; switches zero page, stack memory area
- ; ------- New stack and ZP -------
-
- ; Set ptr1 back up (the old ptr1 was on the other ZP)
- lda switch_proc_ptr
- sta ptr1
- lda switch_proc_ptr+1
- sta ptr1+1
-
- ; check u_data->u_ptab matches what we wanted
- lda U_DATA__U_PTAB
- cmp ptr1
- bne switchinfail
- lda U_DATA__U_PTAB+1
- cmp ptr1+1
- bne switchinfail
-
- lda #P_RUNNING
- ldy #P_TAB__P_STATUS_OFFSET
- sta (ptr1),y
-
- lda #0
- sta _runticks
- sta _runticks+1
-
- ; restore machine state -- note we may be returning from either
- ; _switchout or _dofork
- ldx U_DATA__U_SP
- txs
- pla
- sta sp+1
- pla
- sta sp
- lda _inint
- beq swtchdone ; in ISR, leave interrupts off
- cli
-swtchdone:
- pla ; Return code
- tax
- pla
- rts
-
-switchinfail:
- lda ptr1+1
- jsr outcharhex
- lda ptr1
- jsr outcharhex
- lda #<badswitchmsg
- ldx #>badswitchmsg
- jsr outstring
- ; something went wrong and we didn't switch in what we asked for
- jmp _platform_monitor
-
-; Must not put this in ZP ?
-;
-; Move to commondata ??
-;
-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
- sei ; should already be the case ... belt and braces.
-
- ; new process in X, get parent pid into y
-
- sta fork_proc_ptr
- stx fork_proc_ptr+1
-
- ldy #P_TAB__P_PID_OFFSET
- sta ptr1
- stx ptr1+1
-
- ; Save the stack pointer and critical registers.
- ; 6502 at least doesn't have too many of those 8)
-
- ; When this process (the parent) is switched back in, it will be as if
- ; it returns with the value of the child's pid.
- lda (ptr1),y
- pha
- iny
- lda (ptr1),y
- pha
-
- ; 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) the child PID.
- lda sp
- pha
- lda sp+1
- pha
- tsx
- stx U_DATA__U_SP
-
- ; now we're in a safe state for _switchin to return in the parent
- ; process.
-
- ;
- ; Assumes ptr1 still holds the new process ptr
- ;
-
- jsr fork_copy
-
- ; --------- we switch stack copies here -----------
- lda fork_proc_ptr
- ldx fork_proc_ptr+1
- sta ptr1
- stx ptr1+1
- ldy #P_TAB__P_PAGE_OFFSET
- lda (ptr1),y
- sta $FF8A ; switch to child and child stack
- ; and zero page etc
- ; 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.
- pla
- pla
- pla
- pla
-
- lda fork_proc_ptr
- ldx fork_proc_ptr+1
-;
-; FIXME: turn these into a C argument!
-;
- jsr _newproc
-
- ; any calls to map process will now map the childs memory
-
- ; runticks = 0;
- lda #0
- sta _runticks
- sta _runticks+1
-
- ; in the child process, fork() returns zero.
- tax
-
- ; 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
-
-;
-; On entry ptr1 points to the process table of the child, and
-; the U_DATA is still not fully modified so holds the parents bank
-; number.
-;
-fork_copy:
- ldy #P_TAB__P_PAGE_OFFSET
- ldx #0
- stx tmp1 ; last bank copied (to spot end mark dups)
-copy_loop:
- lda U_DATA__U_PAGE,x
- sta $FF8C ; 0x4000
- cmp tmp1 ; last map ?
- beq done_early ; repeating page -> end of a shorter process
- lda (ptr1),y ; child->p_pag[n]
- sta $FF8D ; 0x6000
- tya
- pha
- txa
- pha
- jsr bank2bank ; copies 8K
- inc $FF8C ; next 8K
- inc $FF8D
- jsr bank2bank
- pla
- tax
- pla
- tay
- iny
- inx
- cpx #4
- bne copy_loop
-done_early:
- jmp map_kernel ; put the kernel mapping back as it should be
-
-bank2bank: ; copy 4K between the blocks mapped
- ; at 0x4000 and 0x6000
- lda #$40
- sta ptr3+1
- lda #$60
- sta ptr4+1
- lda #0
- sta ptr3
- sta ptr4
- tay
- ldx #$20 ; 32 x 256 bytes = 8K
-copy1:
- lda (ptr3),y
- sta (ptr4),y
- iny
- bne copy1
- inc ptr3+1
- inc ptr4+1
- dex
- bne copy1
- rts
-
-;
-; The switch proc pointer cannot live anywhere in common as we switch
-; common on process switch
-;
- .data
-
-switch_proc_ptr: .word 0
+++ /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
-