Mercurial > hg > Members > kono > nitros9-code
changeset 3170:18306d646f71
mc09: First release of working L2 port to MC09 platform
Kernel has conditional code so should build for all targets, but it's
been split out into a separate file to avoid polluting the main code.
The included system call source code only has minor conditional
additions so it is shared.
author | Neal Crook <foofoobedoo@gmail.com> |
---|---|
date | Thu, 20 Apr 2017 20:15:19 +0100 |
parents | 1ff3d7673e36 |
children | 0116eacf444a |
files | level1/modules/rel.asm level2/mc09l2/bootfiles/makefile level2/mc09l2/modules/makefile level2/modules/kernel/falltsk.asm level2/modules/kernel/fld.asm level2/modules/kernel/fldabx.asm level2/modules/kernel/fmove.asm level2/modules/kernel/fsrqmem.asm level2/modules/kernel/mc09krn.asm |
diffstat | 9 files changed, 1732 insertions(+), 93 deletions(-) [+] |
line wrap: on
line diff
--- a/level1/modules/rel.asm Mon Apr 17 22:59:28 2017 +0100 +++ b/level1/modules/rel.asm Thu Apr 20 20:15:19 2017 +0100 @@ -1,4 +1,4 @@ -******************************************************************** +******************************************************************* * REL - Relocation routine * * $Id$ @@ -11,24 +11,24 @@ * * 2004/11/09 P.Harvey-Smith * Added code to flip Dragon Alpha into text mode on boot. -* +* nam REL ttl Relocation routine - IFP1 + IFP1 use defsfile - ENDC + ENDC XX.Size equ 6 number of bytes before REL actually starts Offset equ Bt.Start+XX.Size - IFEQ Level-1 + IFEQ Level-1 ScStart equ $8000 screen start in memory - ELSE + ELSE ScStart equ $8008 screen start in memory - ENDC + ENDC -tylg set Systm+Objct +tylg set Systm+Objct atrv set ReEnt+rev rev set $05 edition set 5 @@ -50,45 +50,283 @@ IFGT Level-1 ************************************************************************* -* Level2/level3 +** Start of Level2/Level3 code +** +** The boot-loader loads the "kernelfile" from track34 of the disk into +** memory at $26xx and then jumps into it at address $2602. The +** kernelfile is formed by concatenating the modules REL, BOOT, KRN. +** The entry point jumps via the REL module header to label "start". +** +** One function of REL is to copy the kernelfile from $26xx to high +** memory (specifically, to Bt.Start). $1200 bytes are copied. +** +** The size of each of these modules is controlled with filler bytes (eg, +** see label "Filler" below) so that (after relocation): +** REL starts at $ED00 and is $130 bytes in size +** BOOT starts at $EE30 and is $1D0 bytes in size +** KRN starts at $F000 and ends at $FEFF (but the 'emod' comes before +** the end of krn -- refer to the source file for details) +** +** When REL starts, it has NO STACK +************************************************************************* + + IFNE mc09 + +************************************************************************* +** Start of Level2 code for mc09 **************************************** ************************************************************************* -L001F fcb $6C MMU, IRQ, Vector page, SCS - fcb $00 map type 0 - fcb $00 no FIRQ - fcb $00 no IRQ - fdb $0900 timer - fcb $00 unused - fcb $00 unused - IFEQ TkPerSec-50 - fcb $0B 50Hz refresh, alphanumeric display, 8 lines/char row - ELSE - fcb $03 60Hz refresh, alphanumeric display, 8 lines/char row - ENDC +crash lda #'* signal a crash error + jsr <D.BtBug + tfr b,a save error code + jsr <D.BtBug and dump this out, too +badbad bra badbad + + +* Entry point for REL. Code is currently running at $26xx. Arrive with +* MMU enabled (with 1-1 mapping), ROM disabled, TR=0, FRT=0. +* +* The MMU (which Coco calls Dynamic Address Translator, DAT) maps +* 8Kbyte blocks of physical memory into 8Kbyte regions of the CPU +* address space. +* +* There don't seem to be consistent names for stuff but I try to use: +* Page - a 256Byte region of memory +* Block - an 8Kbyte hunk of physical memory +* Map - an 8Kbyte region of CPU address space. Map 0-7 +* are addressed when TR=0, Map 8-15 are in use +* when TR=1. +* Mapping register - one of 16 registers (8 for TR=0, 8 for TR=1) +* that control which block appears in which map. +* +* There are 64 blocks ($00-$3F) on 512K system, 128 blocks ($00-7F) +* on 1MByte system. At the moment we assume 512K. +* +* In order to start krn, need to: +* - put block 0 in map 0 ($0000 in CPU address space) +* - put block 7 in map 7 ($E000 in CPU address space) +* - enable FRT (makes top 512 locations of block 7 permanently +* mapped at CPU address $FE00 - $FFFF). +* +* Need to use block 7 for the top of memory because that is where +* the mc09 MMU hardware implements the special fixed-RAM-top (FRT) +* functionality that keeps a tiny piece of the NitrOS9 kernel +* permanently mapped into memory. +* +* This is different from the COCO, which uses block $3f. $3f also +* holds the I/O space on COCO whereas for mc09, the I/O space overlays +* and is not affected by the MMU at all. + +start ldx #MMUADR + lda #(MMU_TR0|0) Select mapping reg 0, with TR=0 + ldb #$0 Select bottom block of physical memory + std ,x Write A to MMUADR to set MAPSEL=0, then write B to MMUDAT + + lda #(MMU_TR0|7) Select mapping reg 7, with TR=0 + ldb #$7 Select block 7 of physical memory (512Kbyte system) + std ,x Write A to MMUADR to set MAPSEL=7, then write B to MMUDAT + + lda #MMU_TR0FRT + sta ,x Enable FixedRamTop + +* The setup below has been reordered compared with the Coco code. This code does +* the copy/branch high before any of the page0 setup, reflecting an earlier code +* version where MMU setup was deferred (and so page0 was not yet mapped). Could restore +* the Coco ordering, if that allows more common code, or just leave it as-is. + +* Copy kernelfile image from $26xx to Bt.Start ($ED00) +L00E2 tfr pc,d get the address at which we're executing + cmpa #$26 the bootfile starts out at $2600 + bne L0101 if not at $26xx, already copied: continue with booting + ldu #$2600 else move rel, Boot, krn over + ldx #$1200 number of bytes to copy + ldy #Bt.Start where to put it + +cpkrn ldd ,u++ from + std ,y++ to + leax -2,x update count + bne cpkrn +* Go to copy in high memory + jmp >Offset+L0101 + +* Now executing at $EDxx +L0101 ldb #$FF negative - do complete boot + +start1 orcc #IntMasks turn off IRQ's + +* [NAC HACK 2016Dec05] todo: turn off timer interrupt in case this is a reboot + + clra make A=0 for later + tfr a,dp + clr <D.CBStrt cold boot start: don't re-boot on reset + + lds #$1FFF set stack to the end of block 0 + stb ,-s save status of start, $00=cold, $01=warm [NAC HACK 2016Dec06] $FF = startup: do complete boot (above) +* This is done so I can tell what went on in the direct page if there's +* a crash. 0(crash) 1(reset) -1(startup) +* beq Cont --don't clear out direct page if it's a crash + + clrb clear out ALL of direct page + tfr d,x here, too +L0072 sta ,x+ clear out the direct page + incb Boot won't be using any of it! + bne L0072 BUT RAMMER/MD DOES!!! + +* Use D.TINIT as a shadow of the MMU address register, so that we can +* do read/mod/write of TR bit later on + lda #MMU_TR0 + sta <D.TINIT + + +** tst ,s check status : 0(crash) 1(reset) -1(startup) +** bmi StoreQ if NOT a crash or reset, start at the start... +** bne ClrLoop + +MoveTxt leau <BootMsg,pcr point to OS-9 Welcome Message + bsr OutMsg +* 0 = crash +* 1 = reset +* -1 = startup + ldb ,s+ check state of boot + bne L0101a if OK, continue +* X pointing to FailMsg + bsr OutMsg +L00E0 bra L00E0 loop forever + - IFEQ Width-80 - fcb $34 200 lines, 80 column mode, no attribute byte (monochrome) - fcb $3F white border -BOOTLINE set 11 80-col start line for BOOT/FAIL messages - ENDC +* display null-terminated message at U to UART. U, A, CC updated. +OutMsg lda VDUSTA + bita #2 + beq OutMsg + lda ,u+ + beq MsgDone + sta VDUDAT + bra OutMsg +MsgDone rts + + +BootMsg + fcc /NITROS9 BOOT/ + fcb 0 +FailMsg + fcc / FAILED/ + fcb 0 + + +* Copy X bytes from U to Y +L00FD lda ,u+ + sta ,y+ + leax -1,x + bne L00FD + rts + - IFEQ Width-40 - fcb $24 200 lines, 40-col, no attribute byte - fcb $3F white border -BOOTLINE set 13 40-col start line for BOOT/FAIL messages - ENDC +* Debug routine. Not executed here, but copied to D.Crash +* [NAC HACK 2017Jan21] the copy/space assigned is 16 bytes +* [NAC HACK 2017Jan21] so make sure it fits!! Ought to be a check.. +* Come here with ASCII code in A. Clear bit 7 then +* display code on the VDU at the current cursor position. +* All registers except A are preserved. Vital to preserve CC +* because the caller needs it to detect that bit 7 was set - +* indicating the end of the string for some callers. +BtDebug pshs cc,d,x save the registers +DebBsy ldb VDUSTA + bitb #2 + beq DebBsy wait until UART non-full + anda #$7f make valid ASCII + sta VDUDAT send character + puls cc,d,x,pc restore regs and exit + + + +* [NAC HACK 2016Dec06] not sure there's any logic to what's done +* while we're at $2600 and what's done now we're at $EExx +* ..I think the distinction is what's done on a reboot-without-reload. Check. +* [NAC HACK 2016Dec06] At D.BtBug there are 3 bytes which +* default to RTS <16-bit address of debug routine> +* for debug, change the RTS ($39) to JMP ($7E) +* Come here in high memory: $EExx +L0101a +* lda #$39 RTS + lda #$7E JMP + sta <D.BtBug + leax <BtDebug,pc point to debug routine + stx <D.BtBug+1 + + leau <R.Crash,pcr point to D.Crash, D.CBStart + ldy #D.Crash move it over + ldx #$10 + bsr L00FD + - IFEQ Width-32 - fcb $20 200 lines, 32-col, no attribute byte - fcb $00 black border -BOOTLINE set 13 32-col start line for BOOT/FAIL messages - ENDC + ldx #$F000 we KNOW where krn module starts in memory + ldd M$Exec,x get execution start address of module + jmp d,x jump to it + +* D.Crash +R.Crash +*[NAC HACK 2017Jan21] since we're not planning to crash it's OK to comment this out, for now, +*[NAC HACK 2017Jan21] but I'm puzzled about why we'd set TR=0 (user mode??) on a crash +*[NAC HACK 2016Dec08] L003F clr >$FF91 go to map type 0 - called by CC3Go from map 1 + jmp >Offset+crash + + fcb $00 warm start flag + fdb $0074 go to $0074, next routine + +* reset vector: map ROMs out and go to REL in the default DECB block map, +* which is still block $3F at the top of memory + nop required for the ROMs to believe it's a reset vector + clr >$FFDF go to all RAM mode +**[NAC HACK 2016Dec05] jmp >Offset+reset and re-start the boot + +* Filler to get to a total size of $130. XX.Size is bytes at the start of +* this file - before the module header. 3 is bytes after this filler - the +* end boilerplate for the module. +Filler fill $39,$130-XX.Size-3-* + + ELSE match IFNE mc09 + +************************************************************************** +** Start of Level2/Level3 code for coco3 ********************************* +************************************************************************** - fcb $00 display in lower 512k bank - fcb $00 vertical fine scroll set to 0 - fcb Bt.Block*4 display block where-ever - fcb $01 offset 8 bytes - fcb $00 no horizontal scroll +* GIME setup data stored at $FF90-$FF9F and in direct page +L001F fcb $6C D.HINIT MMU, IRQ, Vector page, SCS + fcb $00 D.TINIT set MMU map type 0 + fcb $00 D.IRQER no FIRQ + fcb $00 D.FRQER no IRQ + fdb $0900 D.TIMxx timer + fcb $00 D.RESV1 unused + fcb $00 D.RESV2 unused + IFEQ TkPerSec-50 + fcb $0B D.VIDMD 50Hz refresh, alphanumeric display, 8 lines/char row + ELSE + fcb $03 D.VIDMD 60Hz refresh, alphanumeric display, 8 lines/char row + ENDC + + IFEQ Width-80 + fcb $34 D.VIDRS 200 lines, 80 column mode, no attribute byte (monochrome) + fcb $3F D.BORDR white border +BOOTLINE set 11 80-col start line for BOOT/FAIL messages + ENDC + + IFEQ Width-40 + fcb $24 D.VIDRS 200 lines, 40-col, no attribute byte + fcb $3F D.BORDR white border +BOOTLINE set 13 40-col start line for BOOT/FAIL messages + ENDC + + IFEQ Width-32 + fcb $20 D.VIDRS 200 lines, 32-col, no attribute byte + fcb $00 D.BORDR black border +BOOTLINE set 13 32-col start line for BOOT/FAIL messages + ENDC + + fcb $00 D.RESV3 (Distro 2Byte updates) display in lower 512k bank + fcb $00 D.VOFF2 vertical fine scroll set to 0 + fcb Bt.Block*4 D.VOFF1 display block where-ever + fcb $01 D.VOFF0 offset 8 bytes + fcb $00 D.HOFF0 no horizontal scroll crash lda #'* signal a crash error jsr <D.BtBug @@ -115,7 +353,18 @@ tfr a,dp ENDC clr <D.CBStrt cold boot start: don't re-boot on reset - clr >$FFA0 map in block 0 + +* Coco3 enters this code with TR=1 and the MMU mappings set thus: +* TR=0: map 0-7: $??,$39,$3A,$3B,$3C,$3D,$3E,$3F +* TR-1: map 0-7: $38,$30,$31,$32,$33,$3D,$35,$3F +* +* Enter krn with TR=0. Only 2 (TR=0) mappings need to be set up: +* Physical RAM block $3F mapped to the top of memory (already by default) +* Physical RAM block $0 mapped to the bottom of memory. +* +* RAM block 0 about to get mapped. TR set to 0 by the GIME setup below. + + clr >DAT.Regs+0 map RAM block 0 to block 0 in DAT lds #$1FFF set stack to the end of the block stb ,-s save status of start, $00=cold, $01=warm * This is done so I can tell what went on in the direct page if there's @@ -134,6 +383,9 @@ leay <L001F,pcr point to the video setup data ldx #$0090 set video mapping deca now D=$FF00, versus STU >-$0100,x (saves 1 byte) + +* Copy setup data to (1) the GIME at $FF90-$FFA0 and (2) shadow copy +* in the direct page at $0090 (D.HINIT etc). L0084 ldu ,y++ get the bytes stu d,x save in the hardware stu ,x++ and in the direct page @@ -159,7 +411,7 @@ bmi StoreQ if NOT a crash or reset, start at the start... cmpd ,x are they the same? beq MoveTxt don't bother clearing the screen if it's there -StoreQ +StoreQ IFNE H6309 stq ,x otherwise save the bytes on-screen ELSE @@ -211,7 +463,7 @@ leax -1,x bne L00FD ENDC - rts + rts L0011 fdb ScStart+(BOOTLINE*Width)+((Width-L1)/2) fcb L1 length of the text below @@ -248,7 +500,7 @@ clr >$FFA0 map block 0 in again puls cc,d,x,pc restore X and exit -L0101 +L0101 lda #$7E RTS sta <D.BtBug leax <BtDebug,pc point to debug routine @@ -270,7 +522,7 @@ jmp d,x jump to it * D.Crash -R.Crash fcb $10 size of the data to move over +R.Crash fcb $10 size of the data to move over - 6 for D.Crash, $B for D.CBStrt L003F clr >$FF91 go to map type 0 - called by CC3Go from map 1 jmp >Offset+crash @@ -283,28 +535,40 @@ clr >$FFDF go to all RAM mode jmp >Offset+reset and re-start the boot -* L2 kernel file is composed of rel, boot, krn. The size of each of these -* is controlled with filler, so that (after relocation): -* rel starts at $ED00 and is $130 bytes in size -* boot starts at $EE30 and is $1D0 bytes in size -* krn starts at $F000 and ends at $FEFF (there is no 'emod' at the end -* of krn and so there are no module-end boilerplate bytes) -* * Filler to get to a total size of $130. XX.Size is bytes at the start of * this file - before the module header. 3 is bytes after this filler - the * end boilerplate for the module. Filler fill $39,$130-XX.Size-3-* + ENDC match IFNE mc09 ELSE match IFGT Level-1 ************************************************************************* -* Entry point for level1 +** Start of Level1 code +** +** The boot-loader loads the "kernelfile" from track34 of the disk into +** memory at $26xx and then jumps into it at address $2602. The +** kernelfile is formed by concatenating modules REL, BOOT, KRN, +** KRNP2, INIT -- and maybe others, depending upon the hardware +** configuration. +** The entry point jumps via the REL module header to label "start". +** +** One function of REL is to copy the kernelfile from $26xx to high +** memory (specifically, to Bt.Start). Bt.Size ($1000-$1080) bytes are +** copied. +** +** Unlike the Level2/Level3 case, the size of each of the modules in the +** kernelfile is not padded. +** +** When REL starts, it has NO STACK +************************************************************************* + +************************************************************************* +* Entry point for Level1 (all platforms) ******************************** ************************************************************************* Start - IFNE mc09 -* currently we have NO STACK - + IFNE mc09 leax <BootMsg,pcr outbsy lda VDUSTA bita #2 @@ -315,16 +579,16 @@ bra outbsy done - ELSE match IFNE mc09 + ELSE match IFNE mc09 clr PIA0Base+3 - IFNE (tano+d64+dalpha) + IFNE (tano+d64+dalpha) clr PIA0Base+1 added for Dragon, works on CoCo - ENDC - IFNE H6309 + ENDC + IFNE H6309 ldmd #3 native mode - ENDC + ENDC sta $FFDF turn off ROM * locate Boot Text Screen at $8000 @@ -335,15 +599,15 @@ bne L262B sta 1,x - IFNE dalpha - clr $ffc0 * Reset to text mode if Dragon Alpha - clr $ffc2 - clr $ffc4 - - lda $ff22 - anda #$07 - sta $ff22 - ENDC + IFNE dalpha + clr $ffc0 Reset to text mode if Dragon Alpha + clr $ffc2 + clr $ffc4 + + lda $ff22 + anda #$07 + sta $ff22 + ENDC * Clear VDG screen ldx #ScStart @@ -362,16 +626,16 @@ decb bne L2649 - IFNE (tano+d64+dalpha) + IFNE (tano+d64+dalpha) tst <$72 - ELSE + ELSE ldd #$1212 cmpd <$0078 - ENDC + ENDC beq L266E - ENDC match IFNE mc09 + ENDC match IFNE mc09 * Copy boot track from $2600 to $EE00 - not quite all of it though. The whole boot * track is $1200 bytes and would take us right up to $FFFF. We actually copy up to @@ -394,18 +658,18 @@ jmp d,x BootMsg - IFNE mc09 + IFNE mc09 fcn / Boot / - ELSE - IFNDEF dalpha save some bytes on Dragon Alpha + ELSE + IFNDEF dalpha save some bytes on Dragon Alpha fcc /NITROSy/ fcb $60 - ENDC + ENDC fcc /BOOT/ BootMLen equ *-BootMsg - ENDC match IFNE mc09 + ENDC match IFNE mc09 - ENDC match IFGT Level-1 + ENDC match IFGT Level-1 emod eom equ *
--- a/level2/mc09l2/bootfiles/makefile Mon Apr 17 22:59:28 2017 +0100 +++ b/level2/mc09l2/bootfiles/makefile Thu Apr 20 20:15:19 2017 +0100 @@ -7,7 +7,7 @@ DEPENDS = ./makefile # The _80 in rel_80 refers to 80-column screen -KERNEL_MC09SD = $(MD)/rel_80 $(MD)/boot_sdc $(MD)/krn +KERNEL_MC09SD = $(MD)/rel_80 $(MD)/boot_sdc $(MD)/mc09krn MC09SDC_80D = $(MD)/mc09sdc.dr $(MD)/dds0_80d.dd $(MD)/s0_80d.dd $(MD)/s1_80d.dd $(MD)/s2_80d.dd $(MD)/s3_80d.dd
--- a/level2/mc09l2/modules/makefile Mon Apr 17 22:59:28 2017 +0100 +++ b/level2/mc09l2/modules/makefile Thu Apr 20 20:15:19 2017 +0100 @@ -14,7 +14,7 @@ TPB = $(3RDPARTY)/booters BOOTERS = boot_sdc -BOOTTRACK = rel_80 $(BOOTERS) krn +BOOTTRACK = rel_80 $(BOOTERS) mc09krn KERNEL = krnp2 krnp3_perr krnp4_regdump SYSMODS = ioman init sysgo_dd rominfo vectors @@ -49,14 +49,14 @@ # The following macros represent a collection of modules for various # kernel tracks and bootfile configurations. # -KERNEL_MC09SD = rel_80 boot_sdc krn +KERNEL_MC09SD = rel_80 boot_sdc mc09krn ALLOBJS = $(BOOTTRACK) $(KERNEL) $(SYSMODS) $(CLOCKS) $(RBF) $(SCF) $(PIPE) $(RFM) all: $(ALLOBJS) # Kernel -ccbkrn krn krnp2: +mc09krn krn krnp2: $(CD) kernel; make $@ $(OS9COPY) kernel/$@ .
--- a/level2/modules/kernel/falltsk.asm Mon Apr 17 22:59:28 2017 +0100 +++ b/level2/modules/kernel/falltsk.asm Thu Apr 20 20:15:19 2017 +0100 @@ -82,7 +82,11 @@ stu b,x save DAT image pointer in task table cmpb #2 is it either system or GrfDrv? bhi L0C9F no, return + IFNE mc09 + lda <D.TINIT + ELSE ldx #DAT.Regs update system DAT image + ENDC lbsr L0E93 go bash the hardware L0C9F puls cc,d,x,u,pc
--- a/level2/modules/kernel/fld.asm Mon Apr 17 22:59:28 2017 +0100 +++ b/level2/modules/kernel/fld.asm Thu Apr 20 20:15:19 2017 +0100 @@ -22,6 +22,14 @@ clrb Clear carry/setup for STB pshs cc Preserve interrupt status/settings orcc #IntMasks shut IRQ's off + IFNE mc09 + ldb <D.TINIT Current MMU mask - selects block 0 + stb >MMUADR Select block 0 + sta >MMUDAT Map block into $0000-$1FFF + lda ,x Get byte + clrb + stb >MMUDAT Map block 0 into $0000-$1FFF + ELSE sta >DAT.Regs Map block into $0000-$1FFF IFNE H6309 brn L0AC8 short delay @@ -31,6 +39,7 @@ IFNE H6309 brn L0AC8 short delay ENDC + ENDC puls pc,cc Get interrupt status/(or turn on) & return * Get 1st byte of LDDDXY - also used by many other routines @@ -39,9 +48,18 @@ pshs b,cc clrb Clear carry/setup for STB orcc #IntMasks Shut off interrupts + IFNE mc09 + ldb <D.TINIT Current MMU mask - selects block 0 + stb >MMUADR Select block 0 + sta >MMUDAT Map in MMU block into slot 0 + lda ,x+ Get byte + clrb + stb >MMUDAT Map block 0 back in + ELSE sta >DAT.Regs Map in MMU block into slot 0 lda ,x+ Get byte stb >DAT.Regs + ENDC * clr >DAT.Regs Map in MMU block #0 into slot 0 * andcc #^IntMasks puls b,cc @@ -77,15 +95,19 @@ * Get 2 bytes for LDDDXY (also called by other routines) * Should simply map in 2 blocks, and do a LDD (don't have to worry about wrap) + IFNE mc09 +L0B02 pshs u,y,x,dp Preserve regs (x, y adjusted by AdjBlk0) + ELSE L0B02 pshs u,y,x Preserve regs (x, y adjusted by AdjBlk0) - IFNE H6309 + ENDC + + IFNE H6309 addr d,x Point X to X+D - ELSE + ELSE leax d,x - ENDC + ENDC bsr AdjBlk0 Wrap address around for 1 block ldu <D.SysDAT Get sys DAT Image ptr -* lda 1,u Get MMU block #0 clra system block 0 =0 always ldb 3,u Get MMU block #1 tfr d,u make U=blocks to re-map in once done @@ -93,7 +115,35 @@ ldb 3,y Get MMU block #1 pshs cc Preserve int. status orcc #IntMasks shut off int. + IFNE mc09 + lda <D.TINIT Current MMU mask - selects block 0 + inca Select block 1 + + ldb 1,y Get MMU block #0 + tfr b,dp Save it for later + ldb 3,u Get restore value for MMU block #1 + tfr d,u Save it for later + + ldb 3,y Get MMU block #1 + std >MMUADR Set address and block 1 + + deca Select block 0 + tfr dp,b + std >MMUADR Set address and block 0 + + ldy ,x Get 2 bytes + + tfr u,d + std >MMUADR Restore original MMU block #1 + deca Select block 0 + clrb system block 0 =0 always + std >MMUADR Restore original MMU block #0 + + tfr y,d Put the data in the right place + puls pc,u,y,x,dp,cc Restore regs & return + ELSE std >DAT.Regs Map in both blocks ldd ,x Get 2 bytes stu >DAT.Regs Map original blocks in puls pc,u,y,x,cc Restore regs & return + ENDC
--- a/level2/modules/kernel/fldabx.asm Mon Apr 17 22:59:28 2017 +0100 +++ b/level2/modules/kernel/fldabx.asm Thu Apr 20 20:15:19 2017 +0100 @@ -19,11 +19,20 @@ * Exit : B=Byte from other task L0C40 pshs cc,a,x,u bsr L0BF5 Calculate offset into DAT image (fmove.asm) - ldd a,u + ldd a,u [NAC HACK 2017Jan25] why ldd when a is never used?? orcc #IntMasks + IFNE mc09 + lda <D.TINIT Current MMU mask - selects block 0 + sta >MMUADR Select block 0 + + stb >MMUDAT Map selected block into $0000-$1FFF + ldb ,x + clr >MMUDAT Restore mapping at $0000-$1FFF + ELSE stb >DAT.Regs Map block into $0000-$1FFF ldb ,x clr >DAT.Regs Restore mapping at $0000-$1FFF + ENDIF puls cc,a,x,u stb R$A,u Save into caller's A & return @@ -63,9 +72,21 @@ pshs cc,d,x,u bsr L0BF5 Calculate offset into DAT image (fmove.asm) ldd a,u Get memory block + IFNE mc09 + orcc #IntMasks + lda <D.TINIT Current MMU mask - selects block 0 + sta >MMUADR Select block 0 + + lda 1,s Haven't lost stack yet so this is safe + + stb >MMUDAT Map selected block into $0000-$1FFF + sta ,x + clr >MMUDAT Restore mapping at $0000-$1FFF + ELSE lda 1,s orcc #IntMasks stb >DAT.Regs Map selected block into $0000-$1FFF sta ,x clr >DAT.Regs Restore mapping at $0000-$1FFF + ENDIF puls cc,d,x,u,pc
--- a/level2/modules/kernel/fmove.asm Mon Apr 17 22:59:28 2017 +0100 +++ b/level2/modules/kernel/fmove.asm Thu Apr 20 20:15:19 2017 +0100 @@ -19,10 +19,10 @@ * in the $AXXX range, and as a result, the process stack pointer would get * switched out when $FFA5-$FFA6 was written and the stack would disappear. * - IFEQ H6309 + IFEQ H6309 L0A01 clrb rts - ENDC + ENDC FMove ldd R$D,u get source & destination task #'s L0B25 ldy R$Y,u Get # bytes to move @@ -146,10 +146,27 @@ L0B84 std $0F,s puls y orcc #IntMasks + IFNE mc09 + lda <D.TINIT Current MMU mask - selects block 0 + ora #5 + sta >MMUADR Select block 5 + lda $0E,s stack could disappear in the remapping.. + exg d,y swap them; final destination for d + sta >MMUDAT +***** NO STACK USE BETWEEN HERE..... + lda <D.TINIT Current MMU mask - selects block 0 + ora #6 + sta >MMUADR Select block 6 + stb >MMUDAT +* the coco code did a "tfr d,y". mc09 did a "exg d,y" which +* left y correct but we also need d=y at the end.. + tfr y,d + ELSE lda $0E,s +++ sty >DAT.Regs+5 ***** NO STACK USE BETWEEN HERE..... tfr d,y +++ + ENDIF andb #$07 beq L0B99 L0B92 lda ,x+ @@ -191,9 +208,21 @@ bne L0BA4 +++ exg x,u L0BBC ldy <D.SysDAT + IFNE mc09 + lda <D.TINIT Current MMU mask - selects block 0 + ora #5 + sta >MMUADR Select block 5 + ldb $0B,y + stb >MMUDAT Restore it + inca + sta >MMUADR Select block 6 + ldb $0D,y + stb >MMUDAT Restore it + ELSE lda $0B,y ldb $0D,y std >DAT.Regs+5 + ENDIF ***** AND HERE........... puls cc ldd $0E,s
--- a/level2/modules/kernel/fsrqmem.asm Mon Apr 17 22:59:28 2017 +0100 +++ b/level2/modules/kernel/fsrqmem.asm Thu Apr 20 20:15:19 2017 +0100 @@ -258,7 +258,7 @@ * Link to module and execute L090C lda #Systm+Objct os9 F$Link - bcs L08F3 return with error + bcs L08F3 return with error. lda #'b calling boot jsr <D.BtBug jsr ,y load boot file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/level2/modules/kernel/mc09krn.asm Thu Apr 20 20:15:19 2017 +0100 @@ -0,0 +1,1271 @@ +******************************************************************** +* krn - NitrOS-9 Level 2 Kernel +* +* $Id$ +* +* Edt/Rev YYYY/MM/DD Modified by +* Comment +* ------------------------------------------------------------------ +* 19r6 2002/08/21 Boisy G. Pitre +* Assembles to the os9p1 module that works on my NitrOS-9 system. +* +* 19r7 2002/09/26 Boisy G. Pitre +* Added check for CRC feature bit in init module +* +* 19r8 2003/09/22 Boisy G. Pitre +* Back-ported to OS-9 Level Two. +* +* 19r8 2004/05/22 Boisy G. Pitre +* Renamed to 'krn' +* +* 19r9 2004/07/12 Boisy G. Pitre +* F$SRqMem now properly scans the DAT images of the system to update +* the D.SysMem map. + + nam krn + ttl NitrOS-9 Level 2 Kernel + + IFP1 + use defsfile + ENDC + +* defines for customizations +Revision set 9 module revision +Edition set 19 module Edition +Where equ $F000 absolute address of where Kernel starts in memory + + mod eom,MName,Systm,ReEnt+Revision,entry,0 + +MName fcs /Krn/ + fcb Edition + +* The 8K RAM block that is mapped to $E000-$FFFF and holds +* the kernel and I/O space. $3f for COCO, $7 for mc09. +KrnBlk set $7 + + +* Might as well have this here as just past the end of Kernel... +DisTable + fdb L0CD2+Where D.Clock absolute address at the start + fdb XSWI3+Where D.XSWI3 + fdb XSWI2+Where D.XSWI2 + fdb D.Crash D.XFIRQ crash on an FIRQ + fdb XIRQ+Where D.XIRQ + fdb XSWI+Where D.XSWI + fdb D.Crash D.XNMI crash on an NMI + fdb $0055 D.ErrRst ??? Not used as far as I can tell + fdb Sys.Vec+Where Initial Kernel system call vector +DisSize equ *-DisTable +* ^ +* Code using 'SubSiz', below, assumes that SubStrt follows on directly after +* the end of DisTable. Therefore, DO NOT ADD ADD ANYTHING BETWEEN THESE 2 LABELS +* v +LowSub equ $0160 start of low memory subroutines +SubStrt equ * +* D.Flip0 - switch to system task 0 +R.Flip0 equ * + IFNE H6309 + aim #$FE,<D.TINIT map type 0 + lde <D.TINIT another 2 bytes saved if GRFDRV does: tfr cc,e + ste >DAT.Task and we can use A here, instead of E + ELSE + pshs a + lda <D.TINIT Get value from shadow + IFNE mc09 + anda #$BF force TR=0 + sta <D.TINIT Update shadow + sta >MMUADR Update MMU + ELSE + anda #$FE force TR=0 + sta <D.TINIT + sta >DAT.Task + ENDC + puls a + ENDC + clr <D.SSTskN + tfr x,s + tfr a,cc + rts +SubSiz equ *-SubStrt +* ^ +* Code around L0065, below, assumes that Vectors follows on directly after +* the end of R.Flip0. Therefore, DO NOT ADD ADD ANYTHING BETWEEN THESE 2 LABELS +* v +* Interrupt service routine +Vectors jmp [<-(D.SWI3-D.XSWI3),x] (-$10) (Jmp to 2ndary vector) + + IFNE mc09 +CPUVect fdb SWI3VCT+Where SWI3 at $FFF2 + fdb SWI2VCT+Where SWI2 at $FFF4 + fdb FIRQVCT+Where FIRQ at $FFF6 + fdb IRQVCT+Where IRQ at $FFF8 + fdb SWIVCT+Where SWI at $FFFA + fdb NMIVCT+Where NMI at $FFFC + fdb $0000+Where RESET at $FFFE + ENDC + +* [NAC HACK 2016Dec07] to do a real reset on Multicomp09 need first to +* disable the MMU and re-enable the ROM. Maybe implement a little blob +* of code to do that? Otherwise, implement some kind of crash/dump. + +* Initialize the system block (the lowest 8Kbytes of memory) +* rel.asm has cleared the DP already, so start at address $100. +entry equ * + IFNE H6309 + ldq #$01001f00 start address to clear & # bytes to clear + leay <entry+2,pc point to a 0 + tfm y,d+ + std <D.CCStk set pointer to top of global memory to $2000 + lda #$01 set task user table to $0100 + ELSE + ldx #$100 start address + ldy #$2000-$100 bytes to clear + clra + clrb +L001C std ,x++ clear it 16-bits at a time + leay -2,y + bne L001C + stx <D.CCStk Set pointer to top of global memory to $2000 + inca D = $0100 + ENDC + +* Set up system variables in DP + std <D.Tasks set Task Structure pointer to $0100 + addb #$20 + std <D.TskIPt set Task image table pointer to $0120 + clrb + +******************************************************************** +* The memory block map is a data structure that is used to manage +* physical memory. Physical memory is assigned in 8Kbyte "blocks". +* 256 bytes are reserved for the map and so the maximum physical +* memory size is 256*8Kbyte=2Mbyte. D.BlkMap is a pointer to the +* start of the map (set to $0200, below). D.BlkMap+2 is a pointer +* to the end of the map. Rather than simply setting it to $0300, +* the end pointer is set by the memory sizing routine at L0111. +* (Presumably) this makes it faster to search for unused pages +* and also acts as the mechanism to avoid assigning non-existent +* memory. A value of 0 indicates an unused block and since the +* system block has been initialised to 0 (above) every block starts +* off marked as unused. Initial reservation of blocks occurs +* below, after the memory sizing. +* See "Level 2 flags" in os9.d for other byte values. + + inca set memory block map start pointer + std <D.BlkMap to $0200 + + inca set system service dispatch table pointer + std <D.SysDis to 0x300 + inca set user dispatch table pointer to $0400 + std <D.UsrDis + inca set process descriptor block pointer to $0500 + std <D.PrcDBT + inca set system process descriptor pointer to $0600 + std <D.SysPrc + std <D.Proc set user process descriptor pointer to $0600 + adda #$02 set stack pointer to $0800 + tfr d,s + inca set system stack base pointer to $0900 + std <D.SysStk + std <D.SysMem set system memory map ptr $0900 + inca set module directory start ptr to $0a00 + std <D.ModDir + std <D.ModEnd set module directory end ptr to $0a00 + adda #$06 set secondary module directory start to $1000 + std <D.ModDir+2 + std <D.ModDAT set module directory DAT pointer to $1000 + std <D.CCMem set pointer to beginning of global memory to $1000 +* In following line, CRC=ON if it is STA <D.CRC, CRC=OFF if it is a STB <D.CRC + stb <D.CRC set CRC checking flag to off + +* Initialize interrupt vector tables in DP by moving pointer data down from DisTable + + IFNE mc09 +* Brett's ccbkrn identified this as a bug in the original code.. +* which has not been fixed. Should be easy to demonstrate which is +* correct.. + leay DisTable,pcr point to table of absolute vector addresses + ELSE + leay <DisTable,pcr point to table of absolute vector addresses + ENDC + ldx #D.Clock where to put it in memory + IFNE H6309 + ldf #DisSize size of the table - E=0 from TFM, above + tfm y+,x+ move it over + ELSE + ldb #DisSize +l@ + lda ,y+ load a byte from source + sta ,x+ store a byte to dest + decb bump counter + bne l@ loop if we're not done + ENDC + +* Initialize D.Flip0 routine in low memory by copying lump of code down from R.Flip0. +* ASSUME: Y left pointing to R.Flip0 by previous copy loop. + + ldu #LowSub somewhere in block 0 that's never modified + stu <D.Flip0 switch to system task 0 + IFNE H6309 + ldf #SubSiz size of it + tfm y+,u+ copy it over + ELSE + ldb #SubSiz +Loop2 lda ,y+ load a byte from source + sta ,u+ and save to destination + decb bump counter + bne Loop2 loop if not done + ENDC + +* Initialize secondary interrupt vectors to all point to Vectors for now +* ASSUME: Y left pointing to Vectors by previous copy loop + tfr y,u move the pointer to a faster register +L0065 stu ,x++ Set all IRQ vectors to go to Vectors for now + cmpx #D.NMI + bls L0065 + + IFNE mc09 +* Initialize CPU vectors + leay CPUVect,pcr Data source + ldx #$FFF2 Data destination + ldb #14 7 vectors to copy +L0067 lda ,y+ + sta ,x+ + decb + bne L0067 + ENDC + +* Initialize user interupt vectors + ldx <D.XSWI2 Get SWI2 (os9 command) service routine pointer + stx <D.UsrSvc Save it as user service routine pointer + ldx <D.XIRQ Get IRQ service routine pointer + stx <D.UsrIRQ Save it as user IRQ routine pointer + + leax >SysCall,pc Setup System service routine entry vector + stx <D.SysSvc + stx <D.XSWI2 + + leax >S.SysIRQ,pc Setup system IRQ service vector + stx <D.SysIRQ + stx <D.XIRQ + + leax >S.SvcIRQ,pc Setup in system IRQ service vector + stx <D.SvcIRQ + leax >S.Poll,pc Setup interrupt polling vector + stx <D.Poll ORCC #$01;RTS + leax >S.AltIRQ,pc Setup alternate IRQ vector: pts to an RTS + stx <D.AltIRQ + + lda #'K debug: signal that we are in Kernel + jsr <D.BtBug + + leax >S.Flip1,pc Setup change to task 1 vector + stx <D.Flip1 + +* Setup System calls + leay >SysCalls,pc load y with address of table, below + lbsr SysSvc copy table below into dispatch table + +* Initialize system process descriptor + ldu <D.PrcDBT get process table pointer + ldx <D.SysPrc get system process pointer + +* These overlap because it is quicker than trying to strip hi byte from X + stx ,u save it as first process in table + stx 1,u save it as the second as well + IFNE H6309 + oim #$01,P$ID,x Set process ID to 1 (inited to 0) + oim #SysState,P$State,x Set to system state (inited to 0) + ELSE + ldd #$01*256+SysState + sta P$ID,x set PID to 1 + stb P$State,x set state to system (*NOT* zero ) + ENDC + clra set System task as task #0 + sta <D.SysTsk + sta P$Task,x + coma Setup its priority & age ($FF) + sta P$Prior,x + sta P$Age,x + leax <P$DATImg,x point to DAT image + stx <D.SysDAT save it as a pointer in DP +* actually, since block 0 is tfm'd to be zero, we can skip the next 2 lines + IFNE H6309 + clrd + ELSE + clra + clrb + ENDC + std ,x++ initialize 1st block to 0 (for this DP) + +******************************************************************** +* The DAT image is a data structure that is used to indicate which +* Dynamic Address Translator (DAT) mapping registers are in use. + +* [NAC HACK 2016Dec06] future: I should be able to make this 7 if not 8.. +* DAT.BlCt-ROMCount-RAMCount = 8 - 1 - 1 = 6 + lda #$06 initialize the rest of the blocks to be free + ldu #DAT.Free +L00EF stu ,x++ store free "flag" + deca bump counter + bne L00EF loop if not done + +* [NAC HACK 2016Dec06] on the Coco, block $3F holds the I/O space so it cannot +* be used for anything else. Future: We can remove that restriction for mc09 + ldu #KrnBlk Block $3F is in use, at the top of system DAT image + stu ,x + + ldx <D.Tasks Point to task user table + inc ,x mark first 2 in use (system & GrfDrv) + inc 1,x + +******************************************************************** +* The system memory map is a data structure that is used to manage +* the 64Kbyte CPU address space. D.SysMem is a pointer to the start +* of the map (set to $0900, above) and the map is a fixed size of +* 256 bytes. Each byte in the map represents one 256-byte "page" +* (256 entries of 256 bytes is 64Kbytes). A value of 0 indicates +* an unused page and since the system block has been initialised +* to 0 (above) every page starts off marked as unused. +* See "Level 2 flags" in os9.d for other byte values. + +* Update the system memory map to reserve the area used for +* global memory. + ldx <D.SysMem Get system memory map pointer + ldb <D.CCStk Get MSB of top of CC memory +* X indexes the system memory map. +* B represents the number of 256-byte pages available. +* Walk through the map changing the corresponding elements +* from 0 (the initialisation value) to 1 (indicating 'used'). Higher +* entries in the map remain as 0 (indicating 'unused'). +L0104 inc ,x+ Mark it as used + decb Done? + bne L0104 No, go back till done + +******************************************************************** +* Deduce how many 8Kbyte blocks of physical memory are available and +* update the memory block map end pointer (D.BlkMap+2) accordingly + ldx <D.BlkMap get ptr to 8k block map + inc <KrnBlk,x mark block $3F as used (kernel) + IFNE mc09 + inc <$00,x mark block $00 as used (global memory) +* For mc09 memory size is 512Kbyte or 1MByte. For now, hard-wire +* the memory size to 512Kbyte. + ldd #$0240 + ELSE +* This memory sizing routine uses location at X (D.BlkMap) as +* a scratch location. At exit, it leaves this location at 1 which +* has the (until now) undocumented side-effect of marking block 0 +* as used. It is essential that this is done because that block +* does need to be reserved; it's used for global memory. + IFNE H6309 + ldq #$00080100 e=Marker, D=Block # to check +L0111 asld get next block # + stb >DAT.Regs+5 Map block into block 6 of my task + ste >-$6000,x save marker to that block + cmpe ,x did it ghost to block 0? + bne L0111 No, keep going till ghost is found + stb <D.MemSz Save # 8k mem blocks that exist + addr x,d add number of blocks to block map start + ELSE + ldd #$0008 +L0111 aslb + rola + stb >DAT.Regs+5 + pshs a + lda #$01 + sta >-$6000,x + cmpa ,x + puls a + bne L0111 + stb <D.MemSz + pshs x + addd ,s++ + ENDC + ENDC + std <D.BlkMap+2 save memory block map end pointer + +******************************************************************** +* Initial reservation of blocks in the memory block map. Code above +* reserved one block (block 0) for global memory and one block +* (usually block $3F) for krn. +* +* At this point, the value of D indicates the memory size: +* $0210 - 128k ( 16, 8KByte blocks) +* $0220 - 256k ( 32, 8KByte blocks) +* $0240 - 512k ( 64, 8KByte blocks) +* $0280 - 1024k (128, 8KByte blocks) +* $0300 - 2048k (256, 8KByte blocks) + bitb #%00110000 block above 128K-256K? + beq L0170 yes, no need to mark block map + tstb 2 meg? + beq L0170 yes, skip this +* Mark blocks from 128k-256K to block $3F as NOT RAM + abx add maximum block number to block map start + leax -1,x Skip good blocks that are RAM + lda #NotRAM Not RAM flag + subb #$3F Calculate # blocks to mark as not RAM +L0127 sta ,x+ Mark them all + decb + bne L0127 + +* ASSUME: however we got here, B=0 +L0170 ldx #Bt.Start start address of the boot track in memory + lda #18 size of the boot track is $1800 + +* Verify the modules in the boot track and update/build a module index + lbsr I.VBlock + bsr L01D2 go mark system map + +* See if init module is in memory already +L01B0 leax <init,pc point to 'Init' module name + bsr link try & link it + bcc L01BF no error, go on +L01B8 os9 F$Boot error linking init, try & load boot file + bcc L01B0 got it, try init again + bra L01CE error, re-booting do D.Crash + +* So far, so good. Save pointer to init module and execute krnp2 +L01BF stu <D.Init Save init module pointer + lda Feature1,u Get feature byte #1 from init module + bita #CRCOn CRC feature on? + beq ShowI if not, continue + inc <D.CRC else inc. CRC flag + +ShowI lda #'i debug: signal that we found the init module + jsr <D.BtBug + +L01C1 leax <krnp2,pc Point to its name + bsr link Try to link it + bcc L01D0 It worked, execute it + os9 F$Boot It doesn't exist try re-booting + bcc L01C1 No error's, let's try to link it again +L01CE jmp <D.Crash obviously can't do it, crash machine +L01D0 jmp ,y execute krnp2 + +* Update the system memory map to reserve the area used by the kernel +L01D2 ldx <D.SysMem Get system memory map pointer + ldd #NotRAM*256+(Bt.Start/256) B = MSB of start of the boot + abx point to Bt.Start - start of boot track + comb we have $FF-$ED pages to mark as inUse + sta b,x Mark I/O as not RAM +L01DF lda #RAMinUse get inUse flag +L01E1 sta ,x+ mark this page + decb done? + bne L01E1 no, keep going + ldx <D.BlkMap get pointer to start of block map + sta <KrnBlk,x mark kernel block as RAMinUse, instead of ModInBlk +S.AltIRQ rts return + +* Link module pointed to by X +link lda #Systm Attempt to link system module + os9 F$Link + rts + +init fcs 'Init' +krnp2 fcs 'krnp2' + +* Service vector call pointers +SysCalls fcb F$Link + fdb FLink-*-2 + fcb F$PrsNam + fdb FPrsNam-*-2 + fcb F$CmpNam + fdb FCmpNam-*-2 + fcb F$CmpNam+SysState + fdb FSCmpNam-*-2 + fcb F$CRC + fdb FCRC-*-2 + fcb F$SRqMem+SysState + fdb FSRqMem-*-2 + fcb F$SRtMem+SysState + fdb FSRtMem-*-2 + fcb F$AProc+SysState + fdb FAProc-*-2 + fcb F$NProc+SysState + fdb FNProc-*-2 + fcb F$VModul+SysState + fdb FVModul-*-2 + fcb F$SSvc+SysState + fdb FSSvc-*-2 + fcb F$SLink+SysState + fdb FSLink-*-2 + fcb F$Boot+SysState + fdb FBoot-*-2 + fcb F$BtMem+SysState + fdb FSRqMem-*-2 + IFNE H6309 + fcb F$CpyMem + fdb FCpyMem-*-2 + ENDC + fcb F$Move+SysState + fdb FMove-*-2 + fcb F$AllImg+SysState + fdb FAllImg-*-2 + fcb F$SetImg+SysState + fdb FFreeLB-*-2 + fcb F$FreeLB+SysState + fdb FSFreeLB-*-2 + fcb F$FreeHB+SysState + fdb FFreeHB-*-2 + fcb F$AllTsk+SysState + fdb FAllTsk-*-2 + fcb F$DelTsk+SysState + fdb FDelTsk-*-2 + fcb F$SetTsk+SysState + fdb FSetTsk-*-2 + fcb F$ResTsk+SysState + fdb FResTsk-*-2 + fcb F$RelTsk+SysState + fdb FRelTsk-*-2 + fcb F$DATLog+SysState + fdb FDATLog-*-2 + fcb F$LDAXY+SysState + fdb FLDAXY-*-2 + fcb F$LDDDXY+SysState + fdb FLDDDXY-*-2 + fcb F$LDABX+SysState + fdb FLDABX-*-2 + fcb F$STABX+SysState + fdb FSTABX-*-2 + fcb F$ELink+SysState + fdb FELink-*-2 + fcb F$FModul+SysState + fdb FFModul-*-2 + fcb F$VBlock+SysState + fdb FVBlock-*-2 + IFNE H6309 + fcb F$DelRAM + fdb FDelRAM-*-2 + ENDC + fcb $80 + +* SWI3 vector entry +XSWI3 lda #P$SWI3 point to SWI3 vector + fcb $8C skip 2 bytes + +* SWI vector entry +XSWI lda #P$SWI point to SWI vector + ldx <D.Proc get process pointer + ldu a,x user defined SWI[x]? + beq L028E no, go get option byte +GoUser lbra L0E5E Yes, go call users's routine + +* SWI2 vector entry +XSWI2 ldx <D.Proc get current process descriptor + ldu P$SWI2,x any SWI vector? + bne GoUser yes, go execute it + +* Process software interupts from a user state +* Entry: X=Process descriptor pointer of process that made system call +* U=Register stack pointer +L028E ldu <D.SysSvc set system call processor to system side + stu <D.XSWI2 + ldu <D.SysIRQ do the same thing for IRQ's + stu <D.XIRQ + IFNE H6309 + oim #SysState,P$State,x mark process as in system state + ELSE + lda P$State,x + ora #SysState + sta P$State,x + ENDC +* copy register stack to process descriptor + sts P$SP,x save stack pointer + leas (P$Stack-R$Size),x point S to register stack destination + + IFNE H6309 + leau R$Size-1,s point to last byte of destination register stack + leay -1,y point to caller's register stack in $FEE1 + ldw #R$Size size of the register stack + tfm y-,u- + leau ,s needed because the TFM is u-, not -u (post, not pre) + ELSE +* Note! R$Size MUST BE an EVEN number of bytes for this to work! + leau R$Size,s point to last byte of destination register stack + lda #R$Size/2 +Loop3 ldx ,--y + stx ,--u + deca + bne Loop3 + ENDC + andcc #^IntMasks +* B=function code already from calling process: DON'T USE IT! + ldx R$PC,u get where PC was from process + leax 1,x move PC past option + stx R$PC,u save updated PC to process +* execute function call + ldy <D.UsrDis get user dispatch table pointer + lbsr L033B go execute option + IFNE H6309 + aim #^IntMasks,R$CC,u Clear interrupt flags in caller's CC + ELSE + lda R$CC,u + anda #^IntMasks + sta R$CC,u + ENDC + ldx <D.Proc get current process ptr + IFNE H6309 + aim #^(SysState+TimOut),P$State,x Clear system & timeout flags + ELSE + lda P$State,x + anda #^(SysState+TimOut) + sta P$State,x + ENDC + +* Check for image change now, which lets stuff like F$MapBlk and F$ClrBlk +* do the short-circuit thing, too. Adds about 20 cycles to each system call. + lbsr TstImg it doesn't hurt to call this twice + lda P$State,x get current state of the process + ora <P$Signal,x is there a pending signal? + sta <D.Quick save quick return flag + beq AllClr if nothing's have changed, do full checks + +DoFull bsr L02DA move the stack frame back to user state + lbra L0D80 go back to the process + +* add ldu P$SP,x, etc... +AllClr equ * + IFNE H6309 + inc <D.QCnt + aim #$1F,<D.QCnt + beq DoFull every 32 system calls, do the full check + ldw #R$Size --- size of the register stack + ldy #Where+SWIStack --- to stack at top of memory + orcc #IntMasks + tfm u+,y+ --- move the stack to the top of memory + ELSE + lda <D.QCnt + inca + anda #$1F + sta <D.QCnt + beq DoFull + ldb #R$Size + ldy #Where+SWIStack + orcc #IntMasks +Loop4 lda ,u+ + sta ,y+ + decb + bne Loop4 + ENDC + lbra BackTo1 otherwise simply return to the user + +* Copy register stack from user to system +* Entry: U=Ptr to Register stack in process dsc +L02CB pshs cc,x,y,u preserve registers + ldb P$Task,x get task # + ldx P$SP,x get stack pointer + lbsr L0BF3 calculate block offset (only affects A&X) + leax -$6000,x adjust pointer to where memory map will be + bra L02E9 go copy it + +* Copy register stack from system to user +* Entry: U=Ptr to Register stack in process dsc +L02DA pshs cc,x,y,u preserve registers + ldb P$Task,x get task # of destination + ldx P$SP,x get stack pointer + lbsr L0BF3 calculate block offset (only affects A&X) + leax -$6000,x adjust pointer to where memory map will be + exg x,y swap pointers & copy +* Copy a register stack +* Entry: X=Source +* Y=Destination +* A=Offset into DAT image of stack +* B=Task # +L02E9 leau a,u point to block # of where stack is + IFNE mc09 + orcc #IntMasks shutdown interupts while we do this + + lda #5 + bsr prepmmu Select block 5 + + lda 1,u get first block + ldb 3,u get a second just in case of overlap + + sta >MMUDAT Set value for block 5 + + lda #6 + bsr prepmmu Select block 6 + + stb >MMUDAT Set value for block 6 + + ldb #R$Size +Loop5 lda ,x+ + sta ,y+ + decb + bne Loop5 + ldx <D.SysDAT remap the blocks we took out + + lda #5 + bsr prepmmu Select block 5 + + lda $0B,x + ldb $0D,x + + sta >MMUDAT Restore value for block 5 + lda #6 + bsr prepmmu Select block 6 + + stb >MMUDAT Restore value for block 6 + ELSE + lda 1,u get first block + ldb 3,u get a second just in case of overlap + orcc #IntMasks shutdown interupts while we do this + std >DAT.Regs+5 map blocks in + IFNE H6309 + ldw #R$Size get size of register stack + tfm x+,y+ copy it + ELSE + ldb #R$Size +Loop5 lda ,x+ + sta ,y+ + decb + bne Loop5 + ENDC + ldx <D.SysDAT remap the blocks we took out + lda $0B,x + ldb $0D,x + std >DAT.Regs+5 + ENDIF + puls cc,x,y,u,pc restore & return + + IFNE mc09 +* A holds the MMU register we want to select. Merge in +* the stored value and write the result to MMUADR. This is +* a desperate attempt to save a few bytes.. +prepmmu + ora <D.TINIT Merge with current MMU mask + sta >MMUADR Select block + rts + ENDIF + + +* Process software interupts from system state +* Entry: U=Register stack pointer +SysCall leau ,s get pointer to register stack + lda <D.SSTskN Get system task # (0=SYSTEM, 1=GRFDRV) + clr <D.SSTskN Force to System Process + pshs a Save the system task number + lda ,u Restore callers CC register (R$CC=$00) + tfr a,cc make it current + ldx R$PC,u Get my caller's PC register + leax 1,x move PC to next position + stx R$PC,u Save my caller's updated PC register + ldy <D.SysDis get system dispatch table pointer + bsr L033B execute system call + puls a restore system state task number + lbra L0E2B return to process + +* Entry: X = system call vector to jump to +Sys.Vec jmp ,x execute service call + +* Execute system call +* Entry: B=Function call # +* Y=Function dispatch table pointer (D.SysDis or D.UsrDis) +L033B + lslb is it a I/O call? (Also multiplys by 2 for offset) + bcc L0345 no, go get normal vector +* Execute I/O system calls + ldx IOEntry,y get IOMan vector +* Execute the system call +L034F pshs u preserve register stack pointer + jsr [D.SysVec] perform a vectored system call + puls u restore pointer +L0355 tfr cc,a move CC to A for stack update + bcc L035B go update it if no error from call + stb R$B,u save error code to caller's B +L035B ldb R$CC,u get callers CC, R$CC=$00 + IFNE H6309 + andd #$2FD0 [A]=H,N,Z,V,C [B]=E,F,I + orr b,a merge them together + ELSE + anda #$2F [A]=H,N,Z,V,C + andb #$D0 [B]=E,F,I + pshs b + ora ,s+ + ENDC + sta R$CC,u return it to caller, R$CC=$00 + rts + +* Execute regular system calls +L0345 + clra clear MSB of offset + ldx d,y get vector to call + bne L034F it's initialized, go execute it + comb set carry for error + ldb #E$UnkSvc get error code + bra L0355 return with it + + use fssvc.asm + + use flink.asm + + use fvmodul.asm + + use ffmodul.asm + + use fprsnam.asm + + use fcmpnam.asm + + use fsrqmem.asm + +* use fallram.asm + + + IFNE H6309 + use fdelram.asm + ENDC + + use fallimg.asm + + use ffreehb.asm + + use fdatlog.asm + + use fld.asm + + IFNE H6309 + use fcpymem.asm + ENDC + + use fmove.asm + + use fldabx.asm + + use falltsk.asm + + use faproc.asm + +* System IRQ service routine +XIRQ ldx <D.Proc get current process pointer + sts P$SP,x save the stack pointer + lds <D.SysStk get system stack pointer + ldd <D.SysSvc set system service routine to current + std <D.XSWI2 + ldd <D.SysIRQ set system IRQ routine to current + std <D.XIRQ + jsr [>D.SvcIRQ] execute irq service + bcc L0D5B + + ldx <D.Proc get current process pointer + ldb P$Task,x + ldx P$SP,x get it's stack pointer + + pshs u,d,cc save some registers + leau ,s point to a 'caller register stack' + lbsr L0C40 do a LDB 0,X in task B + puls u,d,cc and now A ( R$A,U ) = the CC we want + + ora #IntMasks disable it's IRQ's + lbsr L0C28 save it back +L0D5B orcc #IntMasks shut down IRQ's + ldx <D.Proc get current process pointer + tst <D.QIRQ was it a clock IRQ? + lbne L0DF7 if not, do a quick return + + lda P$State,x Get it's state + bita #TimOut Is it timed out? + bne L0D7C yes, wake it up +* Update active process queue + ldu #(D.AProcQ-P$Queue) point to active process queue + ldb #Suspend get suspend flag +L0D6A ldu P$Queue,u get a active process pointer + beq L0D78 + bitb P$State,u is it suspended? + bne L0D6A yes, go to next one in chain + ldb P$Prior,x get current process priority + cmpb P$Prior,u do we bump this one? + blo L0D7C + +L0D78 ldu P$SP,x + bra L0DB9 + +L0D7C anda #^TimOut + sta P$State,x + +L0D80 equ * +L0D83 bsr L0D11 activate next process + + use fnproc.asm + +* The following routines must appear no earlier than $E00 when assembled, as +* they have to always be in the vector RAM pages ($FE00-$FEFF) + + IFNE mc09 +* Copied nicer automatic padding from ccbkrn +* CCB: this code (after pad) start assembling *before* 0xfe00, it's too big to +* fit into the memory as stated above!!!! + +PAD fill $00,($0dfc-*) fill memory to ensure the above happens + ELSE +PAD fill $00,($0df1-*) fill memory to ensure the above happens + ENDC + + +* Default routine for D.SysIRQ +S.SysIRQ + lda <D.SSTskN Get current task's GIME task # (0 or 1) + beq FastIRQ Use super-fast version for system state + clr <D.SSTskN Clear out memory copy (task 0) + jsr [>D.SvcIRQ] (Normally routine in Clock calling D.Poll) + inc <D.SSTskN Save task # for system state + IFNE mc09 + lda #$40 mc09 MMU Task 1 + ora <D.TINIT Merge task bit into Shadow version + sta <D.TINIT Update shadow + sta >MMUADR Save to MMU as well + ELSE + lda #1 Task 1 + ora <D.TINIT Merge task bit into Shadow version + sta <D.TINIT Update shadow + sta >DAT.Task Save to GIME as well + ENDC + bra DoneIRQ Check for error and exit + +FastIRQ jsr [>D.SvcIRQ] (Normally routine in Clock calling D.Poll) +DoneIRQ bcc L0E28 No error on IRQ, exit + IFNE H6309 + oim #IntMasks,0,s Setup RTI to shut interrupts off again + ELSE + lda ,s + ora #IntMasks + sta ,s + ENDC +L0E28 rti + +* return from a system call +L0E29 clra Force System task # to 0 (non-GRDRV) +L0E2B ldx <D.SysPrc Get system process dsc. ptr + lbsr TstImg check image, and F$SetTsk (PRESERVES A) + orcc #IntMasks Shut interrupts off + sta <D.SSTskN Save task # for system state + beq Fst2 If task 0, we're done + IFNE mc09 + lda #$40 [NAC HACK 2016Dec07] hope only 1 bit means anything.. + ora <D.TINIT Merge task bit into Shadow version + sta <D.TINIT Update shadow + sta >MMUADR Save to MMU + ELSE + ora <D.TINIT Merge task bit into Shadow version + sta <D.TINIT Update shadow + sta >DAT.Task Save to GIME as well + ENDC +Fst2 leas ,u Stack ptr=U & return + rti + +* Switch to new process, X=Process descriptor pointer, U=Stack pointer +L0E4C equ * + IFNE H6309 + oim #$01,<D.TINIT switch GIME shadow to user state + lda <D.TINIT + ELSE + lda <D.TINIT + IFNE mc09 + ora #$40 + ELSE + ora #$01 + ENDC + sta <D.TINIT + ENDC + IFNE mc09 + sta >MMUADR save it to MMU + ELSE + sta >DAT.Task save it to GIME + ENDC + leas ,y point to new stack + tstb is the stack at SWISTACK? + bne MyRTI no, we're doing a system-state rti + + IFNE H6309 + ldf #R$Size E=0 from call to L0E8D before + ldu #Where+SWIStack point to the stack + tfm u+,y+ move the stack from top of memory to user memory + ELSE + ldb #R$Size + ldu #Where+SWIStack point to the stack +RtiLoop lda ,u+ + sta ,y+ + decb + bne RtiLoop + ENDC +MyRTI rti return from IRQ + + +* Execute routine in task 1 pointed to by U +* comes from user requested SWI vectors +L0E5E equ * + IFNE H6309 + oim #$01,<D.TINIT switch GIME shadow to user state + ldb <D.TINIT + ELSE + ldb <D.TINIT + IFNE mc09 + orb #$40 + ELSE + orb #$01 + ENDC + stb <D.TINIT + ENDC + IFNE mc09 + stb >MMUADR + ELSE + stb >DAT.Task + ENDC + jmp ,u + +* Flip to task 1 (used by GRF/WINDInt to switch to GRFDRV) (pointed to +* by <D.Flip1). All regs are already preserved on stack for the RTI +S.Flip1 ldb #2 get Task image entry numberx2 for Grfdrv (task 1) + bsr L0E8D copy over the DAT image + IFNE H6309 + oim #$01,<D.TINIT + lda <D.TINIT get copy of GIME Task side + ELSE + lda <D.TINIT + IFNE mc09 + ora #$40 force TR=1 in mc09 MMU + ELSE + ora #$01 force TR=1 + ENDC + sta <D.TINIT + ENDC + IFNE mc09 + sta >MMUADR save it to MMU register + ELSE + sta >DAT.Task save it to GIME register + ENDC + inc <D.SSTskN increment system state task number + rti return + +* Setup MMU in task 1, B=Task # to swap to, shifted left 1 bit +L0E8D cmpb <D.Task1N are we going back to the same task + beq L0EA3 without the DAT image changing? + stb <D.Task1N nope, save current task in map type 1 + IFNE mc09 + ldu <D.TskIPt get task image pointer table + ldu b,u get address of DAT image + + lda <D.TINIT + adda #8 1st MMU value for process's mappings + +* COME HERE FROM FALLTSK +* Update 8 MMU mappings. +* A = MMUADR value for 1st MMU register to update +* U = address of DAT image to update into MMU +L0E93 ldb #8 number of MMU mappings to set + pshs b squirrel it away + leau 1,u point to actual MMU block for 1st mapping + +L0E9B ldb ,u++ get a bank, point to next bank + std >MMUADR save it to MMU + inca next mapsel value + dec ,s + bne L0E9B no, keep going + leas 1,s done. Tidy up the stack + ELSE + ldx #DAT.Regs+8 get MMU start register for process's + ldu <D.TskIPt get task image pointer table + ldu b,u get address of DAT image +* COME HERE FROM FALLTSK +* Update 8 MMU mappings. +* X = address of 1st DAT MMU register to update +* U = address of DAT image to update into MMU +L0E93 leau 1,u point to actual MMU block + IFNE H6309 + lde #4 get # banks/2 for task + ELSE + lda #4 + pshs a + ENDC +L0E9B lda ,u++ get a bank + ldb ,u++ and next one + std ,x++ Save it to MMU + IFNE H6309 + dece done? + ELSE + dec ,s + ENDC + bne L0E9B no, keep going + IFEQ H6309 + leas 1,s done. Tidy up the stack + ENDC + ENDC +L0EA3 rts return + +* Execute FIRQ vector (called from $FEF4) +FIRQVCT ldx #D.FIRQ get DP offset of vector + bra L0EB8 go execute it + +* Execute IRQ vector (called from $FEF7) +IRQVCT orcc #IntMasks disable IRQ's + ldx #D.IRQ get DP offset of vector + +* Execute interrupt vector, B=DP Vector offset + IFNE mc09 +L0EB8 lda #$a0 [NAC HACK 2016Dec08] add equates.. + sta >MMUADR Force to System State (Task 0) + clra + tfr a,dp ASSUME: A=0 from earlier +MapGrf equ * come here from elsewhere, too. + lda <D.TINIT + anda #$BF force TR=0 in mc09 MMU shadow + sta <D.TINIT +MapT0 sta >MMUADR come here from elsewhere, too. + jmp [,x] execute it + ELSE +* Execute interrupt vector, B=DP Vector offset +L0EB8 clra (faster than CLR >$xxxx) + sta >DAT.Task Force to Task 0 (system state) + IFNE H6309 + tfr 0,dp setup DP + ELSE + tfr a,dp ASSUME: A=0 from earlier + ENDC +MapGrf equ * come here from elsewhere, too. + IFNE H6309 + aim #$FE,<D.TINIT switch GIME shadow to system state + lda <D.TINIT set GIME again just in case timer is used + ELSE + lda <D.TINIT + anda #$FE + sta <D.TINIT + ENDC +MapT0 sta >DAT.Task come here from elsewhere, too. + jmp [,x] execute it + ENDC + + + +* Execute SWI3 vector (called from $FEEE) +SWI3VCT orcc #IntMasks disable IRQ's + ldx #D.SWI3 get DP offset of vector + bra SWICall go execute it + +* Execute SWI2 vector (called from $FEF1) +SWI2VCT orcc #IntMasks disasble IRQ's + ldx #D.SWI2 get DP offset of vector + +* This routine is called from an SWI, SWI2, or SWI3 +* saves 1 cycle on system-system calls +* saves about 200 cycles (calls to I.LDABX and L029E) on grfdrv-system, +* or user-system calls. +SWICall ldb [R$PC,s] get callcode of the system call + IFNE mc09 +* [NAC HACK 2016Dec08] confused? it says, "go to map type 1" but +* it is setting a 0. + lda #$a0 [NAC HACK 2016Dec08] add equates.. + sta >MMUADR Force to System State (Task 0) + clra + ELSE +* NOTE: Alan DeKok claims that this is BAD. It crashed Colin McKay's +* CoCo 3. Instead, we should do a clra/sta >DAT.Task. +* clr >DAT.Task go to map type 1 + clra + sta >DAT.Task + ENDC +* set DP to zero + IFNE H6309 + tfr 0,dp + ELSE + tfr a,dp ASSUME: A=0 from earlier + ENDC + +* These lines add a total of 81 addition cycles to each SWI(2,3) call, +* and 36 bytes+12 for R$Size in the constant page at $FExx +* It takes no more time for a SWI(2,3) from system state than previously, +* ... and adds 14 cycles to each SWI(2,3) call from grfdrv... not a problem. +* For processes that re-vector SWI, SWI3, it adds 81 cycles. BUT SWI(3) +* CANNOT be vectored to L0EBF cause the user SWI service routine has been +* changed + lda <D.TINIT get map type flag + IFNE mc09 + bita #$40 check it without changing it in mc09 MMU + ELSE + bita #$01 check it without changing it + ENDC + +* Change to LBEQ R.SysSvc to avoid JMP [,X] +* and add R.SysSvc STA >DAT.Task ??? + beq MapT0 in map 0: restore hardware and do system service + tst <D.SSTskN get system state 0,1 + bne MapGrf if in grfdrv, go to map 0 and do system service + +* the preceding few lines are necessary, as all SWI's still pass thru +* here before being vectored to the system service routine... which +* doesn't copy the stack from user state. + IFNE mc09 + sta >MMUADR go to map type X again to get user's stack + ELSE + sta >DAT.Task go to map type X again to get user's stack + ENDC +* a byte less, a cycle more than ldy #$FEED-R$Size, or ldy #$F000+SWIStack + leay <SWIStack,pc where to put the register stack: to $FEDF + tfr s,u get a copy of where the stack is + IFNE H6309 + ldw #R$Size get the size of the stack + tfm u+,y+ move the stack to the top of memory + ELSE + pshs b + ldb #R$Size +Looper lda ,u+ + sta ,y+ + decb + bne Looper + puls b + ENDC + bra L0EB8 and go from map type 1 to map type 0 + +* Execute SWI vector (called from $FEFA) +SWIVCT ldx #D.SWI get DP offset of vector + bra SWICall go execute it + +* Execute NMI vector (called from $FEFD) +NMIVCT ldx #D.NMI get DP offset of vector + bra L0EB8 go execute it + +* The end of the kernel module is here + emod +eom equ * + +* What follows after the kernel module is the register stack, starting +* at $FEDD (6309) or $FEDF (6809). This register stack area is used by +* the kernel to save the caller's registers in the $FEXX area of memory +* because it doesn't get "switched out" no matter the contents of the +* MMU registers. +SWIStack + fcc /REGISTER STACK/ same # bytes as R$Size for 6809 + IFNE H6309 + fcc /63/ if 6309, add two more bytes of space + ENDC + + fcb $55 D.ErrRst + + IFNE mc09 +* For Multicomp09, the processor vectors are in RAM so they can be loaded +* with the service addresses directly, instead of requiring another indirection +* The vectors are set up by a data table copy of CPUVect + ELSE +* This list of addresses ends up at $FEEE after the kernel track is loaded +* into memory. All interrupts come through the 6809 vectors at $FFF0-$FFFE +* and get directed to here. From here, the BRA takes CPU control to the +* various handlers in the kernel. + bra SWI3VCT SWI3 vector comes here + nop + bra SWI2VCT SWI2 vector comes here + nop + bra FIRQVCT FIRQ vector comes here + nop + bra IRQVCT IRQ vector comes here + nop + bra SWIVCT SWI vector comes here + nop + bra NMIVCT NMI vector comes here + nop + ENDC + +* The final byte (eg the NOP after bra NMIVCT) should be at offset $EFF +* and will end up at address $FEFF in physical memory. If any code above +* is changed, you must inspect the listing and adjust the addresses at +* the label PAD. + end