;       CP/M 2.0 disk re-definition library
;
;       Copyright (c) 1979
;       Digital Research
;       Box 579
;       Pacific Grove, CA
;       93950
;
;       BUGS fixed 07/07/82     JDW Software Source.
;
;       Unterminated IF in 'diskdef' macro itself
;
;       Unecessary complexity of 'lds' & 'defds' macros
;       'lds' now does both jobs, 'defds' removed (not needed).
;
;
;       'comment' dummy in 'ddw' & 'ddb' altered to 'messag'
;       because of apparent BUG in Macro-80 ver 3.44
;
;       'eq' 'gt' 'ge' etc replace '=' '>' '>=' in conditionals
;
;
;
;       Now will work with Macro-80 ver 3.44 as well as MAC.
;       if using M80, may need to alter 'set' psuedo-op
;       to aset equivalent if inside a .z80.
;
;
;
;       CP/M logical disk drives are defined using the
;       macros given below, where the sequence of calls
;       is:
;
;       disks   n
;       diskdef parameter-list-0
;       diskdef parameter-list-1
;       ...
;       diskdef parameter-list-n
;       endef
;
;       where n is the number of logical disk drives attached
;       to the CP/M system, and parameter-list-i defines the
;       characteristics of the ith drive (i=0,1,...,n-1)
;
;       each parameter-list-i takes the form
;               dn,fsc,lsc,[skf],bls,dks,dir,cks,ofs,[0]
;       where
;       dn      is the disk number 0,1,...,n-1
;       fsc     is the first sector number (usually 0 or 1)
;       lsc     is the last sector number on a track
;       skf     is optional "skew factor" for sector translate
;       bls     is the data block size (1024,2048,...,16384)
;       dks     is the disk size in bls increments (word)
;       dir     is the number of directory elements (word)
;       cks     is the number of dir elements to checksum
;       ofs     is the number of tracks to skip (word)
;       [0]     is an optional 0 which forces 16K/directory entry
;
;       for convenience, the form
;               dn,dm
;       defines disk dn as having the same characteristics as
;       a previously defined disk dm.
;
;       a standard four drive CP/M system is defined by
;               disks   4
;               diskdef 0,1,26,6,1024,243,64,64,2
;       dsk     set     0
;               rept    3
;       dsk     set     dsk+1
;               diskdef %dsk,0
;               endm
;               endef
;
;       the value of "begdat" at the end of assembly defines the
;       beginning of the uninitialize ram area above the bios,
;       while the value of "enddat" defines the next location
;       following the end of the data area.  the size of this
;       area is given by the value of "datsiz" at the end of the
;       assembly.  note that the allocation vector will be quite
;       large if a large disk size is defined with a small block
;       size.
;
dskhdr  macro   dn
;;      define a single disk header list
dpe&dn: dw      xlt&dn,0000h    ;translate table
       dw      0000h,0000h     ;scratch area
       dw      dirbuf,dpb&dn   ;dir buff,parm block
       dw      csv&dn,alv&dn   ;check, alloc vectors
       endm
;
disks   macro   nd
;;      define nd disks
ndisks  set     nd      ;;for later reference
dpbase  equ     $       ;base of disk parameter blocks
;;      generate the nd elements
dsknxt  set     0
       rept    nd
       dskhdr  %dsknxt
dsknxt  set     dsknxt+1
       endm
       endm
;
dpbhdr  macro   dn
dpb&dn  equ     $               ;disk parm block
       endm
;
ddb     macro   data,messag
;;      define a db statement
       db      data            messag
       endm
;
ddw     macro   data,messag
;;      define a dw statement
       dw      data            messag
       endm
;
gcd     macro   m,n
;;      greatest common divisor of m,n
;;      produces value gcdn as result
;;      (used in sector translate table generation)
gcdm    set     m       ;;variable for m
gcdn    set     n       ;;variable for n
gcdr    set     0       ;;variable for r
       rept    65535
gcdx    set     gcdm/gcdn
gcdr    set     gcdm - gcdx*gcdn
       if      gcdr eq 0
       exitm
       endif
gcdm    set     gcdn
gcdn    set     gcdr
       endm
       endm
;
diskdef macro   dn,fsc,lsc,skf,bls,dks,dir,cks,ofs,k16
;;      generate the set statements for later tables
       if      nul lsc
;;      current disk dn same as previous fsc
dpb&dn  equ     dpb&fsc ;equivalent parameters
als&dn  equ     als&fsc ;same allocation vector size
css&dn  equ     css&fsc ;same checksum vector size
xlt&dn  equ     xlt&fsc ;same translate table
       else
secmax  set     lsc-(fsc)       ;;sectors 0...secmax
sectors set     secmax+1;;number of sectors
als&dn  set     (dks)/8 ;;size of allocation vector
       if      ((dks) mod 8) ne 0
als&dn  set     als&dn+1
       endif
css&dn  set     (cks)/4 ;;number of checksum elements
;;      generate the block shift value
blkval  set     bls/128 ;;number of sectors/block
blkshf  set     0       ;;counts right 0's in blkval
blkmsk  set     0       ;;fills with 1's from right
       rept    16      ;;once for each bit position
       if      blkval eq 1
       exitm
       endif
;;      otherwise, high order 1 not found yet
blkshf  set     blkshf+1
blkmsk  set     (blkmsk shl 1) or 1
blkval  set     blkval/2
       endm
;;      generate the extent mask byte
blkval  set     bls/1024        ;;number of kilobytes/block
extmsk  set     0       ;;fill from right with 1's
       rept    16
       if      blkval eq 1
       exitm
       endif
;;      otherwise more to shift
extmsk  set     (extmsk shl 1) or 1
blkval  set     blkval/2
       endm
;;      may be double byte allocation
       if      (dks) gt 256
extmsk  set     (extmsk shr 1)
       endif
;;      may be optional [0] in last position
       if      not nul k16
extmsk  set     k16
       endif
;;      now generate directory reservation bit vector
dirrem  set     dir     ;;# remaining to process
dirbks  set     bls/32  ;;number of entries per block
dirblk  set     0       ;;fill with 1's on each loop
       rept    16
       if      dirrem eq 0
       exitm
       endif
;;      not complete, iterate once again
;;      shift right and add 1 high order bit
dirblk  set     (dirblk shr 1) or 8000h
       if      dirrem gt dirbks
dirrem  set     dirrem-dirbks
       else
dirrem  set     0
       endif
       endm
       dpbhdr  dn      ;;generate equ $
       ddw     %sectors,<;sec per track>
       ddb     %blkshf,<;block shift>
       ddb     %blkmsk,<;block mask>
       ddb     %extmsk,<;extnt mask>
       ddw     %(dks)-1,<;disk size-1>
       ddw     %(dir)-1,<;directory max>
       ddb     %dirblk shr 8,<;alloc0>
       ddb     %dirblk and 0ffh,<;alloc1>
       ddw     %(cks)/4,<;check size>
       ddw     %ofs,<;offset>
;;      generate the translate table, if requested
       if      nul skf
xlt&dn  equ     0               ;no xlate table
       else
       if      skf eq 0
xlt&dn  equ     0               ;no xlate table
       else
;;      generate the translate table
nxtsec  set     0       ;;next sector to fill
nxtbas  set     0       ;;moves by one on overflow
       gcd     %sectors,skf
;;      gcdn = gcd(sectors,skew)
neltst  set     sectors/gcdn
;;      neltst is number of elements to generate
;;      before we overlap previous elements
nelts   set     neltst  ;;counter
xlt&dn  equ     $               ;translate table
       rept    sectors ;;once for each sector
       if      sectors lt 256
       ddb     %nxtsec+(fsc)
       else
       ddw     %nxtsec+(fsc)
       endif
nxtsec  set     nxtsec+(skf)
       if      nxtsec ge sectors
nxtsec  set     nxtsec-sectors
       endif
nelts   set     nelts-1
       if      nelts eq 0
nxtbas  set     nxtbas+1
nxtsec  set     nxtbas
nelts   set     neltst
       endif
       endm
       endif   ;;end of nul fac test
       endif   ;;end of nul bls test
       endif   ;; BUG for end of repeat last defn.
       endm
;
lds     macro   lb,dn,val
lb&dn:  ds      val&dn
       endm
;
endef   macro
;;      generate the necessary ram data areas
begdat  equ     $
dirbuf: ds      128     ;directory access buffer
dsknxt  set     0
       rept    ndisks  ;;once for each disk
       lds     alv,%dsknxt,als
       lds     csv,%dsknxt,css
dsknxt  set     dsknxt+1
       endm
enddat  equ     $
datsiz  equ     $-begdat
;;      db 0 at this point forces hex record
       endm
;