8MB RAM testing work.
Lots to do here (plus some of the core code like the scheduler doesn't really
scale to 128 processes!)
--- /dev/null
+
+CSRCS = devtty.c devhd.c
+CSRCS += devices.c main.c
+
+LSRCS = ../lib/65c816.s
+LOBJS = $(patsubst ../lib/%.s,%.o, $(LSRCS))
+
+NSRCS = ../dev/net/net_native.c
+NOBJS = $(patsubst ../dev/net/%.c,%.o, $(NSRCS))
+
+ASRCS = v65.s crt0.s
+ASRCS += commonmem.s
+
+COBJS = $(CSRCS:.c=$(BINEXT))
+AOBJS = $(ASRCS:.s=$(BINEXT))
+OBJS = $(COBJS) $(AOBJS) $(LOBJS) $(NOBJS)
+
+JUNK = $(CSRCS:.c=.o) $(CSRCS:.c=.s) $(ASRCS:.s=.o)
+
+all: $(OBJS)
+
+$(COBJS): %$(BINEXT): %.c
+ $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_SEG1) $<
+
+$(NOBJS): %$(BINEXT): ../dev/net/%.c
+ $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_SEG1) -o $@ $<
+
+$(AOBJS): %$(BINEXT): %.s
+ $(CROSS_AS) $(ASOPTS) $< -o $*$(BINEXT)
+
+$(LOBJS): %$(BINEXT): ../lib/%.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 \
+ v65.o ../start.o ../version.o ../lowlevel-65c816.o \
+ 65c816.o main.o ../timer.o ../kdata.o devhd.o devices.o \
+ ../devio.o ../filesys.o ../process.o ../inode.o ../syscall_fs.o \
+ ../syscall_proc.o ../syscall_other.o ../mm.o ../bank65c816.o \
+ ../tty.o ../devsys.o ../syscall_fs2.o ../syscall_fs3.o \
+ ../syscall_exec16.o ../usermem.o ../usermem_std-65c816.o devtty.o \
+ ../syscall_net.o net_native.o ../level2.o ../syscall_level2.o \
+ ../select.o
+ dd if=../fuzix.bin of=fuzix.img bs=256 skip=255 count=1
+ dd if=../fuzix.bin of=fuzix.img bs=256 seek=1 skip=1 conv=notrunc
\ No newline at end of file
--- /dev/null
+Use a modern cc65 from https://github.com/cc65/cc65
+
+Prototyping for 'large model' kernels for bigger memory maps. This set up uses
+a split I/D arrangement for the kernel with bank 0 holding kernel DP/S IRQ S
+and IRQ DP plus the I/O window and vectors. Bank 1 holds kernel code which with
+the room available can be built optimized better. Bank 2 holds the kernel data
+including 32K of buffer cache and the other buffers tuned to match the 2BSD
+Unix recommendations for a 16 user system.
+
+
+Our memory mapping looks like this
+
+Bank 0:
+ 0x0000 Kernel DP
+ 0x0100 Kernel Stack (CPU)
+ 0x0200 IRQ stack
+ 0x0400 First user DP/Stack
+ 0xFE00 I/O Window
+ 0xFF00 Vectors and IRQ DP
+
+Bank 1:
+ ... Kernel image
+
+Bank 2:
+ ... Kernel data and C stacks
+
+
+Bank 3+
+
+And in user space
+
+ 0x0000 Unused
+ 0x00FE syscall vector
+ 0x0100 Program (CPU stack is in bank 0)
+ 0xFC00 Udata copy (512 bytes)
+ 0xFE00 Spare
+ 0xFF00 Stubs [signal return etc]
+ (keep in 0 page ?)
+
+We don't yet allow for a split I/D user program using two banks and having 64K
+code and 64K data. We also then need to track 'texts' as V7 does so that we
+can share code segments when possible (often).
+
+To build:
+Set the platform/target
+make clean
+make
+
+
+TODO
+----
+- Rewrite crt0.s to set up the banks correctly and clear the data not code
+- Set memory size etc correctly
+- Add code to copy vectors from the right bank to each user bank
+- Stubs in bank 0 to long jump vectors into bank 2 (65C816 pushes the bank
+ so we just need to jump long into the right universe)
+- Rework KERNEL_BANK/KERNEL_FAR according to whether it is data or code
+- Fix compiler generated and helper stubs that self modify code (jmpvec in
+ particular must be modified to force kernel code bank and link itself into
+ kernel code)
+- See 65c816 port for general notes
+
+Optimisations We Need To Do
+--------------------------------------------------------------
+- Only copy the needed memory when forking, not 64K ?
--- /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 kstackc_top
+ .export istack_top
+ .export istackc_top
+ .export istack_switched_sp
+
+ .segment "COMMONDATA"
+ .include "zeropage.inc"
+
+ .p816
+ .a8
+ .i8
+
+;
+; The udata for 65C816 is a bit different to 6502 as we have both a C
+; stack and a small CPU stack in the banking
+;
+; Our current layout is
+; [udata][cpu stack] in 256 bytes
+; [C stack] in 256 (will it be sufficient ?)
+;
+; There is a separate IRQ DP, stack and C stack.
+;
+_ub: ; first 512 bytes: starts with struct u_block, with the kernel stack working down from above
+_udata:
+kstack_base:
+ .res 256,0
+kstack_top:
+kstackc_base:
+ .res 256,0
+kstackc_top:
+
+;
+; We have a single istack so we can stuff that anywhere we like
+;
+ .bss
+
+istack_base:
+ .res 64,0 ; should be tons
+istack_top:
+istackc_base:
+ .res 254,0 ; overkill - tune me
+istackc_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
+/* Use fixed banks for now. It's simplest and we've got so much memory ! */
+#define CONFIG_BANKS 1
+
+#define CONFIG_CALL_R2L /* Runtime stacks arguments backwards */
+
+/* Networking (not usable yet but for debug/development) */
+#define CONFIG_NET
+#define CONFIG_NET_NATIVE
+/* Level 2 feature set */
+#define CONFIG_LEVEL_2
+
+/*
+ * We have 8MB of RAM and have to allocate it in banks due to the CPU
+ * bank granularity. That gives us 125 processes plus kernel and more
+ * if we add swap.
+ */
+#define CONFIG_BANK_65C816
+#define KERNEL_BANK 0
+#define MAX_MAPS 125
+#define MAP_SIZE 0xFC00 /* 0-FBFF */
+
+/* 0xEE because our first bank is 1 and 0xEE + 2 * 1 = 0xF0 */
+#define STACK_BANKOFF 0x00 /* 0400-FDFF */
+
+#define TICKSPERSEC 100 /* Ticks per second */
+#define MAPBASE 0x0000 /* We map from 0 */
+#define PROGBASE 0x0100 /* also data base */
+#define PROGLOAD 0x0100
+#define PROGTOP 0xFC00 /* Top of program. If we fixed a few things we
+ could go to FE00 */
+
+#define BOOT_TTY 513 /* Set this to default device for stdio, stderr */
+
+/* We need a tidier way to do this from the loader */
+#define CMDLINE NULL /* Location of root dev name */
+
+/* Device parameters */
+#define NUM_DEV_TTY 1
+#define TTYDEV BOOT_TTY /* Device used by kernel for messages, panics */
+#define NBUFS 64 /* Number of block buffers */
+#define NMOUNTS 8 /* Number of mounts at a time */
+
+#define platform_discard() /* for now - wants fixing */
+
+/* Override defaults for a big system */
+
+/* Note: select() in the level 2 code will not work on this configuration
+ at the moment as select is limited to 16 processes. FIXME - support a
+ hash ELKS style for bigger systems where wakeup aliasing is cheaper */
+
+#define PTABSIZE 125
+#define UFTSIZE 16
+#define OFTSIZE 160
+#define ITABSIZE 176
--- /dev/null
+ ; imported symbols
+ .import init_early
+ .import init_hardware
+ .import _fuzix_main
+ .import kstack_top
+ .import kstackc_top
+ .import vector
+ .import nmi_handler
+ .import interrupt_handler
+ .import emulation
+ .import illegal_inst
+ .import trap_inst
+ .import abort_inst
+
+ .import __BSS_RUN__, __BSS_SIZE__
+ .importzp ptr1, ptr2, tmp1
+
+ ; startup code @0200
+ .include "kernel.def"
+ .include "../kernel816.def"
+ .include "zeropage.inc"
+
+;
+; So we end up first in the image
+;
+ .segment "START"
+ .byte 65
+ .byte 81
+
+ .p816
+ .a8
+ .i8
+
+entry:
+;
+; We are entered at $0102 just after the required magic number
+;
+; We get run from bank 0, our I/O writes would otherwise need to be
+; 24bit
+;
+ sep #$30 ; ensure we are in 8bit mode
+ lda #'F'
+ sta $FE20 ; signal our arrival
+
+ sei ; interrupts off
+ cld ; decimal off
+
+
+ ; vectors is packed in DP, move it to FF00
+ rep #$30
+ .a16
+ .i16
+ lda #255
+ ldx #0
+ ldy #$FF00
+ mvn KERNEL_BANK,KERNEL_BANK
+
+ sep #$30
+ .a8
+ .i8
+
+
+ lda #'u'
+ sta $FE20
+
+ rep #$10
+ .i16
+
+ ldx #kstack_top-1
+ txs ; Stack (6502 not C)
+
+ lda #'z'
+ sta $FE20
+
+ ldx #kstackc_top-1 ; C stack
+ stx sp
+
+ ldx #__BSS_RUN__
+
+ lda #'i'
+ sta $FE20
+
+ txy
+ iny
+
+ ; Wipe the BSS
+
+ rep #$20
+ .a16
+
+ lda #__BSS_SIZE__-2 ; must be >=2 bytes or else
+ stz a:0,x
+ mvn 0,0
+
+ sep #$30
+ .a8
+ .i8
+
+ lda #'x'
+ sta $FE20
+
+ jsr init_early
+ lda #'.'
+ sta $FE20
+ jsr init_hardware
+ jmp code
+
+ .code
+
+ .a8
+ .i8
+code:
+ lda #13
+ sta $FE20
+ lda #10
+ sta $FE20
+ jsr _fuzix_main ; Should never return
+ sei ; Spin
+stop: bra stop
+
+
+;
+; Processor vector table (0xFFE0)
+;
+ .segment "VECTORS"
+
+
+ .word 0 ; unused
+ .word 0 ; unused
+ .word illegal_inst ; COP
+ .word trap_inst ; BRK
+ .word abort_inst ; ABORT
+ .word nmi_handler ; NMI
+ .word 0 ; Unused (native reset)
+ .word interrupt_handler
+
+ ;
+ ; Emulation mode vectors. If called badness occurred
+ ;
+ .word emulation
+ .word emulation
+ .word emulation
+ .word emulation
+ .word emulation
+ .word emulation
+ .word emulation
+ .word emulation
+
+
--- /dev/null
+/*
+ * ROMdisc hack for testing
+ */
+
+#include <kernel.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devhd.h>
+
+extern uint8_t hd_kmap;
+
+extern void hd_read_data(uint16_t addr);
+extern void hd_write_data(uint16_t addr);
+
+volatile uint8_t *disknum = (volatile uint8_t *)0xFE30;
+volatile uint8_t *diskcylh = (volatile uint8_t *)0xFE31;
+volatile uint8_t *diskcyll = (volatile uint8_t *)0xFE32;
+volatile uint8_t *diskcmd = (volatile uint8_t *)0xFE33;
+volatile uint8_t *diskstat = (volatile uint8_t *)0xFE35;
+
+static int hd_transfer(uint8_t minor, bool is_read, uint8_t rawflag)
+{
+ uint16_t dptr, nb;
+ irqflags_t irq;
+ uint8_t err;
+
+ /* FIXME: add swap */
+ if(rawflag == 1 && d_blkoff(9))
+ return -1;
+
+ /* For swap it'll be the swap bank passed */
+ hd_kmap = rawflag ? udata.u_page : KERNEL_BANK;
+
+ dptr = (uint16_t)udata.u_dptr;
+ nb = udata.u_nblock;
+
+ while (udata.u_nblock--) {
+ *disknum = minor;
+ *diskcylh = udata.u_block >> 8;
+ *diskcyll = udata.u_block;
+ *diskcmd = 1;
+ if ((err = *diskstat) != 0) {
+ kprintf("hd%d: disk error %x\n", err);
+ udata.u_error = EIO;
+ return -1;
+ }
+ /* We shouldn't need the di any more */
+ irq = di();
+ if (is_read)
+ hd_read_data(dptr);
+ else
+ hd_write_data(dptr);
+ irqrestore(irq);
+ udata.u_block++;
+ dptr += 512;
+ }
+ return nb << BLKSHIFT;
+}
+
+int hd_open(uint8_t minor, uint16_t flag)
+{
+ used(flag);
+ if(minor != 0) {
+ udata.u_error = ENODEV;
+ return -1;
+ }
+ return 0;
+}
+
+int hd_read(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+ used(flag);
+ return hd_transfer(minor, true, rawflag);
+}
+
+int hd_write(uint8_t minor, uint8_t rawflag, uint8_t flag)
+{
+ used(flag);
+ return hd_transfer(minor, false, rawflag);
+}
+
--- /dev/null
+#ifndef __DEVHD_DOT_H__
+#define __DEVHD_DOT_H__
+
+/* public interface */
+int hd_read(uint8_t minor, uint8_t rawflag, uint8_t flag);
+int hd_write(uint8_t minor, uint8_t rawflag, uint8_t flag);
+int hd_open(uint8_t minor, uint16_t flag);
+
+#endif /* __DEVHD_DOT_H__ */
--- /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 <devhd.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 */
+ { hd_open, no_close, hd_read, hd_write, no_ioctl },
+ /* 1: /dev/hd Hard disc block devices (absent) */
+ { nxio_open, no_close, no_rdwr, no_rdwr, no_ioctl },
+ /* 2: /dev/tty TTY devices */
+ { tty_open, tty_close, tty_read, tty_write, tty_ioctl },
+ /* 3: /dev/lpr Printer devices */
+ { no_open, no_close, no_rdwr, no_rdwr, no_ioctl },
+ /* 4: /dev/mem etc System devices (one offs) */
+ { no_open, no_close, sys_read, sys_write, sys_ioctl },
+ /* Pack to 7 with nxio if adding private devices and start at 8 */
+};
+
+bool validdev(uint16_t dev)
+{
+ /* This is a bit uglier than needed but the right hand side is
+ a constant this way */
+ if(dev > ((sizeof(dev_tab)/sizeof(struct devsw)) << 8) - 1)
+ return false;
+ else
+ return true;
+}
+
+void device_init(void)
+{
+}
+
--- /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>
+
+static volatile uint8_t *uart = (volatile uint8_t *)0xFE20;
+static volatile uint8_t *timer = (volatile uint8_t *)0xFE10;
+
+static char tbuf1[TTYSIZ];
+PTY_BUFFERS;
+
+struct s_queue ttyinq[NUM_DEV_TTY + 1] = { /* ttyinq[0] is never used */
+ {NULL, NULL, NULL, 0, 0, 0},
+ {tbuf1, tbuf1, tbuf1, TTYSIZ, 0, TTYSIZ / 2},
+ PTY_QUEUES
+};
+
+/* Output for the system console (kprintf etc) */
+void kputchar(uint8_t c)
+{
+ if (c == '\n')
+ tty_putc(1, '\r');
+ tty_putc(1, c);
+}
+
+ttyready_t tty_writeready(uint8_t minor)
+{
+ return TTY_READY_NOW;
+}
+
+void tty_putc(uint8_t minor, unsigned char c)
+{
+ minor;
+ uart[0] = c;
+}
+
+void tty_setup(uint8_t minor)
+{
+ minor;
+}
+
+void tty_sleeping(uint8_t minor)
+{
+ minor;
+}
+
+/* For the moment */
+int tty_carrier(uint8_t minor)
+{
+ minor;
+ return 1;
+}
+
+void tty_poll(void)
+{
+ uint8_t x;
+
+ x = uart[1] & 1;
+ if (x) {
+ x = uart[0];
+ tty_inproc(1, x);
+ }
+}
+
+void platform_interrupt(void)
+{
+ uint8_t t = *timer;
+ tty_poll();
+ while(t--) {
+ timer_interrupt();
+ }
+}
--- /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 $0100 ; stomps over bootstrap
+; 256+256 (U, kstack copy, k C stack copy)
+U_DATA__TOTALSIZE .set $0200
+U_DATA_STASH .set $FC00 ; leaves FFxx for vectors and stubs
+
+PROGLOAD .set $0100
+ZPBASE .set $0
+
+KERNEL_BANK .set $2 ; bank number (data)
+KERNEL_FAR .set $020000 ; 24 bit
+
+; Add this to twice the bank number to get the high 8bits of the 16bit CPU stack
+; for this process
+STACK_BANKOFF .set $00 ; 0400-FDFF
+; Direct page for IRQ processing (saves us saving/restoring DP registers)
+; Can probably use the same page as the IRQ CPU stack... FIXME
+; FIXME clashes with end of stack banks
+IRQ_DP .set $FF00 ; FF00-FF3F
+KERNEL_DP .set $00 ; We use the real ZP for kernel DP
+
+MAP_SIZE .set $FC00
+
+PROGBASE .set $0100
--- /dev/null
+#
+# We map the various bank into different files as if they were at the
+# bank 0 addresses. We don't want any far references but to rely upon
+# bank registers
+#
+
+MEMORY {
+#Bank0
+ RAMZ: start = $0000, size = $0100, type = rw, fill = yes;
+ USEG: start = $0400, size = $FA00, type = rw, fill = yes;
+ IO: start = $FE00, size = $0100, type = rw, fill = yes;
+ STUB: start = $FF00, size = $00E0, type = rw, fill = yes;
+ VECTOR: start = $FFE0, size = $0020, type = rw, fill = yes;
+#Bank1
+ MAIN: file = "fuzix.i", start = $0200, size = $10000, type = rw, fill = yes;
+#Bank2
+ UDATA: file = "fuzix.d", start = $0000, size = $0200, type = rw, fill = yes;
+ BSEG: file = "fuzix.d", start = $0200, size = $FE000, type = rw, fill = yes;
+}
+
+SEGMENTS {
+ ZEROPAGE: load = RAMZ, type = zp, define = yes;
+
+ COMMONDATA: load = UDATA, type = bss;
+
+ START: load = MAIN, type = ro;
+ CODE: load = MAIN, type = ro, define = yes;
+
+ RODATA: load = BSEG, type = ro;
+
+ DATA: load = BSEG, type = rw, define = yes;
+ BSS: load = BSEG, type = bss, define = yes;
+
+ DISCARD: load = MAIN, type = ro;
+ DISCARDDATA: load = BSEG, type = ro;
+
+ STUBS: load = STUB, type = ro;
+ VECTORS: load = VECTOR, type = ro;
+}
+
+FILES {
+ %O: format = bin;
+ "fuzix.i": format = bin;
+ "fuzix.d": format = bin;
+}
--- /dev/null
+#include <kernel.h>
+#include <timer.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devtty.h>
+
+uint8_t kernel_flag = 1;
+uint16_t ramtop = PROGTOP;
+
+void platform_idle(void)
+{
+ irqflags_t flags = di();
+ tty_poll();
+ irqrestore(flags);
+}
+
+void do_beep(void)
+{
+}
+
+/*
+ * 7 banks, kernel in bank 0
+ */
+
+void pagemap_init(void)
+{
+ int i;
+ /* Bank 0 is the kernel */
+ for (i = MAX_MAPS ; i > 0; i--)
+ pagemap_add(i);
+}
+
+void map_init(void)
+{
+}
+
+uint8_t platform_param(char *p)
+{
+ return 0;
+}
+
+char *pathbuf(void)
+{
+ return tmpbuf();
+}
+
+void pathfree(char *p)
+{
+ tmpfree(p);
+}
--- /dev/null
+export CPU = 65c816
+export USERCPU = 6502
+
--- /dev/null
+;
+; v65 platform functions
+;
+
+ .export init_early
+ .export init_hardware
+ .export _program_vectors
+
+ ; exported debugging tools
+ .export _trap_monitor
+ .export _trap_reboot
+ .export outchar
+ .export ___hard_di
+ .export ___hard_ei
+ .export ___hard_irqrestore
+
+ .import _ramsize
+ .import _procmem
+ .import nmi_handler
+ .import syscall_vector
+ .import kstack_top
+ .import istack_switched_sp
+ .import istack_top
+ .import _kernel_flag
+ .import pushax
+
+ .import outcharhex
+ .import outxa
+ .import incaxy
+
+ .include "kernel.def"
+ .include "../kernel816.def"
+ .include "zeropage.inc"
+
+ .p816
+ .a8
+ .i8
+;
+; syscall is jsr [$00fe]
+;
+syscall = $FE
+
+ .code
+
+_trap_monitor:
+ jmp _trap_monitor
+
+_trap_reboot:
+ sep #$30
+ .a8
+ .i8
+ lda #$A5
+ sta $FE40 ; Off
+ jmp _trap_reboot ; FIXME: original ROM map and jmp
+
+___hard_di:
+ php
+ sei ; Save old state in return to C
+ pla ; Old status
+ rts
+
+___hard_ei:
+ cli ; on 6502 cli enables IRQs!!!
+ rts
+
+___hard_irqrestore:
+ and #4 ; IRQ flag
+ beq irq_on
+ sei
+ rts
+irq_on:
+ cli
+ rts
+
+;
+; This could go in discard once we make that useful FIXME
+;
+init_early:
+ lda #1
+ sep #$30
+ .a8
+ .i8
+
+init_loop:
+ sta common_patch+1 ; destination bank
+ phb ; save our bank (mvn will mess it)
+ pha ; and count
+
+ rep #$30
+ .a16
+ .i16
+
+ ldx #$FF00
+ txy
+ lda #$00FE
+common_patch:
+ mvn KERNEL_BANK,0 ; copy the block
+
+ sep #$30
+ .a8
+ .i8
+
+ pla
+ plb ; bank to kernel bank
+ inc
+ cmp #8
+ bne init_loop
+ rts
+
+ .a8
+ .i8
+
+init_hardware:
+ ; set system RAM size (FIXME: dynamic probe)
+ rep #$10
+ .i16
+ ldx #512
+ stx _ramsize
+ ldx #512-64
+ stx _procmem
+
+ sep #$10
+ .i8
+
+ rts
+;
+; We did this at early boot when we set up the vectors and copied
+; stubs everywhere. Only thing we needed in each bank vector wise
+; was syscall (if we keep to 6502 style syscall)
+;
+_program_vectors:
+ rts
+
+; outchar: Wait for UART TX idle, then print the char in a without
+; corrupting other registers
+outchar:
+ sta $0000FE20
+ rts
+
+
+;
+; I/O logic
+;
+
+ .export _hd_kmap
+ .export _hd_read_data
+ .export _hd_write_data
+
+;
+; Disk copier (needs to be in common), call with ints off
+; for now
+;
+; AX = ptr, length always 512, page in globals
+;
+
+_hd_read_data:
+ sta ptr3
+ stx ptr3+1
+ phd
+ phb
+ rep #$10
+ .i16
+ ldx ptr3 ; buffer address
+ lda _hd_kmap ; page number
+ pha
+ plb ; data now points into user app
+ ldy #$FE00
+ phy
+ pld ; DP is now the I/O space
+
+ ldy #512
+hd_read:
+ lda $34 ; I/O data via DP
+ sta a:$0000,x ; stores into data (user) bank
+ inx
+ dey
+ bne hd_read
+ plb ; restore bank registers
+ pld
+ sep #$10
+ .i8 ; restore expected CPU state
+ rts
+
+_hd_write_data:
+ sta ptr3
+ stx ptr3+1
+ phd
+ phb
+ rep #$10
+ .i16
+ ldx ptr3 ; buffer address
+ lda _hd_kmap ; page number
+ pha
+ plb ; data now points into user app
+ ldy #$FE00
+ phy
+ pld ; DP is now the I/O space
+
+ ldy #512
+hd_write:
+ lda a:$0000,x ; load from data (user) bank
+ sta $34 ; I/O data via DP
+ inx
+ dey
+ bne hd_write
+ plb ; restore bank registers
+ pld
+ sep #$10
+ .i8 ; restore expected CPU state
+ rts
+
+ .bss
+_hd_kmap:
+ .res 1
--- /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
+