home *** CD-ROM | disk | FTP | other *** search
/ Oakland CPM Archive / oakcpm.iso / cpm / kaypro / dskdrv13.lbr / DSKDRV13.ZQ0 / DSKDRV13.Z80
Text File  |  1985-06-05  |  43KB  |  1,632 lines

  1.     title    'DSKDRIVE foreign disk driver - using RSX (85/02/02)'
  2.     subttl    'default IBM CPM86 DSDD on Kaypro 4'
  3. ;
  4.     .z80;        for M80 benefit
  5. ver    equ    13;    Version number to be filled in. <10 debug
  6. false    equ    0
  7. true    equ    NOT false
  8. ;
  9. ; customise the @RSX value for the application.  See BDOS call lists
  10. ; below for guidance.  Try to avoid values likely to create conflicts
  11. @RSX    equ    115;    115 is GSX graphics on CPM86, probably safe
  12. driver    equ    true;    TRUE installs drivers visible to DOS
  13. ;
  14. ; Copyright (c) 1985 by C.B Falconer       (203) 281-1438
  15. ; 680 Hartford Tpk, Hamden, Ct 06504.   All rights reserved.
  16. ;
  17. ; This program may be copied/used/modified etc, but it may NOT
  18. ; be sold without express written permission from C.B. Falconer
  19. ;
  20. ; This system provides a foreign disk driver on the Kaypro 4
  21. ; which can then be configured to any suitable format.  The 
  22. ; default format is that for the IBM PC running CPM86 (DSDD).
  23. ; Once installed (by running) the drive configuration can be
  24. ; altered by auxiliary software (still to be written).  To remove
  25. ; the driver run the program again.  The default foreign drive
  26. ; type can easily be altered, once the paramaters are known.
  27. ;
  28. ; The system uses the generalized CPM 2.2 RSX system published
  29. ; and documented separately, and whose source code is embodied
  30. ; within this program.  The program uses Z80 opcodes only in the
  31. ; actual disk driver (for hardware reasons) and in the transfer
  32. ; between user storage and disk buffer (for performance).  This
  33. ; should ease porting to 8080 only systems.
  34. ;
  35. ; NOTE:    This source file requires SLRs Z80ASM or M80 for assembly,
  36. ;    and RELOCCP.SYS for run-time load and relocation.  M80 has
  37. ;    not been checked.  I suspect some labels may be too long.
  38. ;
  39. ; Revisions:        (in LIFO order)
  40. ; 1.3    85/5/15. Revised alternate table for Kaypro 2 SSDD. No code
  41. ;    changes whatsoever.
  42. ; 1.2    85/2/3. Added support for single density.  DOS dskreset call
  43. ;    resets this drive.  SECSHF calculated from HSTBLK.
  44. ; 1.1    85/2/1. Altered configuration table to reduce portion needed
  45. ;    in external cookbook files for reconfiguration.  A | B | C
  46. ;    runtime parameters for alternate drive type selection added,
  47. ;    so that a total of 5 configuration (including native) are
  48. ;    available without the auxiliary ALTDRIVE program.
  49. ; 1.0    85/01/30. Initial release.  Alteration software needed
  50. ; 0.3    85/01/27. First working disk drive.
  51. ; 0.2    85/01/24. Provisions for BDOS driver installation,
  52. ;    checks etc.
  53. ; 0.1    85/01/05. Inactive causes reversion to original BDOS call in
  54. ;    case this was a substitute for it. debug allows testing.
  55. ;    Keep track of current DMA address.
  56. ; 0.0    Original version, by C.B. Falconer (85/Jan/04).
  57. ;
  58. ; WARNING - When an RSX is installed all warm boots are converted
  59. ; into "returns" to the original calling CCP, which is not removed
  60. ; nor reloaded.  The original Digital Research CCP will not start
  61. ; executing SUBMIT jobs under these circumstances.  Installation
  62. ; of CCPLUS will repair this omission.  ZCPR action has not been
  63. ; checked.  Other problems (with the original CCP) may appear on
  64. ; "select errors", i.e. by logging into a non-existent drive.
  65. ;
  66. ; This system is the outline of a generalized RSX system, with
  67. ; initialization and termination code.  It is expected to 
  68. ; respond to BDOS calls with the value @RSX (normally larger
  69. ; than any usual CPM call value), and receive an argument of
  70. ; some form in the (de) register.  Two special values of (de)
  71. ; are reserved (0 and -1).  In usual operation the (de) value
  72. ; is normally a pointer, which cannot take on either of these
  73. ; special values.  For character output RSXs (e.g. list output
  74. ; replacement) this prevents sending a nul or a rubout with all
  75. ; bits set.  Remember this is a full word parameter.
  76. ;
  77. ; 0 implies a residence inquiry, and should return a zero 
  78. ; value if the system is not resident, (as will CPM 2.2 for any
  79. ; invalid calls), and non-zero if resident and activated.  This
  80. ; allows the initialization code to detect that the system is
  81. ; already mounted, and avoid multiple loading.  Similarly
  82. ; application programs can check that the RSX is available.  A
  83. ; zero value returned in (a) signifies the RSX is not available.
  84. ;
  85. ; The second special value is 0ffffh (i.e. -1), which
  86. ; signals the system to become inactive, so that the next
  87. ; warm boot will remove it entirely.
  88. ; A third special argument is 0001h.  This is optional, and is
  89. ; used to return a data address.  For DSKDRIVE in particular
  90. ; this is used to return a pointer to the memory resident
  91. ; drive configuration table (whose structure thus should not
  92. ; be altered in order to maintain compatibility with auxiliary
  93. ; software).  DSKDRIVE actually returns this pointer for all
  94. ; DE arguments other than 0 or -1, but this should not be
  95. ; counted on.
  96. ;
  97. ; This file implements the DSKDRIVE RSX, and indicates where the
  98. ; code should be installed, and the calling conventions for other
  99. ; RSXs.  See the label "chkparms" to allow initialization
  100. ; parameters, and the label "rsx" to install the actual code.
  101. ; Note especially than any code located ahead of the label 
  102. ; "@keep" is available only during initialization.  However 
  103. ; the initialization section can call routines in the retained
  104. ; portion.  The "bthoot" connector allows re-initialization on
  105. ; each "warm boot".
  106. ;
  107. ; The system, when combined with "RELOCCP", loads itself just
  108. ; below the CCP, and keeps the CCP resident. (See RELOCCP.OVR,
  109. ; which is an assembly time option for RELOCCP, for a method
  110. ; of minimizing memory wastage for multiple RSX's).  If RSX.COM
  111. ; is executed while resident, it attempts to remove itself and
  112. ; reclaim memory.  If other systems have been loaded below RSX
  113. ; it will not be able to reclaim memory until those systems 
  114. ; (probably further RSX's) have been removed.
  115. ;
  116. ; To create a custom RSX modify the equate for "@RSX" above,
  117. ; and create any necessary code in the "rsx" and "chkparms"
  118. ; areas.  Give the resultant file an approriate name (e.g. MYRSX),
  119. ; assemble, and create the MYRSX.COM with RELOCCP (See RELOCCP
  120. ; documentation).  When executed you now have available a new
  121. ; BDOS function, which executes whatever you put in.
  122. ;
  123. ; Acknowledgement:  Some of the mechanisms used in this system
  124. ; have been taken from various public domain systems, especially
  125. ; those by Gary Novasielski and Bruce Ratoff.
  126. ;
  127. ; This system was created to ease installation of two operations:
  128. ; a generalized foreign disc driver, and a "CHAIN" mechanism
  129. ; whereby programs can load and execute arbitrary commands.  The
  130. ; pre-existing KEYS program can probably be converted to execute
  131. ; under this system, as can UNSPOOL40 (enhancement of Br. Ratoffs
  132. ; UNSPOL30).
  133. ;
  134. ; While some code economies could easily be made for any particular
  135. ; application, I feel that using one standard environment is much
  136. ; more important.  Thus the provisions for bios driver modification
  137. ; have been installed, with the complete check/restore system.  The
  138. ; disadvantage remains that custom code must be included in this 
  139. ; source and assembled, rather than standing by itself.
  140. ;
  141. ; BDOS Functions:
  142. @SYS    equ    0
  143. @KEY    equ    1
  144. @CON    equ    2
  145. @RDR    equ    3
  146. @PUN    equ    4
  147. @LST    equ    5
  148. @DIO    equ    6
  149. @RIO    equ    7
  150. @SIO    equ    8
  151. @MSG    equ    9
  152. @INP    equ    10
  153. @RDY    equ    11
  154. @VER    equ    12
  155. @LOG    equ    13
  156. @DSK    equ    14
  157. @OPN    equ    15
  158. @CLS    equ    16
  159. @DIR    equ    17
  160. @NXT    equ    18
  161. @DEL    equ    19
  162. @FRD    equ    20
  163. @FWR    equ    21
  164. @MAK    equ    22
  165. @REN    equ    23
  166. @LGV    equ    24
  167. @CUR    equ    25
  168. @DMA    equ    26
  169. @ALO    equ    27
  170. @WPT    equ    28
  171. @GRO    equ    29
  172. @CHG    equ    30
  173. @GPM    equ    31
  174. @USR    equ    32
  175. @RRD    equ    33
  176. @RWR    equ    34
  177. @SIZ    equ    35
  178. @REC    equ    36
  179. @RDV    equ    37
  180. @WRZ    equ    40;    38 and 39 are MPM functions
  181. ;
  182. ; some CPM 3.0 functions, for reference.  Match function if
  183. ; possible when a 2.2 RSX is created.
  184. ; 41 thru 50 are used
  185. @CHN    equ    47;    Chain to command line in (dmaadr)
  186. @OVL    equ    59;    Load overlay
  187. ;@RSX    equ    60;    Call RSX.  Different usage than here
  188. ; 98 thru 112 are used.  115 is CPM86 GSX graphics.
  189. @PFN    equ    152;    parse filename
  190. ;
  191. ; System equates:
  192. CPMBASE    equ    0
  193. boot    equ    CPMBASE
  194. bdos    equ    boot+5
  195. tfcb    equ    boot+5CH
  196. tfcb1    equ    tfcb
  197. tfcb2    equ    tfcb+16
  198. tbuff    equ    boot+80H
  199. TPA    equ    boot+100H
  200. CTRL    equ    ' '-1;        CTRL CHAR MASK
  201. CR    equ    CTRL AND 'M'
  202. LF    equ    CTRL AND 'J'
  203. TAB    equ    CTRL AND 'I'
  204. FF    equ    CTRL AND 'L'
  205. BS    equ    CTRL AND 'H'
  206. eof    equ    CTRL AND 'Z'
  207. fcblen    equ    36;        Length of input FCB
  208. ;
  209. ; nvects is larger than the CPM 2.2 standard to allow for:
  210. ;   1. CPM 3 bios system
  211. ;   2. Other systems with extended bios calls and/or use
  212. ;      e.g. Kaypro has a key table, which some applications
  213. ;      alter (via the pointer at 1).  If the space is not
  214. ;      reserved system crashes will result.
  215. nvects    equ    29;        Number of BIOS vectors
  216. n22vec    equ    16;        Number of CPM 2.2 vectors
  217. ;
  218. ; Macro Definitions
  219. ;
  220. ; Force location counter zero modulo val
  221. ; with respect to "relative" by filling with "fill" bytes
  222. align    macro    val,relative,fill
  223.     local    here
  224. here    equ    $-relative
  225.     if    (here+val)/val*val-here-val
  226.      if    nul fill
  227.       ds    (here+val)/val*val-here
  228.      else;;    Z80ASM specific coding.
  229.       ds    (here+val)/val*val-here,fill
  230.      endif
  231.     endif
  232.     endm
  233. ;
  234. ; ************************************************************
  235. ; * This is my standard page relocatable system. See RELOCCP *
  236. ; ************************************************************
  237. ;
  238.     cseg;    system requires org 0 and org 100h modules
  239. ;        You may replace this with two "orgs" in two
  240. ;        different assemblies to get the overall system
  241. ;        for RELOCCP to prepare and relocate at run-time.
  242. ;
  243. ; This defines the first location of the relocated image.
  244. ; The portion from here to "@keep" is not retained after
  245. ; initialization.  The data here is used for relocation
  246. @base:    jp    intro;        Following is std relocation data
  247. @size:    dw    segsiz;        size of segment to relocate
  248. @memsz:    db    pages;        total memory use in pages
  249. ;
  250. ; Patch/alter this value to non-zero if the RSX may only be
  251. ; loaded in a virgin system.  This should be done if the system
  252. ; installs bios modifications that the BDOS can see.
  253. chkflg:    db    driver;        Set non-zero for virgin system only
  254. ;
  255. ; This code gets everything started
  256. intro:    ld    hl,(bdos+1);    First so other calls work
  257.     ld    (gobdos+1),hl;    Save the BDOS entry point
  258.     ld    de,signon
  259.     call    tstr
  260.     call    chkparms;    Do any parameter checking needed
  261.     jp    c,exeunt;    ..with help message on carry=fault
  262.     ld    de,0
  263.     ld    a,@RSX;
  264.     call    DOS;        enquire whether loaded
  265.     or    a;        If loaded, 
  266.     jp    nz,intro1;      then bring it down
  267.     call    rsxsetup;    initialize.
  268.     call    init;        Customized portion
  269.     jp    bootrq;        ..bootrq, which sets connectors
  270. ;
  271. ; already loaded, bring it down
  272. intro1:    ld    de,-1
  273.     ld    a,@RSX
  274.     call    DOS;        tell it to come down on next boot
  275.     jp    boot;        which should kill it
  276. ;
  277. ; Setup the system.  First, check environment to see if
  278. ; BIOS vectors are accessible and reasonable.
  279. rsxsetup:
  280.     ld    a,(boot);    Location BOOT should
  281.     cp    0c3h;        have a JMP instruction
  282.     jp    nz,vecterr
  283.     ld    hl,(boot+1);    Location one points to
  284.     ex    de,hl;         the table of bios jumps
  285.     ld    hl,(bdos+1);    This should point to BDOS
  286.     ld    a,(chkflg)
  287.     ld    (kill+1),a;    Save for use at exit time. Unclean
  288.     or    a;         but want it user patchable (1 place)
  289.     call    nz,chksys;    Hook, prevent loading invalid system
  290.     ex    de,hl
  291.     ld    c,nvects;    preserve z flag in here
  292.     ld    de,biosv
  293.     push    de;        by default init our vector
  294.     jp    nz,vecterr;    after push, to correct stack
  295.     ld    de,bsave;    which we move into
  296.     ex    de,hl;        the code.
  297. rsxsetup1:
  298.     ld    a,nvects-n22vec
  299.     cp    c
  300.     jp    nc,rsxsetup2;    stop checking after 2.2 types
  301.     ld    a,(de)
  302.     xor    (hl);        another JMP?
  303.     and    0f1h;        allow Call or Jmp
  304.     jp    nz,vecterr
  305. rsxsetup2:
  306.     ld    a,(de)
  307.     ld    (hl),a;        bsave[n,0]
  308.     inc    de
  309.     inc    hl
  310.     ex    (sp),hl
  311.     inc    hl
  312.     ld    a,(de)
  313.     ld    (hl),a;        biosv[n,1]
  314.     inc    hl
  315.     ex    (sp),hl
  316.     ld    (hl),a;        bsave[n,1]
  317.     inc    de
  318.     inc    hl
  319.     ld    a,(de)
  320.     ld    (hl),a;        bsave[n,2]
  321.     ex    (sp),hl
  322.     ld    (hl),a;        biosv[n,2]
  323.     inc    hl;    biosv[n+1,0]
  324.     ex    (sp),hl
  325.     inc    hl;    biosv[n+1,0]
  326.     inc    de
  327.     dec    c;    n := n+1;
  328.     jp    nz,rsxsetup1
  329.     pop    hl;        purge 2nd transfer address
  330. ; This was satisfactory, now if "driver" is TRUE, patch the
  331. ; BIOS drivers to point to the new copy (only the std CPM 2.2
  332. ; entries) so that new entries can be made locally.  The final
  333. ; exit mechanism will restore everything.
  334.     ld    a,(chkflg)
  335.     or    a
  336.     call    nz,bpatch
  337. ; Save old vectors and CCP return address. BDOS saved at the very
  338. ; beginning of system. User code can patch new vectors as required.
  339.     ld    hl,(boot+1)
  340.     ld    (boot0+1),hl;    Save the BOOT vector
  341.     ld    hl,2;        Retrieve the CCP
  342.     add    hl,sp;        return address from
  343.     ld    a,(hl);        down the stack a ways.
  344.     inc    hl
  345.     ld    h,(hl)
  346.     ld    l,a
  347.     ld    (ccpret+1),hl;    Save the CCP re-entry point
  348.     ret
  349. ;
  350. ; Patch the original bios drivers, which have been checked
  351. ; for validity and a reasonable location, to point to the
  352. ; new bios table. Only called when "driver" is TRUE.  DO NOT
  353. ; PATCH the original warm/cold boot entries.
  354. bpatch:    ld    hl,(boot+1)
  355.     inc    hl
  356.     inc    hl
  357.     ld    de,biosv
  358.     ld    c,n22vec-1;    count of 2.2 bios entries only
  359. bpat1:    inc    hl
  360.     inc    de
  361.     inc    de
  362.     inc    de
  363.     inc    hl
  364.     ld    (hl),e
  365.     inc    hl
  366.     ld    (hl),d
  367.     dec    c
  368.     jp    nz,bpat1;    more
  369.     ret
  370. ;
  371. ; Check system is in usable state. (de) holds the bios pointer,
  372. ; and (hl) holds the bdos pointer.  If the values are not
  373. ; reasonable, return non-zero flag. 
  374. ; This routine has no relocated code, so it may be patched.
  375. ; a,f,h,l
  376. chksys:    ld    a,e
  377.     cp    3
  378.     ret    nz;        boot pointer should end in 3
  379.     add    e
  380.     sub    l
  381.     ret    nz;        bdos pointer should end in 6
  382.     ld    a,d
  383.     sub    h
  384.     sub    0eh
  385.     ret    nz;        Page difference should be 0eh
  386.     ld    a,(hl)
  387.     sub    0c3h;        JMP instruction
  388.     ret    nz
  389.     inc    hl
  390.     ld    a,(hl)
  391.     sub    011h
  392.     ret    nz;        bdos destination should go to 11
  393.     inc    hl
  394.     ld    a,h
  395.     sub    (hl);        on same page to be valid
  396.     ret
  397. ;
  398. vecterr:
  399.     pop    de;        remove the extra pointer
  400.     ld    de,vcterrmsg
  401. ;    "    "
  402. ; exit with message de^
  403. exeunt:    call    tstr
  404.     jp    boot;        try re-booting.
  405. ;
  406. vcterrmsg:
  407.     db    CR,LF,'Invalid system$'
  408. ;
  409. ; =============================================================
  410. ; ****    Custom portion of initialization code here       ****
  411. ; =============================================================
  412. ;
  413. ; Check run command parameters.  Carry if not satisfactory
  414. ; This version for DSKDRIVE moves alternate configurations into
  415. ; place on "DSKDRIVE A", "DSKDRIVE B" or "DSKDRIVE C" commands.
  416. chkparms:
  417.     ld    hl,alta
  418.     ld    a,(tfcb+1)
  419.     sub    'A';        fcbs are always upshifted
  420.     jp    z,chkp1;    A, go move it in
  421.     dec    a
  422.     or    a;        clear any carry
  423.     ld    hl,altb
  424.     jp    z,chkp1;    B
  425.     dec    a
  426.     ret    nz;        not C
  427.     ld    hl,altc
  428. chkp1:    ex    de,hl;        move configuration (hl) into
  429.     ld    hl,info;    "info" area
  430.     ld    b,infosz
  431. chkp2:    ld    a,(de)
  432.     ld    (hl),a
  433.     inc    de
  434.     inc    hl
  435.     dec    b
  436.     jp    nz,chkp2
  437.     ret
  438. ;
  439. ; Custom initialization. 
  440. ; When this routine is reached the various bios vector copies
  441. ; (and patches if "driver" is true) have been made.  This 
  442. ; routine may alter the connectors in "biosv" to install new
  443. ; drivers, etc.  The original routines are available thru
  444. ; "bsave" table.  Remember that any routines connected MUST
  445. ; live in the retained portion of code, following "@keep"
  446. ; below, and I recommend putting their code in the "rsx" area.
  447. ; If "driver" is false any bios modifications made through
  448. ; this routine will only be available to applications calling
  449. ; the bios directly (through location 1), and not to BDOS.
  450. init:    ld    de,home
  451.     ld    a,8
  452.     call    apatch
  453.     ld    de,seldsk
  454.     ld    a,9
  455.     call    apatch
  456.     ld    de,setrk
  457.     ld    a,10
  458.     call    apatch
  459.     ld    de,setsec
  460.     ld    a,11
  461.     call    apatch
  462.     ld    de,setdma
  463.     ld    a,12
  464.     call    apatch
  465.     ld    de,read
  466.     ld    a,13
  467.     call    apatch
  468.     ld    de,write
  469.     ld    a,14
  470.     call    apatch
  471.     ld    de,sectran
  472.     ld    a,16
  473. ;    "    "
  474. ; Patch bios connector (a) to connect to (de).  Note that
  475. ; the 0th connector is the cold boot entry (per DR standards).
  476. ; Also note that the first entry in biosv is entry # 1
  477. ; DO NOT patch connectors 0 or 1, nor any above "n22vecs"
  478. ; a,f
  479. apatch:    dec    a
  480.     dec    a
  481.     push    hl
  482.     ld    l,a
  483.     add    a
  484.     add    l;        *3
  485.     ld    hl,biosv+4;    offset past "jmp" opcode
  486.     add    l
  487.     ld    l,a
  488.     adc    h
  489.     sub    l
  490.     ld    h,a
  491.     ld    (hl),e
  492.     inc    hl
  493.     ld    (hl),d
  494.     pop    hl
  495.     ret    
  496. ;
  497. signon:    db    'DSKDRIVE [A|B|C] (an RSX) '
  498.     db    ver / 10 + '0', '.', ver MOD 10 + '0', '$'
  499. ;
  500. ; Alternate drive configurations, used on "DSKDRIVE A" 
  501. ; or "DSKDRIVE B" commands.  No parameter uses default.
  502. ; see "info" table for for parameter meanings.  You may
  503. ; reconfigure these tables for your most used types, thus
  504. ; allowing up to five (including native) drive versions.
  505. ;
  506. alta:    dw    40;        cpmspt
  507.     db    3;        bsh
  508.     db    07h,0;        blm,exm
  509.     dw    194;        dsm
  510.     dw    63;        drm
  511.     db    0F0h,0;        al0,al1
  512.     dw    16;        cks
  513.     dw    1;        off
  514.     db    4;        hstblk
  515.     db     0, 1, 2, 3, 4, 5, 6, 7;    sxltbl
  516.     db     8, 9,10,11,12,13,14,15
  517.     db    16,17,18,19,20,21,22,23
  518.     db    24,25,26,27,28,29,30,31
  519.     db    32,33,34,35,36,37,38,39
  520.     db    40,41,42,43,44,45,46,47
  521.     db    48,49,50,51,52,53,54,55
  522.     db    56,57,58,59,60,61,62,63
  523.     db    64,65,66,67,68,69,70,71
  524.     db    72,73,74,75,76,77,78,79
  525.     db    0;        spare
  526.     db    0;        sec1st
  527.     db    0;        config
  528.     db    40;        ntrks
  529.     db    0;        nsecs
  530.     db    'KAYPRO 2 (SSDD)$$$$$$$$$$$$'
  531. ;
  532. altb:    dw    36;        cpmspt
  533.     db    4;        bsh
  534.     db    0Fh,0;        blm,exm
  535.     dw    170;        dsm
  536.     dw    63;        drm
  537.     db    080h,0;        al0,al1
  538.     dw    16;        cks
  539.     dw    4;        off
  540.     db    2;        hstblk
  541.     db     0, 1, 2, 3, 4, 5, 6, 7;    sxltbl
  542.     db     8, 9,10,11,12,13,14,15
  543.     db    16,17,18,19,20,21,22,23
  544.     db    24,25,26,27,28,29,30,31
  545.     db    32,33,34,35,36,37,38,39
  546.     db    40,41,42,43,44,45,46,47
  547.     db    48,49,50,51,52,53,54,55
  548.     db    56,57,58,59,60,61,62,63
  549.     db    64,65,66,67,68,69,70,71
  550.     db    72,73,74,75,76,77,78,79
  551.     db    0;        spare
  552.     db    1;        sec1st
  553.     db    2;        config
  554.     db    40;        ntrks
  555.     db    0;        nsecs
  556.     db    'TS802 (Televideo DSDD)$$$$$'
  557. ;
  558. altc:    dw    32;        cpmspt
  559.     db    3;        bsh
  560.     db    07h,0;        blm,exm
  561.     dw    251;        dsm
  562.     dw    127;        drm
  563.     db    0F0h,0;        al0,al1
  564.     dw    32;        cks
  565.     dw    3;        off
  566.     db    2;        hstblk
  567.     db     0, 1, 2, 3, 4, 5, 6, 7;    sxltbl
  568.     db     8, 9,10,11,12,13,14,15
  569.     db    16,17,18,19,20,21,22,23
  570.     db    24,25,26,27,28,29,30,31
  571.     db    32,33,34,35,36,37,38,39
  572.     db    40,41,42,43,44,45,46,47
  573.     db    48,49,50,51,52,53,54,55
  574.     db    56,57,58,59,60,61,62,63
  575.     db    64,65,66,67,68,69,70,71
  576.     db    72,73,74,75,76,77,78,79
  577.     db    0;        spare
  578.     db    1;        sec1st
  579.     db    2;        config
  580.     db    40;        ntrks
  581.     db    0;        nsecs
  582.     db    'HP125 (DSDD)$$$$$$$$$$$$$$$'
  583. ;
  584. ;
  585. ; ------------------ End custom initialization area ----------------
  586. ;
  587.     align    256,@base,0;    ensure page aligned
  588. ;
  589. ; *******************************************************
  590. ; * The code from here up is retained in memory after     *
  591. ; * initialization.  It may be used by the initializer    *
  592. ; * This code MUST start on a page boundary.        *
  593. ; *******************************************************
  594. @keep:
  595. ;
  596. ; During operation, this location will point to intercept and will
  597. ; be jumped to by BDOS calls from location 5.  This organization 
  598. ; depends on the fact that BDOS calls the bios directly (ignoring
  599. ; the pointer at location 1), except when needing a warm boot
  600. ; (e.g. after a disk error), when it uses the pointer at 1.
  601. ;
  602. ; This must be at the lowest location in the protected code segment.
  603. bdosv:    jp    intercept;    the bdos link
  604. ;
  605. ; This area replaces the bios jump table, allowing intercepts.
  606. ; Any intercepts (usually console commands) are set up by the
  607. ; initializing code, which is discarded after execution. See
  608. ; comments on "nvects" above.  Normally these bios vectors will be
  609. ; accessed only by executing programs, and not by the BDOS unit.
  610. ; To insert drivers in the bios it is necessary to save the original
  611. ; bios pointers (for restoration when the RSX is removed) and
  612. ; install jumps to this revised table in the original table.  Note
  613. ; that the original table may contain a CALL for the warmboot vector,
  614. ; so that ROM based code can tell the CPM system size when called.
  615. biosv:    REPT    nvects
  616.     jp    $-$
  617.     endm
  618. ;
  619. ; This table has two purposes - it allows connection to the original
  620. ; bios vectors destinations, and it saves all the values for
  621. ; restoration upon RSX exit.  Thus the custom initialization section
  622. ; can patch the real bios table to install new disk drivers, etc.
  623. ; Note that this can only work when this is the FIRST rsx installed.
  624. ; Further ones can only intercept user bios calls and BDOS calls.
  625. ; Provided that the bios table in effect on entry to this system
  626. ; does not hold any data areas, the restoration on RSX removal will
  627. ; be harmless.
  628. bsave:    REPT    nvects
  629.     jp    $-$
  630.     endm
  631. ;
  632. ; The "old" entries needed.  Index 0 here is warmboot, not cold
  633. @home        equ    bsave+(7*3)
  634. @seldk        equ    bsave+(8*3)
  635. @setrk        equ    bsave+(9*3)
  636. @setsec        equ    bsave+(10*3)
  637. @setdma        equ    bsave+(11*3)
  638. @read        equ    bsave+(12*3)
  639. @write        equ    bsave+(13*3)
  640. @sectran    equ    bsave+(15*3)
  641. ;
  642. ; This routine intercepts all BDOS calls.
  643. ; Note that the initial code sequence allows applications to
  644. ; find the actual BDOS, if necessary.  See SD88F6 for one use.
  645. intercept:
  646.     ld    a,0ffh
  647.     cp    c
  648.     jp    c,gobdos;    Never taken, but SD trackable
  649.     ld    a,@SYS;        Get function
  650.     cp    c
  651.     jp    z,sysreq;    a reboot request
  652.     ld    a,@DMA
  653.     cp    c
  654.     jp    z,dodma
  655.     ld    a,@LOG
  656.     cp    c
  657.     jp    z,drvreset;    reset this drive also
  658.     ld    a,@RSX;        defined for this system
  659.     cp    c
  660.     jp    nz,gobdos;    not for us
  661. ; DO NOT optimize the above sequence.  It is intended to be
  662. ; trackable by utilities to list the RSX's active.  The series
  663. ; stops when the instruction is not "ld a,bytevalue".  The
  664. ; initial "ld a,0ffh" will not be counted by tracking utilities
  665. ; and the checks on @SYS and @DMA are always expected.  This
  666. ; organization allows a range of BDOS calls to be intercepted.
  667. ;    "    "
  668.     ld    hl,0
  669.     add    hl,sp
  670.     ld    sp,lclstk
  671.     push    hl;        save entry stack pointer
  672.     call    doit;        This is an extension call
  673.     ex    de,hl;        save return value
  674.     pop    hl
  675.     ld    sp,hl
  676.     ex    de,hl;        return its result
  677.     ld    a,l;        copy result to (a)
  678.     ld    b,h;        so (ba)=(hl), like BDOS
  679.     ret;            to the caller.
  680. ;
  681. ; Reset this drive also when application wants a drive reset
  682. ; Added to RSX system for disk drive application.
  683. drvreset:
  684.     push    bc
  685.     call    bthook
  686.     pop    bc
  687.     jp    gobdos
  688. ;
  689. ; Keep track of the current DMA address on general principles
  690. dodma:    ex    de,hl
  691.     ld    (dmadr),hl;    BDOS' view, not BIOS
  692.     ex    de,hl
  693. ;    "    "
  694. ; Connects to the "real" BDOS routine
  695. gobdos:    jp    $-$;        Patched on entry
  696. ;
  697. ; The RSX (resident system extension).  Argument is de as usual,
  698. ; and the extension specified is (c).  Return value is put in hl.
  699. ; The stack is already set to the local stack, with the old
  700. ; stack pointer under the return from doit.
  701. ; a,f,b,c,d,e,h,l (allowed)
  702. doit:    ld    hl,(active);    set "enquiry" return value in (l)
  703.     ld    a,l
  704.     or    a
  705.     jp    z,gobdos;    inactive, use bdos call
  706.     ld    h,0
  707.     ld    a,e;        check for "loaded enquiry"
  708.     or    d
  709.     ret    z;        signal active on enquiry
  710.     ld    a,e
  711.     and    d
  712.     inc    a
  713.     jp    nz,rsx;        not "pulldown" request.
  714. ;    "    "
  715. ; Inactivate the RSX.  Next boot will try to recover the memory.
  716. kill:    ld    a,$-$;        patched with "chkflg" at init
  717.     or    a
  718.     call    nz,unpch;    Remove any bios alterations
  719.     xor    a
  720.     ld    (active),a;    mark inactive
  721.     ld    l,a;        return 0, pulldown accepted
  722.     ld    h,a;        and we are now inactive.
  723.     ret
  724. ;
  725. ; Remove any bios patches made on initialization, in case this is a
  726. ; driver being inactivated, and further RSX's are loaded beyond it.
  727. ; Thus a "kill" request will be logically executed, even though the
  728. ; memory is not reclaimed. However bios alterations via the pointer
  729. ; at 1 cannot be removed until a warm boot occurs (that pointer may
  730. ; be pointing to an RSX installed later).  Thus the table at biosv
  731. ; must be updated to point to the original bios entries
  732. unpch:    ld    de,bsave+3
  733.     ld    hl,(boot0+1)
  734.     inc    hl
  735.     inc    hl
  736.     inc    hl;        start at the constat entry
  737.     push    hl
  738.     ld    hl,biosv+3
  739.     ld    c,n22vec-1;    dont alter the warm boot entries
  740. unpch1:    ld    b,l;        offset, depends on page alignment
  741.     inc    de;        past opcode
  742.     inc    hl;        Ignore the opcode (dont change)
  743.     ld    (hl),b;    biosv[n,1]  --> oldbios[n,0]
  744.     inc    hl
  745.     ex    (sp),hl
  746.     ld    b,h;        oldbios page
  747.     inc    hl
  748.     ld    a,(de);        lsb
  749.     ld    (hl),a;    oldbios[n,1]
  750.     inc    de;        ^msb
  751.     inc    hl
  752.     ld    a,(de);        msb
  753.     ld    (hl),a;    oldbios[n,2]
  754.     inc    hl;    oldbios[n+1,0]
  755.     ex    (sp),hl
  756.     ld    (hl),b;    biosv[n,2] --> oldbios[n,0]
  757.     inc    hl;    biosv[n+1,0]
  758.     inc    de;        next opcode
  759.     dec    c;    n := n+1
  760.     jp    nz,unpch1
  761.     pop    hl
  762.     ret
  763. ;
  764. ; Note that the following "boot" entries will never be reached if a
  765. ; further RSX has been installed, since that RSX will intercept the
  766. ; boot and do a direct return to the CCP (unless it is inactive, and
  767. ; removes itself, when a whole chain of RSX removals can be started)
  768. ;
  769. ; The application process has requested a warm-boot by invoking BDOS
  770. ; function 0.  If the system is inactive remove it, otherwise return
  771. ; to the CCP via the stored (on initialization) CCP return value.
  772. sysreq:    jp    bootrq;        This allows separation if needed
  773. ;
  774. ; The application process has requested a reboot by jumping to
  775. ; location 0.  If we are no longer active, we will honor the request
  776. ; by executing the address found in the BOOT vector at entry.
  777. ; Otherwise return to CCP without rebooting.
  778. bootrq:    ld    sp,lclstk;    set up a valid stack
  779.     ld    a,(active)
  780.     or    a
  781.     jp    z,done;        Not active, all done. Remove self
  782.     call    bthook;        Application specific boot action
  783.     ld    c,@LOG
  784.     call    gobdos;        Reset drives, like any
  785.     ld    de,actmsg;    other reboot does.
  786.     call    tstr
  787.     ld    de,altid;    added message portion for
  788.     call    tstr;          DSKDRIVE use
  789. ;    "    "
  790. ; Reset the system pointers to use this system.
  791.     ld    hl,bdosv
  792.     ld    (bdos+1),hl
  793.     ld    hl,bootrq
  794.     ld    (biosv+1),hl
  795.     ld    hl,biosv
  796.     ld    (boot+1),hl
  797.     ld    hl,tbuff
  798.     ld    (dmadr),hl;    Will be set by CCP
  799. ccpret:    jp    $-$;        Patched on startup
  800. ;
  801. ; Done with the system
  802. done:    ld    de,donemsg;    Message and jump to old boot addr.
  803.     call    tstr;        as originally read from memory wd 1 
  804. boot0:    jp    $-$;        Reboot. Patched on initialization
  805. ;                This value points to old bios table
  806. ;
  807. ; ================================================================
  808. ;          Utility routine area
  809. ; ================================================================
  810. ;
  811. ; Put string (de) to console, '$' terminated
  812. tstr:    ld    a,@MSG
  813. ;    "    "
  814. ; dos call (a) without disturbing registers.  Does not use the RSX
  815. DOS:    push    bc
  816.     push    de
  817.     push    hl
  818.     ld    c,a
  819.     call    gobdos
  820.     pop    hl
  821.     pop    de
  822.     pop    bc
  823.     ret
  824. ;
  825. ; ==================================================================
  826. ; **** To keep as much as possible constant, put real RSX here    ****
  827. ; ==================================================================
  828. ;
  829. ; This routine MUST be supplied
  830. ; The actual code for the application goes here
  831. ; Note that the (de) parameter can never be 0 or 0ffffh on entry.
  832. ; If this system is really an i/o driver (such as a foreign disk
  833. ; reader/writer) then the RSX itself never need do anything, and
  834. ; this code can be left alone (except that a DOS call is available
  835. ; to trigger the message below).
  836. ; Return any value in hl.
  837. rsx:    ld    hl,info;    return info address only
  838.     ret;            Used to reconfigure the driver
  839. ;
  840. ; This routine MUST be supplied.  It may be only a "ret"
  841. ; for DSKDRIVE recalculates some parameters in case the drive
  842. ; configuration has been changed, and ensures drive reset.
  843. ; a,f,b,h,l
  844. bthook:    xor    a
  845.     ld    (hstact),a
  846.     ld    (unacnt),a
  847.     ld    hl,tbuff
  848.     ld    (dmaadr),hl;    BIOS view of it
  849.     ld    a,(hstblk)
  850.     ld    b,-1
  851. bthk1:    inc    b;        compute secshf from hstblk
  852.     rra;            cy was clear
  853.     or    a
  854.     jp    nz,bthk1;    secshf := log2(hstblk)
  855.     ld    a,b
  856.     ld    (secshf),a
  857.     ld    a,(cpmspt)
  858.     ld    b,a
  859.     ld    a,(config)
  860.     and    0fh;        mask off density selector
  861.     cp    1
  862.     jp    nz,bthk4
  863.     ld    a,b
  864.     or    a
  865.     rrca
  866.     ld    b,a
  867. bthk4:    ld    a,(secshf)
  868. bthk5:    or    a
  869.     jp    z,bthk6
  870.     push    af
  871.     ld    a,b
  872.     rrca
  873.     ld    b,a
  874.     pop    af
  875.     dec    a
  876.     jp    bthk5
  877. bthk6:    ld    a,b
  878.     ld    (offsec),a
  879.     ret
  880. ;
  881. ; ----------- Driver configuration area ------------
  882. ;
  883. ; Host specific ports
  884. ctrlpt    equ    10H;        Controller ports (WD 1791)
  885. statpt    equ    ctrlpt
  886. trkreg    equ    ctrlpt+1
  887. secreg    equ    ctrlpt+2
  888. datapt    equ    ctrlpt+3
  889. ;
  890. ; 1791/2/3 Controller chip specific
  891. ; For most Z80 implementations the data request and interrupt from
  892. ; the 1791 is connected to NMI (possibly gated by the CPU halt
  893. ; status line).  Thus a CPU halt is ended by the appropriate
  894. ; controller status, with the RET instruction in memory location
  895. ; 066h.  A status read after the interrupt will reset the interrupt,
  896. ; as will satisfying the data request.  8080s need more hardware.
  897. wrtmsk    equ    0FCH;        Status bits useful after write
  898. rdmask    equ    09CH;            "    "    read
  899. clrcmd    equ    0CH;        clear controller/reset
  900. rdcmd    equ    08CH;        read physical sector
  901. wtcmd    equ    0ACH;        write physical sector
  902. seekcmd    equ    014H;        seek track
  903. ;
  904. ; Kaypro Specific
  905. bitpt    equ    01CH;        KAYPRO control
  906. drvmsk    equ    3;        bits 0 & 1 select drive
  907. sideb    equ    4;        side selection bit
  908. prtbsy    equ    8;        Parallel printer busy (in)
  909. prtstrb    equ    16;        strobe printer data
  910. densb    equ    32;        density selection bit, 1=single
  911. mtroff    equ    64;        1 bit stops drive motors
  912. bank    equ    128;        Select memory bank.
  913. ;
  914. ;    *** This area is accessed/altered by support programs ***
  915. info:
  916. ; The "info" area has been organized to fit into exactly 128 bytes
  917. ; for convenience in auxiliary programs that reconfigure this.
  918. ;
  919. ; The CPM standard Disk Parameter Block, extended
  920. ; Modification to this structure changes the driver
  921. ;
  922. dpblk:    ; Different values for:    KPRO4    KPRO2    HP125    TVTS802
  923. ;     CPM sectors/physical track
  924. cpmspt:    dw    32;        40    40    32    36
  925. ;    log2(sectors/cpmallocation block)
  926. bsh:    db    4;        4    3    3    4
  927. ;    blm, exm calculated from bsh
  928.     db    0FH,01H;    0Fh,1    7,0    7,0    0Fh,0
  929. ;    total blocks on drive
  930. dsm:    dw    157;        196    194    251    170
  931. ;    directory entries - 1
  932. drm:    dw    63;        63    63    127    63
  933. ;    directory/other blocks pre-allocated
  934.     db    80H,00H;    0C0h,0    0F0h,0    0F0h,0    080h,0
  935. ;    cks=(drm+1)/4 (or 0 for fixed)
  936. cks:    dw    16;        16    16    32    16
  937. ;    reserved tracks
  938. off:    dw    1;        1    1    3    4
  939. ;    CPM extension. 1,2,4,8 sectors/phys record
  940. hstblk:    db    4;        4    4    2    2
  941. ;
  942. ; The sector skew translation table. Room for 10k/track
  943. sxltbl:    db     0, 1, 2, 3, 4, 5, 6, 7
  944.     db     8, 9,10,11,12,13,14,15
  945.     db    16,17,18,19,20,21,22,23
  946.     db    24,25,26,27,28,29,30,31
  947.     db    32,33,34,35,36,37,38,39
  948.     db    40,41,42,43,44,45,46,47
  949.     db    48,49,50,51,52,53,54,55
  950.     db    56,57,58,59,60,61,62,63
  951.     db    64,65,66,67,68,69,70,71
  952.     db    72,73,74,75,76,77,78,79
  953. ;
  954. ; Customization tables for system
  955.     db    0;    SPARE BYTE
  956. ;    Physical ID of 1st sector on track
  957. sec1st:    db    1;        0    0    1    1
  958. ;    Strategy in computing physical addresses
  959. config:    db    4;        2    0    2    2
  960. ; (high bit set for single density)
  961. ; = 0:    1 sided, phys adr = hst adr
  962. ;   1:    sec>offsec side1, adrsec=off-sec
  963. ;   2:    odd trks on side 1, trkadr=hstrk/2
  964. ;   3:    side1 is ntrks up
  965. ;   4:    side1 is ntrks up, count backward
  966. maxcase    equ    4
  967. ;    Number of tracks on physical disk
  968. ntrks:    db    40;        40    40    40    40
  969. ;    Correction to side 1 sector adr.
  970. nsecs:    db    0;        10    0    0    0
  971. ;
  972. ; This portion of "actmsg" is used as ID by altdrive.
  973. altid:        db    'IBM PC (CP/M-86 DSDD)$$$$$$'
  974. ; At least one terminal "$" must be left in above message
  975. ; DO NOT CHANGE LENGTH OF MESSAGE
  976. infosz    equ    $-info
  977. ;
  978. ; The following area is not altered when changing disk types,
  979. ; but includes the standard CPM configuration tables.  This
  980. ; portion must be customized on installation to host only.
  981. ;
  982. modrv:    db    1;    Which drive to alter (0 = A)
  983. dskode:    db    02H;     and the drive selection coding
  984. dendbl:    db    0;    base command for double density
  985. densgl:    db    32;    base command for single density
  986. invert:    db    0;    1 to invert data bits on transfer
  987. ;
  988. ; The CPM standard dpb.  Pointers to above and CPM storage.
  989. dpb:    dw    sxltbl;        0 for no translation
  990.     dw    0,0,0;    *** CPM mungs these, must be in RAM ***
  991.     dw    dirbuf;        pointer
  992.     dw    dpblk;        pointer
  993.     dw    csv;        pointer
  994.     dw    alv;        pointer
  995. ;
  996. ; END of Unalterable (except for values) configuration area
  997. ;
  998. ; "donemsg" and "actmsg" messages MUST be supplied
  999. donemsg:    db    cr,lf,'(DSKDRIVE terminated)$'; on removal
  1000. actmsg:    
  1001. drvmsg:        db    cr,lf,'Drive '
  1002. drvid:        db    'B: set to $'
  1003. ;
  1004. ; The revised foreign disk drivers.
  1005. ;
  1006. home:    ld    bc,0
  1007.     call    setrk
  1008.     ld    a,(hstwrt)
  1009.     or    a
  1010.     jp    nz,home1
  1011.     ld    (hstact),a
  1012. home1:    ret    
  1013. ;
  1014. seldsk:    ld    a,c
  1015.     ld    (sekdsk),a
  1016.     ld    a,(modrv)
  1017.     cp    c
  1018.     jp    nz,@seldk
  1019.     ld    hl,dpb
  1020.     ret    
  1021. ;
  1022. ; Postpone actual selection of originals until read/write
  1023. ; to avoid motor turn-ons, pre-seeks etc. until needed
  1024. setrk:    ld    h,b
  1025.     ld    l,c
  1026.     ld    (sektrk),hl
  1027.     ret    
  1028. ;
  1029. setsec:    ld    a,c
  1030.     ld    (seksec),a
  1031.     jp    @setsec
  1032.  
  1033. setdma:    ld    h,b
  1034.     ld    l,c
  1035.     ld    (dmaadr),hl
  1036.     jp    @setdma
  1037. ;
  1038. sectran:
  1039.     ld    a,(sekdsk);    Needed because RAMDISK fouls
  1040.     ld    hl,modrv;    by not knowing it was not
  1041.     cp    (hl);        selected.
  1042.     jp    nz,@sectran
  1043.     ld    a,d
  1044.     or    e
  1045.     jp    z,sectran2;    no translation, return alone
  1046.     ex    de,hl
  1047.     add    hl,bc
  1048.     ld    l,(hl)
  1049.     ld    h,0
  1050.     ret
  1051. sectran2:
  1052.     ld    h,b
  1053.     ld    l,c
  1054.     ret
  1055. ;
  1056. oread:    ld    hl,(sektrk);    do original read routine
  1057.     ld    b,h
  1058.     ld    c,l
  1059.     call    @setrk
  1060.     jp    @read
  1061. ;
  1062. owrite:    push    bc;        do original write routine
  1063.     ld    hl,(sektrk)
  1064.     ld    b,h
  1065.     ld    c,l
  1066.     call    @setrk
  1067.     pop    bc
  1068.     jp    @write
  1069. ;
  1070. ; Digital Researchs (flawed) deblocking algorithm.
  1071. read:    ld    a,(modrv)
  1072.     ld    b,a
  1073.     ld    a,(sekdsk)
  1074.     cp    b
  1075.     jp    nz,oread
  1076.     xor    a
  1077.     ld    (unacnt),a
  1078.     ld    a,1
  1079.     ld    (readop),a
  1080.     ld    (rsflag),a
  1081.     ld    a,2;        mark "write unallocated"
  1082.     ld    (wrtype),a
  1083.     jp    rdwrt
  1084. ;
  1085. write:    ld    a,(modrv)
  1086.     ld    b,a
  1087.     ld    a,(sekdsk)
  1088.     cp    b
  1089.     jp    nz,owrite
  1090.     xor    a
  1091.     ld    (readop),a;    Not a read
  1092.     ld    a,c
  1093.     ld    (wrtype),a
  1094.     cp    2;        Code for "write unallocated"
  1095.     jp    nz,chkuna;    else wrt to unalloc, set params
  1096.     ld    hl,(bsh);    l := bsh, minimum 3
  1097.     ld    a,1
  1098. write1:    rlca
  1099.     dec    l
  1100.     jp    nz,write1;    Compute block size, in sectors
  1101.     ld    (unacnt),a
  1102. ;    ld    a,(sekdsk)
  1103. ;    ld    (unadsk),a
  1104.     ld    hl,(sektrk)
  1105.     ld    (unatrk),hl
  1106.     ld    a,(seksec)
  1107.     ld    (unasec),a
  1108. ;    "    "
  1109. ; Check for write to unallocated sector
  1110. chkuna:    ld    a,(unacnt)
  1111.     or    a
  1112.     jp    z,alloc;    No unallocated remain
  1113.     dec    a
  1114.     ld    (unacnt),a;    Reduce for next time
  1115. ;    ld    a,(sekdsk)
  1116. ;    ld    hl,unadsk
  1117. ;    cp    (hl)
  1118. ;    jp    nz,alloc;    Not same disk
  1119.     ld    hl,unatrk
  1120.     call    eqtrks
  1121.     jp    nz,alloc;    Not same track
  1122.     ld    a,(seksec)
  1123.     ld    hl,unasec
  1124.     cp    (hl)
  1125.     jp    nz,alloc;    seksec <> unasec
  1126. ;
  1127.     inc    (hl);        unacnt > 0, disk, track sector ok
  1128.     ld    a,(hl)
  1129.     ld    hl,cpmspt
  1130.     cp    (hl)
  1131.     jp    c,inbuff;    Not overflow to next track
  1132.     xor    a
  1133.     ld    (unasec),a
  1134.     ld    hl,(unatrk)
  1135.     inc    hl
  1136.     ld    (unatrk),hl
  1137. inbuff:    xor    a
  1138.     ld    (rsflag),a;    match found, mark unnecessary read
  1139.     jp    rdwrt
  1140. ;
  1141. ; Not an unallocated record, requires pre-read
  1142. alloc:    xor    a
  1143.     ld    (unacnt),a
  1144.     inc    a
  1145.     ld    (rsflag),a
  1146. ;    "    "
  1147. rdwrt:    xor    a;        read or write
  1148.     ld    (errflg),a
  1149.     ld    a,(secshf);    Compute host sector
  1150.     ld    b,a
  1151.     inc    b
  1152.     ld    a,(seksec)
  1153.     rla;            Saving Hi bit in carry
  1154. rdwrt1:    rra
  1155.     or    a;        clear carry
  1156.     dec    b
  1157.     jp    nz,rdwrt1;    sekhst := seksec SHR secshf
  1158.     ld    (sekhst),a
  1159.     ld    hl,hstact
  1160.     ld    a,(hl)
  1161.     ld    (hl),01H;    Set hstact for next
  1162.     or    a
  1163.     jp    z,filhst;    Was not active
  1164. ;    ld    a,(sekdsk)
  1165. ;    ld    hl,hstdsk
  1166. ;    cp    (hl)
  1167. ;    jp    nz,flush
  1168.     ld    hl,hsttrk
  1169.     call    eqtrks
  1170.     jp    nz,flush
  1171.     ld    a,(sekhst)
  1172.     ld    hl,hstsec
  1173.     cp    (hl)
  1174.     jp    z,match
  1175. flush:    ld    a,(hstwrt);    Proper disk but not correct sector
  1176.     or    a
  1177.     call    nz,wthst;    dirty buffer, write it out
  1178. ;    "    "
  1179. filhst:    ld    a,(sekhst)
  1180.     ld    (hstsec),a
  1181.     ld    hl,(sektrk)
  1182.     ld    (hsttrk),hl
  1183. ;    ld    a,(sekdsk);    May have to fill the host buffer
  1184. ;    ld    (hstdsk),a
  1185.     ld    a,(rsflag)
  1186.     or    a
  1187.     call    nz,rdhst
  1188.     xor    a
  1189.     ld    (hstwrt),a;    Mark buffer clean
  1190. ;    "    "
  1191. ; Copy data to or from buffer, depending on "readop"
  1192. match:    ld    a,(hstblk)
  1193.     dec    a
  1194.     ld    hl,seksec
  1195.     and    (hl)
  1196.     ld    l,a
  1197.     ld    h,00H
  1198.     add    hl,hl;        *128
  1199.     add    hl,hl
  1200.     add    hl,hl
  1201.     add    hl,hl
  1202.     add    hl,hl
  1203.     add    hl,hl
  1204.     add    hl,hl
  1205.     ld    de,buff
  1206.     add    hl,de;        point to buffer area
  1207.     ex    de,hl
  1208.     ld    hl,(dmaadr)
  1209.     ex    de,hl
  1210.     ld    bc,128
  1211.     ld    a,(readop)
  1212.     or    a
  1213.     jp    nz,rwmov
  1214.     ld    a,01H
  1215.     ld    (hstwrt),a;    Mark buffer dirty for write
  1216.     ex    de,hl;        And trade move direction
  1217. ;    "    "
  1218. ; Transfer hl^ to de^ for bc, invert bits on "invert"
  1219. rwmov:    ld    a,(invert)
  1220.     or    a
  1221.     jp    z,rwmov2
  1222. rwmov1:    ld    a,(hl)
  1223.     cpl
  1224.     ld    (de),a
  1225.     inc    de
  1226.     inc    hl
  1227.     dec    bc
  1228.     ld    a,b
  1229.     or    c
  1230.     jp    nz,rwmov1
  1231.     jp    qflush
  1232. ;
  1233. ; No inversion, move as rapidly as possible
  1234. rwmov2:    ldir;                    *** Z80 code ***
  1235. ;    "    "
  1236. ; Clear host buffer if this is a directory write
  1237. qflush:    ld    a,(wrtype)
  1238.     cp    1;        Code for directory write
  1239.     ld    a,(errflg)
  1240.     ret    nz
  1241.     or    a
  1242.     ret    nz
  1243.     xor    a
  1244.     ld    (hstwrt),a;    will be clean after write
  1245. ;    "    "
  1246. wthst:    call    rwtbgn
  1247. wthst1:    ei;            during seeks
  1248.     call    setup
  1249.     or    a
  1250.     jp    nz,rwtxit
  1251.     ld    a,(hstblk)
  1252.     ld    e,wtcmd;    write command
  1253.     ld    c,datapt;    I/o port for data
  1254.     ld    hl,buff
  1255.     di
  1256.     rrca
  1257.     jp    nc,wthst2;    Not 128 byte physical rcd
  1258.     ld    b,128
  1259.     call    dcmnde
  1260.     jp    w256
  1261. wthst2:    ld    b,0
  1262.     rrca
  1263.     jp    nc,wthst3;    Not 256 byte physical rcd
  1264.     call    dcmnde
  1265.     jp    w256
  1266. wthst3:    rrca
  1267.     jp    nc,wthst4;    1024 byte physical rcd
  1268.     call    dcmnde
  1269.     jp    w512;        512 byte physical rcd
  1270. wthst4:    call    dcmnde
  1271. ;    "    "
  1272. w1024:    halt;            Else 1024 byte rcd.
  1273.     outi;                        *** Z80 code
  1274.     jp    nz,w1024
  1275. w768:    halt
  1276.     outi
  1277.     jp    nz,w768
  1278. w512:    halt
  1279.     outi
  1280.     jp    nz,w512
  1281. w256:    halt
  1282.     outi
  1283.     jp    nz,w256;    May be a W128, on entry bc
  1284. wthst5:    in    a,(statpt)
  1285.     rra
  1286.     jp    c,wthst5;    Await non-busy
  1287.     rla
  1288.     and    wrtmsk
  1289.     jp    z,rwtxit
  1290.     call    clear
  1291.     dec    d
  1292.     jp    nz,wthst1;    retry
  1293.     ld    a,0FFH;        Signal error
  1294.     jp    rwtxit
  1295. ;
  1296. ; Set up NMI return, save controller track setting
  1297. rwtbgn:    ld    a,(0066H)
  1298.     ld    (save66),a
  1299.     ld    a,0C9H;        "RET" instruction for NMI
  1300.     ld    (0066H),a
  1301.     in    a,(trkreg)
  1302.     ld    (trksav),a
  1303.     ld    d,10;        retries
  1304.     ret
  1305. ;
  1306. eqtrks:    ex    de,hl
  1307.     ld    hl,sektrk
  1308.     ld    a,(de)
  1309.     cp    (hl)
  1310.     ret    nz
  1311.     inc    de
  1312.     inc    hl
  1313.     ld    a,(de)
  1314.     cp    (hl)
  1315.     ret    
  1316. ;
  1317. rdhst:    call    rwtbgn
  1318. rdhst1:    ei
  1319.     call    setup
  1320.     or    a
  1321.     jp    nz,rwtxit
  1322.     ld    a,(hstblk)
  1323.     ld    e,rdcmd;    read command
  1324.     ld    c,datapt;    port to read data from
  1325.     ld    hl,buff
  1326.     di
  1327.     rrca
  1328.     jp    nc,rdhst2;    Not 128 bytes per phys. block
  1329.     ld    b,128
  1330.     call    dcmnde
  1331.     jp    r256
  1332. rdhst2:    ld    b,0;        i.e. 256
  1333.     rrca
  1334.     jp    nc,rdhst3;    Not 256 bytes per block
  1335.     call    dcmnde
  1336.     jp    r256
  1337. rdhst3:    rrca
  1338.     jp    nc,rdhst4;    1024 byte physical record
  1339.     call    dcmnde
  1340.     jp    r512;        512 bytes per block
  1341. rdhst4:    call    dcmnde
  1342. ;    "    "
  1343. r1024:    halt;            else 1024 bytes per block
  1344.     ini;                        *** Z80 code
  1345.     jp    nz,r1024
  1346. r768:    halt
  1347.     ini
  1348.     jp    nz,r768
  1349. r512:    halt
  1350.     ini
  1351.     jp    nz,r512
  1352. r256:    halt
  1353.     ini
  1354.     jp    nz,r256;    May be r128, on entry (b)
  1355. rdhst5:    in    a,(statpt)
  1356.     rra
  1357.     jp    c,rdhst5;    Await non-busy status
  1358.     rla
  1359.     and    rdmask
  1360.     jp    z,rwtxit
  1361.     call    clear
  1362.     dec    d
  1363.     jp    nz,rdhst1;    retry
  1364.     ld    a,0FFH;        Signal error
  1365. ;    "    "
  1366. ; Exit, restoring 66, trkreg, setting errflg on (a)
  1367. rwtxit:    push    af
  1368.     ld    a,(save66)
  1369.     ld    (0066H),a
  1370.     ld    a,(trksav)
  1371.     out    (trkreg),a
  1372.     pop    af
  1373.     ei
  1374.     ld    (errflg),a
  1375.     ret    
  1376. ;
  1377. ; docase (a) on table (hl)^
  1378. docase:    add    a
  1379.     add    l
  1380.     ld    l,a
  1381.     adc    h
  1382.     sub    l
  1383.     ld    h,a
  1384.     ld    a,(hl)
  1385.     inc    hl
  1386.     ld    h,(hl)
  1387.     ld    l,a
  1388.     jp    (hl)
  1389. ;
  1390. cases:    dw    case0, case1, case2
  1391.     dw    case3, case4
  1392. ;
  1393. setup:    ld    hl,(hsttrk)
  1394.     ld    (adrtrk),hl
  1395.     ld    a,(hstsec)
  1396.     ld    (adrsec),a
  1397.     xor    a
  1398.     ld    (side),a;    default use side 0
  1399.     ld    a,(config)
  1400.     and    0fh;        remove density selection
  1401.     cp    maxcase+1
  1402.     jp    nc,error
  1403.     ld    hl,cases;    Execute the appropriate code
  1404.     call    docase
  1405.     jp    seek
  1406. ;
  1407. case0:    ret
  1408. ;
  1409. case1:    ld    a,(adrsec);    config = 1
  1410.     ld    hl,offsec
  1411.     sub    (hl)
  1412.     ret    c
  1413.     ld    hl,nsecs
  1414.     add    (hl)
  1415.     ld    (adrsec),a
  1416.     ld    a,1
  1417.     ld    (side),a
  1418.     ret
  1419. ;
  1420. case2:    ld    hl,(adrtrk)
  1421.     ld    a,l
  1422.     and    1
  1423.     ld    (side),a
  1424.     ld    a,h
  1425.     rra
  1426.     ld    h,a
  1427.     ld    a,l
  1428.     rra
  1429.     ld    l,a    
  1430.     ld    (adrtrk),hl
  1431.     ret    nc;        on side 0
  1432.     ld    hl,nsecs
  1433.     ld    a,(adrsec);    side 1, correct sector address
  1434.     add    (hl)
  1435.     ld    (adrsec),a
  1436.     ret
  1437. ;
  1438. case3:    ld    a,(adrtrk)
  1439.     ld    hl,ntrks
  1440.     cp    (hl);        tracks per side
  1441.     ret    c
  1442.     sub    (hl);        On second side
  1443.     ld    (adrtrk),a
  1444.     ld    a,1
  1445.     ld    (side),a
  1446.     ret
  1447. ;
  1448. case4:    ld    a,(adrtrk)
  1449.     ld    hl,ntrks
  1450.     cp    (hl)
  1451.     ret    c;        On first side
  1452.     cpl
  1453.     add    (hl)
  1454.     add    (hl);        Now we count down
  1455.     ld    (adrtrk),a
  1456.     ld    a,1
  1457.     ld    (side),a
  1458.     ret
  1459. ;
  1460. error:    ld    a,0FFH;        config unknown, error
  1461.     ret
  1462. ;
  1463. ; Host specific routines here - setup for Kaypro 4
  1464. seek:    ld    a,(dsktrk);    If we have switched drives set
  1465.     out    (trkreg),a;    the controller to match history
  1466.     ld    a,(config);    Set up for side and density
  1467.     or    a
  1468.     ld    a,(dendbl)
  1469.     jp    p,seek1;    Normal double density system
  1470.     ld    a,(densgl);    else set single density command
  1471. seek1:    ld    b,a
  1472.     ld    a,(side);    Move side selection bit into place.
  1473.     and    1
  1474.     rla
  1475.     rla
  1476.     or    b;        Compute drive selection/density code
  1477.     ld    b,a
  1478.     in    a,(bitpt);    Keep bank (80), turn mtr on (40=0)
  1479.     push    af;        clear DDEN (20), keep lptstrobe (10)
  1480.     and    98H;        ignore prtbusy(8), clear side(4),
  1481.     or    b;        drive code (2, 1)     bit weights
  1482.     ld    b,a
  1483.     ld    a,(dskode)
  1484.     or    b
  1485.     or    10H;        turn off any lptstrobe bit (Kaypro)
  1486.     out    (bitpt),a;    selecting drive/side/density
  1487.     pop    af
  1488.     and    40H
  1489.     call    nz,pause;    Motor was off, wait for it
  1490.     ld    a,(dsktrk)
  1491.     inc    a
  1492.     call    z,clear;    Never used yet
  1493.     ld    a,(adrtrk)
  1494.     ld    hl,dsktrk
  1495.     cp    (hl)
  1496.     jp    z,seek4
  1497. ;    "    "
  1498.     out    (datapt),a;    changing tracks
  1499.     ld    a,seekcmd;    seek track
  1500.     call    dcmnd
  1501.     halt
  1502. seek3:    in    a,(statpt)
  1503.     rra
  1504.     jp    c,seek3;    await non-busy
  1505.     rla
  1506.     and    98H;        Check status
  1507.     jp    z,seek4
  1508.     call    clear
  1509.     dec    d
  1510.     jp    nz,seek;    retry allowd
  1511.     ld    a,0FFH;        Else signal error
  1512.     ret    
  1513. ;
  1514. seek4:    ld    a,(adrsec);    Successful seek
  1515.     ld    hl,sec1st
  1516.     add    a,(hl)
  1517.     out    (secreg),a;    set physical sector
  1518.     ld    a,(adrtrk)
  1519.     ld    (dsktrk),a
  1520.     xor    a
  1521.     ret    
  1522. ;
  1523. ; Clear disc controller.
  1524. ; a,f
  1525. clear:    ld    a,clrcmd
  1526.     call    dcmnd
  1527.     halt
  1528. clear1:    in    a,(statpt);    Await "not busy"
  1529.     rra
  1530.     jp    c,clear1
  1531.     xor    a
  1532.     ld    (dsktrk),a
  1533.     ret    
  1534. ;
  1535. ; command (e) to disk controller
  1536. ; a,f
  1537. dcmnde:    ld    a,e
  1538. ;    "    "
  1539. ; command (a) to disk controller
  1540. ; f
  1541. dcmnd:    out    (ctrlpt),a
  1542.     push    bc
  1543.     ld    b,20
  1544. dcmnd1:    dec    b
  1545.     jp    nz,dcmnd1;    pause for controller status
  1546.     pop    bc
  1547.     ret    
  1548. ;
  1549. ; pause (b) * 10 Millisec.  Set for 2.5 Mhz clock.
  1550. ; a,f,b
  1551. pause:    push    de
  1552. pause1:    ld    de,0686H;    <<<< Change for other clocks <<<
  1553. pause2:    dec    de
  1554.     ld    a,e
  1555.     or    d
  1556.     jp    nz,pause2
  1557.     dec    b
  1558.     jp    nz,pause1
  1559.     pop    de
  1560.     ret    
  1561. ;
  1562. ; ------------------- Initialized storage --------------------------
  1563. active:        db    true;    Non zero if active. allows 1..255
  1564. ;
  1565. ; ==================================================================
  1566. ; ****    Put initialized application storage past this point    ****    
  1567. ; ==================================================================
  1568. ;
  1569. dsktrk:    db    0FFH;    mark not selected/used?
  1570. ;
  1571. ; ------------------ End initialized storage -----------------------
  1572. ;
  1573. ; ------------------- Uninitialized storage ------------------------
  1574. segsiz    equ    $-@base;    Relocation bit table starts here
  1575. dmadr:    ds    2;    This value is known to BDOS.  It is not
  1576. ;            necessarily the same as the BIOS value
  1577. ;
  1578. ; ==================================================================
  1579. ; ****    Put uninitialized application storage past this point    ****
  1580. ; ==================================================================
  1581. ;
  1582. dmaadr:    ds    2;    this is the value known to the BIOS
  1583. secshf:    ds    1;    log2(hstblk).  For run-time addressing
  1584. ;
  1585. sekdsk:    ds    1;    seek ids, at CPM level
  1586. sektrk:    ds    2
  1587. seksec:    ds    1
  1588. ;
  1589. save66:    ds    1;    Save/restore 066h, for NMI operation
  1590. trksav:    ds    1;    Save/restore controller track reg.
  1591. ;
  1592. ;hstdsk: ds    1;    Host ids, at blocked level
  1593. hsttrk:    ds    2
  1594. hstsec:    ds    1
  1595. ;
  1596. adrtrk:    ds    2;    Physical trk adr. for controller
  1597. adrsec:    ds    1;        and sector
  1598. offsec:    ds    1;    Sector offset for 2nd side
  1599. ;
  1600. sekhst:    ds    1;    block/deblock variables
  1601. hstact:    ds    1
  1602. hstwrt:    ds    1
  1603. unacnt:    ds    1
  1604. ;unadsk: ds    1
  1605. unatrk:    ds    2
  1606. unasec:    ds    1
  1607. errflg:    ds    1
  1608. rsflag:    ds    1
  1609. readop:    ds    1
  1610. wrtype:    ds    1
  1611. ;
  1612. side:    ds    1
  1613. dirbuf:    ds    128
  1614. csv:    ds    64
  1615. alv:    ds    64
  1616. buff:    ds    1024;    Can handle 1024 byte host sector
  1617. ;
  1618. ; --------------- End application uninitialized storage --------------
  1619. ;
  1620.     ds    32;    Local stack of at least 16 words
  1621. ;            plus any remainder on page
  1622. ; align to next page boundary
  1623.     align    256,bdosv
  1624. lclstk:
  1625. ;*************************************************
  1626. ; End of segment to be relocated.
  1627. pages    equ    ($-@base)/256;    So loader knows memory needs.
  1628. ;
  1629.     end
  1630. Eô