# HG changeset patch # User Neal Crook # Date 1492715719 -3600 # Node ID 18306d646f71d9e384546f3e31b865c41ac7ff4c # Parent 1ff3d7673e3637d75c36792bfd16dcbd08b2ce71 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. diff -r 1ff3d7673e36 -r 18306d646f71 level1/modules/rel.asm --- 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 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 +* for debug, change the RTS ($39) to JMP ($7E) +* Come here in high memory: $EExx +L0101a +* lda #$39 RTS + lda #$7E JMP + sta $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 $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 -$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 $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 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 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 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 diff -r 1ff3d7673e36 -r 18306d646f71 level2/modules/kernel/fldabx.asm --- 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 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 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 diff -r 1ff3d7673e36 -r 18306d646f71 level2/modules/kernel/fmove.asm --- 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 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 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 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 diff -r 1ff3d7673e36 -r 18306d646f71 level2/modules/kernel/fsrqmem.asm --- 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 DAT.Task and we can use A here, instead of E + ELSE + pshs a + lda MMUADR Update MMU + ELSE + anda #$FE force TR=0 + sta DAT.Task + ENDC + puls a + ENDC + clr SysCall,pc Setup System service routine entry vector + stx S.SysIRQ,pc Setup system IRQ service vector + stx S.SvcIRQ,pc Setup in system IRQ service vector + stx S.Poll,pc Setup interrupt polling vector + stx S.AltIRQ,pc Setup alternate IRQ vector: pts to an RTS + stx S.Flip1,pc Setup change to task 1 vector + stx SysCalls,pc load y with address of table, below + lbsr SysSvc copy table below into dispatch table + +* Initialize system process descriptor + ldu 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 DAT.Regs+5 + pshs a + lda #$01 + sta >-$6000,x + cmpa ,x + puls a + bne L0111 + stb 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 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 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 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.SvcIRQ] execute irq service + bcc L0D5B + + ldx D.SvcIRQ] (Normally routine in Clock calling D.Poll) + inc MMUADR Save to MMU as well + ELSE + lda #1 Task 1 + ora 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 MMUADR Save to MMU + ELSE + ora 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,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,MMUADR + ELSE + stb >DAT.Task + ENDC + jmp ,u + +* Flip to task 1 (used by GRF/WINDInt to switch to GRFDRV) (pointed to +* by MMUADR save it to MMU register + ELSE + sta >DAT.Task save it to GIME register + ENDC + inc 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 MMUADR Force to System State (Task 0) + clra + tfr a,dp ASSUME: A=0 from earlier +MapGrf equ * come here from elsewhere, too. + lda 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,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 DAT.Task ??? + beq MapT0 in map 0: restore hardware and do system service + tst 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