cromemco: further pass over the Cromemco code
authorAlan Cox <alan@linux.intel.com>
Sun, 9 Dec 2018 00:49:33 +0000 (00:49 +0000)
committerAlan Cox <alan@linux.intel.com>
Sun, 9 Dec 2018 00:49:33 +0000 (00:49 +0000)
Hopefully now we have thunked mappings this becomes a bit more viable

Kernel/platform-cromemco/Makefile
Kernel/platform-cromemco/README
Kernel/platform-cromemco/cloader-16fdc.s
Kernel/platform-cromemco/config.h
Kernel/platform-cromemco/cromemco.s
Kernel/platform-cromemco/crt0.s
Kernel/platform-cromemco/fuzix.lnk
Kernel/platform-cromemco/kernel.def
Kernel/platform-cromemco/main.c
Kernel/platform-cromemco/tricks.s

index 2e8ab09..6a6a87b 100644 (file)
@@ -2,7 +2,7 @@
 CSRCS = devtty.c devfd.c
 CSRCS += devices.c main.c
 
-ASRCS = crt0.s cromemco.s
+ASRCS = crt0.s cromemco.s usermem.s
 ASRCS += tricks.s commonmem.s
 
 AOBJS = $(ASRCS:.s=.rel)
@@ -10,7 +10,7 @@ COBJS = $(CSRCS:.c=.rel)
 
 OBJS  = $(AOBJS) $(COBJS)
 
-JUNK = *.rel *.lst *.asm *.sym *.rst
+
 
 all:   $(OBJS)
 
@@ -21,7 +21,10 @@ $(COBJS): %.rel: %.c
        $(CROSS_CC) $(CROSS_CCOPTS) -c $<
 
 clean:
-       rm -f $(OBJS) $(JUNK)  core *~ 
+       rm -f *.rel *.lst *.asm *.sym *.rst core *~
+       rm -f cloader-16fdc.ihx cloader-16fdc.tmp
+       rm -f cloader-16fdc.lk cloader-16fdc.bin
+       rm -f cloader-16fdc.map
 
 image:
        sdasz80 -o cloader-16fdc.s
index 7be076f..efad738 100644 (file)
@@ -1,6 +1,31 @@
 FUZIX on a Cromenco (no hard disk support right now - need docs for that and
 suitable emulation!)
 
+The mapping model is intended to be
+
+Bank 0         Kernel
+               0000-00FF, F200-FFFF are propogated into the other banks
+
+Bank 1-6       User
+               0000-00FF start with shared vectors
+                         FIXME: we need to clean this up in program_vectors
+                         from the kernel copy ????
+               0100-EFFF Application
+               F000-F111 Udata copy for this application
+               F200-FFFF common copy
+
+The kstack and istack exist in each bank. We'll normally only use the kernel
+one but there are cases we switch and borrow a bit of the other bank copy.
+It's easier to arrange this way anyhow.
+
+
+TODO
+-              Debug a loader
+-              An awful lot of early kernel boot debugging
+-              Interrupts properly (and IM2)
+
+
+
 We expect
 
 0              tuart / 4 FDC
index 285e5d5..06cf742 100644 (file)
-               .area ASEG(ABS)
-               .org  0x80
+       .area ASEG(ABS)
+       .org  0x80
 ;
-;      Loader for Fuzix on a Cromenco 16FDC
+;      We have 128 bytes and are loaded by the ROM at 0x0080. The rest is
+;      bascially our problem
 ;
-;      The kernel is written in blocks 1+ SS/SD with no magic
-;      involved. We have 128 bytes, but fortunately a ROM helper
+;      Load sectors 2-26 ( a whopping 3.2K )
 ;
+;      Assumes an 8" disk in SD mode
 ;
-;      Memory map
-;      0x0000-0x002E   Stack
-;      0x0060-0x007F   Used by the boot ROM
-;      0x0080-0x00FF   This boot block
-;      0x0100-0xBFFF   Free RAM
-;      0xC000-0xCFFF   Boot ROM (until we out to 0x40)
-;      0xD000-0xFFFF   May be RAM but may also be ROM shadows
-;
+       ld a,#1
+       out (0x40),a            ; ROM off
+
+       ld hl,#go
+       call strout
+
+restart:
+       ld bc,#0x020F           ; sector 2 , restore
+       ld de,#0x3100           ; D 8", A drive motor on E track
+
+       ld hl,#0x0100
+       ld a,#0x7f
+       out (0x04),a            ; Side 0
+
+       ld a,d                  ; set up drive
+       out (0x34),a
+
+       ld a,c
+
+movecmd:
+       out (0x30),a            ; now doing a restore at lowest speed
 
-set_side       .equ    0xC003
-set_track      .equ    0xC006
-set_sector     .equ    0xC009
-set_buffer     .equ    0xC00C
-disk_restore   .equ    0xC00F
-disk_seek      .equ    0xC012
-disk_read      .equ    0xC015
-disk_write     .equ    0xC018
-setup_uart     .equ    0xC01B
-char_input     .equ    0xC01E
-char_ready     .equ    0xC021
-line_input     .equ    0xC024
-char_output    .equ    0xC027
-newline_output .equ    0xC02A
-
-       .globl start
-       .globl endc
-       .globl end
-       .globl msg
-;      Carry set, drive in A
-start:
-       push af
-       ld hl,#boot
-       call tout
-       ld hl,#0xFC
-       pop af
-       ld (hl),a       ; boot drive
-       inc hl
-       ld a,#16
-       ld (hl),a       ; controller type (16FDC)
-       inc hl
-       ld bc,(0x7E)    ; features and feature save for boot disk
-       ld (hl),c
-       inc hl
-       ld (hl),b
-       inc hl          ; now 0x100
        xor a
-       ld b,a
-       call set_side
-       ld a,(0x6E)     ; sectors per track
-       inc a
-       ld c,a
-       ld a,#1         ; sector 2
-       ld de,#128
-trackloop:
-       push af
+wait:  dec a
+       jr nz,wait
+
+wait2: in a,(0x34)             ; when restore is done we are good
+       rra
+       jr nc, wait2
+
+       in a,(0x30)
+       and #0x98
+       jr nz, restart
+
+       ; Ok drive is up and running
+
        ld a,b
-       call set_track
-       pop af
-secloop:
-       inc a
-       call set_sector
-       call set_buffer
-       ex af,af'       ; shorter than pushing them
-       exx
-       call disk_seek
-       call disk_read
-       jr c, crap
-       exx
-       add hl,de
-       ld a,h
-       cp #0xC0
-       jr z,go
-       ex af,af'
-       cp c
-       jr nz, secloop
-       inc b
-       xor a
-       jr trackloop
-go:
-       ld a,(0x100)
-       cp #0xC3
-       jr z, 0x100
-crap:
-       ld hl, #fail
-       call tout
-       jp 0xC000
-
-tout:
+       out (0x32),a            ; sector we want
+       ld a,d
+       or #0x80                ; autowait
+       out (0x34),a
+
+       ld c,#0x33
+       ld a,#0x9c              ; read multiple 128byte, head load delay
+       out (0x30),a            ; load heads and read
+
+       ; autowait means we don't poll the ready bit
+eoj:
+       in a,(0x34)
+       rra
+       jr c, trackend
+       ini
+       jp eoj
+trackend:
+       ;
+       ; FIXME: now step in until we hit track 19 (63000 bytes)
+       ;
+       in a,(0x30)
+       bit 4,a
+       jr z,restart
+
+       ld a,d
+       out (0x34),a            ; turn off autowait
+
+       inc e
+       ld a,#19
+       cp e
+       jr z, run
+
+       ld a,#'.'               ; We know that one byte per track will not
+       out (0),a               ; overrun!
+
+       ld b,#0x01              ; run from sector 1
+
+       ;
+       ; Step in a track
+       ;
+       ld a,#0x5F              ; step in with verify and update, slowest
+
+
+       jr movecmd
+
+strout:
+       in a,(0x0)
+       rla
+       jr nc,strout
        ld a,(hl)
-       inc hl
        or a
        ret z
-       push hl
-       call char_output
-       pop hl
-       jr tout
+       out (0),a
+       inc hl
+       jr strout
 
-msg:
-boot:  .asciz 'Boot'
-fail:  .ascii ' failed'
-       .byte 13,10,0
+go:    .ascii 'FUZIX LOADER'
+nl:    .db 13,10,0
 
-endc:
-       .org 0xF8
+       .ds 1
 
-       .ascii 'FZSSSD'
+run:
+       ld hl,#nl
+       call strout
 end:
+       ; and runs on into 0x100
index 842cd87..15be6e1 100644 (file)
@@ -20,8 +20,8 @@
 #define TICKSPERSEC 10      /* Ticks per second */
 #define PROGBASE    0x0000  /* also data base */
 #define PROGLOAD    0x0100  /* also data base */
-#define PROGTOP     0xED00  /* Top of program, base of U_DATA copy */
-#define PROC_SIZE   60   /* Memory needed per process */
+#define PROGTOP     0xF000  /* Top of program, base of U_DATA copy */
+#define PROC_SIZE   60     /* Memory needed per process */
 
 #define BOOT_TTY (512 + 1)/* Set this to default device for stdio, stderr */
                           /* In this case, the default is the first TTY device */
index 633cbd9..f598ed4 100644 (file)
 ;      Cromemco hardware support
 ;
 
-            .module cromemco
-
-            ; exported symbols
-            .globl init_early
-            .globl init_hardware
-            .globl _program_vectors
-           .globl platform_interrupt_all
-
-           .globl map_kernel
-           .globl map_process
-           .globl map_process_always
-           .globl map_kernel_di
-           .globl map_process_di
-           .globl map_process_always_di
-           .globl map_process_a
-           .globl map_save_kernel
-           .globl map_restore
-
-           .globl _platform_reboot
-
-           .globl _int_disabled
-
-            ; exported debugging tools
-            .globl _platform_monitor
-            .globl outchar
-
-            ; imported symbols
-            .globl _ramsize
-            .globl _procmem
-
-           .globl unix_syscall_entry
-            .globl null_handler
-           .globl nmi_handler
-            .globl interrupt_handler
-           .globl _doexit
-           .globl _inint
-           .globl kstack_top
-           .globl _panic
-           .globl _need_resched
-           .globl _ssig
-
-            .globl outcharhex
-            .globl outhl, outde, outbc
-            .globl outnewline
-            .globl outstring
-            .globl outstringhex
-
-            .include "kernel.def"
-            .include "../kernel.def"
+       .module cromemco
+
+       ; exported symbols
+       .globl init_early
+       .globl init_hardware
+       .globl _program_vectors
+       .globl platform_interrupt_all
+
+       .globl map_kernel_low
+       .globl map_save_low
+       .globl map_restore_low
+       .globl map_user_low
+       .globl map_page_low
+
+       .globl _platform_reboot
+
+       .globl _platform_doexec
+
+       .globl _int_disabled
+
+       ; exported debugging tools
+       .globl _platform_monitor
+       .globl outchar
+
+       ; imported symbols
+       .globl _ramsize
+       .globl _procmem
+
+       .globl s__COMMONMEM
+       .globl l__COMMONMEM
+
+       .globl unix_syscall_entry
+       .globl my_nmi_handler
+       .globl interrupt_handler
+       .globl _doexit
+       .globl _inint
+       .globl kstack_top
+       .globl istack_top
+       .globl istack_switched_sp
+       .globl _panic
+       .globl _need_resched
+       .globl _ssig
+
+       .globl outcharhex
+       .globl outhl, outde, outbc
+       .globl outnewline
+       .globl outstring
+       .globl outstringhex
+
+       .include "kernel.def"
+       .include "../kernel.def"
 
 ; -----------------------------------------------------------------------------
-; COMMON MEMORY BANK (0xF000 upwards)
+; COMMON MEMORY BANK (0xF200 upwards)
 ; -----------------------------------------------------------------------------
-            .area _COMMONMEM
+        .area _COMMONMEM
 
 _platform_reboot:
 _platform_monitor:
-           jr _platform_monitor
+       jr _platform_monitor
 platform_interrupt_all:
-           ret
+       ret
 
 _int_disabled:
-           .db 1
+       .db 1
 
 ; -----------------------------------------------------------------------------
-; KERNEL MEMORY BANK (below 0xF000, only accessible when the kernel is mapped)
+; KERNEL MEMORY BANK (only accessible when the kernel is mapped)
 ; -----------------------------------------------------------------------------
-            .area _CODE
+       .area _CODE
 
 init_early:
-           ld a,#0x81                  ; Every memory is in bank 7
-           out (0x40),a                ; MMU set
-           ld hl,#0xF000               ; Copy 4K to itself loading
-           ld d,h                      ; into into the other banks
-           ld e,l
-           ld b,#0x10
-           ld c,l
-           ldir
-           ld a,#0x01                  ; bank to the kernel bank
-           out (0x40),a
-            ret
+       ld a,#0x81              ; Every memory writeable, read kernel
+       out (0x40),a            ; MMU set
+
+       ; Write the stubs everywhere
+       ld hl,#stubs_low
+       ld de,#0x0000
+       ld bc,#0x67
+       ldir
+
+       ; And the common across all banks
+       ld hl,#s__COMMONMEM
+       ld d,h
+       ld e,l
+       ld bc,#l__COMMONMEM
+       ldir
+
+       ld a,#0x01              ; bank to the kernel bank
+       out (0x40),a
+        ret
 
 init_hardware:
-            ; set system RAM size
-            ld hl, #448
-            ld (_ramsize), hl
-            ld hl, #(448-64)           ; 64K for kernel
-            ld (_procmem), hl
-
-           ld a, #156                  ; ticks for 10Hz (9984uS per tick)
-           out (8), a                  ; 10Hz timer on
+        ; set system RAM size
+        ld hl, #448            ; Assuming fully loaded for now
+        ld (_ramsize), hl
+        ld hl, #(448-64)       ; 64K for kernel
+        ld (_procmem), hl
 
-            ; 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
+       ld a, #156              ; ticks for 10Hz (9984uS per tick)
+       out (8), a              ; 10Hz timer on
 
-;          ld a, #0xfe                 ; Use FEFF (currently free)
-;          ld i, a
-;            im 2 ; set CPU interrupt mode
-           im 1                        ; really should use a page and im2?
-            ret
+       im 1                    ; really should use a page and im2?
+        ret
 
 
 ;------------------------------------------------------------------------------
 ; COMMON MEMORY PROCEDURES FOLLOW
 
-            .area _COMMONMEM
+       .area _COMMONMEM
 
+;
+;      We switch in one go so we don't have these helpers. This means
+;      we need custom I/O wrappers and custom usercopy functions.
+;
+map_save_low:
+map_kernel_low:
+map_restore_low:
+map_user_low:
+map_page_low:
+       ret
 
 _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 0x38
-            ld hl, #interrupt_handler
-            ld (0x39), hl
-
-           ld a,#0xC3          ; JP
-            ; set restart vector for UZI system calls
-            ld (0x0030), a   ;  (rst 30h is unix function call vector)
-           ld (0x0038), a   ;  (rst 38h)
-            ld hl, #unix_syscall_entry
-            ld (0x0031), hl
-
-            ; now install the interrupt vector at 0x38
-            ld hl, #interrupt_handler
-            ld (0x39), 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
-
-           ; falls through
-
-            ; put the paging back as it was -- we're in kernel mode so this is predictable
-map_kernel:
-map_kernel_di:
-           push af
-           ld a,#1
-           out (0x40), a
-           ld (map_page), a    ; map_page lives in kernel so be careful
-           pop af              ; our common is r/o common so writes won't
-            ret                        ; cross a bank
-map_process:
-map_process_di:
-           ld a, h
-           or l
-           jr z, map_kernel
-           ld a, (hl)
-map_process_a:
-           ld (map_page),a     ; save before we map out kernel
-           out (0x40), a
-            ret
-map_process_always:
-map_process_always_di:
-           push af
-           ld a, (U_DATA__U_PAGE)
-           ld (map_page),a     ; save before we map out kernel
-           out (0x40), a
-           pop af
-           ret
-map_save_kernel:
-           push af             ; map_save will always do a map_kernel
-           ld a, #1            ; map_kernel so we do the map_kernel
-           out (0x40), a       ; first so we can get the variables
-           ld a, (map_page)    ;
-           ld (map_store), a
-           pop af
-           ret     
-map_restore:                   ; called in kernel map
-           push af
-           ld a, (map_store)
-           ld (map_page),a
-           out (0x40), a
-           pop af
-           ret     
-map_store:
-           .db 0
-map_page:
-           .db 0
+       ret
 
 ; outchar: Wait for UART TX idle, then print the char in A
 ; destroys: AF
 outchar:
-           push af
+       push af
 outcharl:
-           in a, (0x00)
-           bit 7,a
-           jr z, outcharl
-           pop af
-           out (0x01), a
-            ret
+       in a, (0x00)
+       bit 7,a
+       jr z, outcharl
+       pop af
+       out (0x01), a
+        ret
 
 ;
 ;      Low level pieces for floppy driver
 ;
-               .globl _fd_reset
-               .globl _fd_seek
-               .globl _fd_operation
-               .globl _fd_map
-               .globl _fd_cmd
+       .globl _fd_reset
+       .globl _fd_seek
+       .globl _fd_operation
+       .globl _fd_map
+       .globl _fd_cmd
 
 ;
 ;      On entry c holds the bits from 0x34, bde must be preserved
@@ -285,13 +208,6 @@ nodisk:
 ;
 ;
 _fd_operation:
-       ;
-       ;       We run in common. Map the kernel or user according to the
-       ;       destination of the transfer
-       ;
-       ld      a, (_fd_map)
-       or      a
-       call    nz, map_process_always
        ;
        ;       Set up the registers in order. The aux register is already
        ;       done by our caller
@@ -347,9 +263,22 @@ nomod:
 issue_command:
        ld      hl,(_fd_cmd+3)          ; buffer
        ld      c,#0x33                 ; data port
-       ld      a,b
+       ld      e,b                     ; save command code
+       di
+
+       ;       If need be flip bank. Remember this also switches stack copy
+       ld      a,(_fd_map)
+       or      a
+       jr      nz, cmdout
+
+       out     (0x40),a                ; switch bank and stack copy
+cmdout:
+       ld      a,e
        out     (0x30),a                ; issue the command
+       ld      a,(_fd_map)
+
 
+       ;       FIXME: mappings
        ;
        ;       For now we only do double density (256 words per sector)
        ;
@@ -375,17 +304,24 @@ patch2:   outi                            ; second byte out
        ;       The transfer is done - wait for EOJ
        ;
 fd_waiteoj:
+       ;
+       ;       Memory and stack back
+       ;
+       ld      a,#1
+       out     (0x40),a                ; kernel map back
+fd_waiteoj_l:
        ei
        in      a,(0x34)
        rra
-       jr      nc, fd_waiteoj
+       jr      nc, fd_waiteoj_l
        ;
        ;       Job complete. Turn off autowait and recover
        ;       the status byte
        ;
 fd_done:
+       ld      a,#1
+       out     (0x40),a                ; kernel map back
        ei
-       call    map_kernel
        ld      a,d                     ; 0x34 bits
        and     #0x7F
        out     (0x34),a                ; autowait off
@@ -477,3 +413,280 @@ delayhl3:
        pop     bc                      ; 10
        ret                             ; 10
 
+;
+; Don't be tempted to put the symbol in the code below ..it's relocated
+; to zero. Instead define where it ends up.
+;
+
+_platform_doexec       .equ    0x18
+
+        .area _DISCARD
+
+       .globl rst38
+       .globl stubs_low
+;
+;      This exists at the bottom of each bank. We move these into place
+;      from discard.
+;
+stubs_low:
+       .byte 0xC3
+       .word 0         ; cp/m emu changes this
+       .byte 0         ; cp/m emu I/O byte
+       .byte 0         ; cp/m emu drive and user
+       jp 0            ; cp/m emu bdos entry point
+rst8:
+       ret
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+rst10:
+       ret
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+rst18:
+       ; Activate the user bank (which also holds these bytes)
+       ld a,(U_DATA__U_PAGE)
+       out (0x40),a
+       ei
+       ; and leap into user space
+       jp (hl)
+       nop
+       nop
+rst20: ret
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+rst28: ret
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+rst30: jp syscall_high
+       nop
+       nop
+       nop
+       nop
+       nop
+;
+;      We only have 38-4F available for this in low space
+;
+rst38: jp interrupt_high               ; Interrupt handling stub
+       nop
+       nop
+       nop
+       nop
+       nop
+       .ds 0x26
+my_nmi_handler:                ; Should be at 0x66
+       retn
+
+;
+;      This stuff needs to live somewhere, anywhere out of the way (so we
+;      use common). We need to copy it to the same address on both banks
+;      so place it in common as we will put common into both banks
+;
+
+       .area _COMMONMEM
+
+       .globl ldir_to_user
+       .globl ldir_from_user
+       .globl ldir_far
+;
+;      This needs some properly optimized versions!
+;
+ldir_to_user:
+       ld de,(U_DATA__U_PAGE)  ; will load with 0 e with page
+       inc d                   ; Kernel is in #1
+ldir_far:
+       push bc
+       ld c,#0x40
+       exx
+       pop bc                  ; get BC into alt bank
+far_ldir_1:
+       exx
+       out (c),d                       ; Select source
+       ld a,(hl)
+       inc hl
+       out (c),e                       ; Select target
+       ld (ix),a
+       inc ix
+       exx
+       dec bc
+       ld a,b
+       or c
+       jr nz, far_ldir_1
+       ld a,#1
+       out (0x40),a            ; Select kernel
+       ret
+ldir_from_user:
+       ld a,(U_DATA__U_PAGE)
+       ld e,#1
+       ld d,a
+       jr ldir_far
+;
+;      High stubs. Present in each bank in the top 256 bytes
+;      of the available space (remembering F000-FFFF is not available
+;      for general usage but is ok for reading)
+;
+interrupt_high:
+       push af
+       push de
+       push hl
+       ex af,af'
+       push af
+       push bc
+       exx
+       push bc
+       push de
+       push hl
+       push ix
+       push iy
+       in a,(0x40)             ; bank register is thankfully R/W
+       ld c,a
+       ld a,#0x01
+       out (0x40),a            ; Kernel map
+       ld (istack_switched_sp),sp      ; istack is positioned to be valid
+       ld sp,#istack_top               ; in both banks. We just have to
+       ;
+       ;       interrupt_handler may come back on a different stack in
+       ;       which case bc is junk. Fortuntely we never pre-empt in
+       ;       kernel so the case we care about bc is always safe. This is
+       ;       not a good way to write code and should be fixed! FIXME
+       ;
+       push bc
+       call interrupt_handler  ; switch on the right SP
+       pop bc
+       ; Restore stack pointer to user. This leaves us with an invalid
+       ; stack pointer if called from user but interrupts are off anyway
+       ld sp,(istack_switched_sp)
+       ; On return HL = signal vector E= signal (if any) A = page for
+       ; high
+       or a
+       jr z, kernout
+       ; Returning to user space
+       out (0x40),a            ; page passed back
+       ; User stack is now valid
+       ; back on user stack
+       xor a
+       cp e
+       call nz, sigpath
+pops:
+       ex af,af'
+       exx
+       pop iy
+       pop ix
+       pop hl
+       pop de
+       pop bc
+       exx
+       pop bc
+       pop af
+       ex af,af'
+       pop hl
+       pop de
+       pop af
+       ei
+       ret
+kernout:
+       ; restore bank - if we interrupt mid user copy or similar we
+       ; have to put the right bank back
+       ld a,c
+       out (0x40),a
+       jr pops
+
+sigpath:
+       push de         ; signal number
+       ld de,#irqsigret
+       push de         ; clean up
+       jp (hl)
+irqsigret:
+       inc sp          ; drop signal number
+       inc sp
+       ret
+
+syscall_high:
+       push ix
+       ld ix,#0
+       add ix,sp
+       push de         ; the syscall if must preserve de for now
+                       ; needs fixing when we change the syscall
+                               ; API for Z80 to something less sucky
+       ld a,4(ix)
+       ld c,6(ix)
+       ld b,7(ix)
+       ld e,8(ix)
+       ld d,9(ix)
+       ld l,10(ix)
+       ld h,11(ix)
+       push hl
+       ld l,12(ix)
+       ld h,13(ix)
+       pop ix
+       di
+       ; FIXME: corrupts af' - probably will define af' and some other '
+       ; registers as non-save in API change anyway
+       ex af, af'      ; Ick - find a better way to do this bit !
+       ld a,#1         ; Kernel
+       out (0x40),a
+       ex af,af'
+       ; Stack now invalid
+       ld (U_DATA__U_SYSCALL_SP),sp
+       ld sp,#kstack_top
+       call unix_syscall_entry
+       ; FIXME check di rules
+       ; stack now invalid. Grab the new sp before we unbank the
+       ; memory holding it
+       ld sp,(U_DATA__U_SYSCALL_SP)
+       ld a, (U_DATA__U_PAGE)  ; back to the user page
+       out (0x40),a
+       xor a
+       cp h
+       call nz, syscall_sigret
+       ; FIXME for now do the grungy C flag HL DE stuff from
+       ; lowlevel-z80 until we fix the ABI
+       ld bc,#0
+       ld a,h
+       or l
+       jr nz, error
+       ex de,hl
+       pop de
+       pop ix
+       ei
+       ret
+error: scf
+       pop de
+       pop ix
+       ei
+       ret
+syscall_sigret:
+       ld a,l          ; DEBUG
+       push hl         ; save errno
+       push de         ; save retval
+       ld l,h
+       ld h,#0
+       push hl         ; signal
+       ld hl,#syscall_sighelp
+       push hl         ; vector
+       ret
+syscall_sighelp:
+       pop de          ; discard signal
+       pop de          ; recover error info
+       pop hl
+       ld h,#0         ; clear signal bit
+       ret
index 027a303..1df55fb 100644 (file)
@@ -44,15 +44,24 @@ init:
         ; Configure memory map
         call init_early
 
-       ; move the common memory where it belongs    
+       ld a,#0x81              ; Every memory writeable, read kernel
+       out (0x40),a            ; MMU set
+
+       ; move the common memory where it belongs in all banks
+
        ld hl, #s__DATA
        ld de, #s__COMMONMEM
        ld bc, #l__COMMONMEM
        ldir
-       ; and the discard
+
+       ld a,#0x01              ; Kernel mapping only
+       out (0x40),a            ; MMU set
+
+       ; and the discard to the kernel
        ld de, #s__DISCARD
        ld bc, #l__DISCARD
        ldir
+
        ; then zero the data area
        ld hl, #s__DATA
        ld de, #s__DATA + 1
index 886a5e1..c1e5e7c 100644 (file)
@@ -1,7 +1,7 @@
 -mwxuy
 -i fuzix.ihx
 -b _CODE=0x0100
--b _COMMONMEM=0xF000
+-b _COMMONMEM=0xF200
 -b _DISCARD=0xE000
 -l z80
 platform-cromemco/crt0.rel
@@ -10,12 +10,12 @@ platform-cromemco/cromemco.rel
 platform-cromemco/main.rel
 start.rel
 version.rel
-lowlevel-z80.rel
-usermem_std-z80.rel
+lowlevel-z80-thunked.rel
 platform-cromemco/tricks.rel
 timer.rel
 kdata.rel
 usermem.rel
+platform-cromemco/usermem.rel
 platform-cromemco/devfd.rel
 platform-cromemco/devices.rel
 devio.rel
index f3a5687..def2cec 100644 (file)
@@ -1,9 +1,9 @@
 ; 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_DATA                      .equ 0xF200       ; (this is struct u_data from kernel.h)
+U_DATA__TOTALSIZE           .equ 0x200        ; 256+256 bytes
 
-U_DATA_STASH               .equ 0xED00       ; ED00-EFFF
+U_DATA_STASH               .equ 0xF000       ; F000-F200
 
 PROGBASE                   .equ 0x0000
 PROGLOAD                   .equ 0x0100
@@ -12,5 +12,12 @@ Z80_TYPE                 .equ 1
 
 Z80_MMU_HOOKS              .equ 0
 
-
 CONFIG_SWAP                .equ 0
+
+;
+;      Select where to put the high code - in our case we need this
+;      in _COMMONMEM
+;
+.macro HIGH
+               .area _COMMONMEM
+.endm
index 8f83fac..5952c42 100644 (file)
@@ -6,6 +6,7 @@ uaddr_t ramtop = PROGTOP;
 void pagemap_init(void)
 {
  int i;
+ /* 1 << 0 is kernel */
  for (i = 1; i < 7; i++)
   pagemap_add(1 << i);
 }
index ee50c07..47bc2da 100644 (file)
@@ -2,4 +2,307 @@
        .include "../kernel.def"
        .include "kernel.def"
 
-       .include "../lib/z80fixedbank.s"
+       ;
+       ; We can't quite use the standard helpers as we have rather weird
+       ; memory mapping logic
+       ;
+        .module cromemcotricks
+
+        .globl _ptab_alloc
+        .globl _makeproc
+        .globl _chksigs
+        .globl _getproc
+        .globl _platform_monitor
+        .globl _platform_switchout
+        .globl _switchin
+        .globl _doexec
+        .globl _dofork
+        .globl _runticks
+        .globl unix_syscall_entry
+        .globl interrupt_handler
+       .globl _need_resched
+       .globl _nready
+       .globl _platform_idle
+       .globl _int_disabled
+       .globl _udata
+
+       .globl ldir_to_user
+       .globl ldir_from_user
+       .globl ldir_far
+
+        ; imported debug symbols
+        .globl outstring, outde, outhl, outbc, outnewline, outchar, outcharhex
+
+        .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().
+; 
+; This function can have no arguments or auto variables.
+;
+_platform_switchout:
+        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
+
+       ; Stash the uarea back into process memory
+       ld hl, #U_DATA
+       ld ix, #U_DATA_STASH
+       ld bc, #U_DATA__TOTALSIZE
+       ; Slow - must be a more elegant way to tackle this ! FIXME
+       call ldir_to_user
+
+        ; find another process to run (may select this one again)
+        call _getproc
+
+        push hl
+        call _switchin
+
+        ; we should never get here
+        call _platform_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
+
+        ld hl, #P_TAB__P_PAGE_OFFSET
+       add hl, de      ; process ptr
+
+.ifne CONFIG_SWAP
+       .globl _swapper
+       ;
+       ;       Always use the swapstack, otherwise when we call map_kernel
+       ;       having copied the udata stash back to udata we will crap
+       ;       somewhere up the stackframe and it's then down to luck
+       ;       if those bytes are discarded or not.
+       ;
+       ;       Yes - this was a bitch to debug, please don't break it !
+       ;
+       ld sp, #_swapstack
+
+        ld a, (hl)
+
+       or a
+       jr nz, not_swapped
+
+       ;
+       ;       Re-enable interrupts while we swap. This is ok because
+       ;       we are not on the IRQ stack when switchin is invoked.
+       ;
+       ;       There are two basic cases
+       ;       #1: pre-emption. Not in a system call, must avoid
+       ;       re-entering pre-emption logic, Z80 lowlevel code sets U_INSYS
+       ;       #2: kernel syscall. Also protected by U_DATA__U_INSYS
+       ;
+       ei
+       xor a
+       ld (_int_disabled),a
+       push hl
+       push de
+       call _swapper
+       pop de
+       pop hl
+       ld a,#1
+       ld (_int_disabled),a
+       di
+.endif
+       ld a, (hl)
+not_swapped:
+       ; We need the swap stack anyway or we run out of registers
+       ld sp, #_swapstack
+
+       ld hl, (U_DATA__U_PTAB)
+       or a
+       sbc hl, de
+       jr z, skip_copyback     ; Tormod's optimisation: don't copy the
+                               ; the stash back if we are the task who
+                               ; last owned the real udata
+
+        ; bear in mind that the stack will be switched now, so we can't use it
+       ; to carry values over this point
+
+       push de
+
+       ld hl, #U_DATA_STASH
+       ld de, #U_DATA
+       ld bc, #U_DATA__TOTALSIZE
+       call ldir_to_user
+
+       pop de
+
+       ; In the non swap case we must set so before we use the stack
+       ; otherwise we risk corrupting the restored stack frame
+        ld sp, (U_DATA__U_SP)
+
+        ; 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==HL
+        jr nz, switchinfail
+
+skip_copyback:
+       ; 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 one byte as that is all we use on this platform
+       ld a, P_TAB__P_PAGE_OFFSET(ix)
+       ld (U_DATA__U_PAGE), a
+        ; 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 we didn't pre-empt in an ISR
+        ld a, (U_DATA__U_ININTERRUPT)
+       ld (_int_disabled),a
+        or a
+        ret nz ; Not an 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 _platform_monitor
+
+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.
+
+       ;
+       ; FIXME: we should no longer need interrupts off for most of a
+       ; fork() call.
+       ;
+        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)
+       ; load existing page ptr
+       ld a, (U_DATA__U_PAGE)
+
+       push bc
+       call bankfork                   ;       do the bank to bank copy
+       pop bc
+
+       ; Copy done
+
+       ; 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 hl, #U_DATA          ; copy the udata from common into the
+       ld de, #U_DATA_STASH    ; target process
+       ld bc, #U_DATA__TOTALSIZE
+
+       call ldir_to_user
+
+        ; 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,#_udata
+       push hl
+        ld  hl, (fork_proc_ptr)
+        push hl
+        call _makeproc
+        pop bc 
+       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
+
+       .area _COMMONMEM
+;
+;      We can keep a stack because we don't have enough registers
+;      to do all the bank trickery we need
+;
+       .ds 256
+_swapstack:
+_need_resched: .db 0
+
+       ;
+       ;       FIXME: optimize ldir_far. or maybe add an ldir_far_aligned
+       ;       This one is really hard to do at a sensible speed
+       ;
+bankfork:
+       ld d,c                  ; source
+       ld e,a                  ; dest
+       ld hl,#0x0000
+       ld ix,#0x0000
+       ld bc,#0xF000
+       call ldir_far
+       ret