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 / JSAGE / ZSUS / TCJ / TCJ-ZDOS.LBR / ZSART2.WZ / ZSART2.WS%a0
Text File  |  2000-06-30  |  44KB  |  899 lines

  1. ..No justification
  2. ..No multiple spaces, use TAB chars (^P^I)
  3. ..Bolding with ^P^B, Italics with ^P^Y
  4.  
  5. ZSDOS, Anatomy of an Operating System, Part II
  6.  
  7.                                by
  8. Harold F. Bower, Major, US Army Signal Corps; BSEE, MSCIS, Ham ì
  9. (WA5JAY), avid homebuilder (starting with 8008 running SCELBAL).
  10.                                and
  11. Cameron W. Cotrill, Vice President, Advanced Multiware Systems; ì
  12. specialist in "impossible" real-time hardware and software ì
  13. systems.
  14.  
  15.  
  16. In the first part of this article, we presented the philosophy ì
  17. and the features of ZSDOS (Z-System Disk Operating System). In ì
  18. this portion, we will summarize the performance of ZSDOS, share a ì
  19. few of the tricks we used to shoehorn all these features into 7 ì
  20. bytes, and give a few programming examples showing how to use ì
  21. some of the new features of ZSDOS and ZDDOS.
  22.  
  23. ZSDOS Performance.
  24.  
  25. Measuring the performance improvements of ZSDOS is a complicated ì
  26. matter. During development, an entire suite of tests was run on ì
  27. ZS/ZDDOS in various configurations in an attempt to validate the ì
  28. design tradeoffs. The most revealing tests of BDOS differences ì
  29. turned out to be a series of assemblies done under control of a ì
  30. command script. This should be no surprise as assemblies are by ì
  31. nature disk intensive. 
  32.  
  33. To reduce the perception that our results are "tailored" or ì
  34. skewed in favor of a particular system or configuration, ì
  35. different processor chips (Z80 and HD64180), different BIOSes ì
  36. (MicroMint, XBIOS, Ampro), and different media (RAM disk, Hard ì
  37. Disk and Floppy disk) were used in the timed runs. Since the ì
  38. results were most affected by the media, results are shown in the ì
  39. categories of RAM, Hard Disk and Floppy Disk performance. No form ì
  40. of file date stamping was done since ZSDOS would have a distinct ì
  41. advantage in this field.
  42.  
  43. Three sets of hardware were used in these analyses in an attempt ì
  44. to minimize the effect of any unique processes in a given system ì
  45. from skewing the results. The first system (System 1 in the ì
  46. timing runs) was a "stock" MicroMint SB-180 operating at a 6.144 ì
  47. MHz clock speed. System 2 was an Ampro Little Board 1A with a Z80 ì
  48. running at 4.0 MHz, and System 3 was a homebrew Z-180 system ì
  49. designed to be compatible with the SB-180 operating at 9.216 MHz. ì
  50. Complete information on each system in the Appendix.
  51.  
  52.  
  53. OPERATING  SYSTEMS.
  54.  
  55. CP/M 2.2. Gary Kildall and Digital Research developed this ì
  56. operating system for 8-bit processors in an evolutionary process ì
  57. on early 8080-based computers. A subsequent product, CP/M Plus ì
  58. (also known as CP/M 3) is still in limited use, but has not ìègained the wide acceptance of the earlier release. CP/M 2.2 is ì
  59. coded in 8080 assembly language and is a non-banked, non-ì
  60. reentrant single-user, single tasking operating system.
  61.  
  62. ZRDOS 1.9. Echelon Incorporated released many versions of this ì
  63. CP/M 2.2-compatible operating system over the past several years. ì
  64. It is coded in Z80 assembly language and will therefore not ì
  65. execute on 8080 processors. Some additional features were added, ì
  66. such as one-level reentrancy under user control, and return of ì
  67. the current DMA address. Later versions (after 1.5) include ì
  68. enhanced support for hard disk media by not rebuilding the ì
  69. allocation bit map on a disk relog command. Version 1.9 added ì
  70. larger disk and file sizes. Like CP/M, it is single-user and ì
  71. single-tasking.
  72.  
  73. ZSDOS. This is the topic of this article, with details and ì
  74. descriptions of features contained in Part I. ZSDOS is coded in ì
  75. Z80  assembly language and is also a single-user,  single-tasking ì
  76. operating system capable of single-level reentrancy.
  77.  
  78. Since this report was an aimed at formalizing an evaluation of ì
  79. the performance characteristics of ZSDOS, a number of different ì
  80. variants to the above operating systems were initially timed. ì
  81. Because the performance of these systems was very similar to ì
  82. others in the test, their comparative results are simply ì
  83. summarized below.
  84.  
  85. CP/M 2.2 with Plu*Perfect Systems' PUBlic patch. Only minor ì
  86. differences in performance from the basic CP/M 2.2 were noted, so ì
  87. results of the patched system were not included in the final ì
  88. results.
  89.  
  90. ZRDOS 1.2. The performance of ZRDOS 1.2 was very close to CP/M ì
  91. 2.2, being a couple of percent slower in the majority of cases. ì
  92. It was therefore not included in the final timing analyses.
  93.  
  94. ZRDOS 1.7. Timing tests indicate no significant performance ì
  95. differences between ZRDOS 1.7 and 1.9.
  96.  
  97. ZDDOS. Since ZSDOS and ZDDOS are largely the same code and since ì
  98. comparative timings between them show less than a 1% difference, ì
  99. only times for ZSDOS will be presented. 
  100.  
  101.  
  102. BASIC  IO SYSTEMS (BIOSes).
  103.  
  104. MICRO MINT, SB-180. While MicroMint currently ships Version 3.2 ì
  105. with their systems, a slightly modified version of 2.7 was used ì
  106. in these timings on the SB-180. The changes included independent ì
  107. step rates for floppy drives, different floppy formats and fixing ì
  108. of eight-inch drivers as well as a slight amount of optimization. ì
  109. Little performance difference from the standard BIOS should be ì
  110. noticed. A 54k system size was used. The BIOS uses programmed IO ì
  111. on most peripherals with DMA functions of the 64180 processor ì
  112. used for Floppy and RAM disk data movement.è
  113. XBIOS, SB-180. XSystems' XBIOS version 1.1 is an extremely ì
  114. powerful and flexible banked system with excellent tools and ì
  115. interfaces. Malcom Kemp has concentrated on providing functions ì
  116. in this release, and has deferred optimization to future ì
  117. releases. XBIOS fully supports the ETS180 IO+ board, allows ì
  118. complete configuration of peripherals, and provides a larger TPA ì
  119. since only a small kernel resides in the primary memory area. ì
  120. Most of the BIOS code resides in an alternate memory bank. XBIOS ì
  121. installs the largest possible TPA when used which was 57.5k for ì
  122. these tests. XBIOS was installed with three buffers for disk IO.
  123.  
  124. AMPRO, Little Board-1A. A stock version of the Ampro version 3.8 ì
  125. BIOS assembled with no ZCPR support was used for testing. A ì
  126. system size of 59k was chosen to provide support for 5 hard disk ì
  127. partitions spread over two physical drives. NZCOM was then loaded ì
  128. to provide Z-System support. The Ampro BIOS is strictly a polled ì
  129. system and uses no interrupts or DMA.
  130.  
  131.  
  132. EVALUATION  PROCEDURES.
  133.  
  134. Since the goal of evaluating performance was to heavily exercise ì
  135. BDOS functions, a set of fourteen assembly modules, thirteen of ì
  136. which were 2-4k in size, and one of 6k were assembled to produce ì
  137. Microsoft REL files. To restrict external influences, no file ì
  138. date stamping was used, and many ZSDOS features such as Public ì
  139. and Path were disabled. On the other hand, to provide a semi-ì
  140. realistic setting, ZEX.COM and the executable assemblers were ì
  141. placed in a different Drive/User with the ZCPR search path set to ì
  142. locate the files on the second directory scan. SLR's SLR180 ì
  143. assembler was used on system 2, while tests on systems 1 and 3 ì
  144. used Z80ASM+. Assembly was done under the control of a memory-ì
  145. based SUBMIT utility (ZEX Version 3.1A) script file. Times were ì
  146. measured from the carriage return terminating the command ì
  147. invoking the ZEX file to display of the "Done" message after ì
  148. assembly of the last file. After each run, the .REL files ì
  149. produced by the assembly were erased so that the same disk space ì
  150. could be used in the next run. No other files were added or ì
  151. deleted to any media during the timing runs. At least three runs ì
  152. were performed for each configuration, and the results averaged. ì
  153. Timing was manually performed with a stopwatch.
  154.  
  155. Due to the radical differences in access times for different ì
  156. media, three categories of times were considered; RAM disk, Hard ì
  157. Disk, and Floppy disk. If you think you know how each system ì
  158. fared, read on - there may be a twist or two in the plot. 
  159.  
  160. RAM DISK. The Ampro has no RAM disk, so timings in this category ì
  161. reflect only the SB180. The SB180 computer is equipped with 256k ì
  162. of memory. The standard MicroMint BIOS divides this into a 64k ì
  163. main memory area and a 192k RAM disk. With XBIOS as tested here, ì
  164. 64k is allocated for the main memory, 24k for the banked portion ì
  165. of XBIOS, buffers and banked system extensions. The remaining ì
  166. space is available for a RAM disk. RAM disks on the SB180 use ìèbuilt-in DMA capabilities of the HD64180 processor to move ì
  167. "sectors" of data rather than the slower block move instructions ì
  168. used by Z80 systems.
  169.  
  170. Exiting a program via the Warm Boot vector in CP/M relogs the A ì
  171. drive. To minimize time penalties imposed by this, a Hard disk ì
  172. partition was defined as the A drive. Needed programs as well as ì
  173. the assembly modules were placed on the RAM disk (M:), with ì
  174. ZEX.COM and Z80ASM+.COM placed in User 15 and the sources files ì
  175. in User 0. The search path for this phase was: Drive M, User 0 to ì
  176. Drive M, User 15.
  177.  
  178. Since the RAM disk is defined as a non-removable media in the ì
  179. Disk Parameter Block, the "Rapid Relog" feature of ZSDOS and ì
  180. ZRDOS was expected to produce much shorter execution times than ì
  181. CP/M for this series of measurements. As can be seen from the ì
  182. results, this was indeed the case. The raw timings in seconds ì
  183. with percentage changes from the shortest time are:
  184.  
  185.         ZSDOS         ZRDOS 1.9     CP/M 2.2
  186.         +------------------------------------------------+
  187.  BIOS 2.7   | 17.0 (---)    17.1 (+4%)    36.4 (+114%) |
  188.  XBIOS 1.1  | 14.2 (---)    14.5 (+2%)    34.5 (+144%) |
  189.         +------------------------------------------------+
  190.  
  191. The effects of the Rapid Relog feature were borne out, with ZSDOS ì
  192. being a couple of percent faster. Disabling the Rapid Relog ì
  193. feature of ZSDOS produced nearly identical results to CP/M, so ì
  194. most of the additional time for that system may be attributed to ì
  195. rebuilding the disk allocation bit maps for Drives A and M on ì
  196. each warm boot.
  197.  
  198.  
  199. HARD DISK.
  200.  
  201. Three systems, 6.144 MHz SB-180 (System 1), 4.0 MHz Ampro Little ì
  202. Board-1A (System 2), 9.216 MHz Z-180 Homebrew SB-180 (System 3), ì
  203. were used to gather information for this phase. This latter ì
  204. system was added to demonstrate performance on a heavily loaded ì
  205. system.
  206.  
  207.               ZSDOS          ZRDOS 1.9      CP/M 2.2
  208.          +------------------------------------------------+
  209.  1-BIOS 2.7  | 0:54.7 (---)    1:16.6 (+40%)    1:34.7 (+73%) |
  210.  1-XBIOS 1.1 | 0:52.2 (---)    1:15.4 (+44%)    1:33.4 (+79%) |
  211.  2-AMPRO     | 1:55   (---)    2:44   (+43%)    3:15   (+70%) |
  212.  3-BIOS 2.7  | 1:07.7 (---)    1:40.6 (+49%)    1:50.2 (+63%) |
  213.  3-XBIOS 1.1 | 1:29.5 (---)    2:06.4 (+41%)    2:11.3 (+47%) |
  214.          +------------------------------------------------+
  215.  
  216. As in the previous RAM Disk results, the results of ZSDOS with ì
  217. "Rapid Relog" disabled and CP/M were nearly the same confirming ì
  218. that rebuilding the allocation bit maps on a disk relog is the ì
  219. principle cause for the increased CP/M times.
  220. èAll reported times were made with a path which forced a search of ì
  221. the current directory before locating executable files on the ì
  222. second path element. As an experiment, the path on the Ampro ì
  223. system was changed to go directly to A2:, eliminating the current ì
  224. directory scan. All DOSes showed an identical 10 second speedup, ì
  225. indicating directory scan time for all DOSes was the same.
  226.  
  227. A further point to note is the effect of multiple disk buffers on ì
  228. performance. For system 1, the number of buffers was adequate to ì
  229. retain directory information which improved performance over the ì
  230. single-buffer Micromint BIOS by 1-5%. In system 3, the buffering ì
  231. was inadequate to retain necessary information, so the multiple ì
  232. buffers were of no benefit.
  233.  
  234.  
  235. FLOPPY DISK.
  236.  
  237. Examination of system performance on a Floppy Disk system was ì
  238. tailored to duplicate, as closely as possible, a hypothetical ì
  239. operating configuration using multiple drives with non-trivial ì
  240. search path along differing Drives and User area lines.
  241.  
  242. Since all three primary operating systems of interest to this ì
  243. analysis (ZSDOS, CP/M 2.2 and ZRDOS 1.9) rebuild removable-media ì
  244. disk allocation maps on a relog, there was no need to explicitly ì
  245. disable the "Rapid Relog" feature of ZSDOS for this portion of ì
  246. the study. Results are:
  247.  
  248.         ZSDOS         ZRDOS 1.9      CP/M 2.2
  249.           +----------------------------------------------+
  250.  BIOS 2.3     | 2:18.7 (+2%)    2:22.4 (+5%)    2:16.0 (---) |
  251.  XBIOS 1.0    | 2:29.5 (+0.5%)    2:32.7 (+3%)    2:29.0 (---) |
  252.  AMPRO        | 2:26   (+1%)    2:28   (+2%)    2:25   (---) |
  253.           +----------------------------------------------+
  254.  
  255. Since all of the operating systems are functionally identical in a ì
  256. Floppy Disk configuration, we did not expect large differences in ì
  257. measured times. We were therefore not surprised with variations ì
  258. over a spread of only five percent. While we strove to make ZSDOS ì
  259. as efficient as possible, CP/M was still the champ on floppy ì
  260. systems by a nose.
  261.  
  262. As a final comparison test between the three DOSes, the amount of ì
  263. time WordStar 4 took to ^QC and ^QR through the 92k ZSDOS source ì
  264. file was measured under all three DOSes. All timings were within ì
  265. 1%, indicating that read/write to open file times were similar.
  266.  
  267.  
  268. PERFORMANCE CONCLUSIONS.
  269.  
  270. ZSDOS offers significant improvements in system performance on ì
  271. CP/M 2.2 compatible Z80-compatible computer systems with fixed ì
  272. media even under the restricted test conditions which disabled ì
  273. some of the most powerful features of ZSDOS. Even more impressive ì
  274. results may be obtained in a "tuned" installation with such ìèfeatures as Public files, and proper selection of the DOS search ì
  275. path (improvements of 9% on a hard disk system are typical).
  276.  
  277. The other major conclusion that can be drawn from this effort is ì
  278. that the selection of a BIOS tailored to the requirements is ì
  279. crucial to achieving optimum performance. The multiple buffering ì
  280. capability of XBIOS offers speed increases in systems where an ì
  281. adequate number of buffers exists, but degrades floppy-based and ì
  282. heavily loaded hard disk performance.
  283.  
  284. During the data gathering for this report, an anomaly was noted ì
  285. with respect to CP/M Plus (or P2DOS) stamps. System #1 was ì
  286. initialized for P2DOS stamps on the disk holding data files to ì
  287. quantify the differences. In all cases ZSDOS was affected less ì
  288. than one percent, yet ZRDOS increased to seven percent longer ì
  289. than ZSDOS on RAM disk, 20% longer on floppy and 144% longer on ì
  290. hard disk. CP/M 2.2 was similarly affected, but to a lesser ì
  291. degree, increasing times over ZSDOS to 115% on RAM disk, ten ì
  292. percent on floppy and 140% on hard disk. While neither ZRDOS nor ì
  293. CP/M 2.2 can manipulate this type of stamp, merely using a disk ì
  294. which is so prepared will result in slower processing.
  295.  
  296.  
  297. HOW WE DID IT.
  298.  
  299. During the year or so that we pursued our independent paths in ì
  300. modifying H.A.J. Ten Brugge's excellent P2DOS alternative to CP/M ì
  301. 2.2's BDOS, our approaches were somewhat diverse. While Cam's ì
  302. approach was directed at perfecting features, Hal's effort was ì
  303. directed at streamlining the code to create a "speed demon" ì
  304. operating system, and Carson concentrated on enhancing embedded ì
  305. Date Stamping. In mid-1987, Bridger Mitchell was instrumental in ì
  306. getting us to pool our resources and collaborate in a joint ì
  307. venture. The results have been more than worth it. In Part I, we ì
  308. described the functional enhancements and standards embodied in ì
  309. ZSDOS, and have just shown the performance improvements compared ì
  310. to CP/M 2.2 and ZRDOS 1.9. In our efforts to foster better code ì
  311. for our 8-bit systems, we would now like to describe how the task ì
  312. of adding features and decreasing execution time was accomplished ì
  313. without increasing the Operating System memory requirements.
  314.  
  315. The topic of code optimization is a controversial one. In the ì
  316. early days of computers, programmers were saddled with small ì
  317. memory space and slow processors, so every effort was made to ì
  318. optimize programs for speed and size. As memory became cheaper ì
  319. and processors emerged with ever increasing clock speeds, ì
  320. programming techniques became lost to all but a few. This same ì
  321. path of evolution has also been followed in the Personal Computer ì
  322. field.
  323.  
  324. To demonstrate this point, first compare the 3.5 kbyte CP/M 2.2 ì
  325. BDOS and the 1 kbyte Plu*Perfect DateStamper to the functionally ì
  326. superior 3.5k ZDDOS. Next, compare the 3.5 kbyte size of CP/M 2.2 ì
  327. and ZSDOS to the 16 kbyte size of the functionally similar MS-DOS ì
  328. 2.1. To carry the point further, contrast the almost 16 kbyte ìèCOMMAND.COM to the 7 kbyte size of a more capable ZCPR3 Command ì
  329. Processor with a full environment. Some of this bloat is ì
  330. understandable with the change in processor chips. On the other ì
  331. hand, the more powerful instructions of 16-bit 808x processors ì
  332. should have counteracted a good portion of this code bloat.
  333.  
  334. In line with the size comparisons, execution speeds also suffer ì
  335. with the larger code. Friends and co-workers who are used to ì
  336. working with PCs and clones operating at 4.77 and 8 MHz clock ì
  337. rates are constantly amazed at the speed of even a lowly 4 MHz ì
  338. ZSDOS system, and dazzled at the 6 and 9 MHz Hitachi 64180 ì
  339. systems running the same software! While much of this is ì
  340. subjective, quite a bit is due to the fact that the "smaller" 8-ì
  341. bit code has been hand-coded and optimized, whereas the PC arena ì
  342. is devoting more of its energy to coding in high-level languages. ì
  343. This makes sense under certain circumstances (e.g. during ì
  344. development and for long-term maintainability), but it most ì
  345. certainly does NOT make sense for operating systems where size ì
  346. and speed are of the essence.
  347.  
  348. Since all of our efforts have been directed at the Zilog Z80 and ì
  349. compatible family of microprocessors (including Hitachi's 64180 ì
  350. and National's NSC800), the optimization steps covered here apply ì
  351. directly only to these. Having stated that, we also need to point ì
  352. out that many of the basic concepts will still apply to other ì
  353. processors, although details may differ.
  354.  
  355. No matter what processor is used, the goals of faster program ì
  356. execution and smaller memory size are in conflict. Smaller memory ì
  357. size normally means using each section of code as many times as ì
  358. possible - typically by using many subroutines. Faster code ì
  359. execution often means avoiding as many subroutine calls as ì
  360. possible. In every program undergoing optimization, the ì
  361. conflicting size and speed requirements must be balanced. This ì
  362. balance can be highly subjective. In ZSDOS, code size was the ì
  363. primary concern though significant effort was given to making the ì
  364. smaller code run as fast as possible. 
  365.  
  366. Now for the minutiae. If you are not a programmer, or are ì
  367. interested only in how to use ZSDOS, you might want to skip to ì
  368. PROGRAMMING FOR ZSDOS. For the diehards - here it is!
  369.  
  370. One of the first techniques we used in optimizing code was to ì
  371. examine all JUMP instructions. The basic instruction is three ì
  372. bytes long and executes in 10 clock cycles on a Z80. These ì
  373. absolute jumps may be unconditional (JP addr), or conditional (JP ì
  374. C,addr) based on the contents of the Carry, Zero or ì
  375. Parity/Overflow flags. The Z80 also features a two-byte Relative ì
  376. jump (JR) which also may be absolute (JR addr), or conditional ì
  377. (JR C,addr) based on the Carry or Zero flags. The relative jump ì
  378. is only two bytes long and may branch only to addresses within ì
  379. the range of +127 to -128 bytes of the jump instruction. While it ì
  380. is relatively easy to blindly change all jump instructions within ì
  381. range to Relative jumps, the careful programmer will also note ì
  382. that the Relative jump may carry a time penalty. The absolute ìèrelative jump, and conditional jumps where the condition is ì
  383. satisfied (the jump is taken) require 12 clock cycles compared to ì
  384. the long jump consuming only 10 cycles regardless of condition. ì
  385. On the other hand, conditional relative jumps need only 7 cycles ì
  386. if the condition is false. This type of optimization was one of ì
  387. the first used in our efforts to enhance P2DOS.
  388.  
  389. The next simple optimizing technique we used was to make maximum ì
  390. use of the Decrement-B and Jump Relative if Not Zero (DJNZ) ì
  391. instruction. This two-byte sequence executes in 8 or 13 clock ì
  392. cycles (B=0 and B<>0 respectively) for an absolute time and code ì
  393. saving over separate decrement/jump sequences. In some of our ì
  394. work on ZSDOS, using this instruction required redefining ì
  395. register usage to free up the B register for use as a counter.
  396.  
  397. Another simple optimizing step was examining the use of the IX ì
  398. register. IX holds the argument passed to DOS in the DE register ì
  399. (typically a file control block pointer). Despite having this ì
  400. value available all the time, there were a significant number of ì
  401. cases when faster and/or shorter code was produced by moving the ì
  402. pointer into HL. This was normally the case when the same offset ì
  403. within the FCB was accessed two or more times in succession.
  404.  
  405. The final "simple" optimization technique we used was to examine ì
  406. all PUSHes and POPs to the stack and delete any found to be ì
  407. unnecessary. While this sounds simple, it is quite a chore in a ì
  408. complex program such as ZSDOS where CALLs call other CALLs which ì
  409. call still other CALLs, etc. Each path must be examined to insure ì
  410. that the registers are, in fact, not altered or needed.
  411.  
  412. After the above "simple" optimizations were performed, A series ì
  413. of what we term "moderate" optimization steps were undertaken. ì
  414. One of these involved examining all series of sequential checks ì
  415. on a byte (such as the input command character scanner) and ì
  416. structure the check sequences to optimize performance based on ì
  417. clock cycle counting mentioned above, and estimated frequency of ì
  418. access for various commands. In the case of the command ì
  419. dispatcher, this technique resulted in extremely fast command ì
  420. parsing implemented with minimum code.
  421.  
  422. Sequential bit shifts and rotates are another area where more ì
  423. analysis is required before final code can be written. Sixteen-ì
  424. bit shifts, and 8-bit shifts in registers other than the ì
  425. accumulator are areas where gains can be achieved. The usual ì
  426. method of using a subroutine which loads all bytes to the ì
  427. accumulator for shifts and rotates fares poorly if only one or ì
  428. two bit shifts are needed. While most of these cases had been ì
  429. removed from the P2DOS code by the original author, the ì
  430. replacement inline code still suffered from some inefficiencies. ì
  431. A two-bit shift right (division by 4) of the 16-bit HL register ì
  432. pair in the STDIR routine using the code:
  433.  
  434.     SRL    H    ; Divide by 2
  435.     RR    L
  436.     SRL    H    ; Divide by 4è    RR    L
  437.  
  438. proved optimum. Using a two-iteration loop with the DJNZ ì
  439. instruction around a single SRL H, RR L sequence would have ì
  440. produced the same 8-byte code length, but at a penalty of 21 ì
  441. clock cycles. A call to a subroutine would have fared even worse ì
  442. with a 27 clock cycle CALL/RET penalty, and four bytes of ì
  443. overhead. On the other hand, three-bit shifts of the HL ì
  444. register pair occurred in a number of routines. These were ì
  445. consolidated into a single callable routine that uses the B ì
  446. register as a counter in an iterative loop with the sequence:
  447.  
  448. SHRHL3:    LD    B,3
  449. SHRHLB:    SRL    H
  450.     RR    L
  451.     DJNZ    SHRHLB
  452.     RET
  453.  
  454. While the replacement code added overhead, it saved 3-5 bytes  of ì
  455. code  (depending on entry point) which were sorely needed to  add ì
  456. additional features. ZSDOS calls this routine from three places, ì
  457. while  ZDDOS calls it from five. The difference is due to  ZSDOS ì
  458. "unrolling" the loop in time critical routines.
  459.  
  460. Shifts to the left were occasionally handled a little more ì
  461. efficiently by using the 16-bit ADD instructions of the HL ì
  462. register pair to perform bit shifts. An example of this appeared ì
  463. in the CALST routine. In this case, the DE register pair was ì
  464. rotated one bit to the left with sequential RL E, RL D ì
  465. instructions, with the Carry bit shifted into the HL register ì
  466. pair. Where the original code used the sequence: RL L, RL H to ì
  467. shift the bit into the HL pair, a two byte code savings was ì
  468. achieved with the single two-byte ADC HL,HL instruction.
  469.  
  470. Another area where considerable code and time savings were ì
  471. realized was in the consolidation of routines into "straight-ì
  472. line" code. While this seems to be an anathema to structured ì
  473. programmers, it is often a must to obtain the performance ì
  474. improvements which we sought from our efforts. As a first step, ì
  475. all routines ending in Jump instructions were examined. Target ì
  476. addresses were then checked to insure that no other routine "fell ì
  477. through" to them. If it was in fact a "stand-alone" routine, it ì
  478. was moved to the end of the first routine so that the Jump could ì
  479. be deleted. An example of this is where the INITDR routine was ì
  480. moved to follow SELDK directly saving the two-byte relative jump ì
  481. and 12 clock cycles. Other cases involving long jumps saved three ì
  482. bytes and 10 clock cycles. A minor variation in relocation of ì
  483. code is to group functions to bring them within range of relative ì
  484. jumps thereby saving one byte at the expense of two clock cycles. ì
  485. This minor penalty in time often outweighed the value of a single ì
  486. byte of code in our efforts.
  487.  
  488. A variant on this concept involved examining sequences of code ì
  489. for duplicity, and combining identical sequences into new ì
  490. routines which "fall through" to the destination. This was amply ìèused to define a new routine:
  491.  
  492. SRCT15:    LD    A,15
  493.     CALL    SEARCH
  494.  
  495. This sequence was placed immediately before the TSTFCT routine, ì
  496. and replaced three occurrences of:
  497.  
  498.     LD    A,15
  499.     CALL    SEARCH
  500.     CALL    TSTFCT
  501.  
  502. with a single CALL to SRCT15. The overall effect of this one ì
  503. change was a savings of 10 bytes of code and 24 clock cycles for ì
  504. each of the three sequences replaced.
  505.  
  506. Detailed examination of code also produced unexpected savings by ì
  507. merely defining new labels. As an example, the last three ì
  508. instructions of the routine OPENEX were:
  509.  
  510.     LD    A,0FFH
  511.     LD    (PEXIT),A
  512.     RET
  513.  
  514. This sequence occurred two other times in the original code, and ì
  515. three times in the latest version of ZSDOS. The last two ì
  516. instructions were repeated in many locations, so one location was ì
  517. selected (centrally located to take advantage of relative jumps), ì
  518. with other instances accessing it with a call or jump to the new ì
  519. label, SAVEA. Setting the value to 0FFH in OPENEX was labeled as ì
  520. SETCFF, and the other two occurrences jumping to this location. ì
  521. While a small time penalty was incurred in jumping to this common ì
  522. code, the three byte savings was again needed to add features.
  523.  
  524. Our code "walk-throughs" and optimization efforts did not stop ì
  525. with the original code, but continued with every test version. ì
  526. First, we discovered a common "shell" of instructions around the ì
  527. DELETE, CSTAT, and RENAME functions and combined them with a net ì
  528. savings of 12 bytes. Later, a trick used in public-domain inline ì
  529. print routines to pass addresses on the processor's stack was ì
  530. used to recover five bytes of code by replacing three sequences ì
  531. of:
  532.  
  533.     LD    HL,(address)
  534.     JR    COMCOD
  535.  
  536. with three 3-byte CALL COMCOD instructions. The trick involved in ì
  537. this change was to place the CALLs immediately in front of the ì
  538. routines whose addresses were to be passed to COMCOD. When ì
  539. executed, the CALL placed the routine address on the stack. A ì
  540. one-byte POP HL instruction at the beginning of COMCOD completed ì
  541. the change by placing the address in the desired HL register. ì
  542. Still later, the internal code in the COMCOD routine was again ì
  543. optimized to remove several memory references. This saved another ì
  544. four bytes.è
  545. Cameron's rewrite of the Console IO routines demonstrated another ì
  546. technique of reducing code size with very little overhead. The ì
  547. majority of affected code involved different DOS commands, yet ì
  548. exited through common code with absolute jumps. By PUSHing the ì
  549. exit address on the stack prior to jumping to the routines, a ì
  550. simple RETurn instruction sufficed to direct execution through ì
  551. the exit code saving two bytes per occurrence. The four bytes ì
  552. required to set the return address meant that the code size ì
  553. break-even point occurred at two instances. Since far more cases ì
  554. than that were involved, a significant code size reduction was ì
  555. realized. For DOS function calls, the time penalty incurred was ì
  556. 21 clock cycles, however, that was not considered significant ì
  557. when dealing with the normal serial IO devices used in console ì
  558. functions.
  559.  
  560. A final noteworthy trick was added by Cameron which neither of us ì
  561. had ever seen documented in the Z80 world. It used the sixteen-ì
  562. bit load instruction into the IX register (a four byte ì
  563. instruction) to "fall through" successive 16-bit loads to the ì
  564. primary registers. In this fashion, the sequence:
  565.  
  566. CMND27:    LD    HL,(ALV)
  567.     JR    SAVHL
  568.  
  569. CMND24:    LD    HL,(LOGIN)
  570.     JR    SAVHL
  571.  
  572. CMND31:    LD    HL,(IXP)
  573.     JR    SAVHL
  574.  
  575. CMND47:    LD    HL,(DMA)
  576. SAVHL:    LD    (PEXIT),HL
  577.     RET
  578.  
  579. was replaced by a more efficient (in code size) construct. The ì
  580. bytes, as coded, are on the left, with the instructions seen by ì
  581. CMND27 shown on the right:
  582.  
  583. CMND27:    LD    HL,(ALV)    CMND27: LD    HL,(ALV)
  584.     DEFB    0DDH            LD    IX,(LOGIN)
  585. CMND24:    LD    HL,(LOGIN)
  586.     DEFB    0DDH            LD    IX,(IXP)
  587. CMND31:    LD    HL,(IXP)
  588.     DEFB    0DDH            LD    IX,(DMA)
  589. CMND47:    LD    HL,(DMA)
  590. SAVHL:    LD    (PEXIT),HL        LD    (PEXIT),HL
  591.     RET                RET
  592.  
  593. This code works because the IX register is not used in the ì
  594. remainder of the exit code, and the entry IX value is restored ì
  595. upon returns from ZSDOS functions. Each cascaded value saves one ì
  596. byte of code, but adds additional clock cycles to the execution ì
  597. time. Where the original code required a constant 28 clock cycles ì
  598. before arriving at the SAVHL routine, the new code execution time ìèis different for each entry point. In this example, the time (in ì
  599. clock cycles) required for each entry point to arrive at SAVHL ì
  600. is:
  601.  
  602.     CMND47    - 16 cycles
  603.     CMND31    - 20 + 16 = 36
  604.     CMND24    - 20 + 20 + 16 = 56
  605.     CMND27    - 20 + 20 + 20 + 16 = 76
  606.  
  607. At this point, an analysis of probable calling frequency was done ì
  608. to order the calls so that the most frequently used functions ì
  609. would incur the least penalty. The ordering shown here was judged ì
  610. to be the optimum sequence.
  611.  
  612. In a similar manner, eight-bit loads of the A register were ì
  613. consolidated at the beginning of the SEARCH routine. Our analyses ì
  614. of the code showed that SEARCH was called several times with ì
  615. values of 12 and 15 in the A register. Loading of these values ì
  616. was relocated to the beginning of SEARCH, then consolidated with ì
  617. another single-byte DEFB prefix. The resultant code as entered, ì
  618. and as seen by SEAR12 is:
  619.  
  620. SEAR12:    LD    A,12        SEAR12:    LD    A,12
  621.     DEFB    21H            LD    HL,0F3EH
  622. SEAR15:    LD    A,15
  623. SEARCH:    ...            SEARCH:    ...
  624.  
  625. Instead of posing a time penalty as the LD IX,nn trick described ì
  626. above, this case saved one byte over a relative jump and two ì
  627. clock cycles (JR = 12 cycles, LD HL,nn = 10 cycles). As above, ì
  628. this worked because the HL register contents were "don't care" ì
  629. upon entry to the SEARCH routine.
  630.  
  631. These techniques are very powerful when code size is at a ì
  632. premium. Any sequence of code that loads a register or register ì
  633. pair then jumps or calls a common routine is a candidate for this ì
  634. technique. You need a register pair to throw away, but this is ì
  635. usually easy to find. 
  636.  
  637. The final case of optimization is the most difficult, and ì
  638. involved complete logic redesigns. This area is so specific and ì
  639. lengthy that it will not be covered here. As so often stated in ì
  640. textbooks, it is "left as an exercise for the reader" to examine ì
  641. the original P2DOS source and identify areas which can be ì
  642. redesigned. Much logic redesign was required as a part of the ì
  643. added ZSDOS and ZDDOS features, though the effort didn't stop ì
  644. there.
  645.  
  646. Just as important as what we did to gain speed and reduce size is ì
  647. what we didn't do. P2DOS originally used some self modifying code ì
  648. in the error printing routine. We decided from the outset that we ì
  649. would avoid this practice (tempting though it is..) in order to ì
  650. produce code that could be ROMed and/or run on the Z280 in ì
  651. protected mode. This decision cost us several bytes of code, but ì
  652. allowed us to accomplish our goals.è
  653. PROGRAMMING FOR ZSDOS.
  654.  
  655. ZSDOS places a few restrictions on systems which do not exist in ì
  656. other CP/M compatible operating systems. The most significant is ì
  657. that the BIOS MUST NOT DISTURB THE IX REGISTER. So far, the Epson ì
  658. QX-10 and Zorba computers have been identified as having BIOSes ì
  659. that corrupt this register. With NZCOM, we have developed a ì
  660. "protective" NZBIOS (look for ZSNZBI12.LBR on most Z-Nodes) that ì
  661. shields the Z80 registers from ill-behaved BIOSes, but operation ì
  662. without NZCOM on such systems will require that the BIOS be re-ì
  663. written.
  664.  
  665. On this topic, we would like to propose that all programmers ì
  666. observe register usage more closely. The Z80 alternate and index ì
  667. registers belong to APPLICATION programs, and must be preserved ì
  668. by all operating system components. On the other hand, the "I" ì
  669. and "R" registers, as well as all new 64180 and Z280 registers ì
  670. (with the exception of the Z280's SSP) belong to the BIOS since ì
  671. they are hardware specific and directly I/O related. The Z280 SSP ì
  672. should be reserved for BDOS use.
  673.  
  674. Before trying to access any of the expanded ZSDOS features ì
  675. discussed in the last issue, you should first insure that the ì
  676. program is in fact executing under ZSDOS. This is a two-step ì
  677. procedure involving a call to check for CP/M 2.2, then a call to ì
  678. the ZSDOS Return Version function. By checking in this manner, ì
  679. your program will be able to identify CP/M 1, 2 and 3 (aka Plus) ì
  680. as well as ZSDOS, ZDDOS and ZRDOS. Code to accomplish this task ì
  681. is:
  682.     LD    C,12        ; Return CP/M Version
  683.     CALL    0005        ; ..via BDOS
  684.     CP    30H        ; Is it CP/M Plus?
  685.     JR    NC,ISCPM3    ; ..jump if so
  686.     CP    20H        ; Is it CP/M 1.x?
  687.     JR    C,ISCPM1    ; ..jump if so w/version # in A
  688.     CP    22H        ; Is it CP/M 2.2?
  689.     JR    NZ,BADVER    ; ..jump to unknown 2.x version
  690.     LD    C,48        ; Now make the extended call
  691.     CALL    0005        ; ..via BDOS
  692.     LD    A,H        ; Check the DOS type first
  693.     CP    'D'        ; Is it ZDDOS?
  694.     JR    Z,ISZD        ; ..jump if so, Ver # in L
  695.     CP    'S'        ; Is it ZSDOS?
  696.     JR    Z,ISZS        ; ..jump if so, Ver # in L
  697.     OR    A        ; Is it ZRDOS?
  698.     JR    Z,ISZR        ; ..jump if so, Ver # in L
  699.     ...            ; Else can't identify, do error
  700.  
  701. Bridger Mitchell's Advanced CP/M column in TCJ #36 also provides ì
  702. sample code to perform this function. A slight variation on the ì
  703. above sequence is used in utilities provided with ZSDOS to enable ì
  704. them to work under a variety of different operating systems. We ì
  705. propose that this technique be used for any future Disk Operating ì
  706. systems by returning a different unique character in the "H" ìèregister.
  707.  
  708. Many programs in the past have relied on unpublished locations ì
  709. within the BDOS to alter the performance or functionality of the ì
  710. system. With ZSDOS, we provide published "standard" ways to ì
  711. dynamically tailor DOS parameters. The most important way of ì
  712. accomplishing this is with a set of configuration bits, or flags. ì
  713. To accommodate future expansion, a word value of sixteen bits is ì
  714. defined with only the lower seven used in the current 1.0 ì
  715. release. The Flag bits used in ZSDOS 1.0 are:
  716.  
  717.     D D D D D D D D
  718.     7 6 5 4 3 2 1 0
  719.      \ \ \ \ \ \ \ \_Public File Access
  720.       \ \ \ \ \ \ \__Public/Path Write
  721.        \ \ \ \ \ \___Read-Only Disk
  722.         \ \ \ \ \____Fast Fixed Disk Relog
  723.          \ \ \ \_____Disk Change Warning
  724.           \ \ \______BDOS Search Path    *
  725.            \ \_______Path w/o SYS Attribute    *
  726.             \________(Reserved)
  727.  
  728. The cited function is activated by setting the respective bit to ì
  729. a "1", and disabled by clearing the bit to a "0". Since ZDDOS has ì
  730. no search path capability, the features marked with an asterisk ì
  731. pertain only to the full ZSDOS configuration, and are "don't ì
  732. care" bits in ZDDOS. The bits will be returned as the lower byte ì
  733. in the 16-bit word field in the "L" register. Code for returning ì
  734. them is:
  735.  
  736.     LD    C,100        ; Get the FLAGS bits
  737.     CALL    0005        ; ..with DOS call
  738.     ...            ; "L" has present 7 bits
  739.  
  740. Likewise, the flags may be set from applications programs with ì
  741. Function 101 as:
  742.  
  743.     LD    DE,(FLAGS)    ; 1.0 only recognizes byte in E
  744.     LD    C,101        ; Now set flags in ZSDOS
  745.     CALL    0005        ; ..with DOS call
  746.     ...            ; New settings are now effective
  747.  
  748. Date and Time capabilities are just as easily accessed. The 6-ì
  749. byte Clock data may be retrieved to a specified buffer with DOS ì
  750. Function 98 as:
  751.  
  752.     LD    DE,TIMEAD    ; Address of 6-byte buffer
  753.     LD    C,98
  754.     CALL    0005        ; Read Clock from DOS
  755.     INC    A        ; Any Errors? (FF --> 0)
  756.     JR    Z,ERROR        ; ..jump if error (no clock?)
  757.     ...            ; Else use the retrieved time
  758. TIMEAD:    DEFB    0,0,0,0,0,0    ; Initialized Null DateSpec
  759.  
  760. With the File Date Stamping capabilities of ZSDOS, we developed a ìèsingle standardized way of accessing individual file stamps. ì
  761. Function 102 will copy the set of stamps for a specified file to ì
  762. the current DMA address, while 103 will set the stamps for the ì
  763. specified file to the values at the current DMA address. Since ì
  764. all supported stamping methods (currently DateStamper(tm) and the ì
  765. CP/M Plus compatible P2DOS) feature the same format at the ZSDOS ì
  766. level, no user conversions are needed. Indeed, using special ì
  767. stamp drivers provided with the ZSDOS package, either stamp type ì
  768. may be read with both being written by Function 103 if the ì
  769. destination disk has been so prepared. A sample of code used to ì
  770. copy stamp data from one file to another is:
  771.  
  772.     LD    DE,DSBUF    ; Point to 15-byte stamp buffer
  773.     LD    C,26        ; ..and set the DMA address
  774.     CALL    0005
  775.     LD    DE,SRCFCB    ; Source FCB (User set already)
  776.     LD    C,102        ; Get the source's Stamps
  777.     CALL    0005
  778.     ...            ; Set User to destination?
  779.     LD    DE,DSTFCB    ; Destination FCB
  780.     LD    C,103        ; Write Stamps from DMA buffer
  781.     CALL    0005        ; ..to Dest file
  782.     ...
  783.  
  784.  
  785. FINAL THOUGHTS.
  786.  
  787. ZSDOS was a labor of love. Though we didn't really start out to ì
  788. create such a significant step forward in 2.2 compatible BDOSes, ì
  789. it turned out that way. It is our hope that the ideas presented ì
  790. in ZSDOS will form the basis for the next generation of BDOS ì
  791. replacements. If nothing else, we hope that ZSDOS stimulates the ì
  792. Z80 compatible community to address the issues of standards for ì
  793. datestamping, enhanced error handling, and global file access.
  794.  
  795. The next step for an improved operating system will be to break ì
  796. the 64k barrier. Joe Wright and Jay Sage's efforts in dynamic ì
  797. system configuration with NZCOM are very useful, but fail to ì
  798. address the fundamental problem - we need to use the banked ì
  799. memory featured in most newer systems. Furthermore, this must be ì
  800. done in a way that allows existing applications to run properly. ì
  801. This means (unlike CP/M Plus) a BDOS that lets BIOS deblock, a ì
  802. BIOS jump table that is directly callable from all banks, system ì
  803. vectors at the normal locations, etc. This also means ì
  804. establishing standards for bank sizes and addresses, hardware and ì
  805. processor independence, and finally universal DOS level and BIOS ì
  806. level interfaces to banked memory. Other standards that will be ì
  807. needed by the next generation of OS's include banked RSX ì
  808. standards (though Bridger Mitchell and Malcom Kemp seem to have ì
  809. this nailed down), banked device driver standards, and expanded ì
  810. TCAPS and ENV definitions (aren't these properly BIOS structures ì
  811. folks?). Now is the time to come together, speak up on these ì
  812. matters, carefully weigh all alternatives, and make our wishes ì
  813. known.
  814. èAlso, we urge the community to support those doing active ì
  815. development for our systems by purchasing legal copies of the ì
  816. software you use. This will allow and encourage development of ì
  817. things like a new, better, and faster banked systems with all the ì
  818. goodies we really want. We applaud the efforts of MicroPro in ì
  819. developing and releasing WordStar 4 for CP/M systems, and ì
  820. encourage other vendors to update their CP/M offerings in the ì
  821. fields of Database Management systems and Spreadsheets for the ì
  822. new generation of systems. Further, let's agree to agree on what ì
  823. we really want. In this manner, we can all concentrate our ì
  824. efforts on applications programs, not rewriting BDOS. In short, ì
  825. let's work together to create a computing environment that will ì
  826. turn the big blue clones green with envy.
  827.  
  828. In conclusion, what started as independent "labors of love" to ì
  829. produce a better operating system rapidly became identical ì
  830. obsessions as we reverted to counting clock cycles and bytes. We ì
  831. are satisfied with the results, and hope that others will benefit ì
  832. from our work and produce smaller, faster and more full-featured ì
  833. programs to help make our lives easier (and keep from emptying ì
  834. our wallets with requirements for constant upgrades). Finally, we ì
  835. must thank H.A.J. Ten Brugge for beginning this entire episode by ì
  836. releasing P2DOS. Without his efforts, none of us (Cam, Hal and ì
  837. Carson) would have been tempted into the area of operating system ì
  838. authorship, and would have left it to "others" to determine what ì
  839. we need in our respective systems.
  840.  
  841. APPENDIX: The hardware used in these analyses is:
  842.  
  843. System #1: MicroMint SB-180.
  844.  
  845.  Processor:    HD64180 operating at 6.144 MHz clock rate with
  846.         No memory wait states and 2 IO wait states.
  847.  Console:    Serial Console connected to ACSI port 1 at 19.2
  848.         kbps, Interrupt-driven buffered keyboard input.
  849.  Interfaces:    ETS180 IO+ providing SCSI interface and RTC.
  850.  CCP:        ZCPR 3.3 with full environment.
  851.  BIOS:        MicroMint 2.7 modified / XSystems XBIOS 1.1.
  852.  Search Path:    $$:, A15: (Current Drive & User, then A15:)
  853.  Hard Disk:    Syquest SQ-306R 5 Megabyte removeable-media,
  854.         Interleave of 3, 12 microsecond buffered seek,
  855.         Adaptec 4010 controller.
  856.         A: 1576k of 2552k free, 94 files, 68 in User 15.
  857.         B: 2432k of 2568k Free, 17 files, 16 in User 1.
  858.  Floppy Disks:    A: NEC 80-track DSDD, 4 mS step, 4 mS Head Load,
  859.         16k of 782k free, 93 files, 68 in User 15.
  860.         C: Shugart SA465 80-track DSDD, 6mS step, 736k of
  861.         782k Free, 17 files in User 1.
  862.  
  863. System #2: Ampro Little Board 1A.
  864.  
  865.  Processor:    Z80A operating at 4.0 MHz.
  866.  Console:    Serial Console connected to DART port 1 at 9600
  867.         baud, hardware handshake enabled.
  868.  Interfaces:    SCSI daughter board with NCR 5830 driving 1610-4ìè        controller.
  869.  CCP:        ZCPR 3.4 with full environment.
  870.  BIOS:        Ampro V3.8/NZCOM.
  871.  Search Path:    $$:, A2:, A0: (Current Drive & User, then A2, A0:)
  872.  Hard Disks:    Seagate ST-225 20 Megabyte, interleave of 2,
  873.         200 microsecond buffered seek, Shugart 1610-4
  874.         controller. A Shugart 5Mb full height drive was
  875.         also connected to the controller, but was not
  876.         used in the test.
  877.         A: 2744k of 8160k free, 425 files, 77 in User 2.
  878.         C: 984k of 4192k free, 258 files, 32 in User 3.
  879.  Floppy Drives:    A: Teac 55F 80 track DSDD, 6 mS step, 10k of
  880.         782k free, 74 files.
  881.         B: Teac 55F 80 track DSDD, 6 mS step, 736k of
  882.         782k free, 17 files in User 0.
  883.  
  884. System #3: Homebrew SB-180 compatible.
  885.  
  886.  Processor:    Z-180 operating at 9.216 MHz clock rate with
  887.         No memory wait states and 3 IO wait states.
  888.  Console:    Serial Console connected to ACSI port 1 at 19.2
  889.         kbps, Interrupt-driven buffered keyboard input.
  890.  Interfaces:    ETS180 IO+ providing SCSI interface and RTC.
  891.  CCP:        ZCPR 3.0 with full environment.
  892.  BIOS:        MicroMint 2.7 modified / XSystems XBIOS 1.1.
  893.  Search Path:    A15: (ZCPR 3.0 searches current, then A15:)
  894.  Hard Disk:    Shugart SA-712 10 Megabyte, Interleave of 1,
  895.         12 microsecond buffered seek, Shugart 1610-3
  896.         controller.
  897.         A: 324k of 2552k free, 179 files, 101 in User 15.
  898.         D: 252k of 2792k Free, 438 files, 16 in User 5.
  899.