z80pack32: Prototyping work to support 32K + 32K fixed better
authorAlan Cox <alan@etchedpixels.co.uk>
Tue, 25 Nov 2014 22:39:54 +0000 (22:39 +0000)
committerAlan Cox <alan@etchedpixels.co.uk>
Tue, 25 Nov 2014 22:39:54 +0000 (22:39 +0000)
Initial test work to see what is needed to handle machines that have a 32K
chunk you can page and a fixed 32K chunk (MTX512, N8VEM v2, MicroBee etc)

Buildable prototype but needs work doing on the crt0.s/binman setup to cope
with binaries containing a big hole in the middle.

16 files changed:
Kernel/Makefile
Kernel/bank32k.c
Kernel/include/kernel.h
Kernel/platform-z80pack32/Makefile [new file with mode: 0644]
Kernel/platform-z80pack32/README [new file with mode: 0644]
Kernel/platform-z80pack32/bootblock.s [new file with mode: 0644]
Kernel/platform-z80pack32/commonmem.s [new file with mode: 0644]
Kernel/platform-z80pack32/config.h [new file with mode: 0644]
Kernel/platform-z80pack32/crt0.s [new file with mode: 0644]
Kernel/platform-z80pack32/devices.c [new file with mode: 0644]
Kernel/platform-z80pack32/kernel.def [new file with mode: 0644]
Kernel/platform-z80pack32/main.c [new file with mode: 0644]
Kernel/platform-z80pack32/tricks.s [new file with mode: 0644]
Kernel/platform-z80pack32/uzi.lnk [new file with mode: 0644]
Kernel/platform-z80pack32/z80pack.s [new file with mode: 0644]
Kernel/swap.c

index 60fe9d7..3fab9de 100644 (file)
@@ -1,6 +1,6 @@
-TARGET_LIST = platform-nc100 platform-micropack platform-pcw8256 platform-socz80 platform-zx128 platform-trs80 platform-z80pack platform-z80pack-lite 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
 
-export TARGET= z80pack
+export TARGET= z80pack32
 export CPU = z80
 #export TARGET = dragon
 #export CPU = 6809
index e9b388d..b5aaa65 100644 (file)
@@ -4,8 +4,9 @@
 
 #ifdef CONFIG_BANK32
 
-#ifndef bank32_invalidate_cache
-#define bank32_invalidate_cache(x) do {} while(0)
+/* 32K common, ldir copying to use for 48K apps */
+#ifndef CONFIG_COMMON_COPY
+#define invalidate_cache(x) do {} while(0)
 #endif
 
 /*
@@ -61,7 +62,7 @@ void pagemap_free(ptptr p)
        pfree[pfptr--] = *ptr;
        if (*ptr != ptr[1]) {
                pfree[pfptr--] = ptr[1];
-                bank32_invalidate_cache(ptr[1]);
+                invalidate_cache((uint16_t)ptr[1]);
         }
 }
 
@@ -73,7 +74,7 @@ static int maps_needed(uint16_t top)
        /* Usually we have 0x1000 common - 1 for shift and inc */
        if (needed & 0x8000)
                return 2;
-       return return 1;
+       return 1;
 }
 
 /*
@@ -85,7 +86,6 @@ int pagemap_alloc(ptptr p)
 {
        uint8_t *ptr = (uint8_t *) & p->p_page;
        int needed = maps_needed(udata.u_top);
-       int i;
 
 #ifdef SWAPDEV
        /* Throw our toys out of our pram until we have enough room */
@@ -107,12 +107,17 @@ int pagemap_alloc(ptptr p)
 
 /*
  *     Reallocate the maps for a process
+ *
+ *     Subtlety: On a 32K box we have the udata area being copied to/from
+ *     the stash. As we always realloc for the live process we don't have
+ *     to worry about this in the 32K + common case because we'll switchin
+ *     at one size, and switchout at the other and the udata will just get
+ *     saved/restored to the right places.
  */
 int pagemap_realloc(uint16_t size) {
        int have = maps_needed(udata.u_top);
        int want = maps_needed(size);
        uint8_t *ptr = (uint8_t *) & udata.u_page;
-       int i;
 
        /* If we are shrinking then free pages and propogate the
           common page into the freed spaces */
index 018923c..cf3e2d6 100644 (file)
@@ -703,6 +703,8 @@ CODE2 void platform_idle(void);
 /* Will need a uptr_t eventually */
 extern uint16_t ramtop;             /* Note: ramtop must be in common in some cases */
 CODE2 extern void platform_interrupt(void);
+COMMON void invalidate_cache(uint16_t page);
+COMMON void flush_cache(ptptr p);
 
 CODE2 int16_t __exit(void);        /* FUZIX system call 0 */
 CODE2 int16_t _open(void);         /* FUZIX system call 1 */
diff --git a/Kernel/platform-z80pack32/Makefile b/Kernel/platform-z80pack32/Makefile
new file mode 100644 (file)
index 0000000..1bcbe00
--- /dev/null
@@ -0,0 +1,36 @@
+
+DSRCS = ../dev/z80pack/devlpr.c ../dev/z80pack/devtty.c ../dev/z80pack/devfd.c
+CSRCS += devices.c main.c
+
+ASRCS = crt0.s z80pack.s
+ASRCS += tricks.s commonmem.s
+
+AOBJS = $(ASRCS:.s=.rel)
+COBJS = $(CSRCS:.c=.rel)
+DOBJS = $(patsubst ../dev/z80pack/%.c,%.rel, $(DSRCS))
+
+OBJS  = $(AOBJS) $(COBJS) $(DOBJS)
+
+CROSS_CCOPTS += -I../dev/z80pack/ --codeseg CODE3
+
+JUNK = *.rel *.lst *.asm *.sym *.rst
+
+all:   $(OBJS)
+
+$(AOBJS): %.rel: %.s
+       $(CROSS_AS) $(ASOPTS) $<
+
+$(COBJS): %.rel: %.c
+       $(CROSS_CC) $(CROSS_CCOPTS) -c $<
+
+$(DOBJS): %.rel: ../dev/z80pack/%.c
+       $(CROSS_CC) $(CROSS_CCOPTS) -c $<
+
+
+clean:
+       rm -f $(OBJS) $(JUNK)  core *~ 
+
+image:
+       sdasz80 -o bootblock.s
+       sdldz80 -m -i bootblock.rel
+       makebin -s 128 bootblock.ihx > bootblock.bin
diff --git a/Kernel/platform-z80pack32/README b/Kernel/platform-z80pack32/README
new file mode 100644 (file)
index 0000000..61a5922
--- /dev/null
@@ -0,0 +1,37 @@
+Z80 Pack Test For 32K  + cached high for bigger binaries
+
+Kernel
+0000-07FFF     CODE1, CODE2
+0x8000-0xBFFF  User cache area   (0xB000 discard)
+0xC000         Udata
+0xC300         CONST, CODE3, DATA ...
+0xF000         Common
+
+TODO
+
+We waste 16K per high process but its not clear how much of a win it would
+be to pack them, and if we can squash stuff better we might go over 48K and
+break it.
+
+binman has no idea how to pack such an image, probably better to have a new
+tool as binman is getting too unwieldy. Perhaps it's time to have a tool and
+crt0.s that simply reads a table of block/offsets to ldir then runs ? 
+
+Also need to pack carefully so we don't overwrite source data. Probably
+means we need to start at the end of the image and lddr back down it.
+
+Need to fix the packing/crt0.s before we can test any of this
+
+
+Disk swap device recommended
+
+Put the kernel at the end of a floppy image from cyl 60
+Add the fs in the first 60 cyls (390 blocks)
+
+Put the bootblock in sector 0
+
+dd the kernel image to offset 199680
+
+ie
+
+dd if=fuzix.bin of=drivea.cpm bs=1 seek=199680 conv=notrunc
diff --git a/Kernel/platform-z80pack32/bootblock.s b/Kernel/platform-z80pack32/bootblock.s
new file mode 100644 (file)
index 0000000..887293f
--- /dev/null
@@ -0,0 +1,81 @@
+;
+;      Z80pack cpmsim loads the first (128 byte) sector from the disk
+;      into memory at 0 then executes it
+;      We are a bit tight on space here
+;
+;      Floppy loader: 
+;      Our boot disc is 77 tracks of 26 x 128 byte sectors, and we put
+;      the OS on tracks 60+, which means we can put a file system in the
+;      usual place providing its a bit smaller than a whole disc.
+;
+;
+;      assemble with sdasz80
+;
+               .area   ASEG(ABS)
+               .org    0
+
+start:         jr diskload
+
+rootdev:       .dw 0                   ; patched by hand
+swapdev:       .dw 0                   ; ditto
+               .dw 0                   ; spare
+
+progress:      .db '/', '-', '\', '|'
+
+diskload:      di
+               ld sp, #stack
+               ld hl, #0x88
+               exx
+               xor a
+               ld h, a
+               ld b, a
+               out (17), a             ; sector high always 0
+               out (10), a             ; drive always 0
+               ld a, #59               ; start on track 60
+               out (11), a
+               exx
+               ld c, #17               ; number of tracks to load (56Kish)
+load_tracks:   in a, (11)
+               inc a                   ; track
+               out (11), a
+               xor a
+               out (12), a
+               ld b, #26               ; sectors
+load_sectors:  exx
+               ld a, b
+               and #3
+               add #progress
+               ld l, a
+               ld a, (hl)
+               out (01), a
+               ld a, #8
+               out (01), a
+               inc b
+               exx
+
+               in a, (12)
+               inc a
+               out (12), a             ; sector
+               ld a, l
+               out (15), a             ; dma low
+               ld a, h
+               out (16), a             ; dma high
+               xor a                   ; read
+               out (13), a             ; go
+               in a, (14)              ; status
+               ld de, #128
+               add hl, de
+               djnz load_sectors       ; 26 sectors = 3328 bytes
+               dec c
+               jr nz, load_tracks
+               ld a, #0xc9             ; to help debug
+               ld (start), a
+               ld a, #13
+               out (1), a
+               ld a, #10
+               out (1), a
+               jp 0x88
+
+               .ds 26
+stack:
+               .db 0xff
diff --git a/Kernel/platform-z80pack32/commonmem.s b/Kernel/platform-z80pack32/commonmem.s
new file mode 100644 (file)
index 0000000..522503a
--- /dev/null
@@ -0,0 +1,9 @@
+;
+;      Common on z80pack is at 0xF000 as defined by hardware.
+;
+
+        .module commonmem
+
+        .area _COMMONMEM
+
+       .include "../cpu-z80/std-commonmem.s"
diff --git a/Kernel/platform-z80pack32/config.h b/Kernel/platform-z80pack32/config.h
new file mode 100644 (file)
index 0000000..e6f391e
--- /dev/null
@@ -0,0 +1,46 @@
+/* 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) */
+#define CONFIG_PROFIL
+/* Multiple processes in memory at once */
+#define CONFIG_MULTI
+/* Single tasking */
+#undef CONFIG_SINGLETASK
+/* CP/M emulation */
+#undef CONFIG_CPM_EMU
+/* 32K banking */
+#define CONFIG_BANK32
+/* but with the high block copied on switch as needed */
+#define CONFIG_COMMON_COPY
+/* 8 32K banks, 1 is kernel */
+#define MAX_MAPS       7
+#define MAP_SIZE       0x8000U
+
+/* Banks as reported to user space */
+#define CONFIG_BANKS   2
+
+#define TICKSPERSEC 100   /* Ticks per second */
+#define PROGBASE    0x0000  /* also data base */
+#define PROGLOAD    0x0100  /* also data base */
+#define PROGTOP     0xBC00  /* Top of program, base of U_DATA copy */
+
+#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 */
+#define MAX_SWAPS      64      /* The full drive would actually be 85! */
+
+#define BOOT_TTY (512 + 1)/* Set this to default device for stdio, stderr */
+                          /* In this case, the default is the first TTY device */
+
+/* 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 3
+
+#define TTYDEV   BOOT_TTY /* Device used by kernel for messages, panics */
+#define SWAPDEV  (256 + 1)  /* Device for swapping. (z80pack drive J) */
+#define NBUFS    10       /* Number of block buffers */
+#define NMOUNTS         4        /* Number of mounts at a time */
diff --git a/Kernel/platform-z80pack32/crt0.s b/Kernel/platform-z80pack32/crt0.s
new file mode 100644 (file)
index 0000000..bce4e13
--- /dev/null
@@ -0,0 +1,74 @@
+; 2013-12-18 William R Sowerbutts
+
+        .module crt0
+
+        ; Ordering of segments for the linker.
+        ; WRS: Note we list all our segments here, even though
+        ; we don't use them all, because their ordering is set
+        ; when they are first seen.
+        .area _CODE
+        .area _CODE2
+       .area _CODE3
+        .area _CONST
+        .area _INITIALIZED
+        .area _DATA
+        .area _BSEG
+        .area _BSS
+        .area _HEAP
+        ; note that areas below here may be overwritten by the heap at runtime, so
+        ; put initialisation stuff in here
+        .area _INITIALIZER
+        .area _GSINIT
+        .area _GSFINAL
+       .area _DISCARD
+        .area _COMMONMEM
+
+        ; imported symbols
+        .globl _fuzix_main
+        .globl init_early
+        .globl init_hardware
+        .globl s__INITIALIZER
+        .globl s__COMMONMEM
+        .globl l__COMMONMEM
+        .globl s__DISCARD
+        .globl l__DISCARD
+        .globl s__DATA
+        .globl l__DATA
+        .globl kstack_top
+
+        ; startup code
+        .area _CODE
+init:
+        di
+        ld sp, #kstack_top
+
+        ; Configure memory map
+        call init_early
+
+       ; move the common memory where it belongs    
+       ld hl, #s__INITIALIZER
+       ld de, #s__COMMONMEM
+       ld bc, #l__COMMONMEM
+       ldir
+       ; and the discard
+       ld de, #s__DISCARD
+       ld bc, #l__DISCARD
+       ldir
+       ; then zero the data area
+       ld hl, #s__DATA
+       ld de, #s__DATA + 1
+       ld bc, #l__DATA - 1
+       ld (hl), #0
+       ldir
+
+        ; Hardware setup
+        call init_hardware
+
+        ; Call the C main routine
+        call _fuzix_main
+    
+        ; main shouldn't return, but if it does...
+        di
+stop:   halt
+        jr stop
+
diff --git a/Kernel/platform-z80pack32/devices.c b/Kernel/platform-z80pack32/devices.c
new file mode 100644 (file)
index 0000000..c60640f
--- /dev/null
@@ -0,0 +1,43 @@
+#include <kernel.h>
+#include <version.h>
+#include <kdata.h>
+#include <tty.h>
+#include <devfd.h>
+#include <devsys.h>
+#include <devlpr.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  */
+  {  fd_open,     no_close,    fd_read,   fd_write,   no_ioctl },
+  /* 1: /dev/hd                Hard disc block devices (absent) */
+  {  hd_open,     no_close,    hd_read,   hd_write,   no_ioctl },
+  /* 2: /dev/tty       TTY devices */
+  {  tty_open,     tty_close,   tty_read,  tty_write,  tty_ioctl },
+  /* 3: /dev/lpr       Printer devices */
+  {  lpr_open,     lpr_close,   no_rdwr,   lpr_write,  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)
+{
+  int i;
+  /* Add 64 swaps (4MB) to use the entire J drive */
+  for (i = 0; i < MAX_SWAPS; i++)
+    swapmap_add(i);
+}
diff --git a/Kernel/platform-z80pack32/kernel.def b/Kernel/platform-z80pack32/kernel.def
new file mode 100644 (file)
index 0000000..d5211a9
--- /dev/null
@@ -0,0 +1,7 @@
+; UZI mnemonics for memory addresses etc
+
+U_DATA                      .equ 0xF000       ; (this is struct u_data from kernel.h)
+U_DATA__TOTALSIZE           .equ 0x300        ; 256+256+256 bytes.
+
+U_STASH_HIGH               .equ 0xBD00       ; BD00-BFFF
+U_STASH_LOW                .equ 0x7D00       ; 7D00-BFFF
diff --git a/Kernel/platform-z80pack32/main.c b/Kernel/platform-z80pack32/main.c
new file mode 100644 (file)
index 0000000..eb6b778
--- /dev/null
@@ -0,0 +1,36 @@
+#include <kernel.h>
+#include <timer.h>
+#include <kdata.h>
+#include <printf.h>
+#include <devtty.h>
+
+uint16_t ramtop = PROGTOP;
+
+
+void pagemap_init(void)
+{
+ int i;
+ for (i = 1; i < 8; i++)
+  pagemap_add(i);
+}
+
+/* On idle we spin checking for the terminals. Gives us more responsiveness
+   for the polled ports */
+void platform_idle(void)
+{
+  /* We don't want an idle poll and IRQ driven tty poll at the same moment */
+  irqflags_t irq = di();
+  tty_pollirq(); 
+  irqrestore(irq);
+}
+
+void platform_interrupt(void)
+{
+ tty_pollirq();
+ timer_interrupt();
+}
+
+/* Nothing to do for the map of init */
+void map_init(void)
+{
+}
diff --git a/Kernel/platform-z80pack32/tricks.s b/Kernel/platform-z80pack32/tricks.s
new file mode 100644 (file)
index 0000000..3f70cf3
--- /dev/null
@@ -0,0 +1,442 @@
+; 2013-12-21 William R Sowerbutts
+
+        .module tricks
+
+        .globl _ptab_alloc
+        .globl _newproc
+        .globl _chksigs
+        .globl _getproc
+        .globl _trap_monitor
+        .globl trap_illegal
+        .globl _inint
+        .globl _switchout
+        .globl _switchin
+        .globl _doexec
+        .globl _dofork
+        .globl _runticks
+        .globl unix_syscall_entry
+        .globl interrupt_handler
+        .globl dispatch_process_signal
+       .globl _swapper
+       .globl _cached_page
+       .globl _flush_cache
+       .globl _invalidate_cache
+
+        ; imported debug symbols
+        .globl outstring, outde, outhl, outbc, outnewline, outchar, outcharhex
+
+        .include "kernel.def"
+        .include "../kernel.def"
+
+        .area _COMMONMEM
+
+; 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:
+        di
+        call _chksigs
+        ; save machine state
+
+        ld hl, #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:
+        push hl ; return code
+        push ix
+        push iy
+        ld (U_DATA__U_SP), sp ; this is where the SP is restored in _switchin
+
+        ; set inint to false
+        xor a
+        ld (_inint), a
+
+       ; Stash the uarea back into process memory
+       ld hl, (U_DATA__U_PAGE)
+       ld a, l
+       out (21), a
+       cp h                    ; small or large process ?
+       jr z, switchoutlow
+       ld de, #U_STASH_HIGH
+switchoutlow:
+       ld hl, #U_DATA
+       ld de, #U_STASH_LOW
+       ld bc, #U_DATA__TOTALSIZE
+       ldir
+       xor a
+       out (21), a
+
+        ; find another process to run (may select this one again)
+        call _getproc
+
+        push hl
+        call _switchin
+
+        ; we should never get here
+        call _trap_monitor
+
+badswitchmsg: .ascii "_switchin: FAIL"
+            .db 13, 10, 0
+swapped: .ascii "_switchin: SWAPPED"
+            .db 13, 10, 0
+
+_switchin:
+        di
+        pop bc  ; return address
+        pop de  ; new process pointer
+;
+;      FIXME: do we actually *need* to restore the stack !
+;
+        push de ; restore stack
+        push bc ; restore stack
+
+       xor a
+       out (21), a
+
+       push de
+        ld hl, #P_TAB__P_PAGE_OFFSET
+       add hl, de      ; process ptr
+       pop de
+
+        ld a, (hl)
+
+       or a
+       jr nz, not_swapped
+
+       ;
+       ;       We are still on the departing processes stack, which is
+       ;       fine for now.
+       ;
+       ld sp, #_swapstack
+       push hl
+       push de
+       call _swapper
+       pop de
+       pop hl
+       ld a, (hl)
+
+not_swapped:
+       ; Decide where the uarea stash lives right now and check the cache
+       inc hl
+       cp (hl)                 ; must cp first as (hl) vanishes on the out
+       jr z, switchinlow
+       ld hl, #_cached_page
+       cp (hl)
+       push af
+       call z, update_cache
+       pop af
+       out (21), a
+       exx                     ; thank goodness for exx 8)
+       ld hl, #U_STASH_HIGH
+       jr switchin_page
+switchinlow:
+       ; Pages please !
+       out (21), a
+       exx                     ; thank goodness for exx 8)
+       ld hl, #U_STASH_LOW
+switchin_page:
+        ; bear in mind that the stack will be switched now, so we can't use it
+       ; to carry values over this point
+       ld de, #U_DATA
+       ld bc, #U_DATA__TOTALSIZE
+       ldir
+       exx
+
+       ; Return to kernel mappings
+       xor a
+       out (21), a
+        
+switchlow2:
+
+        ; check u_data->u_ptab matches what we wanted
+        ld hl, (U_DATA__U_PTAB) ; u_data->u_ptab
+        or a                    ; clear carry flag
+        sbc hl, de              ; subtract, result will be zero if DE==IX
+        jr nz, switchinfail
+
+       ; wants optimising up a bit
+       ld ix, (U_DATA__U_PTAB)
+        ; next_process->p_status = P_RUNNING
+        ld P_TAB__P_STATUS_OFFSET(ix), #P_RUNNING
+
+       ; Fix the moved page pointers
+       ; Just do two bytes as that is all we use on this platform
+       ld l, P_TAB__P_PAGE_OFFSET(ix)
+       ld h, P_TAB__P_PAGE_OFFSET+1(ix)
+       ld (U_DATA__U_PAGE), hl
+        ; runticks = 0
+        ld hl, #0
+        ld (_runticks), hl
+
+        ; restore machine state -- note we may be returning from either
+        ; _switchout or _dofork
+        ld sp, (U_DATA__U_SP)
+
+        pop iy
+        pop ix
+        pop hl ; return code
+
+        ; enable interrupts, if the ISR isn't already running
+        ld a, (_inint)
+        or a
+        ret z ; in ISR, leave interrupts off
+        ei
+        ret ; return with interrupts on
+
+switchinfail:
+       call outhl
+        ld hl, #badswitchmsg
+        call outstring
+       ; something went wrong and we didn't switch in what we asked for
+        jp _trap_monitor
+
+; (hl) points to cached page ptr, a is desired page
+update_cache:
+       ld (hl), a
+       ld hl, #0
+       ld de, #0x8000
+       ld bc, #0x7D00
+       ; map that page low (interrupts *must* be off)
+       out (21), a
+       ldir
+       ; put the kernel back
+       xor a
+       out (21), a
+       ret
+
+;
+;      Invalidate a freed page - cache becomes void
+;
+_invalidate_cache:
+       pop de
+       pop hl
+       push hl
+       push de
+       ld a, (_cached_page)
+       cp l
+       ret nz
+       ld a, #0xff
+       ld (_cached_page), a
+       ret
+
+
+_flush_cache:          ; argument is the process it may apply to 
+       pop de
+       pop hl
+       push hl
+       push de
+       ld a, i
+       push af
+       ld de, #P_TAB__P_PAGE_OFFSET + 1
+       add hl, de
+       ld a, (_cached_page)
+       cp (hl)
+       jr nz, flush_none
+       di
+       call flush_cache_self
+       pop af
+       ret po
+       ei
+       ret
+flush_none:
+       pop af
+       ret
+
+; interrupts must be disabled
+flush_cache_self:
+       push af
+       ld a, (_cached_page)
+       cp #0xff
+       jr z, no_cache
+       push bc
+       push de
+       push hl
+       ld hl, #0x8000          ; copy into the page
+       ld de, #0
+       ld bc, #0x7D00
+       ; map that page low (interrupts *must* be off)
+       out (21), a
+       ldir
+       ; put the kernel back
+       xor a
+       out (21), a
+       pop hl
+       pop de
+       pop bc
+no_cache:
+       pop af
+       ret
+
+fork_proc_ptr: .dw 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
+        di ; should already be the case ... belt and braces.
+
+        pop de  ; return address
+        pop hl  ; new process p_tab*
+        push hl
+        push de
+
+        ld (fork_proc_ptr), hl
+
+        ; prepare return value in parent process -- HL = p->p_pid;
+        ld de, #P_TAB__P_PID_OFFSET
+        add hl, de
+        ld a, (hl)
+        inc hl
+        ld h, (hl)
+        ld l, a
+
+        ; 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.
+        push hl ; HL still has p->p_pid from above, the return value in the parent
+        push ix
+        push iy
+
+        ; 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.
+        ld (U_DATA__U_SP), sp
+
+        ; now we're in a safe state for _switchin to return in the parent
+       ; process.
+        ; --------- copy process ---------
+
+        ld hl, (fork_proc_ptr)
+        ld de, #P_TAB__P_PAGE_OFFSET
+        add hl, de
+        ; load p_page
+        ld c, (hl)
+       inc hl
+       ; load p_page + 1 (high page)
+       ld b, (hl)
+       push af
+       ld a, c
+       call outcharhex
+       pop af
+       ; load existing page ptr
+       ld a, (U_DATA__U_PAGE)
+
+       call bankfork                   ;       do the bank to bank copy
+
+       ; Copy done
+
+       ld a, (U_DATA__U_PAGE)  ; parent memory
+       out (21), a             ; Switch context to parent
+
+       ; We are going to copy the uarea into the parents uarea stash
+       ; we must not touch the parent uarea after this point, any
+       ; changes only affect the child
+       ld de, #U_STASH_LOW             ; parent location
+       ld hl, #U_DATA__U_PAGE
+       ld a, (hl)
+       inc hl
+       cp (hl)
+       jr z, stash_low
+       ld de, #U_STASH_HIGH            ; high stash
+stash_low:
+       ld hl, #U_DATA          ; copy the udata from common
+       ld bc, #U_DATA__TOTALSIZE
+       ldir
+       ; Return to the kernel mapping
+       xor a
+       out (21), a
+        ; now the copy operation is complete we can get rid of the stuff
+        ; _switchin will be expecting from our copy of the stack.
+        pop bc
+        pop bc
+        pop bc
+
+        ; Make a new process table entry, etc.
+        ld  hl, (fork_proc_ptr)
+        push hl
+        call _newproc
+        pop bc 
+
+        ; runticks = 0;
+        ld hl, #0
+        ld (_runticks), hl
+        ; 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().
+        ret
+
+;
+;      This is related so we will keep it here. Copy the process memory
+;      for a fork. a is the page base of the parent, c of the child
+;      (this API will be insufficient once we have chmem and proper use of
+;      banks - as well as needing to support fork to disk)
+;
+;      Assumption - fits into a fixed number of whole 256 byte blocks
+;
+;      The parent must be running here, therefore the parent must be
+;      mapped, therefore the cached page is loaded with the parent
+;
+bankfork:
+       push af
+       ld hl, #U_DATA__U_PAGE + 1
+       cp (hl)                 ; Are we a two pager ?
+       jr z, bankfork_low      ; If not skip the high space
+       call flush_cache_self   ; Flush the parent cache
+       ld a, b
+       ld (_cached_page), a    ; High cache is now child (which runs first)
+       ld b, #0x80
+       jr bankfork_go          ; Now copy the low 32K
+bankfork_low:
+       ld b, #0x7D             ; 32K minus UAREA stash
+bankfork_go:
+       pop af                  ; A is now the parent bank
+       ld hl, #0               ; base of memory to fork (vectors included)
+bankfork_1:
+       push bc                 ; Save our counter and also child offset
+       push hl
+       out (21), a             ; switch to parent bank
+       ld de, #bouncebuffer
+       ld bc, #256
+       ldir                    ; copy into the bounce buffer
+       pop de                  ; recover source of copy to bounce
+                               ; as destination in new bank
+       pop bc                  ; recover child page number
+       push bc
+       ld b, a                 ; save the parent bank id
+       ld a, c                 ; switch to the child
+       out (21), a
+       push bc                 ; save the bank pointers
+       ld hl, #bouncebuffer
+       ld bc, #256
+       ldir                    ; copy into the child
+       pop bc                  ; recover the bank pointers
+       ex de, hl               ; destination is now source for next bank
+       ld a, b                 ; parent bank is wanted in a
+       pop bc
+       djnz bankfork_1         ; rinse, repeat
+       ret
+
+;
+;      For the moment
+;
+bouncebuffer:
+       .ds 256
+;
+;      We can keep a stack in common because we will complete our
+;      use of it before we switch common block. In this case we have
+;      a true common so it's even easier. This can share with the bounce
+;      buffer used by bankfork as we won't switchin mid way through the
+;      banked fork() call.
+;
+_swapstack:
+_cached_page:
+       .db 0xff
diff --git a/Kernel/platform-z80pack32/uzi.lnk b/Kernel/platform-z80pack32/uzi.lnk
new file mode 100644 (file)
index 0000000..9f6e996
--- /dev/null
@@ -0,0 +1,38 @@
+-mwxuy
+-i uzi.ihx
+-b _CODE=0x0088
+-b _CODE3=0xC000
+-b _COMMONMEM=0xF000
+-b _DISCARD=0xB000
+-l z80
+platform-z80pack32/crt0.rel
+platform-z80pack32/commonmem.rel
+platform-z80pack32/z80pack.rel
+platform-z80pack32/main.rel
+start.rel
+version.rel
+lowlevel-z80.rel
+usermem_std-z80.rel
+platform-z80pack32/tricks.rel
+timer.rel
+kdata.rel
+usermem.rel
+platform-z80pack32/devfd.rel
+platform-z80pack32/devices.rel
+devio.rel
+filesys.rel
+process.rel
+inode.rel
+syscall_exec.rel
+syscall_fs.rel
+syscall_fs2.rel
+syscall_proc.rel
+syscall_other.rel
+tty.rel
+mm.rel
+bank32k.rel
+swap.rel
+devsys.rel
+platform-z80pack32/devlpr.rel
+platform-z80pack32/devtty.rel
+-e
diff --git a/Kernel/platform-z80pack32/z80pack.s b/Kernel/platform-z80pack32/z80pack.s
new file mode 100644 (file)
index 0000000..1390024
--- /dev/null
@@ -0,0 +1,214 @@
+;
+;      Z80Pack hardware support
+;
+;
+;      This goes straight after udata for common. Because of that the first
+;      256 bytes get swapped to and from disk with the uarea (512 byte disk
+;      blocks). This isn't a problem but don't put any variables in here.
+;
+;      If you make this module any shorter, check what follows next
+;
+
+
+            .module z80pack
+
+            ; exported symbols
+            .globl init_early
+            .globl init_hardware
+            .globl _program_vectors
+            .globl _system_tick_counter
+           .globl platform_interrupt_all
+
+           .globl map_kernel
+           .globl map_process
+           .globl map_process_always
+           .globl map_save
+           .globl map_restore
+
+           .globl _fd_bankcmd
+
+           .globl _kernel_flag
+
+            ; exported debugging tools
+            .globl _trap_monitor
+            .globl outchar
+
+            ; imported symbols
+            .globl _ramsize
+            .globl _procmem
+
+           .globl unix_syscall_entry
+            .globl null_handler
+           .globl nmi_handler
+            .globl interrupt_handler
+
+            .globl outcharhex
+            .globl outhl, outde, outbc
+            .globl outnewline
+            .globl outstring
+            .globl outstringhex
+
+            .include "kernel.def"
+            .include "../kernel.def"
+
+; -----------------------------------------------------------------------------
+; COMMON MEMORY BANK (0xF000 upwards)
+; -----------------------------------------------------------------------------
+            .area _COMMONMEM
+
+_trap_monitor:
+           ld a, #128
+           out (29), a
+platform_interrupt_all:
+           ret
+
+_trap_reboot:
+           ld a, #1
+           out (29), a
+
+;
+;      We need the right bank present when we cause the transfer
+;
+_fd_bankcmd:pop de             ; return
+           pop bc              ; command
+           pop hl              ; bank
+           push hl
+           push bc
+           push de             ; fix stack
+           ld a, i
+           di
+           push af             ; save DI state
+           call map_process    ; HL alread holds our bank
+           ld a, c             ; issue the command
+           out (13), a         ;
+           call map_kernel     ; return to kernel mapping
+           pop af
+           ret po
+           ei
+           ret
+
+; -----------------------------------------------------------------------------
+; KERNEL MEMORY BANK (below 0xC000, only accessible when the kernel is mapped)
+; -----------------------------------------------------------------------------
+            .area _CODE
+
+init_early:
+           ld a, #240                  ; 240 * 256 bytes (60K)
+           out (22), a                 ; set up memory banking
+           ld a, #8    
+           out (20), a                 ; 8 segments
+            ret
+
+init_hardware:
+            ; set system RAM size
+            ld hl, #480
+            ld (_ramsize), hl
+            ld hl, #(480-64)           ; 64K for kernel
+            ld (_procmem), hl
+
+           ld a, #1
+           out (27), a                 ; 100Hz timer on
+
+            ; set up interrupt vectors for the kernel (also sets up common memory in page 0x000F which is unused)
+            ld hl, #0
+            push hl
+            call _program_vectors
+            pop hl
+
+            im 1 ; set CPU interrupt mode
+            ret
+
+
+;------------------------------------------------------------------------------
+; COMMON MEMORY PROCEDURES FOLLOW
+
+            .area _COMMONMEM
+
+
+_program_vectors:
+            ; we are called, with interrupts disabled, by both newproc() and crt0
+           ; will exit with interrupts off
+            di ; just to be sure
+            pop de ; temporarily store return address
+            pop hl ; function argument -- base page number
+            push hl ; put stack back as it was
+            push de
+
+           call map_process
+
+            ; write zeroes across all vectors
+            ld hl, #0
+            ld de, #1
+            ld bc, #0x007f ; program first 0x80 bytes only
+            ld (hl), #0x00
+            ldir
+
+            ; now install the interrupt vector at 0x0038
+            ld a, #0xC3 ; JP instruction
+            ld (0x0038), a
+            ld hl, #interrupt_handler
+            ld (0x0039), hl
+
+            ; set restart vector for UZI system calls
+            ld (0x0030), a   ;  (rst 30h is unix function call vector)
+            ld hl, #unix_syscall_entry
+            ld (0x0031), hl
+
+            ; Set vector for jump to NULL
+            ld (0x0000), a   
+            ld hl, #null_handler  ;   to Our Trap Handler
+            ld (0x0001), hl
+
+            ld (0x0066), a  ; Set vector for NMI
+            ld hl, #nmi_handler
+            ld (0x0067), hl
+
+           ; our platform has a "true" common area, if it did not we would
+           ; need to copy the "common" code into the common area of the new
+           ; process.
+
+           ; falls through
+
+            ; put the paging back as it was -- we're in kernel mode so this is predictable
+map_kernel:
+           push af
+           xor a
+           out (21), a
+           pop af
+            ret
+map_process:
+           ld a, h
+           or l
+           jr z, map_kernel
+           ld a, (hl)
+           out (21), a
+            ret
+map_process_always:
+           push af
+           ld a, (U_DATA__U_PAGE)
+           out (21), a
+           pop af
+           ret
+map_save:
+           push af
+           in a, (21)
+           ld (map_store), a
+           pop af
+           ret     
+map_restore:
+           push af
+           ld a, (map_store)
+           out (21), a
+           pop af
+           ret     
+map_store:
+           .db 0
+
+_kernel_flag:
+           .db 1
+
+; outchar: Wait for UART TX idle, then print the char in A
+; destroys: AF
+outchar:
+           out (0x01), a
+            ret
index f9f6454..ea39596 100644 (file)
@@ -16,8 +16,8 @@
 #define UDATA_BLOCKS   0
 #endif
 
-#ifndef swap_flush_cache
-#define swap_flush_cache(p)    do {} while(0)
+#ifndef CONFIG_COMMON_COPY
+#define flush_cache(p) do {} while(0)
 #endif
 
 uint8_t *swapbase;
@@ -77,7 +77,7 @@ int swapout(ptptr p)
                /* Are we out of swap ? */
                if (swapptr == 0)
                        return ENOMEM;
-                swap_flush_cache(p);
+                flush_cache(p);
                map = swapmap[--swapptr];
                blk = map * SWAP_SIZE;
 #ifdef UDATA_SWAPSIZE