changeset 3290:24bfa6f85ba6

Add fixed emudsk driver from EJJaquay. Add emudsk operating system disk image.
author tlindner <tlindner@macmess.org>
date Fri, 17 Sep 2021 20:13:53 -0700
parents a68d565ba339
children c467fd80252c
files 3rdparty/drivers/emudsk/emudsk.asm 3rdparty/drivers/emudsk/makefile 3rdparty/drivers/nocan/makefile 3rdparty/packages/arcadepak/.DS_Store level2/coco3/bootfiles/makefile level2/coco3/makefile
diffstat 6 files changed, 281 insertions(+), 120 deletions(-) [+]
line wrap: on
line diff
--- a/3rdparty/drivers/emudsk/emudsk.asm	Mon Apr 12 14:45:41 2021 -0700
+++ b/3rdparty/drivers/emudsk/emudsk.asm	Fri Sep 17 20:13:53 2021 -0700
@@ -15,7 +15,11 @@
 *  03    Corrected minor errors in GetSect.        R. Gault 11/12/26
 *  04    Corrected more logic errors.              R. Gault 11/12/29
 *                                                & R. Gault 12/02/24
-
+*  05    Correct frame errors                      EJJaquay 20/12/29
+*        small optimization to branch table        LCB      20/12/29
+*  06    Clear drive select in INIT. Rearrange
+*        getsect slightly to reduce use of stack.  EJJaquay 21/01/05
+*
 * EmuDisk floppy disk controller driver
 * Edition #1
 * 04/18/96 : Written from scratch by Alan DeKok
@@ -25,16 +29,14 @@
 *                  All Rights Reserved.
 *  License is given to individuals for personal use only.
 *
-*
 *  Comments: Ensure that device descriptors mark it as a hard drive
 *
-*
 *   $FF80-$FF82: logical record number
 LSN      equ  $FF80           where to put the logical sector number
 
 *
 *   $FF83: command/status register.
-*          Output: 0=read, 1=write, 2=close.  
+*          Output: 0=read, 1=write, 2=close.
 *          Input: 0=no error, non-zero=error codes (see below).
 command  equ  $FF83           where to put the commands
 
@@ -42,9 +44,10 @@
 *   $FF84-$FF85: 6809's 16-bit buffer address (cannot cross an 8K boundary due
 *          to interference from the MMU emulation).
 buffer   equ  $FF84           pointer to the buffer
+
 *   $FF86: controls .vhd drive 0=drive1 1=drive2
 vhdnum   equ  $FF86
-*
+
 * Returns:
 *
 * 0=successful
@@ -56,20 +59,20 @@
 * 254=invalid command byte
 * 255=power-on state or closed.
 *
-*  The "close" command just flushes all the read/write buffers and
+* The "close" command just flushes all the read/write buffers and
 * restores the metacontroller to its power-up state.  The hard drive must be
 * enabled by the user using the MS-DOS command "ECHO >COCO3.VHD" (another
 * crash safeguard), so error code 2 indicates this has not been done.
 
          nam   EmuDsk
-         ttl   os9 device driver    
+         ttl   os9 device driver
 
          ifp1
          use   os9.d
          use   rbf.d
          endc
 
-tylg     set   Drivr+Objct   
+tylg     set   Drivr+Objct
 atrv     set   ReEnt+rev
 rev      set   $02
 
@@ -77,168 +80,248 @@
 
          org   0
          rmb   DRVBEG+(DRVMEM*2) Normal RBF device mem for 2 drives RG
-prevdr   rmb   1               previously used drive RG
+prevdr   rmb   1                 previously used drive RG
          rmb   255-.             residual page RAM for stack etc. RG
 size     equ   .
 
-         fcb   $FF            This byte is the driver permissions
+         fcb   $FF               This byte is the driver permissions
 name     fcs   /EmuDsk/
-         fcb   4               edition #4 RG
+         fcb   6
 
-start    lbra   INIT           3 bytes per entry to keep RBF happy
-         lbra   READ
-         lbra   WRITE
-         lbra   GETSTA
-         lbra   SETSTA
-         lbra   TERM
-
+**************************************************************************
+* Init
+*
 * Entry: Y=Ptr to device descriptor
 *        U=Ptr to device mem
+*        V.PAGE and V.PORT 24 bit device address
+*
+* Exit:  CC carry set on error
+*        B  error code if any
+*
+* Actions:
+*
+*   Set V.NDRV to number of drives supported (2)
+*   Set DD.TOT to something non-zero
+*   Set V.TRACK to $FF
+*   Initialize device control registers?
 *
 * Default to only one drive supported, there's really no need for more.
 * Since MESS now offers second vhd drive, EmuDsk will support it. RG
+**************************************************************************
+
 INIT     ldd   #$FF02        'Invalid' value & # of drives
          stb   V.NDRV,u      Tell RBF how many drives
          leax  DRVBEG,u      Point to start of drive tables
-init2    sta   DD.TOT+2,x      Set media size to bogus value $FF0000
+init2    sta   DD.TOT+2,x    Set media size to bogus value $FF0000
          sta   V.TRAK,x      Init current track # to bogus value
          leax  DRVMEM,x      Move to second drive memory. RG
          decb
          bne   init2
          stb   prevdr,u      preset previous drive to 1st vhd
+         stb   >vhdnum       let emulator know EJJ 05jan21
+
+**************************************************************************
+* Term
+*
 * for now, TERM routine goes here.  Perhaps it should be pointing to the
 * park routine? ... probably not.
+**************************************************************************
 TERM
+
+**************************************************************************
+* GetSta
+*
+* Entry: Y   = path dsc. ptr
+*        U   = Device mem ptr
+*
+* Exit:  CC carry set on error
+*        B  error code if any
+*
+**************************************************************************
 GETSTA   clrb                 no GetStt calls - return, no error, ignore
-         rts   
+         rts                  return to caller
+
+**************************************************************************
+* Module Jump table here to minimize long branches LCB
+**************************************************************************
 
+start    bra    INIT          3 bytes per entry to keep RBF happy
+         nop
+         bra    READ
+         nop
+         bra    WRITE
+         nop
+         bra    GETSTA
+         nop
+         lbra   SETSTA
+         bra    TERM
+         nop
+
+**************************************************************************
+* Read
+*
 * Entry: B:X = LSN
 *        Y   = path dsc. ptr
 *        U   = Device mem ptr
+*
+* Exit:  CC carry set on error
+*        B  error code if any
+*
+* Actions:
+*  Load A with read command and call GetSect
+*  If error return it in reg B
+*  if LSN is not zero use GETSTA to return
+*  If LSN is zero copy first DD.SIZ bytes of sector to drive table
+*
+**************************************************************************
 READ     clra                 READ command value=0
-         bsr   GetSect        Go read the sector, exiting if there's an error
-         tstb                 msb of LSN
-         bne   GETSTA         if not sector 0, return
+         bsr   GetSect        Get the sector
+         bne   reterr         error return if not zero
+         tstb                 test msb of LSN
+         bne   noerr          if not sector 0, return
          leax  ,x             sets CC.Z bit if lsw of LSN not $0000
-         bne   GETSTA         if not sector zero, return
+         bne   noerr          if not sector zero, return
+* Copy LSN0 data to the drive table each time LSN0 is read
+         ldx   PD.BUF,y       get ptr to sector buffer
+         leau  DRVBEG,u       point to first drive table
+         lda   PD.DRV,y       get vhd drive number from descriptor RG
+         beq   copy.0         go if first vhd drive
+         leau  DRVMEM,u       point to second drive table
+       IFNE  H6309
+copy.0   ldw   #DD.SIZ        # bytes to copy over
+         tfm   x+,u+
+       ELSE
+copy.0   ldb   #DD.SIZ        # bytes to copy over
+copy.1   lda   ,x+            grab from LSN0
+         sta   ,u+            save into device static storage
+         decb
+         bne   copy.1
+       ENDC
+noerr    clrb
+         rts
 
-* LSN0, standard OS-9 format
-* Actually, this isn't really necessary for a HD, as the information in
-* LSN0 never changes after it's read in once.  But we'll do it anyhow
-         ldx   PD.BUF,y       Get ptr to sector buffer
-         leau  DRVBEG,u       point to the beginning of the drive tables
-         ldb   #DD.SIZ        copy bytes over
-         lda   PD.DRV,y       Get vhd drive number from descriptor RG
-         beq   copy.0         go if first vhd drive
-         leau  DRVMEM,u       point to second drive memory
-         IFNE  H6309
-copy.0   clra
-         tfr   d,w
-         tfm   x+,u+
-         ELSE
-copy.0   lda   ,x+            grab from LSN0
-         sta   ,u+            save into device static storage 
-         decb
-         bne   copy.0
-         ENDC
-         clrb
-         rts   
+**************************************************************************
+* Write
+*
+* Entry: B:X = LSN
+*        Y   = path dsc. ptr
+*        U   = Device mem ptr
+*
+* Exit:  CC carry set on error
+*        B  error code if any
+*
+* Actions:
+*  Load reg A with write command and call get sect
+*  Return with error if any in reg B
+**************************************************************************
 
 WRITE    lda   #$01           WRITE command = 1
+         bsr   GetSect
+         bne   reterr
+         clrb
+         rts
 
-* Get Sector comes here with:
+reterr   tfr    a,b           Move error code to reg B
+         coma                 Set the carry flag
+         rts
+
+**************************************************************************
+* GetSect
+*
 * Entry: A = read/write command code (0/1)
 *        B,X = LSN to read/write
-*        Y   = path dsc. ptr
-*        U   = Device static storage ptr
-* Exit:  A   = error status from command register
-GetSect  pshs  x,d            Moved up in routine to save command code. RG
+*        Y = path dsc. ptr
+*        U = Device static storage ptr
+*
+* Exit:  A = Error code, zero if none (also sets CC)
+*        B,X,Y,U are preserved
+*
+* Note: Returns from READ or WRITE on errors to preserve stack frame - EJJ
+*
+* Actions:
+*  Put buffer address from PD.BUF
+*  Put drive from PD.DRV
+*  Put LSN from B,X
+*  Put command to cause emulator to do syncronous DMA transfer
+*  Translate and return error code
+**************************************************************************
+
+GetSect  pshs  x,a            Save regs x and a
          lda   PD.DRV,y       Get drive number requested
          cmpa  #2             Only two drives allowed. RG
-         bhs   DrivErr        Return error if "bad" drive#
+         bhs   DriveErr       Too many?
          cmpa  prevdr,u       did the drive change? RG
-         beq   gs.2           no, then don't reset the drive
-         sta   >vhdnum         set to new vhd# RG
+         beq   gs.1           no, then don't reset the drive
+         sta   >vhdnum        set to new vhd# RG
          sta   prevdr,u       update RG
-gs.2     stb   >LSN           Tell MESS which LSN
+gs.1     stb   >LSN           Tell emulator which LSN
          stx   >LSN+1
          ldx   PD.BUF,y       Where the 256-byte LSN should go
+
 * Note: OS-9 allocates buffers from system memory on page boundaries, so
 * the low byte of X should now be $00, ensuring that the sector is not
 * falling over an 8K MMU block boundary.
 * This should be the job of RBF not EmuDsk! RG
 
          stx   >buffer        set up the buffer address
-         puls  a              recover command
+         puls  x,a            restore regs
          sta   >command       get the emulator to blast over the sector
          lda   >command       get the error status
-         bne   FixErr         if non-zero, go report the error and exit
-         puls  b,x,pc         restore registers and exit
+         bne   FixErr         if non-zero translate the error and return
+         rts                  return with LSN intact and no error
 
-DrivErr  leas  6,s            kill address of calling routine (Read/Write)
-         comb
-* FIND ERROR CODE TO USE
-         ldb   #E$NotRdy      not ready
-         rts
+* Translate emulator error code to OS-9 code and return to caller.
+
+DriveErr puls  x,a            restore regs
+         bra   NotRdy         not ready
 
-* Emulator error codes translated to OS-9 error codes.
-*
-* 2=not enabled
-*      E$NotRDy - drive is not ready
-*
-* 4=too many MS-DOS files open,
-*      E$
-*
-* 5=access denied (virtual HD file locked by another program
-*      or MS-DOS read-only status)
-*      E$WP  - write protect
-*
-* 6/12=internal error
-*      E$CRC - CRC error
-*
-* 254=invalid command byte
-*      E$
-*
-* 255=power-on state or closed.
-*      E$NotRdy - drive is not ready
-*
-FixErr   leas  5,s         kill B,X,PC from GetSect routine
-         cmpa  #02
+* Entry: A=error code from emulator
+FixErr   cmpa  #02            not enabled
+         beq   NotRdy
+         cmpa  #255           power on state or closed
          beq   NotRdy
-         cmpa  #255
-         beq   NotRdy
-         cmpa  #5
+         cmpa  #5             access denied or DOS read-only
          beq   WP
-         cmpa  #6
+         cmpa  #6             internal error
          beq   CRC
-         cmpa  #12
+         cmpa  #12            internal error
          beq   CRC
 
 * if it's something we don't recognize, it's a seek error
-         comb
-         ldb   #E$Seek        seek error
-         rts   
+Seek     lda   #E$Seek        seek error
+         rts
+
+NotRdy   lda   #E$NotRdy      not ready
+         rts
 
-NotRdy   comb  
-         ldb   #E$NotRdy      not ready
-         rts   
+WP       lda   #E$WP          write protect
+         rts
 
-WP       comb  
-         ldb   #E$WP          write protect
-         rts   
+CRC      lda   #E$CRC         CRC error
+         rts
+
+*L03D4    lda   #E$Write       write error
+*         rts
 
-CRC      comb  
-         ldb   #E$CRC         CRC error
-         rts   
+*L03E0    lda   #E$Read        Read error
+*         rts
 
-L03D4    comb  
-         ldb   #E$Write       write error
-         rts   
-
-
-L03E0    comb  
-         ldb   #E$Read        Read error
-         rts   
+**************************************************************************
+* SetSta
+*
+* Entry: Y   = path dsc. ptr
+*        U   = Device mem ptr
+*
+* Exit:  CC carry set on error
+*        B  error code if any
+*
+* Actions:
+*   Get function code from stack PD.RGS,Y
+*   Get drive number from stack PD.DRV,Y
+*   issue park command if requested
+*   ignore other requests
+*
+**************************************************************************
 
 SETSTA   ldx   PD.RGS,y       Get caller's register stack ptr
          ldb   R$B,x          Get function code
@@ -250,22 +333,23 @@
          beq   park
          comb                 set carry for error
          ldb   #E$UnkSvc      return illegal service request error
-         rts   
+         rts
 
 * This next is pointless for a virtual drive but probably does not hurt.
-* MESS does not require this if hard drives are swapped in mid-stream. In
+* Emulators do not require this if hard drives are swapped in mid-stream. In
 * real hardware, this is important as would be closing all open files. RG
+
 park     lda   PD.DRV,y       get drive number RG
          cmpa  #2             test for illegal value RG
          bhs   format         ignore if illegal RG
          sta   >vhdnum        tell which drive to halt RG
          ldb   #$02           close the drive
          stb   >command       save in command register
-         clr   >vhdnum        force the drive to first vhd drive although it may not be needed RG
-
+         clr   >vhdnum        Reset drive to H0 RG
+         clr   prevdr,u       Clear prevdr to match vhdnum EJJ
 format   clrb                 ignore physical formats.  They're not
          rts                  necessary
 
          emod
+eom      equ   *
 
-eom      equ   *
--- a/3rdparty/drivers/emudsk/makefile	Mon Apr 12 14:45:41 2021 -0700
+++ b/3rdparty/drivers/emudsk/makefile	Fri Sep 17 20:13:53 2021 -0700
@@ -4,8 +4,8 @@
 
 DRIVERS		= emudsk_6809.dr emudsk_6309.dr
 DESCS		= h0.dd ddh0.dd h1.dd
-ALLOBJS		= $(DRIVERS) $(DESCS)
 DSK			= Modules_EmuDisk.dsk
+ALLOBJS		= $(DRIVERS) $(DESCS) $(DSK)
 
 all:	$(ALLOBJS) $(DEPENDS)
 
--- a/3rdparty/drivers/nocan/makefile	Mon Apr 12 14:45:41 2021 -0700
+++ b/3rdparty/drivers/nocan/makefile	Fri Sep 17 20:13:53 2021 -0700
@@ -4,8 +4,8 @@
 
 DRIVERS		=	rammer_nocan.dr rammer_nocan_63.dr
 DESCS		= r0_nocan.dd
-ALLOBJS		= $(DRIVERS) $(DESCS)
 DSK			= Modules_NoCan_Rammer.dsk
+ALLOBJS		= $(DRIVERS) $(DESCS) $(DSK)
 
 all:	$(ALLOBJS) $(DEPENDS)
 
Binary file 3rdparty/packages/arcadepak/.DS_Store has changed
--- a/level2/coco3/bootfiles/makefile	Mon Apr 12 14:45:41 2021 -0700
+++ b/level2/coco3/bootfiles/makefile	Fri Sep 17 20:13:53 2021 -0700
@@ -2,6 +2,7 @@
 
 # Module directory
 MD		= ../modules
+THIRD   = ../../../3rdparty
 
 DEPENDS		= ./makefile
 
@@ -75,6 +76,9 @@
 CLOCK60HZ  = $(MD)/clock_60hz $(MD)/clock2_soft
 CLOCK60HZDW = $(MD)/clock_60hz $(MD)/clock2_dw
 CLOCK60HZCC3FPGA = $(MD)/clock_60hz $(MD)/clock2_coco3fpga
+EMUDSK6809 = $(THIRD)/drivers/emudsk/emudsk_6809.dr \
+		$(THIRD)/drivers/emudsk/h0.dd \
+		$(THIRD)/drivers/emudsk/h1.dd
 
 # NitrOS-9 disk bootfile to allow booting from DriveWire server
 # on a DE1 or Xilinx using Gary Becker's CoCo 3 FGPA
@@ -404,6 +408,16 @@
 		$(PIPE) \
 		$(CLOCK50HZ)
 
+BOOTFILE_EMUDSK	= $(MD)/krnp2 $(MD)/ioman $(MD)/init \
+		$(MD)/rbf.mn \
+		$(FLOPPY_80D) \
+		$(MD)/ddd0_80d.dd \
+		$(MD)/scf.mn \
+		$(VTIO_COGRF_80) \
+		$(PIPE) \
+		$(CLOCK60HZ) \
+		$(EMUDSK6809)
+
 BOOTFILES	= bootfile_40d bootfile_40d_50hz bootfile_80d \
 		bootfile_80d_50hz bootfile_dw bootfile_dw_headless \
 		bootfile_becker bootfile_arduino bootfile_becker_headless \
@@ -411,7 +425,8 @@
 		bootfile_coco3fpga bootfile_coco3fpga_sd bootfile_coco3fpga_sd_rtc \
 		bootfile_coco3fpga_rom bootfile_coco3fpga_rom_dw bootfile_coco3fpga_rom_rtc \
 		bootfile_rs232pak bootfile_directmodempak bootfile_rs232pak_headless \
-		bootfile_directmodempak_headless bootfile_cocolink_headless bootfile_cocolink
+		bootfile_directmodempak_headless bootfile_cocolink_headless bootfile_cocolink \
+		bootfile_emudsk
 
 KERNELS		= kernel_1773 kernel_1773_50hz kernel_dw kernel_becker \
 		kernel_arduino kernel_cocosdc kernel_ide kernel_dide \
@@ -494,6 +509,9 @@
 bootfile_ide: $(BOOTFILE_IDE) $(DEPENDS)
 	$(MERGE) $(BOOTFILE_IDE)>$@
 
+bootfile_emudsk: $(BOOTFILE_EMUDSK) $(DEPENDS)
+	$(MERGE) $(BOOTFILE_EMUDSK)>$@
+
 # Kernels
 kernel_becker: $(KERNEL_BECKER) $(DEPENDS)
 	$(MERGE) $(KERNEL_BECKER)>$@
--- a/level2/coco3/makefile	Mon Apr 12 14:45:41 2021 -0700
+++ b/level2/coco3/makefile	Fri Sep 17 20:13:53 2021 -0700
@@ -20,6 +20,7 @@
 BOOTFILE_80D	= bootfiles/bootfile_80d
 BOOTFILE_40D_50HZ	= bootfiles/bootfile_40d_50hz
 BOOTFILE_80D_50HZ	= bootfiles/bootfile_80d_50hz
+BOOTFILE_EMUDSK	= bootfiles/bootfile_emudsk
 KERNELFILE	= bootfiles/kernel_1773
 KERNELFILE_50HZ	= bootfiles/kernel_1773_50hz
 KERNELFILE_DW	= bootfiles/kernel_dw
@@ -88,18 +89,22 @@
 LDSKCOCOSDC	= $(DISTRONAME)_cocosdc.dsk
 LDSKBECKERHEADLESS	= $(DISTRONAME)_becker_headless.dsk
 LDSKARDUINOHEADLESS	= $(DISTRONAME)_arduino_headless.dsk
+DSKEMUDSK = $(DISTROVER)_emudsk.dsk
+LDSKEMUDSK = $(DISTRONAME)_emudsk.dsk
 TESTDSK		= test.dsk
 
 DSKS		= $(DSK360K_1) $(DSK360K_1_50HZ) $(DSK360K_2) \
 		$(DSK720K) $(DSK720K_50HZ) $(DSKDW) $(DSKDWHEADLESS) \
 		$(DSKBECKER) $(DSKARDUINO) $(DSKBECKERHEADLESS) \
 		$(DSKARDUINOHEADLESS) $(DSKCOCOSDC) $(DSKRS232PAK) $(DSKDIRECTMODEMPAK) \
-		$(DSKCOCOLINK) $(DSKCOCOLINKHEADLESS) $(DSKRS232PAKHEADLESS) $(DSKDIRECTMODEMPAKHEADLESS)
+		$(DSKCOCOLINK) $(DSKCOCOLINKHEADLESS) $(DSKRS232PAKHEADLESS) $(DSKDIRECTMODEMPAKHEADLESS) \
+		$(DSKEMUDSK)
 LDSKS		= $(LDSK360K_1) $(LDSK360K_1_50HZ) $(LDSK360K_2) \
 		$(LDSK720K) $(LDSK720K_50HZ) $(LDSKDW) $(LDSKDWHEADLESS) \
 		$(LDSKBECKER) $(LDSKARDUINO) $(LDSKBECKERHEADLESS) \
 		$(LDSKARDUINOHEADLESS) $(LDSKCOCOSDC) $(LDSKRS232PAK) $(LDSKDIRECTMODEMPAK) \
-		$(LDSKCOCOLINK) $(LDSKCOCOLINKHEADLESS) $(LDSKRS232PAKHEADLESS) $(LDSKDIRECTMODEMPAKHEADLESS)
+		$(LDSKCOCOLINK) $(LDSKCOCOLINKHEADLESS) $(LDSKRS232PAKHEADLESS) $(LDSKDIRECTMODEMPAKHEADLESS) \
+		$(LDSKEMUDSK)
 
 # Make all components
 all:
@@ -1019,6 +1024,60 @@
 	$(RM) $(LDSK720K_50HZ)
 	$(SOFTLINK) $@ $(LDSK720K_50HZ)
 
+$(DSKEMUDSK):
+	$(RM) $@
+	$(OS9FORMAT_DS80) -q $@ -n"NitrOS-9/$(CPU) Level $(LEVEL)"
+	$(OS9GEN) $@ -b=$(BOOTFILE_EMUDSK) -t=$(KERNELFILE)
+	$(MAKDIR) $@,CMDS
+	$(MAKDIR) $@,SYS
+	$(MAKDIR) $@,DEFS
+	$(OS9COPY) modules/$(CCBKRN) $@,$(CCBKRN)
+	$(OS9COPY) modules/$(SYSGO) $@,sysgo
+	$(OS9ATTR_EXEC) $@,sysgo
+	$(CD) cmds; $(OS9COPY) $(sort $(CMDS) $(CMDS_D2)) ../$@,CMDS
+	$(OS9ATTR_EXEC) $(foreach file,$(sort $(CMDS) $(CMDS_D2)),$@,CMDS/$(file))
+	$(CD) sys; $(OS9COPY) $(SYSBIN) ../$@,SYS
+	$(OS9ATTR_TEXT) $(foreach file,$(SYSBIN),$@,SYS/$(file))
+	$(CD) sys; $(CPL) $(SYSTEXT) ../$@,SYS
+	$(OS9ATTR_TEXT) $(foreach file,$(notdir $(SYSTEXT)),$@,SYS/$(file))
+	$(CD) defs; $(CPL) $(DEFS) ../$@,DEFS
+	$(OS9ATTR_TEXT) $(foreach file,$(DEFS),$@,DEFS/$(file))
+	$(CPL) $(STARTUP) $@,startup
+	$(OS9ATTR_TEXT) $@,startup
+	$(MAKDIR) $@,NITROS9
+	$(MAKDIR) $@,NITROS9/$(DISTRO)
+	$(MAKDIR) $@,NITROS9/$(DISTRO)/CMDS
+	$(CD) cmds; $(OS9COPY) $(MODULECMDS) ../$@,NITROS9/$(DISTRO)/CMDS
+	$(OS9ATTR_EXEC) $(foreach file,$(MODULECMDS),$@,NITROS9/$(DISTRO)/CMDS/$(file))
+	$(MAKDIR) $@,NITROS9/$(DISTRO)/MODULES
+	$(MAKDIR) $@,NITROS9/$(DISTRO)/MODULES/BOOTTRACK
+	$(CD) modules; $(OS9COPY) $(BOOTTRACK) ../$@,NITROS9/$(DISTRO)/MODULES/BOOTTRACK
+	$(OS9ATTR_EXEC) $(foreach file,$(BOOTTRACK),$@,NITROS9/$(DISTRO)/MODULES/BOOTTRACK/$(file))
+	$(MAKDIR) $@,NITROS9/$(DISTRO)/MODULES/KERNEL
+	$(CD) modules; $(OS9COPY) $(KERNEL) ../$@,NITROS9/$(DISTRO)/MODULES/KERNEL
+	$(OS9ATTR_EXEC) $(foreach file,$(KERNEL),$@,NITROS9/$(DISTRO)/MODULES/KERNEL/$(file))
+	$(MAKDIR) $@,NITROS9/$(DISTRO)/MODULES/SYSMODS
+	$(CD) modules; $(OS9COPY) $(SYSMODS) ../$@,NITROS9/$(DISTRO)/MODULES/SYSMODS
+	$(OS9ATTR_EXEC) $(foreach file,$(SYSMODS),$@,NITROS9/$(DISTRO)/MODULES/SYSMODS/$(file))
+	$(MAKDIR) $@,NITROS9/$(DISTRO)/MODULES/CLOCKS
+	$(CD) modules; $(OS9COPY) $(CLOCKS) ../$@,NITROS9/$(DISTRO)/MODULES/CLOCKS
+	$(OS9ATTR_EXEC) $(foreach file,$(CLOCKS),$@,NITROS9/$(DISTRO)/MODULES/CLOCKS/$(file))
+	$(MAKDIR) $@,NITROS9/$(DISTRO)/MODULES/RBF
+	$(CD) modules; $(OS9COPY) $(RBF) ../$@,NITROS9/$(DISTRO)/MODULES/RBF
+	$(OS9ATTR_EXEC) $(foreach file,$(RBF),$@,NITROS9/$(DISTRO)/MODULES/RBF/$(file))
+	$(MAKDIR) $@,NITROS9/$(DISTRO)/MODULES/SCF
+	$(CD) modules; $(OS9COPY) $(SCF) ../$@,NITROS9/$(DISTRO)/MODULES/SCF
+	$(OS9ATTR_EXEC) $(foreach file,$(SCF),$@,NITROS9/$(DISTRO)/MODULES/SCF/$(file))
+	$(MAKDIR) $@,NITROS9/$(DISTRO)/MODULES/PIPE
+	$(CD) modules; $(OS9COPY) $(PIPE) ../$@,NITROS9/$(DISTRO)/MODULES/PIPE
+	$(OS9ATTR_EXEC) $(foreach file,$(PIPE),$@,NITROS9/$(DISTRO)/MODULES/PIPE/$(file))
+	$(MAKDIR) $@,NITROS9/$(DISTRO)/BOOTLISTS
+	$(CD) bootlists; $(CPL) *.bl ../$@,NITROS9/$(DISTRO)/BOOTLISTS
+	$(MAKDIR) $@,NITROS9/$(DISTRO)/SCRIPTS
+	$(CD) scripts; $(CPL) mb* ../$@,NITROS9/$(DISTRO)/SCRIPTS
+	$(RM) $(LDSKEMUDSK)
+	$(SOFTLINK) $@ $(LDSKEMUDSK)
+
 info:
 	@$(ECHO) "*** NitrOS-9/$(CPU) Level $(LEVEL) for the $(MACHINE) ***"
 	@$(foreach dsk, $(DSKS), $(ECHO) $(dsk);)