From d88706a3d92b61345738d0a883d6bc3c4288a305 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Sat, 23 Sep 2017 18:19:44 +0100 Subject: [PATCH] 65c816: further updates At this point it compiles although there is stuff to finish fixing up before it's even worth trying to boot an image. --- Kernel/bank65c816.c | 28 +-- Kernel/lib/65c816.s | 37 ++-- Kernel/lowlevel-65c816.s | 292 +++++++++++++++++++++------- Kernel/platform-v65c816/Makefile | 14 +- Kernel/platform-v65c816/README | 16 +- Kernel/platform-v65c816/commonmem.s | 32 ++- Kernel/platform-v65c816/config.h | 3 + Kernel/platform-v65c816/crt0.s | 203 +++++++++++-------- Kernel/platform-v65c816/devhd.c | 4 +- Kernel/platform-v65c816/kernel.def | 23 ++- Kernel/platform-v65c816/ld65.cfg | 15 +- Kernel/platform-v65c816/main.c | 8 +- Kernel/platform-v65c816/target.mk | 2 +- Kernel/platform-v65c816/v65.s | 62 ++++-- Kernel/usermem_std-65c816.s | 16 +- 15 files changed, 510 insertions(+), 245 deletions(-) diff --git a/Kernel/bank65c816.c b/Kernel/bank65c816.c index a39093c0..6e8e19f9 100644 --- a/Kernel/bank65c816.c +++ b/Kernel/bank65c816.c @@ -10,20 +10,22 @@ * don't support split I/D (different code/data page) at this point. * * Beyond that it's a normal banked platform. The oddities are that we - * have no common, and that we must also swap the ZP/Stack separately + * have no common, and that we must also swap the Stack separately * from bank 0, as well as the program bank. * - * Define MAP_SIZE for the space in the 64K available to the process, - * this needs to be no more than 63.5K (udata and kstack copies...) + * Note: The code assumes we have the normal user map of 0x0000-0xFBFF + * then 512 bytes of udata material, then a gap then stubs and that we + * swap the full 64K minus stubs/gap. If we extend udata then stubs will + * end up getting swapped in the final block but it's R/O so nobody + * should care. */ #include #include #include -#ifdef CONFIG_BANK_65C812 +#ifdef CONFIG_BANK_65C816 -uint16_t pzero[NPROC]; /* Kernel is 0, apps 1,2,3 etc */ static unsigned char pfree[MAX_MAPS]; static unsigned char pfptr = 0; @@ -92,10 +94,10 @@ int swapout(ptptr p) if (map == 0) return ENOMEM; blk = map * SWAP_SIZE; - /* Write the kstack and zero page to disk */ - swapwrite(SWAPDEV, blk, 512, pzero[p-ptab], 0); - /* Write the app (and possibly the uarea etc..) to disk */ - swapwrite(SWAPDEV, blk, SWAPTOP - SWAPBASE, SWAPBASE, p->p_page); + /* Write the user CPU stack to disk */ + swapwrite(SWAPDEV, blk, 512, (STACK_BANKOFF+(p-ptab)) << 8, 0); + /* Write the process including DP and C stack, plus the udata cache */ + swapwrite(SWAPDEV, blk + 1, SWAPTOP - SWAPBASE, SWAPBASE, p->p_page); pagemap_free(p); p->p_page = 0; p->p_page2 = map; @@ -119,10 +121,12 @@ void swapin(ptptr p, uint16_t map) kprintf("%x: nopage!\n", p); return; } - /* Read the kstack and zero page from disk */ - swapread(SWAPDEV, blk, 512, pzero[p-ptab], 0); + /* Read the user stack from disk: FIXME - this is half a block + so we need to make sure our disk drivers can cope with this for + read (write is ok) */ + swapread(SWAPDEV, blk, 256, (STACK_BANKOFF+(p-ptab)) << 8, 0); /* Read the process back in */ - swapread(SWAPDEV, blk, SWAPTOP - SWAPBASE, SWAPBASE, p->p_page); + swapread(SWAPDEV, blk + 1, SWAPTOP - SWAPBASE, SWAPBASE, p->p_page); #ifdef DEBUG kprintf("%x: swapin done %d\n", p, p->p_page); #endif diff --git a/Kernel/lib/65c816.s b/Kernel/lib/65c816.s index dd734c6e..98e1c531 100644 --- a/Kernel/lib/65c816.s +++ b/Kernel/lib/65c816.s @@ -2,18 +2,19 @@ ; The 65C816 memory management and switching logic is common ; to all systems so keep it all here ; - .include "kernel.def" + .include "../platform/kernel.def" .include "../kernel816.def" - .include "zeropage.inc" + .include "../platform/zeropage.inc" .export _switchout .export _switchin .export _dofork .importzp ptr1 - .import jump_monitor + .import _trap_monitor .import _chksigs .import _platform_idle + .import _newproc .import _nready .import _inint .import _getproc @@ -21,7 +22,8 @@ .import outcharhex .import outstring - .segment "COMMONMEM" + + .code .p816 .i8 .a8 @@ -86,10 +88,10 @@ slow_path: lda #U_DATA__TOTALSIZE-1 ; including our live stack phb switch_patch_1: - mv KERNEL_BANK:0,0 ; save stack and udata + mvn KERNEL_FAR,0 ; save stack and udata plb sep #$30 - clz _inint + stz _inint jsr _getproc ; x,a holds process jsr _switchin ; switch to process jsr _trap_monitor ; bug out if it fails @@ -125,14 +127,14 @@ _switchin: lda #U_DATA__TOTALSIZE-1 switch_patch_2: ; FIXME check syntax required for bank value ?? - mvn 0,KERNEL_BANK:0 + mvn 0,KERNEL_FAR ; after the MVN our data bank is KERNEL_DATA ; Our stack is now valid and we may use it again, our UDATA ; is for the new process ldx U_DATA__U_PTAB cpx ptr1 bne switchinfail ; wrong process !! - clz _runticks + stz _runticks sep #$20 .a8 lda #P_RUNNING @@ -145,7 +147,7 @@ switch_patch_2: stx sp sep #$10 .i8 - lda U_DATA__U_INTERRUPT + lda U_DATA__U_ININTERRUPT beq notisr cli ; interrupts back on notisr: @@ -161,16 +163,17 @@ switchinfail: ldx #>badswitchmsg jsr outstring ; something went wrong and we didn't switch in what we asked for - jmp _ trap_monitor -badswitchmsg: .byte "_switchin: FAIL" - .byte 13, 10, 0 + jmp _trap_monitor +badswitchmsg: + .byte "_switchin: FAIL" + .byte 13, 10, 0 _dofork: sta ptr1 ; new process ptr. U_DATA gives parent stx ptr1+1 lda U_DATA__U_PAGE sta fork_patch+2 ; source bank (parent) - ldy #P_TAB__P_PAGE + ldy #P_TAB__P_PAGE_OFFSET lda (ptr1),y sta fork_patch+1 ; destination bank (child) sta fork_patch_2+1 @@ -195,12 +198,12 @@ _dofork: lda #MAP_SIZE ; 64K - udata shadow phb fork_patch: - mvn 0,0 ; copy the entire bank + mvn 0,0 ; copy the entire bank below the save ldx #U_DATA ldy #U_DATA_STASH - lda #U_DATA_TOTALSIZE-1 + lda #U_DATA__TOTALSIZE-1 fork_patch_2: - mvn KERNEL_BANK:0,0 + mvn KERNEL_FAR,0 plb ; back to kernel bank ; At this point we have copied the parent into the child bank @@ -208,7 +211,7 @@ fork_patch_2: plx ; discard frame we build for child plx - .sep #$30 ; back to 8bit mode for C + sep #$30 ; back to 8bit mode for C .a8 .i8 lda ptr1 diff --git a/Kernel/lowlevel-65c816.s b/Kernel/lowlevel-65c816.s index 128a323b..e2abb2cb 100644 --- a/Kernel/lowlevel-65c816.s +++ b/Kernel/lowlevel-65c816.s @@ -4,10 +4,21 @@ .I8 .A8 - .export unix_syscall_entry .export _doexec .export interrupt_handler .export nmi_handler + .export map_process_always + .export map_kernel + .export _userpage + + .export sigret_irq + .export sigret + .export syscall_vector + + .export illegal_inst + .export trap_inst + .export abort_inst + .export emulation .export outstring .export outstringhex @@ -15,27 +26,33 @@ .export outcharhex .export outxa - .export _userpage - .export _need_resched + .import istack_top + .import istackc_top + .import istack_switched_sp + + .import kstack_top + .import kstackc_top + + .import _ssig + .import outchar .import _kernel_flag .import _unix_syscall - .import map_restore - .import map_save - .import map_process_always - .import map_kernel .import _platform_interrupt .import platform_doexec .import _inint .import _trap_monitor + .import push0 + .import incaxy + .include "platform/zeropage.inc" .include "platform/kernel.def" .include "kernel816.def" - .segment "COMMONMEM" + .code ; ; Unlike Z80 we need to deal with systems that have no overlapping ; memory banks. We pass the arguments is a single pointer therefore @@ -61,6 +78,9 @@ ; stubs (syscall and signal return) ; - audit and begin testing ; + +syscall = $fe + ; ; This is called from a stub we put into each user process bank that ; does a jsl to the kernel entry point then an rts @@ -69,7 +89,7 @@ syscall_entry: php ; save cpu mode of caller on ustack sei ; interrupts off cld ; get into sane mode - no decimal, known state - sep $30 + sep #$30 .a8 .i8 stx U_DATA__U_CALLNO @@ -100,59 +120,68 @@ copy_args: dey dey lda (ptr1),y ; copy the arguments over - ld - sta KERNEL_BANK:U_DATA__U_ARGN,x + sta KERNEL_FAR+U_DATA__U_ARGN,x inx inx cpy #0 bne copy_args noargs: - rep #$30 - .a16 - .i16 + sep #$30 + .a8 + .i8 + lda #KERNEL_BANK ; our direct and base bank need setting pha plb + + rep #$30 + .a16 + .i16 + lda #KERNEL_DP tcd + rep #$30 - .a8 - .i8 - rep #$10 + .a16 .i16 + ldx sp ; save the C stack - pshx ; on the main stack + phx ; on the main stack ; FIXME: how to check stack space in brk when this is not visible ? tsx stx U_DATA__U_SYSCALL_SP - ldx #kstack_top + ldx #kstack_top-1 txs ; set our CPU stack - ldx #kstack_c ; set our C stack + ldx #kstackc_top-1 ; set our C stack stx sp ; cli ; sane state achieved sep #$10 .i8 + lda #1 sta _kernel_flag ; In kernel mode cli ; Interrupts now ok jsr _unix_syscall ; Enter C space sei ; Interrupts back off stz _kernel_flag + rep #$10 .i16 + ldx U_DATA__U_SYSCALL_SP txs ; Back to the old stack ; We can't restore sp yet as we are ; in the wrong bank - .i8 sep #$10 + .i8 + lda U_DATA__U_CURSIG bne signal_out sep #$20 + .a8 lda U_DATA__U_PAGE - .a16 ; ; We use this trick several times. U_PAGE holds the bank ; register. As we want our DP to be bank:0000 we need to @@ -164,17 +193,20 @@ noargs: lda #0 tcd + rep #$20 + .a16 pla ; pull the saved sp off the ustack sta sp ; and store it 16bit - rep #$20 - .a8 - plp ; off ustack + sep #$20 + .a8 + .i8 ; We may now be in decimal ! ldy U_DATA__U_RETVAL ldx U_DATA__U_RETVAL+1 ; also sets z for us lda U_DATA__U_ERROR + plp rtl ; @@ -199,7 +231,7 @@ noargs: ; rts in bank return to the interruption point ; signal_out: - clz U_DATA__U_CURSIG + stz U_DATA__U_CURSIG rep #$10 .i16 @@ -212,29 +244,28 @@ signal_out: txs sep #$10 .i8 - tax ; Save signal code in X ; Stack the signal return (the signal itself can cause syscalls) ; Be careful here stack ops are currently going to user stack but ; data ops to kernel. Don't mix them up! - lda #>sigret ; needs to be a fixed address in user - pha - lda #emu_trap + lda #=2 bytes or else - clz 0,x - mvn 0,0 + rep #$20 + .a16 + lda #__BSS_SIZE__-2 ; must be >=2 bytes or else + stz 0,x + mvn 0,0 - sep #$30 - .a8 - .i8 - - lda #'i' - sta $FE20 - - lda #'x' - sta $FE20 - - jsr init_early - lda #'.' - sta $FE20 - jsr init_hardware - lda #13 - sta $FE20 - lda #10 - sta $FE20 - jmp code + sep #$30 + .a8 + .i8 + + lda #'i' + sta $FE20 + + lda #'x' + sta $FE20 + + jsr init_early + lda #'.' + sta $FE20 + jsr init_hardware + lda #13 + sta $FE20 + lda #10 + sta $FE20 + jmp code ; The above gets blasted into udata space - .code + .code code: - rep #$30 - .a8 - .i8 - ldx #$U_DATA - ldy #$U_DATA+1 - lda #$UDATA_TOTALSIZE-2 - clz 0,x - mvn 0,0 - - sep #$30 - .a8 - .i8 - - jsr _fuzix_main ; Should never return - sei ; Spin -stop: jmp stop - - .segment "VECTORS" - .addr vector - .addr $0202 ; does it matter ??? - .addr nmi_handler + rep #$30 + .a16 + .i16 + + ldx #U_DATA + ldy #U_DATA+1 + lda #U_DATA__TOTALSIZE-2 + stz 0,x + mvn 0,0 + + sep #$30 + .a8 + .i8 + + jsr _fuzix_main ; Should never return + sei ; Spin +stop: bra stop + + +; +; Processor vector table (0xFFE0) +; + .segment "VECTORS" + + + .word 0 ; unused + .word 0 ; unused + .word illegal_inst ; COP + .word trap_inst ; BRK + .word abort_inst ; ABORT + .word nmi_handler ; NMI + .word 0 ; Unused (native reset) + .word interrupt_handler + + ; + ; Emulation mode vectors. If called badness occurred + ; + .word emulation + .word emulation + .word emulation + .word emulation + .word emulation + .word emulation + .word emulation + .word emulation + + diff --git a/Kernel/platform-v65c816/devhd.c b/Kernel/platform-v65c816/devhd.c index 51b57c50..68e74f56 100644 --- a/Kernel/platform-v65c816/devhd.c +++ b/Kernel/platform-v65c816/devhd.c @@ -7,7 +7,7 @@ #include #include -extern uint8_t hd_map; +extern uint8_t hd_kmap; extern void hd_read_data(uint16_t addr); extern void hd_write_data(uint16_t addr); @@ -29,7 +29,7 @@ static int hd_transfer(uint8_t minor, bool is_read, uint8_t rawflag) return -1; /* For swap it'll be the swap bank passed */ - hd_map = rawflag ? udata.u_page : KERNEL_BANK; + hd_kmap = rawflag ? udata.u_page : KERNEL_BANK; dptr = (uint16_t)udata.u_dptr; nb = udata.u_nblock; diff --git a/Kernel/platform-v65c816/kernel.def b/Kernel/platform-v65c816/kernel.def index 432367aa..aa631a60 100644 --- a/Kernel/platform-v65c816/kernel.def +++ b/Kernel/platform-v65c816/kernel.def @@ -1,10 +1,23 @@ ; UZI mnemonics for memory addresses etc ; (this is struct u_data from kernel.h) -U_DATA .set $0100 ; stomps over bootstrap +U_DATA .set $0100 ; stomps over bootstrap ; 256+256+256 bytes. (U, kstack copy, k C stack copy) -U_DATA__TOTALSIZE .set $300 -U_DATA_STASH .set $FC00 ; leaves FFxx for vectors and stubs +U_DATA__TOTALSIZE .set $300 +U_DATA_STASH .set $FC00 ; leaves FFxx for vectors and stubs -PROGLOAD .set $0200 -ZPBASE .set $0 +PROGLOAD .set $0200 +ZPBASE .set $0 + +KERNEL_BANK .set $0 ; bank number +KERNEL_FAR .set $000000 ; 24 bit + +; Add this to the bank number to get the high 8bits of the 16bit CPU stack +; for this process +STACK_BANKOFF .set $F5 ; F600-FCFF +; Direct page for IRQ processing (saves us saving/restoring DP registers) +; Can probably use the same page as the IRQ CPU stack... FIXME +IRQ_DP .set $FD ; FD00-FDFF +KERNEL_DP .set $00 ; We use the real ZP for kernel DP + +MAP_SIZE .set $FC00 \ No newline at end of file diff --git a/Kernel/platform-v65c816/ld65.cfg b/Kernel/platform-v65c816/ld65.cfg index 0db09c20..93d48aae 100644 --- a/Kernel/platform-v65c816/ld65.cfg +++ b/Kernel/platform-v65c816/ld65.cfg @@ -1,27 +1,28 @@ MEMORY { RAMZ: start = $0000, size = $0100, type = rw, fill = yes; - STACK: start = $0100, size = $0100, type = rw, fill = yes; - BOOT: start = $0200, size = $0200, type = rw, fill = yes; - MAIN: start = $0400, size = $F300, type = rw, fill = yes; + UDATA: start = $0100, size = $0200, type = rw, fill = yes; + MAIN: start = $0300, size = $F400, type = rw, fill = yes; USTACKS:start = $F700, size = $0700, type = rw, fill = yes; IO: start = $FE00, size = $0100, type = rw, fill = yes; - VECTOR: start = $FFF0, size = $0010, type = rw, fill = yes; + STUB: start = $FF00, size = $00E0, type = rw, fill = yes; + VECTOR: start = $FFE0, size = $0020, type = rw, fill = yes; } SEGMENTS { ZEROPAGE: load = RAMZ, type = zp, define = yes; - COMMONDATA: load = MAIN, type = bss; + COMMONDATA: load = UDATA, type = bss; + + START: load = MAIN, type = ro; CODE: load = MAIN, type = ro, define = yes; RODATA: load = MAIN, type = ro; - START: load = BOOT, type = ro; - DATA: load = MAIN, type = rw, define = yes; BSS: load = MAIN, type = bss, define = yes; DISCARD: load = MAIN, type = ro; DISCARDDATA: load = MAIN, type = ro; + STUBS: load = STUB, type = ro; VECTORS: load = VECTOR, type = ro; } diff --git a/Kernel/platform-v65c816/main.c b/Kernel/platform-v65c816/main.c index 4b0e7c36..b16f498e 100644 --- a/Kernel/platform-v65c816/main.c +++ b/Kernel/platform-v65c816/main.c @@ -5,6 +5,7 @@ #include uint8_t kernel_flag = 1; +uint16_t ramtop = PROGTOP; void platform_idle(void) { @@ -18,16 +19,15 @@ void do_beep(void) } /* - * Map handling: We have flexible paging. Each map table consists of a set of pages - * with the last page repeated to fill any holes. + * 7 banks, kernel in bank 0 */ void pagemap_init(void) { int i; /* Bank 0 is the kernel */ - for (i = 15 ; i > 0; i--) - pagemap_add(i * 8); + for (i = 7 ; i > 0; i--) + pagemap_add(i); } void map_init(void) diff --git a/Kernel/platform-v65c816/target.mk b/Kernel/platform-v65c816/target.mk index 677f44e4..7138a635 100644 --- a/Kernel/platform-v65c816/target.mk +++ b/Kernel/platform-v65c816/target.mk @@ -1 +1 @@ -export CPU = 658C16 +export CPU = 65c816 diff --git a/Kernel/platform-v65c816/v65.s b/Kernel/platform-v65c816/v65.s index 3384b3c4..1a0c152b 100644 --- a/Kernel/platform-v65c816/v65.s +++ b/Kernel/platform-v65c816/v65.s @@ -13,17 +13,14 @@ .export ___hard_di .export ___hard_ei .export ___hard_irqrestore - .export vector .import _ramsize .import _procmem .import nmi_handler - .import unix_syscall_entry + .import syscall_vector .import kstack_top .import istack_switched_sp .import istack_top - .import _unix_syscall - .import _platform_interrupt .import _kernel_flag .import pushax @@ -31,12 +28,13 @@ .import outxa .import incaxy - .import _create_init_common - .include "kernel.def" .include "../kernel816.def" .include "zeropage.inc" + .p816 + .a8 + .i8 ; ; syscall is jsr [$00fe] ; @@ -71,11 +69,37 @@ irq_on: sei rts +; +; This could go in discard once we make that useful FIXME +; init_early: - ; copy the stubs from bank 0 to all banks so we can keep the - jsr _create_init_common + lda #1 +init_loop: + sep #$30 + .a8 + .i8 + sta common_patch+1 ; destination bank + phb ; save our bank (mvn will mess it) + pha ; and count + + rep #$30 + .a16 + .i16 + ldx #$FF00 + txy + lda #$00FE +common_patch: + mvn KERNEL_FAR,0 ; copy the block + pla + plb ; bank to kernel bank + dec + cmp #8 + bne init_loop rts + .a8 + .i8 + init_hardware: ; set system RAM size for test purposes rep #$10 @@ -84,13 +108,8 @@ init_hardware: stx _ramsize ldx #512-64 stx _procmem - ; TODO - correct vectors for the 816 - ldx #vector - stx $FFFE - ldx #