trs80: bring things up to the bootdev prompt
authorAlan Cox <alan@linux.intel.com>
Thu, 18 Dec 2014 11:56:39 +0000 (11:56 +0000)
committerAlan Cox <alan@linux.intel.com>
Thu, 18 Dec 2014 11:56:39 +0000 (11:56 +0000)
Somewhat of a redesign of the original guesswork.

Kernel/platform-trs80/README
Kernel/platform-trs80/config.h
Kernel/platform-trs80/crt0.s
Kernel/platform-trs80/devtty.c
Kernel/platform-trs80/kernel.def
Kernel/platform-trs80/main.c
Kernel/platform-trs80/tricks.s
Kernel/platform-trs80/trs80.s
Kernel/platform-trs80/trs80load.s
Kernel/platform-trs80/uzi.lnk

index 541ce48..ca8c5cd 100644 (file)
@@ -1,53 +1,75 @@
 TRS80 Model 4/4P
+(or right now more accurately sdltrs/xtrs)
+
+Emulator Bugs:
+       The emulator is horribly insecure, it's default is to allow all
+       sorts of direct access to things. Even if you turn this off I've
+       had it segfault with FUZIX bugs which suggests its not too secure.
+
+       Repeating instructions like LDIR appear to be misemulated. LDIR
+       is performed an emulated block copy, not as an iterated LDI. The
+       real processor actually implements LDIR as  "LDI, if not done
+       PC -= 2". FUZIX doesn't do any overlapped LDIR tricks so shouldn't
+       be affected.
 
 Requirements: 
        128K RAM fitted
        Hard disk drive (will be used for swap), or a suitable memory
        expander board could be used with a bit of tweaking (or both!)
 
-Bank mapping on the trash 80 is a bit weird. We want to get two independent
-64K banks, but we can only have
-
-Port 0x84:
-       
-
-       0 / 1
-       0 / 2
-       0 / 3
-       2 / 1
-       3 / 1
-
-So we put the kernel in 0/3 which allows us to put the apps in 2/1. This
-means we need our kernel logic for things like bank copies not in common
-but in the low 32K.
-
-
-Unfortunately for anyone who wants to do expander board hacks the usual
-expander board hacks exchange 2/3 with other banks so unless you've also got
-the HD64180 mod you may be out of luck, and if you have well its not much
-like a Trash80 any more. Anyway if you want try you'd need to extend the
-0x84 port poking to also poke port 0x94 bits 0-4.
-
-Also we have to deal with the mapping maze on the TRS 80, not only are we
-banked but we have modes and also a pop up boot rom
-
-0x9C bit 0 controls the boot prom
-
-0x80 controls the mapping mode (bits 0/1 select a mode)
-
-Boot occurs in mode 0 with RAM at 0x4000-FFFF ready to load
-
-We need to stick it into mode 2 or 3
-
-2 = 0000-F3FF RAM
-    F400-F7FF keyboard
-    F800-FFFF Video
-
-3 = 0-FFFF RAM
-
-(and probably want to be in mode 3 and flip to 2 for video/kbd work)
-
-Need vid and kbd helps out of common therefore and to save/restore video map
-option on an irq while in kernel mode
-
+Memory Map:
+       Base memory 0-FFFF (with a fair bit of slack) is used for the kernel
+       User processes run 0-7FFF in bank U64L32 or U64U32, in both cases
+       with the upper 32K being kept as the kernel bank.
+
+       It would be good to support 64K processes using the bank32 model.
+       Before that can be done however the TRS80 will need a custom
+       user copy function to deal with access to the upper 32K by mapping
+       it low instead. It will also need the location of the uarea stash to
+       be binary size dependent. Swapper write out is also fairly hairy
+       for the same reasons. So for now we just handle a pair of 32K
+       processes.
+
+       Processes that don't fit are swapped to hard disk. Without swap you
+       can run a pair of 32K processes, just enough for stuff like
+       bootstrap.
+
+Drivers:
+       80 column display is done
+       Keyboard is not started
+       Floppy and Hard disk are fleshed out but not yet tested (need kbd
+       first)
+       Hard disk needs to read block 0, and handle partitions of some form
+       including finding where 'swap' lives
+
+Adding Support For Other Banked RAM:
+       See trs80.s, and the various map_* functions. These can be extended
+       to use U_DATA__U_PAGE+1 to carry a second byte of data. The
+       main.c for the platform sets up the pagemaps as a 16bit value
+       which currently is just the opreg bits for the two banks.
+
+       map_save/restore will also need to handle any sub banking
+       arrangement.
+
+       Finally up MAX_BANKS in platform/config.h accordingly.
+
+
+Setting It Up
+
+       # Tool to make disk images
+       make tools/makejv3
+       # Double density single sided 40 track boot disk
+       tools/makejv3 dd40s /dev/zero mydisk.jv3
+       # Build boot block (not yet converted to sdasz80)
+       zmac platform/z80boot.s
+       # Build kernel (edit Makefile, set target then)
+       make
+       # Add pieces to the disk (boot block in sector 0, kernel at end)
+       dd if=zout/trs80load.cim of=mydisk.jv3 bs=1 seek=8704 conv=notrunc
+       dd if=fuzix.bin of=mydisk.jv3 bs=1 seek=142336 conv=notrunc
+       # Once we get that far you can also put a filesystem in the lower
+       # blocks
+       #
+       sdltrs -emtsafe -disk0 mydisk.jv3 -model 4p
+       #
 
index 8f12ccd..16c6847 100644 (file)
@@ -5,13 +5,17 @@
 /* Profil syscall support (not yet complete) */
 #define CONFIG_PROFIL
 /* Multiple processes in memory at once */
-#undef CONFIG_MULTI
+#define CONFIG_MULTI
 /* Single tasking */
-#define CONFIG_SINGLETASK
+#undef CONFIG_SINGLETASK
 /* Video terminal, not a serial tty */
 #define CONFIG_VT
 /* Simple character addressed device */
 #define CONFIG_VT_SIMPLE
+/* Banked memory set up */
+#define CONFIG_BANK_FIXED
+#define MAX_MAPS       2
+#define MAP_SIZE       0x8000
 
 #define CONFIG_BANKS   2       /* 2 x 32K */
 
 #define TICKSPERSEC 60   /* Ticks per second */
 #define PROGBASE    0x0000  /* Base of user  */
 #define PROGLOAD    0x0100  /* Load and run here */
-#define PROGTOP     0xEA00  /* Top of program, base of U_DATA */
-#define PROC_SIZE   64   /* Memory needed per process */
+#define PROGTOP     0x7D00  /* Top of program, base of U_DATA */
+#define PROC_SIZE   32             /* Memory needed per process */
 
-#define SWAP_SIZE   0x80       /* 64K in blocks (we actually don't need quite all) */
+#define SWAP_SIZE   0x40       /* 32K in blocks */
 #define SWAPBASE    0x0000     /* We swap the lot in one, include the */
-#define SWAPTOP            0xF400      /* vectors so its a round number of sectors */
+#define SWAPTOP            0x8000      /* vectors so its a round number of sectors */
 
-#define MAX_SWAPS            /* Should be plenty */
+#define MAX_SWAPS      16      /* Should be plenty */
 
 #define BOOT_TTY (512 + 1)      /* Set this to default device for stdio, stderr */
                           /* In this case, the default is the first TTY device */
 /* Device parameters */
 #define NUM_DEV_TTY 3
 #define TTYDEV   BOOT_TTY /* Device used by kernel for messages, panics */
-#define SWAPDEV  5       /* Device for swapping. */
+#define SWAPDEV  (258)   /* Device for swapping (2nd hd). */
 #define NBUFS    10       /* Number of block buffers */
 #define NMOUNTS         4        /* Number of mounts at a time */
 
-
-
-
-
index f58837e..18fab50 100644 (file)
@@ -45,6 +45,7 @@ start:
                ld de, #s__COMMONMEM
                ld bc, #l__COMMONMEM
                ldir
+               ; then the discard
                ld de, #s__DISCARD
                ld bc, #l__DISCARD
                ldir
@@ -65,22 +66,3 @@ start:
                di
 stop:          halt
                jr stop
-
-
-
-
-clear:
-               ld a, b
-               or a
-               jr nz, clear_1
-               ld a, c
-               cp #2
-               ret c
-clear_1:
-               dec bc
-               ld (hl), #0
-               ld d, h
-               ld e, l
-               inc de
-               ldir
-               ret
index f0dbb44..b5a39a4 100644 (file)
@@ -3,6 +3,7 @@
 #include <printf.h>
 #include <stdbool.h>
 #include <tty.h>
+#include <vt.h>
 #include <devtty.h>
 #include <stdarg.h>
 
@@ -31,8 +32,8 @@ static bool tty_writeready(uint8_t minor)
 
 void tty_putc(uint8_t minor, unsigned char c)
 {
-    minor;c;
-    /* call vt driver */
+    if (minor == 1)
+        vtoutput(&c, 1);
 }
 
 void tty_pollirq(void)
index 923c2e7..66d1dcb 100644 (file)
@@ -3,4 +3,6 @@
 U_DATA                      .equ 0xEA00       ; (this is struct u_data from kernel.h)
 U_DATA__TOTALSIZE           .equ 0x300        ; 256+256+256 bytes.
 
+U_DATA_STASH               .equ 0x7D00       ; BD00-BFFF
+
 NMOS_Z80                   .equ 1
index 1859ec1..45b6c82 100644 (file)
@@ -25,3 +25,9 @@ void platform_interrupt(void)
 void map_init(void)
 {
 }
+
+void pagemap_init(void)
+{
+ pagemap_add(0x63);    /* Mode 3, U64K low 32K mapped as low 32K */
+ pagemap_add(0x73);    /* Mode 3, U64K high 32K mapped as low 32K */
+}
index dbc775f..8360b5b 100644 (file)
@@ -1,5 +1,6 @@
-; 2013-12-21 William R Sowerbutts
-
+;
+;      This is heavily based on the Z80Pack platform code.
+;
         .module tricks
 
         .globl _ptab_alloc
         .globl interrupt_handler
         .globl dispatch_process_signal
        .globl _swapper
-       .globl _swapout
+
+       .globl map_kernel
+       .globl map_process
+       .globl map_process_a
+       .globl map_process_always
 
         ; imported debug symbols
         .globl outstring, outde, outhl, outbc, outnewline, outchar, outcharhex
@@ -32,8 +37,6 @@
 ; 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:
@@ -53,6 +56,15 @@ _switchout:
         xor a
         ld (_inint), a
 
+       ; Stash the uarea back into process memory
+       ld hl, (U_DATA__U_PAGE)
+       call map_process_always
+       ld hl, #U_DATA
+       ld de, #U_DATA_STASH
+       ld bc, #U_DATA__TOTALSIZE
+       ldir
+       call map_kernel
+
         ; find another process to run (may select this one again)
         call _getproc
 
@@ -64,40 +76,73 @@ _switchout:
 
 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
 
+       call map_kernel
+
+       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:
+       ; Pages please !
+       call map_process_a
+
+        ; bear in mind that the stack will be switched now, so we can't use it
+       ; to carry values over this point
+
+       exx                     ; thank goodness for exx 8)
+       ld hl, #U_DATA_STASH
+       ld de, #U_DATA
+       ld bc, #U_DATA__TOTALSIZE
+       ldir
+       exx
+
+       call map_kernel
+
         ; 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
+        sbc hl, de              ; subtract, result will be zero if DE==IX
         jr nz, switchinfail
 
-       ld hl, #P_TAB__P_STATUS_OFFSET
-       add hl, de
+       ; wants optimising up a bit
+       ld ix, (U_DATA__U_PTAB)
         ; next_process->p_status = P_RUNNING
-        ld (hl), #P_RUNNING
-       ld de, #P_TAB__P_PAGE_OFFSET - P_TAB__P_STATUS_OFFSET
-       add hl, de
-       ld a, (hl)
-       ld (U_DATA__U_PAGE), a
+        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
@@ -105,6 +150,7 @@ not_swapped:
         ; 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
@@ -117,6 +163,7 @@ not_swapped:
         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
@@ -163,10 +210,38 @@ _dofork:
         ; now we're in a safe state for _switchin to return in the parent
        ; process.
 
-       ld hl, (U_DATA__U_PTAB)
-       push hl
-       call _swapout
-       pop hl
+       ; Need to write a new 47.25K bank copy here, then copy the live uarea
+       ; into the stash of the new 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
+       push af
+       ld a, c
+       call outcharhex
+       pop af
+       ld a, (U_DATA__U_PAGE)
+
+       call bankfork                   ;       do the bank to bank copy
+
+       ; Copy done
+
+       call map_process_always
+
+       ; 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
+       ldir
+       ; Return to the kernel mapping
+       call map_kernel
 
         ; now the copy operation is complete we can get rid of the stuff
         ; _switchin will be expecting from our copy of the stack.
@@ -190,3 +265,52 @@ _dofork:
        ; 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
+;
+;      Assumption - fits into a fixed number of whole 256 byte blocks
+;
+bankfork:
+;      ld bc, #(0xC000 - 768)          ;       48K minus the uarea stash
+
+       ld b, #0xBD             ; C0 x 256 minus 3 sets for the uarea stash
+       ld hl, #0               ; base of memory to fork (vectors included)
+bankfork_1:
+       push bc                 ; Save our counter and also child offset
+       push hl
+       call map_process_a
+       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
+       call map_process_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:
index 8607135..7a89759 100644 (file)
@@ -12,6 +12,7 @@
             .globl _system_tick_counter
            .globl map_kernel
            .globl map_process
+           .globl map_process_a
            .globl map_process_always
            .globl map_save
            .globl map_restore
            .globl fd_nmi_handler
            .globl null_handler
 
+           .globl s__COMMONMEM
+           .globl l__COMMONMEM
+
             .include "kernel.def"
             .include "../kernel.def"
 
 ; -----------------------------------------------------------------------------
-; COMMON MEMORY BANK (0xF000 upwards)
+; COMMON MEMORY BANK (0xEA00 upwards)
 ; -----------------------------------------------------------------------------
             .area _COMMONMEM
 
@@ -62,7 +66,7 @@ _trap_reboot:
            out (0x28), a
 
 ; -----------------------------------------------------------------------------
-; KERNEL MEMORY BANK (below 0xF000, only accessible when the kernel is mapped)
+; KERNEL MEMORY BANK (below 0xEA00, only accessible when the kernel is mapped)
 ; -----------------------------------------------------------------------------
             .area _CODE
 
@@ -76,7 +80,7 @@ init_early:
 
             ; load the 6845 parameters
            ld hl, #_ctc6845
-           ld b, #1588
+           ld bc, #1588
 ctcloop:    out (c), b                 ; register
            ld a, (hl)
            out (0x89), a               ; data
@@ -117,8 +121,8 @@ init_hardware:
 
             .area _COMMONMEM
 
-opsave:            .db 0x36
-_opreg:            .db 0x36    ; kernel map, 80 columns
+opsave:            .db 0x06
+_opreg:            .db 0x06    ; kernel map, 80 columns
 _modout:    .db 0x50   ; 80 column, sound enabled, altchars off,
                        ; external I/O enabled, 4MHz
 _kernel_flag:
@@ -162,27 +166,20 @@ _program_vectors:
             ld (0x0067), hl
 
 ;
-;      Fixed mapping set up for the TRS80 4/4P
+;      Mapping set up for the TRS80 4/4P
 ;
-;      Kernel runs mode 2, U64K/U32 mapped at L64K/U32
+;      The top 32K bank holds kernel code and pieces of common memory
+;      The lower 32K is switched between the various user banks. On a
+;      4 or 4P without add in magic thats 0x62 and 0x63 mappings.
 ;
-map_kernel_a:
-           ld a, i
+map_kernel:
            push af
-           di
            ld a, (_opreg)
-           and #0xAC
-           or #0x12
+           and #0x8C           ; keep video bits
+           or #0x02            ; map 2, base memory
            ld (_opreg), a
            out (0x84), a
            pop af
-           ret po
-           ei
-            ret
-map_kernel:
-           push af
-           call map_kernel_a
-           pop af
            ret
 ;
 ;      Userspace mapping is mode 3, U64K/L32 mapped at L64K/L32
@@ -191,32 +188,37 @@ map_process:
            ld a, h
            or l
            jr z, map_kernel
-           call map_process_always_a
-           ret
+map_process_hl:
+           ld a, (_opreg)
+           and #0x8C
+           or (hl)             ; udata page
+           ld (_opreg), a
+           out (0x84), a
+            ret
 
-map_process_always_a:
+map_process_a:                 ; used by bankfork
            push af
+           push bc
+           ld b, a
            ld a, (_opreg)
-           and #0xAC
-           or #0x43
+           and #0x8C
+           or b
            ld (_opreg), a
            out (0x84), a
+           pop bc
            pop af
-            ret
+           ret
 
 map_process_always:
-           ld a, i
            push af
-           di
-           call map_process_always_a
+           ld hl, #U_DATA__U_PAGE
+           call map_process_hl
            pop af
-           ret po
-           ei
            ret
 
 map_save:   push af
            ld a, (_opreg)
-           and #0x53
+           and #0x73
            ld (opsave), a
            pop af
            ret
@@ -227,137 +229,16 @@ map_restore:
            ld a, (opsave)
            ld b, a
            ld a, (_opreg)
-           and #0xAC
+           and #0x8C
            or b
            ld (_opreg), a
            out (0x84), a
+           pop bc
+           pop af
            ret
            
 ; outchar: Wait for UART TX idle, then print the char in A
 ; destroys: AF
 outchar:
-            out (0x01), a
+;            out (0x01), a
             ret
-
-nap:
-       ; FIXME
-          ret
-;
-;      Idle the WD1772
-;
-_fd_idle:
-           in a, (0xF0)
-           rra
-           jr c, _fd_idle
-           ld l, a
-           ld h, #0
-           ret
-
-;
-;      See to a given track in C
-;
-_fd_seek:
-           ld a, c
-           out (0xF1), a               ; track #
-           ld a, #0x1B                 ; Seek
-           out (0xF0), a
-           call nap
-           call _fd_idle
-           and #0x10
-           ret
-
-
-;
-;      Write a 256 byte block to disk. Need to add precomp etc to this
-;      HL = pointer to data
-;      A = bank info (0 kernel, !0 user). We don't handle swap to floppy.
-;
-;
-_fd_write:
-           or a
-           jr z, _fd_kwrite
-           call map_process_always
-_fd_kwrite:
-           ld bc, #0x00F3              ; port F3, 256 bytes
-           ld a, i
-           push af
-           ld a, #0xAC                 ; Write
-           out (0xF0), a
-           call nap
-_fd_writel:
-           in a, (0xF0)
-           bit 1, a
-           jr z, _fd_writec
-           di
-_fd_writeb:
-           otir
-           ei
-           call _fd_idle
-           and #0x5C
-fd_wout:
-           ld l, a
-           call map_kernel
-           pop af
-           ret po
-           ei
-           ret
-_fd_writec: 
-           bit 2, a
-           jr nz, _fd_writel
-           ld a, #0xff
-           jr fd_wout
-
-
-
-;
-;      Read a 256 byte block from disk. Need to add precomp etc to this
-;      HL = pointer to data
-;      A = bank info (0 kernel, !0 user). We don't handle swap to floppy.
-;
-;
-_fd_read:
-           or a
-           jr z, _fd_kwrite
-           call map_process_always
-_fd_kread:
-           ld bc, #0x00F3              ; port F3, 256 bytes
-           ld a, i
-           push af
-           ld a, #0x8C                 ; Read
-           out (0xF0), a
-           call nap
-_fd_readl:
-           in a, (0xF0)
-           bit 1, a
-           jr z, _fd_readc
-           di
-_fd_readb:
-           inir
-           ei
-           call _fd_idle
-           and #0x5C
-fd_rout:
-           ld l, a
-           pop af
-           ret po
-           ei
-           ret
-_fd_readc: 
-           bit 2, a
-           jr nz, _fd_readl
-           ld a, #0xff
-           jr fd_rout
-
-_fdc_idle:
-       ; FIXME
-       ret
-;
-;      Restore the current drive to track 0 (error recovery)
-;
-_fd_reset:
-           ld a, #0xB
-           out (0xF0), a
-           call nap
-           call _fdc_idle
-           and #0x10
-           ret
index 5df52fc..aaa80b8 100644 (file)
@@ -3,7 +3,7 @@
 ;
            .org 0x0
 start:
-           ld a, 0x36                  ; kernel map, 80 column
+           ld a, 0x06                  ; kernel map, 80 column, no remap
            out (0x84), a
            ld a, 0x50                  ; 80 column, sound, altchars off,
                                        ; ext I/O on , 4MHz
@@ -106,7 +106,7 @@ nextsec:
            ld a, (secnum)
            inc a
            ld (secnum), a
-           cp 11
+           cp 19
            jr z, lastsec
            push hl
            call floppy_read
index 6baca8a..e8bfb0b 100644 (file)
@@ -32,7 +32,7 @@ syscall_other.rel
 tty.rel
 mm.rel
 swap.rel
-single.rel
+bankfixed.rel
 vt.rel
 devsys.rel
 platform-trs80/devlpr.rel