home *** CD-ROM | disk | FTP | other *** search
/ ftp.barnyard.co.uk / 2015.02.ftp.barnyard.co.uk.tar / ftp.barnyard.co.uk / cpm / walnut-creek-CDROM / CPM / BDOS / DOSPLSOR.ARK / DOSPLUS.MAC < prev    next >
Text File  |  1986-12-08  |  78KB  |  2,733 lines

  1. title    'DOS+ Disk Operating System 2.5'
  2. ;
  3. ver    equ    5;        3 thru 15 allowable
  4. ;
  5. ; ***************************************************************
  6. ; *                                *
  7. ; *  D O S +  Z80 replacement Disk Operating System Version 2.5    *
  8. ; *                                *
  9. ; * Copyright (c) 1986 by                    *
  10. ; *     C.B. Falconer, 680 Hartford Tpk.,    (203) 281-1438    *
  11. ; *     Hamden, Conn. 06517, USA                *
  12. ; *                    all rights reserved    *
  13. ; ***************************************************************
  14. ;
  15. ; DOS+ is designed for general usage, and is an improved replacement
  16. ; for CPM 2.2.  DOS+ requires a Z80 cpu.  DOS+ has comprehensive
  17. ; provisions for RCPM security, especially when used with CCP+ (the
  18. ; supplied CCP), and is virtually impregnable with BYERSX.  The system
  19. ; allows extension with user installable RSXs (Resident System Exten-
  20. ; sions), which are used for print spool/unspoolers, the XJOB utility,
  21. ; and others.  These RSX's may be dynamically installed and removed,
  22. ; for optimum memory usage.  DSKDRIVE (the foreign disk driver) and
  23. ; BYERSX (the communications system) must be installed for the target
  24. ; system before use.  See below.
  25. ;
  26. ; Some of the code is quite tricky, in order to pack the features into
  27. ; the available space.  The tricks are usually commented.
  28. ;
  29. ; Revisions:
  30. ; 2.5   (86/12/06) cbf. Prevented permanent lockout of random read
  31. ;    files after a bad seek (can now re-seek, aborted Turbo Pascal).
  32. ;    If the bios supports it (by returning an appropriate value in
  33. ;    HL on console output calls) DCIO output calls (function 6) will
  34. ;    return that value as the current X/Y screen position.  GETINFO
  35. ;    arguments 3, 4 & 5 return List, Punch, and Reader status resp-
  36. ;    ectively (punch/reader only when customization addresses set).
  37. ;    A special vector at offset 01Eh now controls the exit point for
  38. ;    aborts, either from DOS errors, or CTL-C (breaks enabled) from
  39. ;    the console.  If used, the vector resets itself to a warm-boot.
  40. ; 2.4    (86/11/05) cbf. Console buffer read simplified.  No CTL-R,
  41. ;    rub equivalent to bs, CTL-U equivalent to CTL-X. No reg. save
  42. ;    Improved error reports.  Compatibility flag bit.  Setting
  43. ;    break inhibit also prevents ^C break on call 10 (cons. input)
  44. ;    and when exiting from CTL-S output pause.  R/O files are not
  45. ;    stamped for access time.  Extended calls GETINFO and TDEC.
  46. ; 2.3    (86/09/20) cbf. Flags expanded to control time access method.
  47. ;    Time routine may be a pointer to storage.  File timestamps for
  48. ;    creation, update, and access (incompatible with CPM3).  Access
  49. ;    stamping controlled separately, allows for disk wrt-protect.
  50. ;    Set/Get time bdos calls changed for compatibility with CPM3
  51. ;    Initial link at bdos+11, compatible with dos finder routines.
  52. ;    Console input modified to make DCIO compatible with other ops.
  53. ;    SYSTEM files, user 0, are visible to all users (for read).
  54. ;    Removed path restriction to SYSTEM files.  Applies to all read
  55. ;    Paths only apply to FCBs with a default drive specification.
  56. ;    User break on any DOS call available. DCIO enabled separately.
  57. ;    Corrected wrt_rand_zero_fill (40) call. Corrected file system
  58. ;    so SUBMIT/JOB files work.  File alteration now resets the
  59. ;    $ARC bit (T3) for proper operation of archiving utilities.
  60. ;    The CPM3 method (via set file attributes) of recording exact
  61. ;    file length in bytes is available (using F6).  Wild cards
  62. ;    rejected for rename, file size, set attributes.
  63. ;
  64. ; 2.1/2    Based on Mr. Ten-Brugges original P2DOS release, which made
  65. ;    this development practical.  Uses CCP+ for best results.
  66. ;
  67. ; New features of DOS+ (over CPM2.2) are:
  68. ;  - Console status call always checks physical input, so that it is
  69. ;    always possible to abort a program by the sequence CTL-S CTL-C.
  70. ;    (assuming the program is making console calls other than DCIO
  71. ;    and that breaks are enabled in the flag byte).
  72. ;  - DCIO calls (function 6) are now compatible with all other console
  73. ;    calls, so that a mixture of functions can be used.  The abilities
  74. ;    are such that direct bios calls are no longer needed.
  75. ;  - DCIO provides the CPM3 conin_wait call (0fdh), and a "lookahead"
  76. ;    call (0fch) so programs may examine input chars without using
  77. ;    them.  The lookahead call also returns the console column (as
  78. ;    viewed by DOS, not the bios) in the h (and b) registers. This may
  79. ;    not be accurate if tabs or cursor positioning sequences etc. have
  80. ;    been used.  If no char is ready lookahead returns 0 (which, if
  81. ;    the status call (0feh) has returned true, is really a ready nul).
  82. ;    The output call (any value less than 0fch in e) returns any value
  83. ;    returned in hl by the bios.  If implemented in the bios, this
  84. ;    should describe the current row (in h) and column (in l) of the
  85. ;    cursor, with an offset of 020h added. Applications can now intel-
  86. ;    ligently control the cursor for windowing, status lines, etc.
  87. ;  - User break on "brkchr" (except DCIO calls, enabled separately).
  88. ;    This can abort a runaway program, provided it makes DOS calls.
  89. ;  - Error routines are more informative, including DOS call number.
  90. ;      DOS+ ERROR ON D: disk I/O
  91. ;            bad drive
  92. ;            file R/O
  93. ;            R/O
  94. ;      Fn=XXX (FILE =FILENAME.TYP)
  95. ;    The option 'FILE =FILENAME.TYP' is displayed only when the DOS
  96. ;    function uses a filename. After all errors a warm boot is done,
  97. ;    except bad sectors, which allow retry/ignore/abort options.
  98. ;    Provisions exist (separate documentation) for applications to
  99. ;    intercept errors, and to detect where the DOS+ call would have
  100. ;    returned if successful.
  101. ;  - Search path is implemented to find files on other drives. The
  102. ;    files must be specified by their exact name.  This takes effect
  103. ;    only after the file is not found on the current default drv/usr,
  104. ;    thus there is no point to a $$ entry in the path string.  If the
  105. ;    FCB specifies a drive no path is searched.
  106. ;  - Any file stored on USER 0 with the $SYS attribute set, is visible
  107. ;    to all other users for read (but not write or erase).  Such files
  108. ;    can be erased from user 0, but not written into.
  109. ;  - Automatic date and time stamp is implemented. The creation date
  110. ;    is set when the function MAKE is executed.  The update date and
  111. ;    time is set as the file is closed (when modified).  The access
  112. ;    date and time is is set whenever the file is opened, UNLESS the
  113. ;    file is marked R/O or the TACESS flags bit is reset.  To enable
  114. ;    this feature you need to have a real time clock and the correct
  115. ;    DOS+ driver (or reserved memory area).  You must also initialize
  116. ;    directories for time stamps (every 4th entry = 021h,0,0....0),
  117. ;    i.e 3,7.. (0 based).  INITDIR utility performs this operation.
  118. ;  - File R/O error message occurs if one of the following file types
  119. ;    is active and a write is attempted:
  120. ;    File R/O    (T1)    (also prevents erase)
  121. ;    System file (T2)    (erasable from base user)
  122. ;  - Disk sizes up to   65536 * 16K = 1 048 576 K BYTE =  1 G BYTE.
  123. ;  - File sizes up to 32 * 64 * 16K =       32 768K BYTE = 32 M BYTE.
  124. ;  - CPM3 function GET TIME (105) is implemented to get the correct
  125. ;    date and time.  Entry DE is address to put time. The date and
  126. ;    time record has the following layout:
  127. ;    date:    ds    2;    date = 1    (Sun 1978-Jan-01)
  128. ;                date = 65535    (Sun 2157-Jun-05)
  129. ;    hour:    ds    1;    hour in BCD
  130. ;    min:    ds    1;    minute in BCD
  131. ;    Functions only if suitable bios function call is installed.
  132. ;  - CPM3 function SET TIME (104) is implemented to set the correct
  133. ;    date and time.  Entry DE is address new time. The date and time
  134. ;    layout is as above.  System seconds field is zeroed.  Functions
  135. ;    only if suitable bios function call is installed.
  136. ;  - BDOS function GETINFO (210) returns system info, on (e) value
  137. ;        e = 0    Returns pointer to Serial # area (BDOS base)
  138. ;        e = 1    Returns current setting of DMA
  139. ;        e = 2    Returns 0, Flushes any pending console input
  140. ;        e = 3    Returns list device status (ready/not ready)
  141. ;        e = 4    Returns punch     "    "    "
  142. ;        e = 5    Returns reader    "    "    "
  143. ;        e = other    Reserved for future. Returns 0.
  144. ;    (operands 4 and 5 function only if suitable connector addresses
  145. ;    have been installed at offsets 01ah and 01ch respectively. Else
  146. ;    these functions return 0, i.e. device not ready)
  147. ;  - BDOS function TDEC (211) writes de as unsigned decimal to the
  148. ;    console, with leading zero suppression.
  149. ;  - Offset 01eh can be set to a trap address after any abort.
  150. ;
  151. ; Possible DOS+ Incompatibilities with CPM 2.2
  152. ;  - The IX and IY registers are used, and restored to user values
  153. ;    on function exit.  Bios calls from DOS+ are protected.  DOS+
  154. ;    does not use the alternate register set.  Interrupt systems
  155. ;    that modify and do not restore IX & IY will cause failure.
  156. ;  - SYS (T2) attribute automatically marks files non-writable.
  157. ;  - The CTL-S pause mechanism always works.  Programs that depend
  158. ;    on 2 char input buffering (DOS buffer and hardware) may fail.
  159. ;  - Console output chars 0fch and 0fdh are now input on function 6.
  160. ;    Compatibility mode inhibits this feature.
  161. ;  - Buffered console input (function 10) treats DEL/RUBOUT as BS,
  162. ;    and does not implement the ^R repeat line operation.  Will not
  163. ;    end a line when full, refuses chars until <cr> entered.  Marks
  164. ;    line end with a 0 byte.  Thus max length 1 less than original.
  165. ;  - Version returned is 2x, where x is DOS+ revision (4 up). Values
  166. ;    in hex. This allows discrimination against CPM2.2, and avoids
  167. ;    confusion with CPM3.  The compatibility bit forces 2.2 value.
  168. ;    Note that call #210 with e = 0 will always return a non-zero
  169. ;    value, so that DOS+ can be detected in compatibility mode.
  170. ;  - Files written with more than 65536 records will not be legible
  171. ;    to CPM2.2 systems (but will be to CPM3 systems).
  172. ;  - Time stamp directory entries may appear as peculiar file names
  173. ;    on user 33 to some utilities.  CPM2 and 3 will not access them.
  174. ;  - The date/time file stamp format is INCOMPATIBLE with CPM3.
  175. ;    dates will be garbage data if read there (and vice-versa).
  176. ;    This is caused by maintenance of 3 (not 2) dates with DOS+
  177. ; NOTE: The following do not agree with CPM2.2, but DO agree with
  178. ;    Digital Researchs CPM 2.2 documentation
  179. ;  - Console status call returns 0ffh for ready, rather than 01
  180. ;  - SYS files on user area 0 are visible to all users
  181. ;
  182. ; Added features can be enabled/disabled by the following data:
  183. ;  - Enable PATH by putting address of PATH in offset 14H. If this
  184. ;    value is 0 no path is used. Suggested value 046H.
  185. ;    NOTE power-on cold-boot should clear the PATH string (0 at Path^)
  186. ;  - Enable DOS+ time and date stamping with a suitable (non-zero)
  187. ;    data address at offset 16H. Suggested value 040h (5 bytes used).
  188. ;  - Enable other features with the flag byte at offset 18h:
  189. ;    MSB 76543210 LSB
  190. ;        ^^^^^  ^----    1 = Echo console to list.  ^P complements
  191. ;     |||||            (this locn allows applications to control)
  192. ;     ||||^-------   1 = compatibility bit.  Causes verno call to
  193. ;     ||||            return 2.2. Disables fc/fd operand on DCIO
  194. ;     |||^--------   1 = do file access time stamp (timeat <> 0)
  195. ;     |||            (disable caters to wrt-protected disks)
  196. ;     ||^---------   1 = enable break on DCIO (if following bit)
  197. ;     |^----------   1 = enable user break, 0 = disable (see 19h)
  198. ;     |            When disabled ^C will not abort either.
  199. ;        ^-----------    0 = time address is location of time array
  200. ;            1 = time address is location of routine
  201. ;             (when non-0 address in offset 16h only)
  202. ;    (value x10x1000b for maximum CPM2 compatibility)
  203. ;  - If user breaks enabled, the char at offset 19h will break.
  204. ;  - CCP+ can access wheel byte, suggested location 045h. This allows
  205. ;    path/wheel to be initialized by "lxi h,0ffh; shld 45" in bios.
  206. ;
  207. ;        -------------
  208. ;
  209. ; NOTE - All features can be controlled in the file DOS.LIB
  210. ;
  211. ; Change with assembler.  Allows for SLRMAC or M80.  The M80 include
  212. ; statement must be changed to MACLIB for RMAC, with other changes.
  213. ; This allows for the widest range of assemblers, even ASM with manual
  214. ; macro expansion by editing.
  215. ;
  216. ; Following must be upper case for M80.
  217. ; SLRMAC can use "maclib z80" and/or dispense with Z80.LIB file
  218. INCLUDE Z80.LIB
  219. ;
  220. ; SLRMAC v1.0 bug fix - mvix/mviy operands interchanged
  221. mvix    macro    disp,value
  222.     db    0ddh,036h,disp,value
  223.     endm
  224. ;
  225. true    equ    -1
  226. false    equ    not true
  227. empty    equ    0e5h;        mark for vacant directory entries
  228. tmstamp    equ    021h;        mark for time-stamp directory entries
  229. ;
  230. ; Following must be upper case for M80.
  231. ; Specifies base/path/ramlow/timesystem/debug
  232. INCLUDE DOS.LIB
  233. ;
  234. ; Ascii control char. definitions
  235. etx    equ    03h;        key to generate warm boot
  236. enq    equ    05h;        break line
  237. bel    equ    07h;        bell
  238. bs    equ    08h;        backspace
  239. tab    equ    09h;        tab
  240. lf    equ    0ah;        line feed
  241. cr    equ    0dh;        carriage return
  242. dle    equ    10h;        set/reset print flag
  243. dc3    equ    13h;        pause console output
  244. nak    equ    15h;        delete line
  245. can    equ    18h;        delete line (backspaces)
  246. rubout    equ    7fh;        delete last char
  247. ;
  248. ; FCB description. Like CPM3, we reserve bits f7 and f8 for internal
  249. ; use.  Caller should initialize to off, and never alter them.
  250. f.usr    equ    0;        usage in directory. 5 bits
  251. f.drv    equ    f.usr;        alternate use for field in FCB
  252. f.name    equ    1;        8 char field
  253. f.ifc6    equ    6;        hi bit, sfattr interface control
  254. f.type    equ    9;        3 char field
  255. f.ro    equ    f.type;        hi bit
  256. f.sys    equ    10;        "
  257. f.arc    equ    11;        "
  258. f.exlo    equ    12;        5 low bits
  259. f.s1    equ    13
  260. f.exhi    equ    14;        6 low bits
  261. f.clean    equ    f.exhi;        hi bit
  262. f.rc    equ    15;        Records in last FCB extent
  263. f.dm    equ    16;        16 bytes/8 words
  264. f.next    equ    32;        next recd, FCB only
  265. f.rrno    equ    33;        3 bytes, FCB only
  266. ;
  267. ; Flag byte bit definitions
  268. fb.tcal    equ    80h;        Timer is routine, not data area
  269. fb.ubrk    equ    40h;        Implement console break
  270. fb.bcio    equ    20h;            also on DCIO calls
  271. fb.tacc    equ    10h;        Do file access time stamps
  272. fb.comp    equ    08h;        Compatibility bit
  273. fb.lflg    equ    01h;        Echo console output to lister
  274. ;
  275. ; bit settings via DOS.LIB
  276. tcal    equ    tfunct AND fb.tcal
  277. ubrk    equ    usrbrk AND fb.ubrk
  278. bcio    equ    dciobk AND fb.bcio
  279. tacc    equ    acctim AND fb.tacc
  280. ;
  281. ; A standard CPM 2.2 Bios arrangement
  282. ; This linkage allows debugging using pre-existing bios.
  283. ;extrn    boot;     0 boot            none        none
  284. extrn    wboot;     1 wboot         "         "
  285. extrn    const;     2 console status     "        A=0FFH  ready
  286. ;                             =0 not ready
  287. extrn    conin;     3 console input      "        A=console char
  288. extrn    conout;     4 console output    C=console char    option xy posn
  289. extrn    list;     5 list output        C=list char     "
  290. extrn    punch;     6 punch output        C=punch char     "
  291. extrn    reader;     7 reader input        none        A=reader char
  292. ;extrn    home;     8 home disk         "        option sysadr.
  293. extrn    seldsk;     9 select disk        C=drv # (0..15)    HL=^Disk table
  294. extrn    settrk;    10 select track        BC=track #    none
  295. extrn    setsec;    11 select sector    BC=sector #     "
  296. extrn    setdma;    12 set DMA address    BC=DMA address     "
  297. extrn    read;    13 read 128 bytes    none        A = 0 no error
  298. ;                            A <> 0 error
  299. extrn    write;    14 write 128 bytes;    C=0 write data    A = 0 no error
  300. ;                    C=1 wrt dir.    A <> 0 error
  301. ;                    C=2 wrt unalloc
  302. extrn    listst;    15 list status        none        A = 0ffh ready
  303. ;                            A = 0 not ready
  304. extrn    sectrn;    16 sector translate    BC = sect    HL = sector #
  305. ;                    DE = ^table
  306. ;                    (from select)
  307. ; XX    time    BC =0 get pointer only    HL=pointer to time array
  308. ;        BC <> 0 allows hard-     HL+0^ date LSB days since
  309. ;         ware to be updated     HL+1^ date MSB (1=1978/1/1)
  310. ;         if a routine call.     HL+2^ hour (bcd)
  311. ;         ignored if timead     HL+3^ minute (bcd)
  312. ;         is purely an address.     HL+4^ seconds (bcd)
  313. ;         BC^ time to set. (no secs) 
  314. ;                    CARRY clear, NZ on exit.
  315. ;
  316. ; Start of BDOS module
  317. serial:    ds    6,0;        Serial number not implemented
  318. ;
  319. ; Linkage for function calls
  320. start:    jmp    entry;        To location 11, for DOSfinders
  321. ;
  322. ; Error trap vector. Programs can alter error traps here
  323. stbdsc:    dw    badsec;        Bad sector
  324. stsel:    dw    selerr;        Select error
  325. stro:    dw    rdonly;        Drive read only
  326. sfilro:    dw    filro;        File read only
  327. ;
  328. ; Connector so DOSfinder routines work. The jump at location
  329. ; bdos+6 must be to bdos+11h.  The above error vector must not
  330. ; be moved or programs that trap BDOS errors will fail.
  331. entry:    jmp    dos
  332. ;
  333. ; -------------------------
  334. ; The following area is patchable.  DOS.LIB sets initial values
  335. ;
  336. ; Location of external path for open file command
  337. path:    dw    pathat
  338. ;
  339. ; Time address. 0 disables all time operations. Array or routine
  340. timead:    dw    timeat;        Routine addr. for time/date stamps
  341. ;
  342. ; Flags for specials
  343. flags:    db    tcal+ubrk+bcio+tacc
  344. brkch:    db    brkchr;        char. for user breaks
  345. ;    "    "
  346. ; If non-zero, address of bios routines. (a): 0ffh=ready, 0=not ready
  347. rdrsta:    dw    0;        rdr status routine ptr
  348. punsta:    dw    0;        pun status routine ptr
  349. ;
  350. ; This specifies control transfer after fatal errors or CTL-C exits
  351. ; when breaks are enabled.  CAUTION: must point to a valid connector.
  352. ; Automatically reset to ramlow if used.
  353. abtrap:    dw    ramlow;        destination on aborts
  354. ;
  355. ; -------------------------
  356. ;
  357. ; Entry point DOS+ function calls
  358. dos:    mov    a,c;        function number
  359.     sta    funct
  360.     sspd    spsave;        Save user SP
  361.     lxi    sp,stack;    Switch stacks
  362.     pushiy
  363.     pushix;            Save
  364.     push    d;        Save parameter
  365.     popix;             in IX
  366.     lxi    h,flags
  367.     mov    a,m
  368.     ani    fb.ubrk
  369.     cnz    userbk;        User break enabled, check it
  370.     xra    a
  371.     sta    drvflg;        Reset drive select done flag
  372.     sta    rdwr;        and read/write flag
  373.     mov    h,a
  374.     mov    l,a;        lxi h,0
  375.     shld    fvalue;        Clear exit value (default)
  376.     mvi    a,maxcmd-1
  377.     cmp    c
  378.     jrc    dos1;        above command table, use last entry
  379.     mov    a,c;        else use specified
  380. dos1:    lxi    h,ctable
  381.     call    jinx;        execute
  382. ;    "    "
  383. ; DOS+ exit routine
  384.     lda    drvflg;        test drive select used flag
  385.     ora    a
  386.     cnz    drvfix;        restore entry drive if modified
  387.     popix
  388.     popiy
  389.     lspd    spsave;        restore saved on entry
  390.     lhld    fvalue;        Get exit code
  391.     mov    a,l;        Copy exit code to ba
  392.     mov    b,h
  393.     ret
  394. ;
  395. ; Jump indexed to (hl + 2 * a).  Max entry a = 127
  396. ; a,f,h,l
  397. jinx:    add    a;        * 2, words
  398.     add    l
  399.     mov    l,a
  400.     adc    h
  401.     sub    l
  402.     mov    h,a;        hl := hl+a
  403. ;    "    "
  404. ; indirect transfer to hl^
  405. ; a,f,h,l
  406. jind:    mov    a,m
  407.     inx    h
  408.     mov    h,m
  409.     mov    l,a;        hl := (hl)
  410. xpchl:    pchl;            implements "call hl"
  411. ;
  412. ; Function 210, Get info, e specifies details. 
  413. ; This can perform anything that does not require input parameters.
  414. getinf:    mov    a,e
  415.     lxi    h,inftbl
  416.     cpi    maxinf
  417.     rnc
  418.     jr    jinx
  419. ;
  420. inftbl:    dw    @serial;  0    pointer to serial dos+/serial # area
  421.     dw    rtndma;      1    current dma setting
  422.     dw    cflush;      2    flush console input buffers
  423.     dw    lsta;      3    list device status (ready/not ready)
  424.     dw    psta;      4    punch device status    "    "
  425.     dw    rsta;      5    reader device status    "    "
  426. maxinf    equ    ($-inftbl) /2
  427. ;
  428. ; Main Command table.  Covers the contiguous opcodes.
  429. ; DOS+ returns values in HL, with BA a copy.  Thus 8 bit values are
  430. ; also returned in A.  Function 0 ignores the pointer at 1, and can
  431. ; be used to force system reloading if bios unaltered.
  432. ctable:    dw    wboot;        warm boot
  433.     dw    cin;        console input
  434.     dw    coute;        console output
  435.     dw    rin;        reader input
  436.     dw    pout;        punch output
  437.     dw    lout;        list output
  438.     dw    dcio;        direct console I/O
  439.     dw    giobyt;        get I/O byte
  440.     dw    siobyt;        set I/O byte
  441.     dw    mesg;        print string
  442.     dw    rdbuf;        read console buffer
  443.     dw    cstat;        get console status
  444.     dw    cmnd12;        get CPM version. num
  445.     dw    cmnd13;        reset disk system
  446.     dw    cmnd14;        select disk
  447.     dw    cmnd15;        open file
  448.     dw    cmnd16;        close file
  449.     dw    cmnd17;        search for first
  450.     dw    cmnd18;        search for next
  451.     dw    cmnd19;        delete file
  452.     dw    cmnd20;        read sequential
  453.     dw    cmnd21;        write sequential
  454.     dw    cmnd22;        make file
  455.     dw    cmnd23;        rename file
  456.     dw    cmnd24;        Get login vector
  457.     dw    cmnd25;        Get current disk
  458.     dw    cmnd26;        Set DMA address
  459.     dw    cmnd27;        get address allocation vector
  460.     dw    cmnd28;        write protect disk
  461.     dw    cmnd29;        Get R/O vector
  462.     dw    cmnd30;        Set file attributes
  463.     dw    cmnd31;        Get addr. disk parameter header (DPH)
  464.     dw    cmnd32;        Get/set user code
  465.     dw    cmnd33;        Read random
  466.     dw    cmnd34;        Write random
  467.     dw    cmnd35;        Compute file size
  468.     dw    cmnd36;        Set random recordd
  469.     dw    cmnd37;        reset individual drive(s)
  470.     dw    other;        last entry, check extensions
  471. maxcmd    equ    (($-ctable)/2);    Number of valid DOS commands
  472. ;
  473. ; Check function in auxiliary table
  474. other:    lxi    h,auxtbl
  475. ;    "    "
  476. ; Search table hl^ up for index c.  last (default) entry is 0ffh
  477. ; execute result.
  478. ; a,f,h,l + executed code
  479. tblchk:    mov    a,m;        get id byte
  480.     cmp    c
  481.     inx    h;        point to operand field
  482.     jrz    jind;        found, hl points to exec adr.
  483.     inr    a
  484.     jrz    jind;        last entry, use as default
  485.     inx    h
  486.     inx    h;        skip operand
  487.     jr    tblchk;        go check next
  488. ;
  489. ; Define table entry format
  490. dt    macro    op,adr
  491.     db    op
  492.     dw    adr
  493.     endm
  494. ;
  495. ; Auxiliary table.  1st entry found fastest. 0ffh terminator
  496. ; This structure allows for unused opcodes.
  497. auxtbl:    dt    40,   cmnd40;    write random w/zero fill
  498.     dt    104,  settim;    set time
  499.     dt    105,  gettim;    get time
  500.     dt    210,  getinf;    return data, e specifies what
  501.     dt    211,  cmd211;    write de in decimal, zero suppress
  502.     dt    0ffh, dummy;    end marker, null operation
  503. ;
  504. ; ***********************
  505. ; *            *
  506. ; * Device I/O routines    *
  507. ; *            *
  508. ; ***********************
  509. ;
  510. ; Read reader. BDOS function 3
  511. rin:    call    reader
  512.     jr    exit;        return rdr char. to caller
  513. ;
  514. ; Write punch. BDOS function 4
  515. pout:    mov    c,e
  516.     jmp    punch;        Char. to punch device
  517. ;
  518. ; Write list. BDOS function 5
  519. lout:    mov    c,e
  520. ;    "    "
  521. ; list from console echo mechanism
  522. listx:    jmp    list;        Char. to list device
  523. ;
  524. ; list status
  525. lsta:    call    listst
  526.     jr    exit
  527. ;
  528. ; reader status
  529. rsta:    lhld    rdrsta
  530.     jr    biosx
  531. ;
  532. ; punch status
  533. psta:    lhld    punsta
  534. ;    "    "
  535. ; Execute routine hl^ if hl non zero, else return 0
  536. biosx:    mov    a,h
  537.     ora    l
  538.     cnz    xpchl;        non-zero, call it
  539.     jr    exit
  540. ;
  541. ; Read Char. from console and echo if in [cr, lf, tab, bs, >= blank]
  542. ; BDOS function 1
  543. cin:    call    getch;        get it
  544.     call    tstch
  545.     cnc    couta;        echo cr, lf, tab, bs, >= blank
  546. exit:    jmp    rtnbyt
  547. ;
  548. ; Get I/O status byte. BDOS function 7
  549. giobyt:    lda    ramlow+3
  550.     jr    exit;        return it to caller
  551. ;
  552. ; Set I/O status byte. BDOS function 8
  553. siobyt:    mov    a,e
  554.     sta    ramlow+3;    Save new value in RAM
  555.     ret
  556. ;
  557. ; Test console status. BDOS function 11
  558. cstat:    call    qwait;        Get console status, check pause
  559.     jr    exit;        and return it
  560. ;
  561. ; Direct console input/output. BDOS function 6
  562. ;  input E : 0ffh - get char or 0 if not ready
  563. ;         0feh - get console status
  564. ;         0fdh - console input, wait for it (CPM3 usage)
  565. ;            0fch - get buffered char, without flushing
  566. ;            (so still available for console input)
  567. ;            (DOS+ also sets b=h=column count)
  568. ; This now co-operates with the 1 char input buffering, and thus can
  569. ; be used intermixed with other console functions.  Output here cannot
  570. ; be paused with CTL-S.  Output via other functions will flush any
  571. ; incoming CTL-S.  This status call (argument = 0feh) will not pause
  572. ; on incoming CTL-S.  Note that a nul input can be detected by calling
  573. ; status (argument 0feh), and if ready then calling input (arg 0ffh)
  574. ; or input-wait (arg 0fdh) or look-ahead (arg 0fch). This allows
  575. ; discrimination between no_char ready and nul ready.  However,
  576. ; console output may not track columns correctly.  Compatibility bit
  577. ; disables arguments 0fch and 0fdh (become output).
  578. ; IF the bios co-operates, console output calls return an indicator
  579. ; of the x/y screen position.  H describes row, L describes column.
  580. dcio:    mov    c,e;        Possible output char.
  581.     inr    e
  582.     jrz    dcio5;        0ffh, do input
  583.     inr    e
  584.     jrz    dcio4;        0feh, get status
  585.     lda    flags
  586.     ani    fb.comp;    compatibility bit
  587.     jrnz    dcio3;        inhibits extra operations over 2.2
  588.     inr    e
  589.     jrz    dcio6;        0fdh, console input, wait
  590.     inr    e
  591. dcio3:    mov    a,c
  592.     lhld    lastch;        assumes status called before
  593.     xchg
  594.     cnz    coraw;        <> 0fch, output char.
  595.     xchg
  596.     jmp    rtnwd;        h is column value
  597. dcio4:    call    csta;        Get console status
  598.     jr    exit;        and return it to caller
  599. dcio5:    call    csta;        Get console status
  600.     rz;            Exit if no char. available
  601. dcio6:    call    getch;        else get char.
  602.     jr    exit;        and return it to caller
  603. ;
  604. ; Call #211, write in decimal to console
  605. cmd211:    xchg
  606.     jr    tdzs
  607. ;
  608. ; output (a) in decimal to console, leading zero suppress. Recursive
  609. ; a,f,b,c,d,e,h,l
  610. tadzs:    mov    l,a
  611.     mvi    h,0
  612. ;    "    "
  613. ; output (hl) in decimal to console, leading zero suppress. Recursive
  614. ; a,f,b,c,d,e,h,l
  615. tdzs:    lxi    b,0100ah;    c=divisor=10, b=iter cnt=16
  616.     xra    a;        clear
  617. tdzs1:    dad    h;        (hl) := (hl)/10; rdr to (a)
  618.     ral;            shift off into (a)
  619.     cmp    c;        test
  620.     jrc    tdzs2;        no bit
  621.     sub    c;        bit = 1
  622.     inx    h
  623. tdzs2:    djnz    tdzs1;        not done
  624.     push    psw;        save output digit
  625.     mov    a,h
  626.     ora    l
  627.     cnz    tdzs;        not left digit, recursive
  628.     pop    psw;        last unlisted digit
  629.     adi    '0'
  630. ;    "    "
  631. ; couta, preserving bcdehl
  632. co:    push    b
  633.     push    d
  634.     push    h
  635.     call    couta
  636.     pop    h
  637.     pop    d
  638.     pop    b
  639.     ret
  640. ;
  641. ; cr/lf to console
  642. ; a,f,b,c,d,e,h,l
  643. crlf:    mvi    a,cr
  644.     call    cout
  645.     mvi    a,lf
  646.     jr    cout
  647. ;
  648. ; Blank to console
  649. ; a,f,b,c,d,e,h,l
  650. blk:    mvi    a,' '
  651. ;    "    "
  652. ; Console output A, no tab expansion. Preserve A. Check for pause
  653. ; However a tab records appropriate column advance here.
  654. ; Column confusion results if hi bit is set in char. or if
  655. ; cursor movement sequences are used.
  656. ; b,c,d,e,h,l
  657. cout:    push    psw;        Save non tab
  658.     call    qwait;        Check for user pause
  659.     pop    psw;        Get char back
  660. ;    "    "
  661. ; Raw console output, attempting to track output column, and
  662. ; implementing any list echo in effect. Guard against evil bioses.
  663. ; If the bios performs, de returns indicating the current x/y posn.
  664. ; b,c,d,e,h,l
  665. coraw:    mov    c,a
  666.     push    psw
  667.     pushix
  668.     pushiy
  669.     push    b
  670.     call    conout;        output it
  671.     pop    b;        get char back to ck
  672.     push    h;        save bios return (x/y posn)
  673.     lda    flags;        Get printer echo flag
  674.     rrc;            test fb.lflg
  675.     cc    listx;        bit set, output char to printer
  676.     pop    d;        may be x/y posn
  677.     popiy
  678.     popix
  679.     pop    psw;        restore char.
  680. ;    "    "
  681. ; Count chars. in line
  682. ; f,h,l
  683. countc:    cpi    rubout
  684.     rz;            non-print, no column update
  685.     lxi    h,column;    Pointer
  686.     inr    m;        advance
  687.     cpi    ' '
  688.     rnc;            printing char, exit
  689.     dcr    m;        control, cancel column advance
  690.     cpi    bs
  691.     jrz    count3;        bs, decrement column
  692.     cpi    cr
  693.     rnz;            Not tab char, ignore for count
  694.     mvi    m,1;        will become 0, for cr
  695. count3:    inr    m
  696.     dcr    m
  697.     rz;            don't reduce past zero
  698.     dcr    m;        reduce, for bs
  699.     ret
  700. ;
  701. ; Backup if column > 0.  Called only from delch, thus rdbuf
  702. ; a,f,b,c,d,e,h,l (because bios)
  703. bakup:    lxi    h,column
  704.     mov    a,m
  705.     ora    a
  706.     rz;            at lh column, absorb
  707.     call    bakup1;        write backspace (in c)
  708.     call    blk;        write space
  709. bakup1:    mvi    a,bs
  710.     jr    coraw
  711. ;
  712. ; Get char. from console, using look ahead buffer. Wait for it
  713. ; a,f,b,c,d,e,h,l (because bios)
  714. getch:    lxi    h,bufull
  715.     mov    a,m;        flag
  716.     mvi    m,0;        Reset buffer full flag
  717.     inx    h;        point to lastch at bufull+1
  718.     ora    a
  719.     mov    a,m;        buffer contents (lastch)
  720.     mvi    m,0;        and reset it to nul
  721.     rnz;            lastch was valid
  722. ;    "    "
  723. ; conin protected against evil bioses
  724. ; a,f,b,c,d,e,h,l (because bios)
  725. cinx:    lxi    h,conin
  726. ;    "    "
  727. ; Guard against a bios that clobbers ix/iy (e.g. Osborne 1).
  728. ; Call (hl)^, saving and restoring ix and iy
  729. ; a,f,b,c,d,e,h,l (because bios)
  730. xbios:    pushix
  731.     pushiy
  732.     call    xpchl
  733.     popiy
  734.     popix
  735.     ret
  736. ;
  737. ; Get console status to a and z flag, using look ahead buffer.
  738. ; When char. ready lastch buffer is loaded.
  739. ; a,f,b,c,d,e,h,l (because bios)
  740. csta:    lda    bufull
  741.     ora    a
  742.     mvi    a,0ffh
  743.     rnz;            buffer is non-empty
  744.     call    cstax;        Physical console status
  745.     ora    a
  746.     rz;            nothing read, return 0
  747.     call    cinx
  748.     sta    lastch;        get char and save
  749.     ori    0ffh;        return true
  750.     sta    bufull;        mark char in buffer
  751.     ret
  752. ;
  753. ; protected const
  754. ; a,f,b,c,d,e,h,l (because bios)
  755. cstax:    lxi    h,const
  756.     jr    xbios
  757. ;
  758. ; Test character
  759. ;  reset carry : cr, lf, tab, bs, OR >= space
  760. ;    set carry : all others
  761. ; f
  762. tstch:    cpi    cr
  763.     rz
  764.     cpi    lf
  765.     rz
  766.     cpi    tab
  767.     rz
  768.     cpi    bs
  769.     rz
  770.     cpi    ' ';        test >= space
  771.     ret
  772. ;
  773. ; Output message.  BDOS function 9
  774. ; a,f,d,e
  775. mesg:    ldax    d
  776.     cpi    '$'
  777.     rz;            End of string
  778.     inx    d;        point to next char.
  779.     call    co;        output
  780.     jr    mesg;        more
  781. ;
  782. ; Delete char.  Called only from rdbuf
  783. ;  Entry : HL = ^ last char in buffer
  784. ;          B  = Char. counter
  785. ;  Exit  : hl decremented, b decremented, z flag on b
  786. ; a,f,b,d,e,h,l
  787. delch:    mov    a,b
  788.     ora    a
  789.     rz;            empty, nothing to do
  790.     push    b
  791.     push    h
  792.     call    bakup
  793.     pop    h
  794.     push    h
  795.     mov    a,m
  796.     cpi    ' '
  797.     cc    bakup;        control, wipe out 2 pos'ns
  798.     pop    h
  799.     pop    b
  800.     dcx    h
  801.     dcr    b;        Char counter
  802.     ret
  803. ;
  804. ; Read buffer IX^.  BDOS function 10        ENTRY below
  805. rdbuf0:    call    delch;        Delete last char in line
  806.     jrnz    rdbuf0;        more to remove
  807. ;    "    "
  808. rdbuf:    pushix;            buffer start addr.    << ENTRY here
  809.     pop    h;        to HL
  810.     mov    c,m;        Max. line length
  811.     inx    h;        Adv. to actual line lgh position
  812.     mvi    b,0;        Clear line length counter
  813. rdbuf1:    push    h
  814.     push    b
  815. rdbuf2:    call    getch
  816.     pop    b
  817.     pop    h
  818.     ani    07fh;        Mask char
  819.     cpi    enq
  820.     jrnz    rdbuf5;        Not CTL-E
  821.     push    h;        SAVE
  822.     push    b
  823.     call    crlf;    newln;    Move cursor to next line
  824.     jr    rdbuf2;        and get next char
  825.  
  826. rdbuf4:    call    delch;        Delete char
  827.     jr    rdbuf1;        Get next char.
  828.  
  829. rdbuf5:    cpi    bs
  830.     jrz    rdbuf4;        backspace
  831.     cpi    rubout
  832.     jrz    rdbuf4;        rubout
  833.     cpi    dle
  834.     jrnz    rdbuf6;        not CTL-P (print enable/disable)
  835.     lda    flags;        Complement print flag
  836.     xri    fb.lflg
  837.     sta    flags;        flip fb.lflg
  838.     jr    rdbuf1;        and get next char
  839.  
  840. rdbuf6:    cpi    nak
  841.     jrz    rdbuf0;        CTL-U, delete line
  842.     cpi    can
  843.     jrz    rdbuf0;        CTL-X, delete line
  844.     cpi    cr
  845.     jrz    rdbufx;        cr, exit
  846.     cpi    lf
  847.     jrz    rdbufx;        lf, exit
  848.     inx    h;        incr. pointer
  849.     mov    m,a;        and save char.
  850.     inr    b;        incr. line counter
  851.     mov    a,c
  852.     cmp    b
  853.     jrnz    rdbuf8
  854.     dcx    h;        line end, refuse char
  855.     dcr    b
  856.     mvi    a,bel
  857.     call    co
  858.     jr    rdbuf1
  859.  
  860. rdbuf8:    mov    a,m
  861.     call    outch;        Echo char.
  862.     cpi    etx
  863.     mov    a,b;        Get line count
  864.     jrnz    rdbuf1;        Not CTL-C
  865.     dcr    a;        If 1st char in line then
  866.     cz    abtchk;         abort if breaks enabled
  867.     jr    rdbuf1;        else just another char.
  868.  
  869. rdbufx:    inx    h
  870.     mvi    m,0;        mark line end for user
  871.     stx    b,+1;        save line counter
  872.     mvi    e,cr;        force carriage return
  873. ;    "    "
  874. ; Write console. BDOS function 2
  875. coute:    mov    a,e;        Char
  876. ;    "    "
  877. ; Write char A to console, expand tabs.  Preserves A
  878. couta:    cpi    tab
  879.     jnz    cout;        not tab
  880. couta1:    call    blk;        expand tab to spaces, 1 or more
  881.     lda    column
  882.     ani    7
  883.     jrnz    couta1;        Not done, repeat
  884.     mvi    a,tab;        return tab
  885.     ret
  886. ;
  887. ; Output char (Control char displays ^CHAR)
  888. outch:    call    tstch
  889.     jnc    co;        cr,lf,tab,bs or >= space
  890.     push    psw
  891.     mvi    a,'^'
  892.     call    co;        write '^'
  893.     pop    psw
  894.     push    psw
  895.     adi    'A'-1;        add offset
  896.     call    co;        output it
  897.     pop    psw;        restore chanr.
  898.     ret
  899. ;
  900. ; *******************************
  901. ; *                *
  902. ; *     ERROR ROUTINES etc.    *
  903. ; *                *
  904. ; *******************************
  905. ;
  906. ; Check for user pause (CTL-S).  Always uses key depression.
  907. ; Returns current console status in a and z flag
  908. qwait:    call    cstax;        bios
  909.     ora    a
  910.     jrz    qwait1;        No key, check buffer
  911.     xra    a
  912.     sta    bufull;        flush buffer on physical input
  913. qwait1:    call    csta
  914.     rz;            no input
  915.     lda    lastch;        what was it
  916.     cpi    dc3
  917.     mvi    a,0ffh;        to return status=ready
  918.     rnz;            not pause
  919.     call    getch;        flush the DC3
  920.     call    getch;        and get the next input
  921.     cpi    etx
  922.     jrz    abtchk;        reboot on CTL-C
  923.     xra    a;        set status = not ready
  924.     ret
  925. ;
  926. ; Check breaks enabled, and abort if so. Else return 0 and z flag
  927. ; a,f
  928. abtchk:    lda    flags
  929.     ani    fb.ubrk
  930.     rz;            breaks disabled
  931.     jr    abort
  932. ;
  933. ; Check for user break. At entry hl points to flags
  934. ; a,f,h,l
  935. userbk:    mov    a,m
  936.     ani    fb.bcio
  937.     jrnz    ubk1;        enabled for DCIO
  938.     mov    a,c
  939.     cpi    6
  940.     rz;            Not for DCIO call
  941. ubk1:    push    b
  942.     push    d
  943.     call    csta
  944.     pop    d
  945.     pop    b
  946.     rz;            no input, no break
  947.     lda    lastch;        look ahead
  948.     lxi    h,brkch
  949.     cmp    m
  950.     rnz
  951. ;    "    "
  952. ; Check operator for abort.
  953. ; a,f,h,l
  954. qabort:    push    d
  955.     push    b
  956.     lxi    d,brkmsg
  957.     call    mesg
  958.     call    cflush;        purge char and input buffer
  959.     call    cin;        Get user response
  960.     push    psw
  961.     call    crlf
  962.     pop    psw
  963.     pop    b
  964.     pop    d
  965.     ani    05fh;        upshift any 'y'
  966.     cpi    'Y'
  967.     rz;            ignore non Y
  968.     jr    abort;        abort
  969. ;
  970. ; Bad sector error
  971. badsec:    lxi    d,mbadsc;    bad sector message
  972.     xra    a;        not file r/o
  973.     call    error;        display, flush input stream
  974. retry:    lxi    d,qretry
  975.     call    mesg
  976.     call    cin
  977.     ani    05fh
  978.     cpi    'R'
  979.     rz;            with z flag for "retry"
  980.     cpi    'A'
  981.     jrz    abort;        else abort
  982.     cpi    'I'
  983.     jrnz    retry
  984.     ora    a
  985.     ret;            with n/z flag for ignore
  986. ;
  987. ; Select error
  988. selerr:    lxi    d,msel;        Select error message
  989.     jr    abterr;        go display error & abort
  990. ;
  991. ; File read only error
  992. filro:    lxi    d,mfilro;    File R/O message
  993.     mvi    a,0ffh;        Set file R/O message flag
  994. ;    "    "
  995. ; Abort error, no option to retry
  996. abtro:    call    error;        display error
  997.     call    getch;        get operator response
  998. ;    "    "
  999. ; Errors and user breaks abort through here. 
  1000. ; Restore input arguments and stack for any debugger.
  1001. abort:    lda    funct
  1002.     mov    c,a;        restore fnct
  1003.     pushix
  1004.     pop    d;        restore argument
  1005.     lspd    spsave;        callers stack
  1006.     lhld    abtrap;        usually 0, reboot
  1007.     push    h
  1008.     lxi    h,ramlow+0
  1009.     shld    abtrap;        reset for next time
  1010.     ret
  1011. ;
  1012. ; Drive read only error
  1013. rdonly:    lxi    d,mro;        Drive R/O messaage
  1014. ;    "    "
  1015. abterr:    xra    a;        not file r/o
  1016.     jr    abtro
  1017. ;
  1018. qretry:    db    cr,lf,'A)bort I)gnore R)etry?$'
  1019. brkmsg:    db    cr,lf,'Resume (y/N)?$'
  1020. ;
  1021. ; Display Error Message
  1022. ;    DOS+ error on D: ERROR MESSAGE
  1023. ;    FUNCTION = NN  [FILE = FILENAME.TYP]
  1024. error:    mov    c,a;        Save file R/O message flag
  1025.     push    b
  1026.     push    d;        Save error message pointer
  1027.     lda    defdrv;        get current drive
  1028.     adi    'A';        make Ascii
  1029.     sta    mdrive;        modify message
  1030.     lxi    d,mberr;    "DOS+ ERROR ON D:"
  1031.     call    mesg;        display message
  1032.     pop    d;        Get error message pointer
  1033.     call    mesg;        display it
  1034.     lxi    d,mbfunc;    "FUNCTION ="
  1035.     call    mesg;        display it
  1036.     lda    funct;        Get function number
  1037.     push    psw
  1038.     call    tadzs;        display number
  1039.     pop    psw;        restore function number
  1040.     pop    b;        Get file R/O flag
  1041.     cpi    15;        Test FCB used in command
  1042.     jrc    cflush;        no
  1043.     cpi    24
  1044.     jrc    error1;        yes
  1045.     cpi    30
  1046.     jrz    error1;        yes
  1047.     cpi    33
  1048.     jrc    cflush;        no
  1049.     cpi    37
  1050.     jrc    error1;        yes
  1051.     cpi    40
  1052.     jrnz    cflush;        no
  1053. error1:    pushix;            yes, display "FILE ="
  1054.     sui    19
  1055.     jrnz    error2;        Not delete file function
  1056.     ora    c
  1057.     jrz    error2;        not file r/o error
  1058.     call    caldir;        Get FCB from directory buffer
  1059.     xthl;            save it
  1060. error2:    lxi    d,mfile;    " FILE ="
  1061.     call    mesg;        Display it
  1062.     pop    h;        ^FCB
  1063.     mvi    b,8;        1st 8 chars.
  1064.     call    filenm
  1065.     mvi    a,'.'
  1066.     call    co;        write '.'
  1067.     mvi    b,3;        last 3 chars
  1068.     call    filenm
  1069. ;    "    "
  1070. ; Flush any incoming console chars
  1071. ; a,f,b,c,d,e,h,l (because bios)
  1072. cflush:    call    csta
  1073.     rz;            nothing ready
  1074.     call    getch;        purge it
  1075.     jr    cflush
  1076. ;
  1077. ; Display hl^ for (b) chars, suppress blanks
  1078. filenm:    inx    h;        adv pointer
  1079.     mov    a,m
  1080.     ani    07fh;        remove any attributes
  1081.     cpi    ' '
  1082.     cnz    co;        write
  1083.     djnz    filenm;        more
  1084.     ret
  1085. ;
  1086. ; *******************************
  1087. ; *                *
  1088. ; *      DISK FUNCTIONS    *
  1089. ; *                *
  1090. ; *******************************
  1091. ;
  1092. ; Return Version Number
  1093. cmnd12:    lda    flags
  1094.     ani    fb.comp
  1095.     mvi    a,22h
  1096.     jrnz    rtnbyt;        return 2.2 in compatibility mode
  1097.     mvi    a,020h+ver;    act like 2.2 compatible, not 3.0
  1098.     jr    rtnbyt;        exit
  1099. ;
  1100. ; Reset disk system
  1101. cmnd13:    lxi    d,ramlow+080h;    Set default DMA address
  1102.     call    cmnd26;        SETDMA, so bios agrees
  1103.     xra    a;        Default drive 'A'
  1104.     sta    defdrv
  1105.     mov    l,a
  1106.     mov    h,a;    lxi h,0
  1107.     shld    login;        All drives logged out
  1108.     shld    dskro;         "    "  read/write
  1109.     call    seldk;        Select drive 'A'
  1110.     lda    subflg;        return submit flag
  1111.     jr    rtnbyt;        exit
  1112. ;
  1113. ; Search for file
  1114. cmnd17:    call    seldrv;        from FCB
  1115.     ldx    a,f.drv
  1116.     sui    '?'
  1117.     jrz    cmd17b;        '?' in drv field, all entries match
  1118.     ldx    a,f.exhi;    Get system byte
  1119.     cpi    '?'
  1120.     jrz    cmd17a;        is '?'
  1121.     mvix    f.exhi,0;    Else set it to zero
  1122. cmd17a:    mvi    a,14;        Test 1st 15 bytes in FCB
  1123. cmd17b:    inr    a;        allow for the zero from above
  1124.     call    search;        do the search.  (leaves result code)
  1125. ;    "    "
  1126. cpydir:    lhld    @dirbuf;    Copy directory buffer
  1127.     lded    dma;        To dma addr.
  1128.     lxi    b,128;        for 128 bytes
  1129.     ldir
  1130.     ret
  1131. ;
  1132. ; Seach for next occurence of file
  1133. cmnd18:    lixd    dcopy;        last FCB used by search
  1134.     call    seldrv;        from FCB
  1135.     call    searcn;        Search next file match
  1136.     jr    cpydir;        and copy directory to DMA addr.
  1137. ;
  1138. ; Delete file
  1139. cmnd19:    call    seldrv;        from FCB
  1140.     call    delete
  1141. ;    "    "
  1142. ; Return search result (found/not found)
  1143. srchcd:    lda    searex;        Get exit byte 00=file found, 0FFH not
  1144.     jr    rtnbyt;        and exit
  1145. ;
  1146. ; Rename file
  1147. cmnd23:    call    seldrv;        From FCB
  1148.     call    renam
  1149.     jr    srchcd;        and exit with code
  1150. ;
  1151. ; Call 212 getinfo, subcall 0.
  1152. ; Return pointer to serial # area of executing system.
  1153. ; (offsets from here can access configuration tables)
  1154. ; In compatibility mode this non-zero value indicates DOS+
  1155. @serial:
  1156.     lxi    h,serial
  1157.     jr    rtnwd
  1158. ;
  1159. ; Return login vector
  1160. cmnd24:    lhld    login
  1161. ;    "    "
  1162. ; Return word value HL
  1163. rtnwd:    shld    fvalue
  1164. ;    "    "
  1165. dummy:    ret;            label for null operations
  1166. ;
  1167. ; Return current drive
  1168. cmnd25:    lda    defdrv;        Get current drive
  1169. ;    "    "
  1170. ; Return byte value A
  1171. rtnbyt:    sta    fvalue
  1172.     ret
  1173. ;
  1174. ; Return pointer to ALV vector
  1175. cmnd27:    lhld    @alv
  1176.     jr    rtnwd;        and exit
  1177. ;
  1178. ; Return disk R/O vector
  1179. cmnd29:    lhld    dskro
  1180.     jr    rtnwd;        and exit
  1181. ;
  1182. ; Change status of file (attributes)
  1183. cmnd30:    call    seldrv;        from FCB
  1184.     call    sfattr;        Change status
  1185.     jr    srchcd;        and exit
  1186. ;
  1187. ; Return pointer to drive table
  1188. cmnd31:    lhld    @ixp
  1189.     jr    rtnwd;        and exit
  1190. ;
  1191. ; Set/get user code. Return current user code
  1192. cmnd32:    mov    a,e;        argument
  1193.     inr    e
  1194.     jrz    cmd32a;        get only, arg 0ffh
  1195.     ani    01fh;        mask
  1196.     sta    user
  1197. cmd32a:    lda    user
  1198.     jr    rtnbyt
  1199. ;
  1200. ; Compute file size
  1201. cmnd35:    call    seldrv;        from FCB
  1202. ;    "    "
  1203. ; Compute file size
  1204. filsz:    lxi    b,0;        Reset file size length
  1205.     mov    d,c
  1206.     call    ldrrc;        in FCB+33,34,35
  1207.     call    nowild;        initial search, check wild cards
  1208.     rnz;            wild card, illegal, error set
  1209.     call    tstfct
  1210.     rz;            Not found, exit with search result
  1211. filsz2:    call    caldir;        Get directory entry to hl & iy
  1212.     xchg;            copy to de
  1213.     lxi    h,f.rc;        Offset to next record
  1214.     call    calrrc;        Calculate random record count
  1215.     mov    a,d;        Test LSB < (IX+33)
  1216.     subx    f.rrno
  1217.     mov    a,c;        Test ISB < (IX+34)
  1218.     sbcx    f.rrno+1
  1219.     mov    a,b;        Test MSB < (IX+35)
  1220.     sbcx    f.rrno+2
  1221.     cnc    ldrrc;        Write new maximum
  1222.     call    searcn;        next file
  1223.     call    tstfct
  1224.     jrnz    filsz2;        and test it
  1225.     jr    rtnbyt;        set 0, file found
  1226. ;
  1227. ; Set random record count
  1228. cmnd36:    lxi    h,f.next;    pointer to next record
  1229.     call    calrrc;        calculate
  1230. ;    "    "
  1231. ; Store bcd (3 bytes) in FCB IX^ random rcd field
  1232. ldrrc:    stx    d,f.rrno
  1233.     stx    c,f.rrno+1
  1234.     stx    b,f.rrno+2
  1235.     ret
  1236. ;
  1237. ; Calculate random record from f.rc or f.next (on entry hl)
  1238. ;  Entry HL = offset in FCB;  DE = FCB pointer
  1239. ;  Exit     B,C,D = <MSB> random record <LSB>
  1240. calrrc:    dad    d;        Point to FCB+15 or FCB+32
  1241.     mov    a,m
  1242.     lxi    h,f.exlo;    Offset to extent number
  1243.     dad    d
  1244.     mov    d,a;        Save record # to use
  1245.     mov    a,m;        extent byte
  1246.     ani    01fh;        Mask it
  1247.     ralr    d;        Shift MSB in carry
  1248.     aci    0;        add carry
  1249.     rar;            Shift 1 time (16 bits)
  1250.     rarr    d
  1251.     mov    c,a;        save ISB
  1252.     inx    h;        exhi, FCB+14
  1253.     inx    h
  1254.     mov    a,m;        Get exhi
  1255.     rrc;            Shift 4 times
  1256.     rrc
  1257.     rrc
  1258.     rrc
  1259.     push    psw;        Save
  1260.     ani    03h;        Mask MSB
  1261.     mov    b,a;        Save
  1262.     pop    psw;        Get LSB
  1263.     ani    0f0h;        Mask
  1264.     add    c;        Add with ISB
  1265.     mov    c,a;        Save ISB
  1266.     rnc;            No carry, return
  1267.     inr    b;        Incr. MSB
  1268.     ret
  1269. ;
  1270. ; Reset specified drives.  No files should be open
  1271. cmnd37:    mov    a,e
  1272.     cma;            Complement input vector
  1273.     mov    e,a
  1274.     mov    a,d
  1275.     cma
  1276.     mov    d,a
  1277.     lhld    login
  1278.     mov    a,e;        mask login vector
  1279.     ana    l
  1280.     mov    l,a
  1281.     mov    a,d
  1282.     ana    h
  1283.     mov    h,a
  1284.     shld    login;        Save resultant login vector
  1285.     xchg;            use result as mask
  1286.     lhld    dskro;        for drive R/O vector
  1287.     mov    a,e
  1288.     ana    l
  1289.     mov    l,a
  1290.     mov    a,d
  1291.     ana    h
  1292.     mov    h,a
  1293.     shld    dskro;        Save resultant drive R/O vector
  1294.     ret
  1295. ;
  1296. ; *******************************
  1297. ; *                *
  1298. ; *  Subroutines and functions    *
  1299. ; *                *
  1300. ; *******************************
  1301. ;
  1302. ; Select disk from FCB. Save 0th byte in FCB0 and set to current user.
  1303. seldrv:    mvi    a,0ffh;        Set disk select done flag
  1304.     sta    drvflg    
  1305.     lda    defdrv
  1306.     sta    drive;        Save current drive
  1307.     mov    e,a;        and to (e)
  1308.     ldx    a,f.drv;    Get drive from FCB
  1309.     sta    fcb0;        save
  1310.     cpi    '?'
  1311.     jrz    cmnd14;        '?', select drive from (e)
  1312.     ani    01fh;        mask drive
  1313.     mov    a,e
  1314.     jrz    seldr0;        0=default, select drive from (e)
  1315.     ldx    a,f.drv;    else get drive from FCB
  1316.     dcr    a;        normalize to 0..maxdrv
  1317. seldr0:    call    seldk
  1318.     lda    user;        set current user in 1st FCB byte
  1319.     stx    a,f.usr;    (for directory searches)
  1320.     ret
  1321. ;
  1322. ; select error occured
  1323. slkter:    lhld    stsel;        error message address
  1324.     pchl;            go display error
  1325. ;
  1326. ; restore entry drive. Used only on exit
  1327. drvfix:    lda    fcb0;        Get FCB byte 0
  1328.     stx    a,f.drv;    restore it in FCB
  1329.     lda    drive;        Get old drive number
  1330.     mov    e,a
  1331. ;    "    "
  1332. ; Select disk e
  1333. cmnd14:    mov    a,e;        drive number
  1334. ;    "    "
  1335. ; select disk a
  1336. seldk:    ani    0fh;        mask
  1337.     mov    b,a;        to b
  1338.     lded    login
  1339.     ora    a
  1340.     jrz    seldk1;        Drive 'A'
  1341. seldk0:    rarr    d;        Rotate login vector
  1342.     rarr    e;        until bit 0 of (e)
  1343.     djnz    seldk0;        represents current drive
  1344. seldk1:    lxi    h,defdrv
  1345.     bit    0,e
  1346.     jrz    seldk2;        Not logged in
  1347.     cmp    m
  1348.     rz;            Already selected, no effort needed
  1349. seldk2:    mov    m,a;        save new current drive
  1350.     push    d;        save logged in flag (e)
  1351.     mov    c,a;        copy drive number
  1352.     lxi    h,seldsk;    bios select, e bit 0 specifies reset
  1353.     call    xbios;        bad bios guard
  1354.     mov    a,h
  1355.     ora    l
  1356.     jrz    slkter;        Error, illegal drive
  1357.     mov    e,m;        Get translation vector
  1358.     inx    h
  1359.     mov    d,m
  1360.     inx    h
  1361.     sded    @trans;        and save
  1362.     shld    @filect;    save addr. temp0
  1363.     lxi    d,6
  1364.     dad    d;        ignore temp1, temp2
  1365.     lxi    d,@dirbuf;    point to dirbuf
  1366.     lxi    b,8;        copy 8 bytes
  1367.     ldir
  1368.     lhld    @ixp;        Get drive parameter addr.
  1369.     mvi    c,15;        copy 15 bytes
  1370.     ldir
  1371.     pop    d;        restore drive logged in flag
  1372.     bit    0,e
  1373.     rnz;            drive was logged in, return
  1374.     lhld    login
  1375.     call    sdrvb;        Set drive bit in login vector
  1376.     shld    login
  1377. ;    "    "
  1378. ; Init drive. Set up ALV bit buffer for blocks assigned. SUBFLG
  1379. ; indicates if drive holds any '$*.*' file on user 0.
  1380. initdr:    lded    maxblk;        Get length ALV buffer-1 (bits)
  1381.     mvi    a,3;        / 8
  1382. initd0:    srlr    d;        to get bytes
  1383.     rarr    e
  1384.     dcr    a
  1385.     jrnz    initd0
  1386.     inx    d;        +1, so all bits are cleared
  1387.     lhld    @alv;        point to ALV buffer
  1388.     push    h
  1389. initd1:    mvi    m,0;        clear 8 bits
  1390.     inx    h
  1391.     dcx    d
  1392.     mov    a,d
  1393.     ora    e
  1394.     jrnz    initd1;        more
  1395.     pop    h;        restore ALV pointer
  1396.     lded    ndir0;        Get 1st 2 bytes ALV buffer (directory)
  1397.     mov    m,e
  1398.     inx    h
  1399.     mov    m,d;        save
  1400.     lhld    @filect;    Clear number of files on this drive
  1401.     xra    a
  1402.     mov    m,a
  1403.     inx    h
  1404.     mov    m,a
  1405.     sta    subflg;        Clear submit flag (Reset disk command)
  1406.     call    setfct;        Set file count
  1407. initd2:    mvi    a,0ffh;        update directory checksum
  1408.     call    rddir;        read FCB'S from directory
  1409.     call    tstfct
  1410.     rz;            last FCB, exit
  1411.     call    caldir;        Point to entry point FCB, get 0th byte
  1412.     cpi    empty
  1413.     jrz    initd2;        Empty dir entry, get next FCB
  1414.     cpi    tmstamp
  1415.     jrz    initd2;        Time stamp entry, get next FCB
  1416.     ora    a
  1417.     jrnz    initd3;        Not on user 0
  1418.     inx    h;        point to filename
  1419.     mov    a,m
  1420.     sui    '$'
  1421.     jrnz    initd3;        1st filename char <> '$'
  1422.     dcr    a;        i.e. 0ffh
  1423.     sta    subflg;        to SUBFLG, may be a submit file active
  1424. initd3:    call    allocb;        Set bits from FCB in ALV buffer
  1425.     call    setlf;        update last file count
  1426.     jr    initd2;        and get next FCB
  1427. ;
  1428. ; Set drive bit in HL for defdrv
  1429. ; a,f,d,e,h,l
  1430. sdrvb:    xchg;            de := hl
  1431.     lxi    h,1
  1432.     lda    defdrv;        Get current drive
  1433.     ora    a
  1434.     jrz    sdrvb1;        Drive 'A', hl is set
  1435. sdrvb0:    dad    h;        left shift bit
  1436.     dcr    a
  1437.     jrnz    sdrvb0;        not positioned yet
  1438. sdrvb1:    mov    a,d;        hl := hl OR de
  1439.     ora    h
  1440.     mov    h,a
  1441.     mov    a,e
  1442.     ora    l
  1443.     mov    l,a
  1444.     ret
  1445. ;
  1446. ; Calculate and set sector/track for directory entry # filcnt
  1447. ; a,f,b,c,d,e,h,l
  1448. stdir:    lhld    filcnt;        Directory FCB counter
  1449.     srlr    h;         /  4
  1450.     rarr    l;        (4 FCB'S / sector)
  1451.     srlr    h
  1452.     rarr    l
  1453.     shld    recdir;        Save (used by checksum)
  1454.     xchg;            de := hl
  1455.     lxi    h,0;        hl := 0
  1456. ;    "    "
  1457. ; Calculate sector/track
  1458. ;  Entry : HL, DE = sector number (128 byte sector)
  1459. ;  Result set track  = HL,DE  /  maxsec
  1460. ;         set sector = HL,DE MOD maxsec
  1461. ; a,f,b,c,d,e,h,l
  1462. calst:    lbcd    maxsec;        sectors/track
  1463.     mvi    a,17;        init loop counter
  1464. calst1:    ora    a;        divide by maxsec.
  1465.     dsbc    b
  1466.     jrnc    calst2;        hl >= bc
  1467.     dad    b;        hl < bc, restore hl, set carry
  1468. calst2:    cmc
  1469.     ralr    e;        shift left result in DE
  1470.     ralr    d
  1471.     dcr    a
  1472.     jrz    calst3;        divide done
  1473.     dadc    h;        shift next bit (left) in hl
  1474.     jr    calst1;        continue
  1475.  
  1476. calst3:    push    h;        Save sector num.
  1477.     lhld    nftrk
  1478.     dad    d;        add 1st track offset
  1479.     mov    b,h;        to BC for bios
  1480.     mov    c,l
  1481.     lxi    h,settrk
  1482.     call    xbios;        bad bios guard
  1483.     pop    b;        sector number
  1484.     lded    @trans;        Get translation table addr.
  1485.     lxi    h,sectrn
  1486.     call    xbios;        bad bios guard
  1487.     mov    b,h;        result to BC
  1488.     mov    c,l
  1489.     lxi    h,setsec
  1490.     jmp    xbios;        bad bios guard
  1491. ;
  1492. ; Get disk map block number for FCB f.next entry
  1493. ;  Exit: HL = Address of FCB DM entry
  1494. ;        DE = DM entry
  1495. ;        BC = offset in DM
  1496. ; a,f,b,c,d,e,h,l
  1497. getdm:    ldx    c,f.next;    c := next record
  1498.     lda    nblock;        a := number of blocks
  1499.     mov    b,a;        to b
  1500. getdm1:    srlr    c;        shift next_record
  1501.     djnz    getdm1;        number_of_blocks times
  1502.     cma
  1503.     adi    1+8
  1504.     mov    b,a;        B := 8-number of blocks
  1505.     lda    nextnd;        Get extent mask
  1506.     andx    f.exlo;        mask with extent
  1507.     rrc
  1508. getdm2:    rlc
  1509.     djnz    getdm2;        8-number of blocks times
  1510.     add    c;        Add  the 2 values to get entry FCB
  1511. ;    "    "
  1512. ; Get block no. for diskmap entry (a) of FCB ix^ (b=0 on entry)
  1513. ; a,f,c,d,e,h,l
  1514. getbk:    pushix;            FCB addr.
  1515.     pop    h
  1516.     mvi    c,f.dm;        Offset 16 to point to DM
  1517.     dad    b
  1518.     mov    c,a;        add entry FCB
  1519.     dad    b
  1520.     lda    maxblk+1
  1521.     ora    a;        Test 8/16 bits FCB entry
  1522.     mov    e,m;        Get 8 bit value
  1523.     mov    d,a;        zero if 8 bits / entry
  1524.     rz;            8 bits per entry only
  1525.     dad    b;        add twice (16 bit values)
  1526.     mov    e,m;        load 16 bit value
  1527.     inx    h
  1528.     mov    d,m
  1529.     dcx    h;        restore pointer
  1530.     ret
  1531. ;
  1532. ; Calculate dirbuf entry point.  Set hl and iy pointers
  1533. ; Return a := directory entry user code (0th byte)
  1534. ; a,f,h,l,iy
  1535. caldir:    lhld    @dirbuf;    hl := dirbuf + secpnt
  1536.     lda    secpnt
  1537.     add    l
  1538.     mov    l,a
  1539.     adc    h
  1540.     sub    l
  1541.     mov    h,a
  1542.     push    h;        Set iy pointer
  1543.     popiy
  1544.     mov    a,m
  1545.     ret
  1546. ;
  1547. ; Init file count
  1548. ; h,l
  1549. setfct:    lxi    h,-1
  1550.     shld    filcnt
  1551.     ret
  1552. ;
  1553. ; Test file count = -1, z flag if so
  1554. ; a,f,h,l
  1555. tstfct:    lhld    filcnt
  1556.     mov    a,h
  1557.     ana    l
  1558.     inr    a;        z if -1
  1559.     ret
  1560. ;
  1561. ; Set last file
  1562. ; a,f,d,e,h,l
  1563. setlf:    call    tstlf;        Test last file
  1564.     rc;            No, exit
  1565.     inx    d;        incr. last file
  1566.     jr    sdem;        Save it in filect
  1567. ;
  1568. ; Test last file
  1569. ; a,f,d,e,h,l
  1570. tstlf:    lhld    @filect;    get pointer to last file
  1571.     lded    filcnt;        get file counter
  1572.     mov    a,e;        DE-(HL)
  1573.     sub    m
  1574.     inx    h
  1575.     mov    a,d
  1576.     sbb    m
  1577.     ret
  1578. ;
  1579. ; Get next FCB from drive
  1580. ; Entry : A=0 Check checksum, A=0FFH update checksum
  1581. ; a,f,b,c,d,e,h,l
  1582. rddir:    mov    c,a;        Save checksum flag
  1583.     lhld    filcnt
  1584.     inx    h;        advance file counter
  1585.     shld    filcnt
  1586.     lded    nfiles;        get max number of files
  1587.     ora    a;        clear cy
  1588.     dsbc    d
  1589.     dad    d;        leaves dsbc flags, restore hl
  1590.     jrz    rddir1;        Not last file
  1591.     jrnc    setfct;        last file, set file count 0FFFFH
  1592. rddir1:    mov    a,l;        Get file count LSB
  1593.     rrc;            *32, around the bend
  1594.     rrc
  1595.     rrc
  1596.     ani    060h;        Mask
  1597.     sta    secpnt;        Save for later use
  1598.     rnz;            Not first FCB sector
  1599.     push    b;        save checksum flag
  1600.     call    stdir;        calculate sector/track directory
  1601.     call    dmadir;        Set DMA for directory
  1602.     call    rdrcd;        Read dir. record from drive
  1603.     call    stdma;        Set DMA for user
  1604.     pop    b;        checksum flag
  1605. ;    "    "
  1606. ; Update/Check directory checksum
  1607. ; Entry : C=0 Check checksum, C=0FFH update checksum
  1608. ; a,f,b,c,d,e,h,l
  1609. chkdir:    lhld    ncheck;        number of checked records
  1610.     lded    recdir;        get current record
  1611.     ora    a
  1612.     dsbc    d;        test current record
  1613.     rz
  1614.     rc;            >= ncheck, exit
  1615.     lhld    @dirbuf
  1616.     mvi    b,128;        Set up counter
  1617.     xra    a;        Clear checksum
  1618. chkdr0:    add    m;        Add checksum
  1619.     inx    h
  1620.     djnz    chkdr0;        128 times
  1621.     lhld    @csv;        pointer to directory checksum
  1622.     dad    d;        add current record
  1623.     inr    c;        test checksum flag
  1624.     jrnz    chkdr2;        0, setup checksum
  1625.     mov    m,a;        0ffh, update checksum
  1626. chkdr2:    cmp    m;        test checksum
  1627.     rz;            ok or setting, exit
  1628. ;    "    "
  1629. ; Set write protect disk command
  1630. cmnd28:    lhld    dskro;        get disk R/O vector
  1631.     call    sdrvb;        include drive bit
  1632.     shld    dskro
  1633.     lded    nfiles;        Get max number of files - 1
  1634.     inx    d
  1635.     lhld    @filect;    point to disk parameter block
  1636. ;    "    "        and set max number of files
  1637. ; Store de in hl^
  1638. ; h,l
  1639. sdem:    mov    m,e
  1640.     inx    h
  1641.     mov    m,d
  1642.     ret
  1643. ;
  1644. ; Read sector from drive
  1645. ; a,f,b,c,d,e,h,l
  1646. rdrcd:    lxi    h,read
  1647.     call    xbios;        guard against bad bios
  1648.     ora    a
  1649.     rz
  1650.     call    rwerr
  1651.     jrz    rdrcd;        retry if error handler returns z
  1652.     ret;            ignore if error handler returns nz
  1653. ;
  1654. ; Write sector to drive
  1655. ; a,f,b,c,d,e,h,l
  1656. wrtrcd:    lxi    h,write
  1657.     call    xbios;        guard against bad bios
  1658.     ora    a
  1659.     rz;            no error
  1660.     call    rwerr
  1661.     mvi    c,1;        retries must put to disk
  1662.     jrz    wrtrcd;        retry if error handler returns z
  1663.     ret;            ignore if error handler returns nz
  1664. ;
  1665. ; read/write error handler
  1666. rwerr:    lhld    stbdsc;        Bad sector message pointer
  1667.     pchl;            DOS+ Error on D: disk I/O
  1668. ;
  1669. ; Set DMA address command.
  1670. ; a,f,b,c,d,e,h,l
  1671. cmnd26:    sded    dma;        Save DMA address
  1672.     call    stdma
  1673. ;    "    "
  1674. ; return current dma setting
  1675. rtndma:    lhld    dma;        echo back setting
  1676.     jmp    rtnwd
  1677. ;
  1678. ; Set DMA Address for user
  1679. ; a,f,b,c,d,e,h,l
  1680. stdma:    lbcd    dma
  1681.     jr    dmaset;        do bios call
  1682. ;
  1683. ; Set DMA Addr. for directory
  1684. ; a,f,b,c,d,e,h,l
  1685. dmadir:    lbcd    @dirbuf;    Get DMA Addr. for directory
  1686. ;    "    "
  1687. ; protected setdma
  1688. dmaset:    lxi    h,setdma
  1689.     jmp    xbios;        guard against bad bios
  1690. ;
  1691. ; Get bit from ALV buffer
  1692. ;  Entry : DE = block number
  1693. ;  EXIT  :  A = bit IN LSB (rotated, other bits meaningful)
  1694. ;           B = bitnumber in A
  1695. ;        HL = pointer in ALV buffer
  1696. ; a,f,b,c,d,e,h,l
  1697. getbit:    mov    a,e;        Get bit number
  1698.     ani    7;        mod 8
  1699.     inr    a;        +1
  1700.     mov    b,a;        to b
  1701.     mov    c,a;        and c
  1702.     srlr    d;        Get byte number
  1703.     rarr    e;        DE = DE/8
  1704.     srlr    d
  1705.     rarr    e
  1706.     srlr    d
  1707.     rarr    e
  1708.     lhld    @alv;        Get start addr. ALV buffer
  1709.     dad    d;        + byte number
  1710.     mov    a,m;        Get 8 bits
  1711. getbt0:    rlc;            select correct bit
  1712.     djnz    getbt0
  1713.     mov    b,c;        restore bit number
  1714.     ret
  1715. ;
  1716. ; Set/reset bit in ALV buffer
  1717. ;  ENTRY : DE = block number
  1718. ;        C = 0 reset bit, C=1 set bit
  1719. ; a,f,b,c,d,e,h,l
  1720. setbit:    push    b
  1721.     call    getbit;        Get bit
  1722.     ani    0feh;        mask it (reset bit)
  1723.     pop    d;        Get set/reset bit
  1724.     ora    e;        set/reset bit
  1725. ;    "    "
  1726. ; position bit and save
  1727. ; a,f,b
  1728. bitset:    rrc;            rotate bit to correct position
  1729.     djnz    bitset
  1730.     mov    m,a;        save 8 bits
  1731.     ret
  1732. ;
  1733. ; Mark allocated blocks from FCB in dirbuf
  1734. allocb:    mvi    c,1
  1735. ;    "    "
  1736. ; Fill bit buffer from FCB in dirbuf
  1737. ;  Entry : C = 0 reset bit, C=1 set bit
  1738. fillbb:    call    caldir;        Get directory entry
  1739.     lxi    d,f.dm;        offset to DM block
  1740.     dad    d
  1741.     mov    b,e;        Get block counter
  1742. fillb0:    mov    e,m;        Get block number, 8 bits extened
  1743.     inx    h;        advance
  1744.     lda    maxblk+1
  1745.     ora    a
  1746.     mov    d,a;        0 if < 256 blocks present
  1747.     jrz    fillb1;        < 256 blocks present
  1748.     dcr    b;        Decr. block counter, 256 or more
  1749.     mov    d,m;        Get correct MSB
  1750.     inx    h;        advance
  1751. fillb1:    mov    a,d
  1752.     ora    e
  1753.     jrz    fillb2;        block number = 0, Get next block
  1754.     push    h;        Save pointer
  1755.     push    b;        counter and set/reset bit
  1756.      lhld    maxblk;        get max length ALV buffer
  1757.     ora    a
  1758.     dsbc    d
  1759.     cnc    setbit;        de <= max length, insert bit
  1760.     pop    b;        counter and set/reset bit
  1761.     pop    h;        pointer
  1762. fillb2:    djnz    fillb0;        repeat over all DM entries
  1763.     ret
  1764. ;
  1765. ; Check file R/O, get DIR entry to hl & iy
  1766. chkfro:    call    caldir;        Get DIR entry to hl & iy
  1767. ;    "    "
  1768. ; Check file iy^ for r/o
  1769. ; f
  1770. ckfyro:    bity    7,f.sys
  1771.     jrnz    fronly;        $SYS file, error
  1772. ;    "    "
  1773. ; For erase, allows SYS files to be erased
  1774. rochk:    bity    7,f.ro
  1775.     rz;            not $R/O file, ok
  1776. ;    "    "
  1777. ; File read/only error
  1778. fronly:    lhld    sfilro;        Pointer to FILE R/O error handler
  1779.     pchl;            Error trap
  1780. ;
  1781. ; Check drive read only
  1782. chkro:    lhld    dskro;        Drive R/O vector
  1783.     call    sdrvb;        Set drive bit
  1784.     dsbc    d;        test extra bit added
  1785.     rnz;            Yes, then drive not R/O
  1786.     lhld    stro;        Pointer to DRIVE R/O error handler
  1787.     pchl;            error trap
  1788. ;
  1789. ; Get free block from ALV buffer
  1790. ;  Entry : DE = old block number
  1791. ;  Exit  : DE = new block number (0 if no free block)
  1792. ;   HL counts up, DE counts down
  1793. getfre:    mov    h,d;        hl := old block
  1794.     mov    l,e
  1795. getfr0:    mov    a,d
  1796.     ora    e
  1797.     jrz    getfr1;        down counter = 0
  1798.     dcx    d;        decrement
  1799.     push    h;        Save up/down counters
  1800.     push    d
  1801.     call    getbit;        from ALV buffer
  1802.     rar
  1803.     jrnc    getfr3;        0, found empty block
  1804.     pop    d;        Get up/down counters
  1805.     pop    h
  1806. getfr1:    lbcd    maxblk;        get max ALV length-1 to BC
  1807.     ora    a
  1808.     dsbc    b;        Test HL >= length ALV -1
  1809.     dad    b;        restore HL (Flags not changed)
  1810.     jrnc    getfr2;        End Buffer
  1811.     inx    h;        Incr up counter
  1812.     push    d;        Save counters
  1813.     push    h
  1814.     xchg;            Up counter to DE
  1815.     call    getbit;        from ALV buffer
  1816.     rar
  1817.     jrnc    getfr3;        0, found empty block
  1818.     pop    h;        Get counters
  1819.     pop    d
  1820.     jr    getfr0;        and test next block
  1821.  
  1822. getfr2:    mov    a,d
  1823.     ora    e
  1824.     jrnz    getfr0;        not last block, test next block
  1825.     ret;            Exit (DE=0)
  1826.  
  1827. getfr3:    stc
  1828.     ral;            Sst block number used
  1829.     call    bitset;        put bit in ALV buffer
  1830.     pop    d;        Get correct counter
  1831.     pop    h;        restore stack pointer
  1832.     ret;            Exit (DE=block number)
  1833. ;
  1834. ; Search for file name, for read/directory operations
  1835. srchrd:    mvi    a,15;        bytes to  match
  1836. ;    "    "
  1837. ; Search for file name
  1838. ;  Entry : A : number of bytes to match
  1839. search:    sta    searnb;        Save number of bytes
  1840.     mvi    a,0ffh;        Set exit code 0FFH (not found)
  1841.     sta    searex
  1842.     sixd    dcopy;        copy FCB pointer to RAM (search next)
  1843.     call    setfct;        init. file counter
  1844. ;    "    "
  1845. ; Search next file name
  1846. searcn:    xra    a;        check checksum directory
  1847.     call    rddir;        Get FCB from directory
  1848.     call    tstfct
  1849.     jrz    nofile;        past last entry
  1850.     lded    dcopy;        Get FCB pointer
  1851.     ldax    d;        user byte
  1852.     cpi    empty
  1853.     jrz    searc1;        empty directory entry
  1854.     push    d;        FCB pointer
  1855.     call    tstlf
  1856.     pop    d
  1857.     jrnc    nofile;        last file on this drive
  1858. searc1:    call    caldir;        hl := iy := dir entry, a := 0th byte
  1859.     cpi    tmstamp
  1860.     jrz    searcn;        time stamp, get next directory entry
  1861.     xra    a
  1862.     sta    wildcd;        no wild card detected yet
  1863.     mov    c,a;        i.e. a zero
  1864.     lda    searnb;        get number of bytes to match (to b)
  1865.     mov    b,a;        save input (a) for search length
  1866. ;    "    "
  1867. ; If dir entry (hl=iy)^ has the sys attribute set, and is stored under
  1868. ; user 0, ignore the user number during the directory search by
  1869. ; advancing the indices appropriately. At entry a contains the length
  1870. ; of the directory entry to be matched, and de points to the input FCB
  1871. ; (i.e. the searchee name). IY^ is the candidate dir entry.
  1872.     sui    15;        differentiate from erase searches
  1873.     jrc    searc4;        not looking for name, orig. algorithm
  1874.     bity    7,f.sys;    test system bit
  1875.     jrz    searc4;        not (sys) file, original algorithm
  1876.     mov    a,m
  1877.     ora    a
  1878.     jrnz    searc4;        not on user 0, original algorithm
  1879. searc2:    sta    wildcd;        set/reset wild card found flag
  1880. searc3:    inx    d
  1881.     inx    h;        skip over the user id
  1882.     inr    c
  1883.     djnz    searc4;        if more bytes to match
  1884. ;    "    "
  1885. ; All bytes matched.
  1886.     call    setlf;        update last file count (empty FCB)
  1887.     lda    filcnt;        Get file counter
  1888.     ani    3;        mask it
  1889.     sta    fvalue;        and set exit code
  1890.     xra    a;        clear exit code search
  1891.     sta    searex
  1892.     ret
  1893. ;
  1894. ; Check for match.
  1895. searc4:    ldax    d;        Get byte from FCB
  1896.     sui    '?'
  1897.     cma;            If zero then a holds 0ffh
  1898.     jrz    searc2;        set wild card found, matches any
  1899.     mov    a,c;        FCB char posn
  1900.     sui    f.s1
  1901.     jrz    searc3;        s1 scratch, then no test
  1902.     inr    a;        cpi f.exlo; test if extent number
  1903.     ldax    d
  1904.     jrz    searc7;        Special case if extent number
  1905.     xra    m;        compare to directory entry
  1906.     ani    07fh;        on mask
  1907. searc6:    jrnz    searcn;        not equal on mask, get next entry
  1908.     jr    searc3;        test next byte
  1909. ;
  1910. ; Special handling for extent number
  1911. searc7:    push    b;        save counters
  1912.     xra    m;        test extents
  1913.     mov    b,a
  1914.     lda    nextnd
  1915.     cma;            complement extent mask
  1916.     ani    01fh
  1917.     ana    b;        mask extents
  1918.     pop    b;        restore counters
  1919.     jr    searc6;        and test result
  1920. ;
  1921. nofile:    call    setfct;        error set file counter
  1922. ;    "    "
  1923. rtnerr:    mvi    a,0ffh;        and set return value
  1924.     jmp    rtnbyt
  1925. ;
  1926. ; delete file
  1927. delete:    call    chkro;        check disk R/O
  1928.     mvi    a,12;        count of bytes to match
  1929.     call    search;        for file
  1930. del0:    call    tstfct
  1931.     rz;            not found, exit
  1932.     call    caldir;        get entry point directory to iy, hl
  1933.     call    rochk;        allow $SYS files to be erased.
  1934.     mvi    m,empty;    remove file
  1935.     mvi    c,0;        remove bits ALV buffer (recycle space)
  1936.     call    fillbb
  1937.     call    wrtdir;        write dir buffer to disk
  1938.     call    searcn;        search next entry
  1939.     jr    del0;        and test it
  1940. ;
  1941. ; Rename file
  1942. renam:    call    schbgn;        Check disk R/O, no wild cards, etc.
  1943.     rnz;            wild cards
  1944. renam0:    call    tstfct;        iy points to dir entry
  1945.     rz;            Not found, exit
  1946.     call    chkfro;        Check file R/O, set iy^ dir entry
  1947.     lxi    b,12*256+16;    Copy FCB+16 to Directory+0 12 times
  1948.     call    wrfcb;        and write dir to disk
  1949.     call    searcn;        search next file
  1950.     jr    renam0;        and test it
  1951. ;
  1952. ; Change status file
  1953. sfattr:    call    schbgn;        Check disk R/O, no wild cards etc.
  1954.     rnz;            wild cards
  1955. sfatr1:    call    tstfct;        iy points to dir entry
  1956.     rz;            Not found, exit
  1957.     bitx    7,f.ifc6
  1958.     jrz    sfatr2;        No byte count update requested
  1959.     ldx    a,f.next
  1960.     sty    a,f.s1;        set byte count
  1961. sfatr2:    lxi    b,12*256+0;    Copy FCB+0 to directory+0 12 times
  1962.     call    wrfcb;        and write dir to disk
  1963.     call    searcn;        search next file
  1964.     jr    sfatr1;        and test it
  1965. ;
  1966. ; Set up for search on name field.  From sfattr and renam
  1967. ; Error if wild cards specified (nz flag) or r/o disk (abort)
  1968. schbgn:    call    chkro;        Check disk R/O
  1969. ;    "    "
  1970. ; Initial search on name field.
  1971. ; nz for wild cards specified when exit errors set
  1972. nowild:    mvi    a,12;        Count of bytes to match
  1973.     call    search;        file. iy points to dir entry
  1974.     lda    wildcd
  1975.     ora    a
  1976.     rz;            No wild cards found, ok
  1977.     sta    searex;        attrib & rename return this
  1978.     jr    rtnerr;        a is 0ffh
  1979. ;
  1980. ; Open file command
  1981. cmnd15:    call    seldrv;        from FCB
  1982.     mvix    f.exhi,0;    clear hi extent
  1983.     call    findf;        find file (using PATH name)
  1984.     call    tstfct
  1985.     rz;            Not found, exit
  1986.     call    fopen
  1987.     ldx    a,f.next
  1988.     inr    a
  1989.     rnz;            Not 0ffh on entry
  1990.     ldx    a,f.s1
  1991.     stx    a,f.next;    else return byte count
  1992.     ret
  1993. ;
  1994. ; Open file/extent, directory entry loaded
  1995. fopen:    ldx    a,f.exlo;    Get extent number from FCB
  1996.     push    psw
  1997.     call    caldir;        Get dir entry, hl & iy
  1998.     pushix
  1999.     pop    d;        FCB entry to de
  2000.     lxi    b,32;        Number of bytes to move
  2001.     ldir;            Move directory to FCB
  2002.     setx    7,f.clean;    Set FCB/FILE not modified
  2003.     ldx    b,f.exlo;    Get extent number
  2004.     ldx    c,f.rc;        Get next record number
  2005.     pop    psw;        old extent number
  2006.     stx    a,f.exlo;    Save it
  2007.     cmp    b
  2008.     jrz    fopen1;        old and new extent numbers same
  2009.     mvi    c,0;        Set next record count 0
  2010.     jrnc    fopen1;        old extent >= new extent
  2011.     mvi    c,80h;        Set next record count to maximum
  2012. fopen1:    stx    c,f.rc;        Save next record count
  2013.     lda    flags
  2014.     ani    fb.tacc
  2015.     rz;            access stamping disabled
  2016.     bitx    7,f.ro
  2017.     mvi    e,8
  2018.     cz    stime;        not r/o, set access time stamp
  2019.     rc;            timer system disabled
  2020.     rnz;            No time stamps, this disk
  2021.     jr    wrtdir;        else time stamp updated
  2022. ;
  2023. ; write FCB to disk directory entry
  2024. ; c is offset into FCB to copy from, b is byte count to copy
  2025. wrfcb:    call    caldir;        Get dir entry to iy, hl, a := usr code
  2026.     xchg;            in DE
  2027.     pushix;            Save FCB entry
  2028.     pop    h;        to hl
  2029.     push    b
  2030.     mvi    b,0
  2031.     dad    b;        add offset into FCB
  2032.     pop    b
  2033.     mov    c,b;        Get number of bytes to move
  2034.     mvi    b,0;        0 extend
  2035.     ldir;            Move
  2036.     resy    7,f.ifc6;    Reset any interface bit
  2037.     sty    a,f.usr;    Restore user code
  2038. ;    "    "
  2039. ; Write directory entry to drive
  2040. wrtdir:    call    stdir;        Calculate sector/track directory
  2041.     mvi    c,0ffh;        Update dir checksum
  2042.     call    chkdir
  2043.     call    dmadir;        Set DMA for directory
  2044.     mvi    c,1;        Write directory flag
  2045.     call    wrtrcd;        write
  2046.     jmp    stdma;        Set DMA for user & exit
  2047. ;
  2048. ; Close file command
  2049. cmnd16:    call    seldrv;        from FCB
  2050. ;    "    "
  2051. ; close file
  2052. close:    bitx    7,f.clean
  2053.     rnz;            FCB/FILE not modified, no close req'd
  2054.     call    chkro;        test disk R/O
  2055.     call    srchrd;        file, match 15 bytes
  2056.     call    tstfct
  2057.     rz;            file not present, exit
  2058.     call    chkfro;        Check file R/O, get directory entry
  2059.     resy    7,f.arc;    and reset any archive bit
  2060.     lxi    b,f.dm;        Offset to DM block
  2061.     dad    b
  2062.     xchg;            to de
  2063.     pushix
  2064.     pop    h;        FCB pointer to HL
  2065.     dad    b;        Add offset
  2066.     lda    maxblk+1
  2067.     ora    a
  2068.     jrz    close0;        number of blocks < 256
  2069.     dcr    b;        Set flag
  2070. close0:    call    copydm;        Copy and test blocks
  2071.     xchg;            exchange copy direction
  2072.     call    copydm;        Copy and test blocks
  2073.     xchg;            Exchange copy direction
  2074.     jnz    rtnerr;        Block not the same, error
  2075.     inx    h;        incr FCB pointer
  2076.     inx    d;        incr DIR pointer
  2077.     bit    0,b
  2078.     jrz    close1;        number of blocks < 256
  2079.     inx    h;        incr FCB pointer
  2080.     inx    d;        incr DIR pointer
  2081.     dcr    c;        decr counter
  2082. close1:    dcr    c;        decr counter
  2083.     jrnz    close0;        not ready
  2084.     lxi    h,f.exlo-f.next; Add -20, point to extent no.
  2085.     dad    d
  2086.     ldx    a,f.exlo;    Get extent number FCB
  2087.     cmp    m;        Compare with extent number DIR
  2088.     jrc    close3;        FCB < DIRECTORY THEN JUMP
  2089.     mov    m,a;        Save extent number in directory
  2090.     inx    h;        Get pointer record count
  2091.     inx    h
  2092.     inx    h
  2093.     ldx    a,f.rc;        Get FCB record count in case
  2094.     mov    m,a;        entry lgh changed (+ normal, - submit)
  2095. close3:    call    updatm;        set last update time
  2096.     jr    wrtdir;        Write FCB on disk
  2097. ;
  2098. ; Copy and test disk map
  2099. ;  Entry : HL : pointer to 1st FCB
  2100. ;          DE : pointer to 2nd FCB
  2101. ;          B  : 000H <  256 blocks
  2102. ;               0FFH >= 256 blocks
  2103. ;  Exit  : ZERO : 1 Blocks are the same
  2104. ;                 0 Blocks are not the same
  2105. copydm:    mov    a,m;        Get byte 1st FCB
  2106.     bit    0,b
  2107.     jrz    copyd0;        number of blocks < 256
  2108.     inx    h;        adv. pointer
  2109.     ora    m;        test byte = 0
  2110.     dcx    h;        restore pointer
  2111. copyd0:    ora    a;        Test block number is zero
  2112.     jrnz    copyd1;        no, compare blocks
  2113.     ldax    d;        Copy block from other FCB
  2114.     mov    m,a;         in empty location
  2115.     bit    0,b
  2116.     rz;            number of blocks < 256, exit
  2117.     inx    h;        incr to MSB block numbers
  2118.     inx    d
  2119.     ldax    d;        Copy block from other FCB
  2120.     mov    m,a;         in empty location
  2121.     jr    copyd2;        JUMP TRICK TO SAVE SPACE
  2122.  
  2123. copyd1:    ldax    d;        Get block number 1st FCB
  2124.     sub    m
  2125.     rnz;            not the same
  2126.     ora    b
  2127.     rz;            < 256 blocks, return
  2128.     inx    h;        incr to MSB block numbers
  2129.     inx    d
  2130. copyd2:    ldax    d;        Get block number 1st FCB
  2131.     sub    m;        test if the same
  2132.     dcx    h;        Decr. block FCB pointers
  2133.     dcx    d
  2134.     ret
  2135. ;
  2136. ; Find file, using path. Only default and current user entries apply
  2137. findf:    call    srchrd;        for read file. Match 15 bytes
  2138.     call    tstfct
  2139.     rnz;            found, exit
  2140.     lda    fcb0
  2141.     ora    a
  2142.     rnz;            drive specified, ignore path
  2143.     lhld    path;        get PATH address
  2144.     mov    a,h
  2145.     ora    l
  2146.     rz;            0, no path, exit
  2147. findf2:    lda    drive
  2148.     mov    b,a;        keep handy. 0..maxdrv
  2149.     mov    a,m;        Get 1st entry PATH name
  2150.     inx    h;        adv. pointer
  2151.     ora    a
  2152.     inx    h
  2153.     jz    nofile;        last entry, not found exit
  2154.     cpi    '$'
  2155.     jrz    findf2;        current drive already searched
  2156.     dcr    a;        put in 0..maxdrv range
  2157.     ani    0fh
  2158.     cmp    b
  2159.     jrz    findf2;        current drive already searched
  2160.     dcx    h
  2161.     push    h;        Different drive, so..
  2162.     call    seldk;        Select drive
  2163.     pop    h;        PATH pointer
  2164.     lda    user;        keep handy
  2165.     mov    b,a
  2166.     mov    a,m;        Get user number
  2167.     inx    h;        adv. pointer
  2168.     cpi    '$'
  2169.     jrz    findf5;        current user, ok, search
  2170.     xra    b
  2171.     ani    01fh;        Mask user no. area only
  2172.     jrnz    findf2;        Path entry not for this user, skip
  2173. findf5:    push    h;        path pointer
  2174.     call    srchrd;        file, match 15 bytes
  2175.     call    tstfct
  2176.     pop    h;        path pointer
  2177.     jrz    findf2;        file not present, test next path entry
  2178.     call    caldir;        Get directory entry
  2179.     lda    defdrv;        Get now current drive
  2180.     inr    a;        in range 1..
  2181.     sta    fcb0;        save it in exit FCB0
  2182.     ret
  2183. ;
  2184. ; Make file command
  2185. cmnd22:    call    seldrv;        from FCB
  2186.     mvix    f.exhi,0;    Clear high extent #
  2187.     call    fdirty;        ensure archive bit reset
  2188. ;    "    "
  2189. ; Make file
  2190. make:    call    chkro;        Check drive r/o
  2191.     ldx    a,f.usr
  2192.     push    psw;        Save user id for file
  2193.     mvix    f.usr,empty;    Set 1st byte to empty file
  2194.     mvi    a,1;        Search for 1 byte
  2195.     call    search;        for empty DIR space. Sets result code
  2196.     pop    psw
  2197.     stx    a,f.usr;    Restore user id for file
  2198.     call    tstfct
  2199.     rz;            No empty entry found, return error
  2200.     xra    a;        clear last record byte count
  2201.     stx    a,f.s1
  2202.     pushix
  2203.     pop    h;        copy FCB pointer to HL
  2204.     lxi    d,f.rc;        Prepare offset
  2205.     dad    d
  2206.     mvi    b,17;        Set loop counter
  2207. make0:    mov    m,a;        Clear rc and dm area
  2208.     inx    h
  2209.     djnz    make0
  2210.     call    caldir;        Get directory entry
  2211.     ldx    a,f.usr;    Get first byte FCB & save in
  2212.     mov    m,a;         directory (write FCB needs this)
  2213.     mvi    e,2;        Set creation date
  2214.     call    stime
  2215.     call    updatm;        Set last update date/time
  2216.     mvi    e,8;        Set last access date/time
  2217.     call    stime
  2218.     lxi    b,32*256+0;    Copy FCB+0 to directory+0 32 times
  2219.     call    wrfcb;        write FCB to disk
  2220.     setx    7,f.clean;    Mark FCB/FILE not modified
  2221.     ret
  2222. ;
  2223. ; Open next extent
  2224. openex:    bitx    7,f.clean
  2225.     jrnz    openx5;        FCB/FILE not modified (write)
  2226.     call    close;        Current FCB.  Reads/loads dir entry.
  2227.     lda    fvalue;        exit code from close
  2228.     inr    a
  2229.     rz;            error, exit
  2230.     call    calnex;        Calculate next extent
  2231.     jrc    openx3;        error
  2232.     jrnz    openx6;        FCB present from close (wrt, dir read)
  2233. openx1:    call    srchrd;        for file, match 15 bytes
  2234.     call    tstfct
  2235.     jrnz    openx6;        file found
  2236.     lda    rdwr
  2237.     ora    a
  2238.     jrz    openx3;        read flag, error (no extent)
  2239.     call    make;        new extent (is write)
  2240.     call    tstfct
  2241.     jrnz    openx7;        successful, exit
  2242. openx3:    setx    7,f.clean;    Set FCB/FILE not modified
  2243.     jmp    nofile;        Set exit code for error
  2244.  
  2245. openx5:    call    calnex;        Calculate next extent
  2246.     jrc    openx3;        error
  2247.     jr    openx1;        use same routine
  2248. ;
  2249. openx6:    call    fopen;        open file
  2250. openx7:    xra    a;        and clear exit code
  2251. ;    "    "
  2252. bytrtn:    jmp    rtnbyt
  2253. ;
  2254. ; Calculate next extent
  2255. ;  exit: carry  => overflow detectedd
  2256. ;        zflag  => search next extent
  2257. ;     nzflag => next extent present in FCB (close)
  2258. ;    (A single directory/FCB entry can hold multiple extents)
  2259. calnex:    ldx    c,f.exlo;    Get extent number
  2260.     ldx    b,f.exhi;    Get high portion
  2261.     bit    6,b;        Test error bit random record
  2262.     stc
  2263.     rnz;            Non-zero, error exit, cy set
  2264.     inr    c;        Incr. extent number
  2265.     mov    a,c
  2266.     ani    01fh;        mask extent number
  2267.     mov    c,a;        to b
  2268.     jrnz    calnx1;        non-zero extent
  2269.     inr    b;        Incr. high order extent
  2270.     mov    a,b
  2271.     ani    03fh;        mask it (c is zero)
  2272.     mov    b,a;        Save it in c
  2273.     stc
  2274.     rz;            file overflow, error flag (cy) set
  2275. ;    "    "        since c is 0 following returns z flag
  2276. ;    "    "         for "not same dir entry"
  2277. calnx1:    lda    nextnd;        Get next extent mask
  2278.     ana    c;        Test if same dir entry (close)
  2279. ;    "    "
  2280. ; Set FCB extent bytes from bc (high/low). Preserve flags.
  2281. ; Return bc = old values
  2282. xchext:    ldx    a,f.exlo
  2283.     stx    c,f.exlo;    Save extent number
  2284.     mov    c,a
  2285.     ldx    a,f.exhi
  2286.     stx    b,f.exhi;    and high portion
  2287.     mov    b,a
  2288.     ret
  2289. ;
  2290. ; Read random record command
  2291. cmnd33:    call    seldrv;        from FCB
  2292.     xra    a;        set read/write flag
  2293.     call    ldfcb;        Load random record in FCB
  2294.     rnz;            Return error
  2295.     jr    reads;        no error, go read sector
  2296. ;
  2297. ; Read sequential
  2298. cmnd20:    call    seldrv;        from FCB
  2299. ;    "    "
  2300. ; Read sector
  2301. reads:    xra    a;        set read/write flag
  2302.     sta    rdwr;        save it
  2303.     ldx    a,f.next;    Get record counter
  2304.     cpi    080h
  2305.     jrnz    reads1;        Not last rcd of this extent
  2306.     call    openex;        Open next extent
  2307.     lda    fvalue;        get exit code
  2308.     ora    a
  2309.     jrnz    eofull;        end of file
  2310.     stx    a,f.next;    Clear record counter
  2311.     jr    reads2
  2312.  
  2313. reads1:    cmpx    f.rc;        illegal rcd ctr fields cause eof
  2314.     jrnc    eofull;        signal EOF
  2315. reads2:    call    getdm;        Get block number from DM in FCB
  2316.     mov    a,d
  2317.     ora    e
  2318.     jrz    eofull;        block number = 0, end file
  2319.     call    calsec;        Calculate sector number (128 bytes)
  2320.     call    calst;        Calculate sector/track number
  2321.     call    rdrcd;        Read data
  2322.     lda    funct;        Get function number
  2323.     cpi    20
  2324.     rnz;            Not read sequential, return
  2325.     inrx    f.next;        incr. next record counter
  2326.     ret
  2327. ;
  2328. ; Signal eof or full
  2329. eofull:    mvi    a,1;        Set EOF flag
  2330.     jr    bytrtn;        and return to caller
  2331. ;
  2332. ; Calculate sector number from start of data area in HLDE
  2333. ;  Entry : DE = block number from FCB
  2334. ; a,f,b,d,e,h,l
  2335. calsec:    lxi    h,0;        clear MSB sector number
  2336.     lda    nblock;        get loop counter
  2337.     mov    b,a;        to b
  2338. calsc1:    slar    e;        shift L,D,E
  2339.     ralr    d
  2340.     ralr    l
  2341.     djnz    calsc1;        B times
  2342.     lda    nmask;        Get sector mask
  2343.     andx    f.next;        and with next record
  2344.     ora    e;        Set up LSB sector number
  2345.     mov    e,a
  2346.     ret
  2347. ;
  2348. ; Write random sector (with zero fill command 40 done in "writes")
  2349. cmnd34:
  2350. cmnd40:    call    seldrv;        from FCB
  2351.     mvi    a,0ffh;        Set read/write flag
  2352.     call    ldfcb;        Load FCB from random record
  2353.     rnz;            return error
  2354.     jr    writes;        no error, write record
  2355. ;
  2356. ; Mark file modified
  2357. fdirty:    resx    7,f.clean;    reset FCB/FILE modified
  2358.     ret
  2359. ;
  2360. ; Write sequential
  2361. cmnd21:    call    seldrv;        from FCB
  2362. ;    "    "
  2363. ; Write sector
  2364. writes:    mvi    a,0ffh;        Set read/write flag
  2365.     sta    rdwr;        and save it
  2366.     call    chkro;        Check disk R/O
  2367.     pushix
  2368.     popiy;            FCB pointer to iy
  2369.     call    ckfyro;        Check file iy^ R/O
  2370.     ldx    a,f.next;    Get record count
  2371.     cpi    080h
  2372.     jrc    writs0;        not end of this extent
  2373.     call    openex;        open next extent
  2374.     lda    fvalue;        error code
  2375.     ora    a
  2376.     jrnz    eofull;        error, directory full
  2377.     stx    a,f.next;    Clear record counter
  2378. writs0:    call    getdm;        Get block number from FCB
  2379.     mov    a,d
  2380.     ora    e
  2381.     jrnz    writs5;        Not 0, write sector
  2382.     push    h;        save pointer to block number
  2383.     mov    a,c
  2384.     ora    a
  2385.     jrz    writs1;        1st block number in extent
  2386.     dcr    a;        Decr pointer to block number
  2387.     call    getbk;        Get prev. blocknumber
  2388. writs1:    call    getfre;        Get nearest free block
  2389.     pop    h;        Get pointer to block number
  2390.     mov    a,d
  2391.     ora    e
  2392.     mvi    a,2
  2393.     jz    rtnbyt;        blocknumber = 0, disk full error
  2394.     call    fdirty;        reset FCB/FILE modified
  2395.     mov    m,e;        Save blocknumber
  2396.     lda    maxblk+1
  2397.     ora    a
  2398.     jrz    writs2;        blocksize < 256
  2399.     inx    h;        adv. to MSB blocknumber
  2400.     mov    m,d;        Save MSB blocknumber
  2401. writs2:    mvi    c,2;        Set write new block flag
  2402.     lda    funct;        Get function number
  2403.     sui    40
  2404.     jrnz    writs6;        Not writeranrcd with zero fill
  2405.     push    d;        save blocknumber
  2406.      lhld    @dirbuf;    use directory buffer for zero fill
  2407.     mvi    b,128;        bytes to clear
  2408. writs3:    mov    m,a;        Clear directory buffer
  2409.     inx    h
  2410.     djnz    writs3;        more
  2411.     call    calsec;        Calculate sector number (128 bytes)
  2412.     lda    nmask;        Get sector mask
  2413.     mov    b,a;        to b
  2414.     inr    b;        Increment to get number of writes
  2415.     cma;            Complement sector mask
  2416.     ana    e;        Mask sector number
  2417.     mov    e,a;        and save it
  2418.     mvi    c,2;        Set write new block flag
  2419. writs4:    push    h;        Save registers
  2420.     push    d
  2421.     push    b
  2422.     call    calst;        Calculate sector/track
  2423.     call    dmadir;        Set DMA directory buffer
  2424.     pop    b;        Get write new block flag
  2425.     push    b;        Save it again
  2426.     call    wrtrcd;        Write record to disk
  2427.     pop    b;        Restore registers
  2428.     pop    d
  2429.     pop    h
  2430.     mvi    c,0;        Clear write new block flag
  2431.     inr    e;        Incr. sector number
  2432.     djnz    writs4;        Write all blocks
  2433.     call    stdma;        Set user DMA address
  2434.     pop    d;        Get block number
  2435. writs5:    mvi    c,0;        Clear write new block flag
  2436. writs6:    call    fdirty;        Reset FCB/FILE unmodified flag
  2437.     push    b
  2438.     call    calsec;        Calculate sector number (128 bytes)
  2439.     call    calst;        Calculate sector/track
  2440.     pop    b;        write new block flag
  2441.     call    wrtrcd;        Write record to disk
  2442.     ldx    a,f.next;    Get record counter
  2443.     cmpx    f.rc;        next record
  2444.     jrc    writs7;        record counter < next record
  2445.     inr    a;        incr. record count
  2446.     stx    a,f.rc;        Save on next record position
  2447. writs7:    lda    funct;        Get function number
  2448.     cpi    21
  2449.     rnz;            not write sequential, return
  2450.     inrx    f.next;        incr. record count
  2451.     ret
  2452. ;
  2453. ; Load FCB for random read/write. NZ flag for error.
  2454. ; Entry a=0 for read, 0ffh for write
  2455. ldfcb:    sta    rdwr;        save read/write flag
  2456.     ldx    a,f.rrno;    Get 1st byte random record
  2457.     mov    d,a;        to d
  2458.     res    7,d;        Rest MSB to get next record
  2459.     ral;            Shift MSB to carry
  2460.     ldx    a,f.rrno+1;    Load next byte
  2461.     ral;            Shift carry
  2462.     push    psw;        Save
  2463.     ani    01fh;        Mask next extent
  2464.     mov    c,a;        Save it in C
  2465.     pop    psw;        Get byte
  2466.     ral;            Shift 4 times
  2467.     ral
  2468.     ral
  2469.     ral
  2470.     ani    0fh;        Mask
  2471.     mov    b,a;        Save FCB+14
  2472.     ldx    a,f.rrno+2;    Get next byte random record
  2473.     mvi    e,6;        Set random record too large flag
  2474.     cpi    4
  2475.     jrnc    ldfcb7;        error, random record too large
  2476.     rlc;            address extent (actually div 16)
  2477.     rlc
  2478.     rlc
  2479.     rlc
  2480.     add    b;        add byte
  2481.     mov    b,a;        Save FCB+14 in B
  2482.     stx    d,f.next;    Set next record count
  2483.     ldx    d,f.exhi;    Get FCB+14
  2484.     bit    6,d
  2485.     jrnz    ldfcb7;        error, earlier random record write
  2486.     mov    a,c;        Get new extent number
  2487.     cmpx    f.exlo;        Compare with FCB
  2488.     jrnz    ldfcb1;        not equal, open next extent
  2489.     mov    a,b;        Get new FCB+14
  2490.     xorx    f.exhi;        Compare with FCB+14
  2491.     ani    03fh;        Mask it
  2492.     jrz    ldfcb5;        FCB at appropriate extent, return
  2493. ldfcb1:    bit    7,d
  2494.     jrnz    ldfcb2;        FCB not modified (not written)
  2495.     push    d
  2496.     push    b
  2497.     call    close;        extent
  2498.     pop    b
  2499.     pop    d
  2500.     mvi    e,3;        Set close error in case
  2501.     lda    fvalue;        Get exit code
  2502.     inr    a
  2503.     jrz    ldfcb6;        close error, exit
  2504. ldfcb2:    call    xchext;        Save new extent # (bc=high/low)
  2505.     push    b
  2506.     call    srchrd;        search file, match 15 bytes
  2507.     pop    b;        previous value for extent fields
  2508.     lda    fvalue;        Get error code
  2509.     inr    a
  2510.     jrnz    ldfcb4;        No error, exit
  2511.     lda    rdwr;        Get read/write flag
  2512.     inr    a
  2513.     jrz    ldfcb3;        write, go make it
  2514.     call    xchext;        read, restore the extent bytes
  2515.     mvi    a,4;        Error, reading empty record
  2516.     jr    ldfcb9;        and exit
  2517.  
  2518. ldfcb3:    call    make;        make new FCB
  2519.     mvi    e,5;        make error code
  2520.     lda    fvalue;        error ?
  2521.     inr    a
  2522.     jrz    ldfcb6;        make error exit
  2523.     jr    ldfcb5;        No error exit (zero set)
  2524.  
  2525. ldfcb4:    call    fopen;        open file
  2526. ldfcb5:    xra    a;        Set Z flag and clear error code
  2527.     jr    ldfcb9
  2528. ;
  2529. ldfcb6:    mvix    f.exhi,0c0h;    Set random record error
  2530. ldfcb7:    setx    7,f.clean;    Set FCB/FILE not modified
  2531.     mov    a,e;        error code
  2532. ldfcb9:    sta    fvalue;        save error code
  2533.     ora    a;        Clear/set zero flag
  2534.     ret
  2535. ;
  2536. ; Set update time
  2537. updatm:    mvi    e,4
  2538. ;    "    "
  2539. ; Set time and date
  2540. ;  Entry :  E = 2 : Set creation date
  2541. ;             4 : Set last update time/date
  2542. ;        8 : Set last access time/date
  2543. ;  Exit :   cy for timer disabled
  2544. ;        nz for no time stamp on drive
  2545. ;           z and nc for directory updated
  2546. stime:    lhld    @dirbuf;    Get directory entry
  2547.     lxi    b,060h;        offset entry point time/date stamp
  2548.     dad    b;        Add offset
  2549.     mov    a,m;        Get byte
  2550.     sui    tmstamp
  2551.     rnz;            No time stamp present, return
  2552.     mov    d,a;        0, clear D
  2553.     dad    d;        Add entry (create/update/access)
  2554.     push    d;        save field id
  2555.     lda    secpnt;        Get sector pointer (0, 32, 64
  2556.     rrc;            Divide / 4
  2557.     rrc
  2558.     mov    e,a;        0, 8, 16
  2559.     rrc;            divide 4 = 0, 2, 4
  2560.     rrc
  2561.     add    e;        Add it (A=0,10,20)
  2562.     mov    e,a;        Save in e
  2563.     dad    d;        point to appropriate field
  2564.     push    h
  2565.     call    getbtm;        point to system time array
  2566.     pop    d;        field pointer
  2567.     pop    b;        restore field id
  2568.     rc;            timer system disabled
  2569.     mov    a,c
  2570.     cpi    2;        no carry for valid field id
  2571.     jrz    mvdate;        2 byte field for creation
  2572. ;    "    "
  2573. ; Move 4 byte time array hl^ to de^, avoid interrupts
  2574. ; b,c,d,e,h,l
  2575. mvtime:    lxi    b,4
  2576. ;    "    "
  2577. ; entry for 2/4 byte fields, bc = length on entry
  2578. ; b,c,d,e,h,l
  2579. mvdate:    di
  2580.     ldir;            store it
  2581.     ei
  2582.     xra    a;        z/nc for good exits
  2583.     ret
  2584. ;
  2585. ; Get time
  2586. gettim:    push    d;        Save address to put time
  2587.     call    getbtm;        get system time adr.
  2588.     pop    d;        Restore address to put time
  2589.     mvi    a,0ffh;        If disabled return error
  2590.     jrc    getim2
  2591.     lxi    b,4
  2592.     call    mvdate;        if timer enabled
  2593.     mov    a,m;        seconds field
  2594. getim2:    jmp    rtnbyt
  2595. ;
  2596. ; Set time
  2597. settim:    push    d;        keep source time ptr
  2598.     push    d
  2599.     pop    b;        if hardware must be accessed to set
  2600.     call    btime;        get system ptr
  2601.     pop    d
  2602.     rc;            timer system disabled
  2603.     rnz;            Bios did it all
  2604.     xchg
  2605.     call    mvtime;        sets a := 0
  2606.     stax    d;        set seconds field 0
  2607.     ret
  2608. ;
  2609. ; Specification for any bios timer routine. Leaves carry clear, NZ flg
  2610. ; Input            Output (always)
  2611. ; BC =  0 get pointer     HL=pointer to time array
  2612. ; BC <> 0 allows hard-     HL+0^ date LSB days since 1977 Dec. 31
  2613. ;  ware to be updated     HL+1^ date MSB (1=1978/1/1) (0=nodate)
  2614. ;  if a routine call.     HL+2^ hour (bcd)
  2615. ;  ignored if timead     HL+3^ minute (bcd)
  2616. ;  is purely an address. HL+4^ seconds (bcd)
  2617. ;  BC^ is time to set.
  2618. ;             Carry and Z flags reset.
  2619. ;
  2620. ; Get time from bios system
  2621. getbtm:    lxi    b,0;        so hardware not updated
  2622. ;    "    "
  2623. ; Execute BIOS time routine.
  2624. ; bc = 0 to get time, <> 0 to set hardware, when bc points to time
  2625. ; to set.  This is used only when hardware ports accessed.
  2626. ; flags 80h bit = 0 for timead = address of array
  2627. ;        = 1 for timead = pointer to routine
  2628. ; net result is to return hl pointer to array
  2629. ; i.e. at exit hl always points to the system array
  2630. ; The routine call allows for interrogation of hardware ports.
  2631. ; The bios routine may leave interrupts disabled, they will be
  2632. ; re-enabled when the time value has been copied.
  2633. ; carry set on exit means timer disabled.
  2634. ; Z flag set on exit if timead is a pointer only
  2635. btime:    lhld    timead;        Get address time routine
  2636.     mov    a,h
  2637.     ora    l;        check disabled
  2638.     stc
  2639.     rz;            disabled, do nothing
  2640.     lda    flags
  2641.     ani    fb.tcal
  2642.     rz;            timead is address of array only
  2643.     pchl;            is address of routine, execute
  2644. ;
  2645. ; Error messages
  2646. mbadsc:    db    'Disk I/O$'
  2647. msel:    db    'No drive$'
  2648. mfilro:    db    'File '
  2649. mro:    db    'R/O$'
  2650. ;
  2651. mbfunc:    db    cr,lf,'Fn: $'
  2652. mfile:    db    ' File: $'
  2653. ;
  2654. mberr:    db    cr,lf,'DOS+ error ';    Last area checksummable
  2655. mdrive:    db    0,': $';    modified
  2656. ;
  2657. ; RAM AREA.  Note mdrive above is a variable
  2658. ;
  2659. dma:    dw    080h;    DMA address
  2660. dskro:    dw    0;    Disk R/O vector
  2661. login:    dw    0;    Login vector
  2662. ;
  2663. ; Console i/o variables.  Keep these 3 in this order (wired into code)
  2664. bufull:    db    0;    Lastch contains unused char.
  2665. lastch:    db    0;    Last console input char.
  2666. column:    db    0;    Current console output column
  2667. ;
  2668. ; Copied in from Bios tables on drive selection
  2669. @trans:     dw    0;    ^Translation vector, 0 for none
  2670. @filect: dw    0;    ^Number of files on drive
  2671.      ds    4;    temp1, temp2 not used
  2672. @dirbuf: dw    0;    ^directory buffer
  2673. @ixp:     dw    0;    ^Disk parameter block
  2674. @csv:     dw    0;    ^Check sum vector
  2675. @alv:     dw    0;    ^Allocation vector
  2676. ;
  2677. ; Copied in from Disk Parameter table on drive selection
  2678. maxsec:    dw    0;    Maximum number of sectors/track
  2679. nblock:    db    0;    Number of blocks
  2680. nmask:    db    0;    Mask number of blocks
  2681. nextnd:    db    0;    Extent mask
  2682. maxblk:    dw    0;    Maximum block number -1
  2683. nfiles:    dw    0;    Maximum number of files - 1
  2684. ndir0:    db    0,0;    First two entries ALV buffer
  2685. ncheck:    dw    0;    Number of checksum entries
  2686. nftrk:    dw    0;    First track number
  2687. ;
  2688. funct:    db    0;    Function number
  2689. fvalue:    dw    0;    Exit code
  2690. drvflg:    db    0;    Drive select used flag
  2691. fcb0:    db    0;    FCB byte 0 (save for exit)
  2692. ;
  2693. rdwr:    db    0;    Read/write flag
  2694. wildcd:    db    0;    Search question mark used
  2695. ;
  2696. user:    db    0;    User number
  2697. drive:    db    0;    Drive number
  2698. defdrv:    db    0;    Default drive number
  2699. subflg:    db    0;    Submit flag (Reset disk command)
  2700. ;
  2701. recdir:    dw    0;    Record directory (checksum)
  2702. filcnt:    dw    0;    File counter
  2703. secpnt:    db    0;    Sector pointer
  2704. ;
  2705. dcopy:    dw    0;    Copy address FCB
  2706. searex:    db    0;    Exit code for search
  2707. searnb:    db    0;    Search number of bytes
  2708. ;
  2709. ; 64 minimum byte stack area.  Copyright re-used for stack.
  2710. stktop:    db    'Copyright (c) 1986 C.B. Falconer (203) 281-1438'
  2711.     ds    64-($-stktop)
  2712. ;
  2713. ; Macro for storage allocation messages only, SLRMAC specific
  2714. px    macro    v, xmsg
  2715.     .printx    v&xmsg
  2716.     endm
  2717. ;
  2718. left    equ    serial+0dfeh-$
  2719.     if    left ge 8000h;    negative
  2720.      +++ ERROR DOS+ too big +++
  2721.          px    %(-left), < too many bytes used>
  2722.     else
  2723.      px    %left, < bytes still available>
  2724.      if    left gt 0
  2725.       ds    left;    space that's left
  2726.      endif
  2727. ; Put stack at end of segment.  Error trappers expect spsave there.
  2728. stack:
  2729. spsave:     dw    0;    Entry stack pointer save at end
  2730.     endif
  2731. ;
  2732.     end
  2733. τ╬