From: Alan Cox Date: Thu, 18 Dec 2014 11:56:39 +0000 (+0000) Subject: trs80: bring things up to the bootdev prompt X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=ea246562cfa51070aa88385612377d14f4d4c692;p=FUZIX.git trs80: bring things up to the bootdev prompt Somewhat of a redesign of the original guesswork. --- diff --git a/Kernel/platform-trs80/README b/Kernel/platform-trs80/README index 541ce48c..ca8c5cd3 100644 --- a/Kernel/platform-trs80/README +++ b/Kernel/platform-trs80/README @@ -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 + # diff --git a/Kernel/platform-trs80/config.h b/Kernel/platform-trs80/config.h index 8f12ccd5..16c6847e 100644 --- a/Kernel/platform-trs80/config.h +++ b/Kernel/platform-trs80/config.h @@ -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 */ @@ -25,14 +29,14 @@ #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 8 /* 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 */ @@ -43,11 +47,7 @@ /* 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 */ - - - - diff --git a/Kernel/platform-trs80/crt0.s b/Kernel/platform-trs80/crt0.s index f58837e1..18fab50f 100644 --- a/Kernel/platform-trs80/crt0.s +++ b/Kernel/platform-trs80/crt0.s @@ -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 diff --git a/Kernel/platform-trs80/devtty.c b/Kernel/platform-trs80/devtty.c index f0dbb444..b5a39a47 100644 --- a/Kernel/platform-trs80/devtty.c +++ b/Kernel/platform-trs80/devtty.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -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) diff --git a/Kernel/platform-trs80/kernel.def b/Kernel/platform-trs80/kernel.def index 923c2e7d..66d1dcb4 100644 --- a/Kernel/platform-trs80/kernel.def +++ b/Kernel/platform-trs80/kernel.def @@ -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 diff --git a/Kernel/platform-trs80/main.c b/Kernel/platform-trs80/main.c index 1859ec11..45b6c821 100644 --- a/Kernel/platform-trs80/main.c +++ b/Kernel/platform-trs80/main.c @@ -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 */ +} diff --git a/Kernel/platform-trs80/tricks.s b/Kernel/platform-trs80/tricks.s index dbc775f4..8360b5b4 100644 --- a/Kernel/platform-trs80/tricks.s +++ b/Kernel/platform-trs80/tricks.s @@ -1,5 +1,6 @@ -; 2013-12-21 William R Sowerbutts - +; +; This is heavily based on the Z80Pack platform code. +; .module tricks .globl _ptab_alloc @@ -18,7 +19,11 @@ .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: diff --git a/Kernel/platform-trs80/trs80.s b/Kernel/platform-trs80/trs80.s index 86071357..7a897594 100644 --- a/Kernel/platform-trs80/trs80.s +++ b/Kernel/platform-trs80/trs80.s @@ -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 @@ -33,11 +34,14 @@ .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 diff --git a/Kernel/platform-trs80/trs80load.s b/Kernel/platform-trs80/trs80load.s index 5df52fc9..aaa80b8b 100644 --- a/Kernel/platform-trs80/trs80load.s +++ b/Kernel/platform-trs80/trs80load.s @@ -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 diff --git a/Kernel/platform-trs80/uzi.lnk b/Kernel/platform-trs80/uzi.lnk index 6baca8af..e8bfb0b5 100644 --- a/Kernel/platform-trs80/uzi.lnk +++ b/Kernel/platform-trs80/uzi.lnk @@ -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