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 / TCJ34.WS < prev    next >
Text File  |  2000-06-30  |  25KB  |  509 lines

  1.                                Z-System Corne≥ (c)
  2.                                  by Jay Sage
  3.                         The Computer Journal, Issue 34
  4.                           Reproduced with permission
  5.                            of author and publisher
  6.  
  7. For this issue I am going to live up to a long-standing tradition: onceì
  8. again I am not going to cover the material that I said I was.  Last time Iì
  9. presented half the new material on ARUNZ and said I would cover the secondì
  10. half this time.  Well, I am not going to.  ARUNZ is now up to version 'N'ì
  11. (it was 'J' last time).  Until it settles down a bit, it is probably futileì
  12. to try to describe it.  Besides that, I am getting a little bored with theì
  13. subject (though obviously not with the program), and perhaps you are, too.
  14.  
  15. Though living up to tradition, I am going to reverse a trend.  For some timeì
  16. now my columns have been getting longer and longer.  This time I really amì
  17. going to write a short one.  Besides the fact that because of me Art Carlsonì
  18. is apparently running low on printer's ink, I am just about written out,ì
  19. having just completed the manuals for NZ-COM and Z3PLUS.
  20.  
  21.  
  22.                              NZ-COM and Z3PLUS
  23.  
  24. Those manuals started out being simple affairs, but I just don't seem to beì
  25. able to get my obsession with thoroughness and completeness under control,ì
  26. and they soon turned into full-fledged books about the respective productì
  27. and Z-System in general.  I've been burning the midnight (actually, 2 am)ì
  28. oil for the past two or three months.  Each manual now runs about 80 pages! ì
  29. No wonder I don't have many words left in my system at this point.
  30.  
  31. Though somewhat reluctant to indulge in self-praise, I have to say that theì
  32. manuals are really quite good, and the products (NZ-COM and Z3PLUS) areì
  33. absolutely fantastic.  Joe Wright (NZ-COM), Bridger Mitchell (Z3PLUS), and Iì
  34. have had a very enjoyable and highly productive partnership in this effort. ì
  35. I sincerely urge you all to buy the automatic, universal, dynamic Z-Systemì
  36. appropriate for your computer: NZ-COM for CP/M-2.2 computers and Z3PLUS forì
  37. CP/M-Plus computers.  Both are $69.95 from Sage Microsystems East,ì
  38. Plu*Perfect Systems, or Alpha Systems (see ads in TCJ).
  39.  
  40. After the experience bringing these products to market, I will no longerì
  41. laugh so heartily when I hear stories about Borland or Lotus or Ashton-Tateì
  42. not delivering their products on the promised dates.  Hopefully you haveì
  43. lost your TCJ issue #32 and have forgotten that I wrote there, and I quote:ì
  44. "By the time you read this, they will definitely be available."  In issueì
  45. #33 I said, "the two new dynamic Z-Systems that will have been released byì
  46. the time you read this."  That almost made a double liar out of me. ì
  47. Luckily, issue #33 was delivered just enough behind schedule to let thatì
  48. statement squeak through -- barely.
  49.  
  50. With respect to NZ-COM, Joe Wright and I have agreed to publicly blame eachì
  51. other for the delay.  Actually, following common practice, we originallyì
  52. both agreed to blame Bridger Mitchell, though he, of course, had nothing toìèdo with the NZ-COM delay (Z3PLUS is another story).  However, now thatì
  53. Bridger has a TCJ column, too, we worried that such a slander might not goì
  54. unanswered.  Anyway, Joe can blame me for not getting the manual done onì
  55. time, and I can blame Joe for not writing the code to conform to myì
  56. description of it in the manual!  You can readily see that no one shouldì
  57. ever get involved in a product development all by himself.  Always make sureì
  58. there is someone else to blame.
  59.  
  60. The truth of the matter is that we really thought the coding was complete byì
  61. early April and that a simple manual could be knocked off in a weekì
  62. (naive!!).  In fact, as I alluded to above, the scope of the manual keptì
  63. expanding.  At the same time, as we attempted to describe the programs veryì
  64. precisely, we discovered a number of deficiencies in the code.  Some codingì
  65. limitations that we thought we would accept in the current version of NZ-COMì
  66. and would upgrade later just didn't seem acceptable any more once we wroteì
  67. them down on paper.  As a result, we have really skipped version 1 of NZ-COMì
  68. and have gone directly to version 2.  There are quite a few exciting newì
  69. features beyond what I described in issue #32; many will appeal especiallyì
  70. to those with a penchant for the unconventional (but I won't say any moreì
  71. about them now).
  72.  
  73.  
  74.                        PRL Files and Type-4 Programs
  75.  
  76. One of the new features introduced with ZCPR34 is the type-4 program.  Aì
  77. number of questions have been appearing in messages on Z-Nodes, so I thoughtì
  78. I would say a few words on this subject.
  79.  
  80. Just to refresh your memory, ordinary CP/M program files are loadedì
  81. beginning at an address of 100H.  This was also true of Z-System programs. ì
  82. They differ from standard CP/M programs in that the code starts with aì
  83. special header.  One item in the header is the text string 'Z3ENV'ì
  84. beginning with the fourth byte of the program.  This string is used toì
  85. identify the program as a Z-System program.
  86.  
  87. After the text string comes a number, now called the program type identifier. ì
  88. If the number is 2, then the so-called environment descriptor is includedì
  89. in the first page of the program file.  These type-2 programs are rarelyì
  90. seen today.  If the number is 1, then the program was designed to run in aì
  91. ZCPR3 system with a permanent operating system memory buffer containing theì
  92. environment descriptor.  The program only has to store the address of thatì
  93. descriptor, and it can then adapt to any system in which it is run.
  94.  
  95. The environment or ENV address is stored in the two bytes immediatelyì
  96. following the program type byte.  Prior to ZCPR version 3.3, the address hadì
  97. to be installed into programs using a utility like Z3INS before they couldì
  98. be used.  Starting with ZCPR33, the command processor installs the value asì
  99. part of the process of loading the file from disk.
  100.  
  101. With ZCPR33, the type-3 program was introduced.  These programs are notì
  102. limited to execution at 100H, as all previous programs had been.  The twoì
  103. bytes after the ENV address contain the address at which the code isìèdesigned to run.  The Z33 command processor examines the program type byte,ì
  104. and if it is 3, it reads the load address from the header and proceeds toì
  105. load the program to the designated address and execute it there.
  106.  
  107. The type-3 program made it possible to load and run programs at addressesì
  108. other than 100H, but the address at which any given program file would runì
  109. was still fixed.  In his column in the last issue, Bridger Mitchellì
  110. described a fascinating and remarkable program structure that allows aì
  111. program to run at whatever address it is loaded to.  That same idea is theì
  112. basis for the new type-4 program.  Bridger's ANYWHERE program could beì
  113. loaded manually to any address and then executed.  Type-4 programs areì
  114. loaded automatically by the command processor to the highest address inì
  115. memory at which they can run without overwriting the command processor orì
  116. any resident system extension (RSX) that is present.  I would like toì
  117. provide some additional details on how type-4 programs work and how they areì
  118. constructed.
  119.  
  120. As with ANYWHERE, type-4 programs are derived from so-called (and, asì
  121. Bridger pointed out, mis-named) page-relocatable or PRL files.  Bridgerì
  122. defined and described those files in his column in the last issue, butì
  123. another shot at it probably won't hurt.  I will approach the subjectì
  124. somewhat differently -- with a concrete example.  Consider the short andì
  125. simple program in Listing 1.  It is set up for a starting address of 100H. ì
  126. Fig. 1 shows the binary image of the sort one would see if the program wereì
  127. loaded with a debugger (e.g., DDT) and displayed.
  128.  
  129. If we change the argument of the ORG directive from 100H to 200H andì
  130. assemble again, we get the results shown in Listing 2 and Fig. 2.  Youì
  131. should examine those results and note the things that have stayed the sameì
  132. and the things that have changed.  Note in particular that only three bytesì
  133. in the code have actually changed.  One is the high order byte of theì
  134. address of the initial jump instruction.  The destination of that jump is inì
  135. the program, and, since the program has moved up by 100H, the jump addressì
  136. has increased by an identical amount.  The second change is in the data wordì
  137. containing the entry point address.  Obviously that address changes when theì
  138. program origin is changed.  The third change is in the value loaded into theì
  139. DE register pair.  It is the address of the message string, which isì
  140. likewise a part of the program.
  141.  
  142. Note that the argument of the jump to DOS has not changed.  It is anì
  143. absolute address outside the program.  Therefore, it does not change.
  144.  
  145. Now let's look at a PRL file for the same program.  I am not aware of anyì
  146. assemblers that can produce a PRL file directly.  The usual procedure is toì
  147. remove the ORG statement from the source code, assemble the program to a RELì
  148. (normal relocatable format), and then use a linker to generate the PRL fileì
  149. from the REL file.  Fig. 3 shows the binary image of a PRL file producedì
  150. using the SLR virtual-memory linker SLRNK+.  Unfortunately, inexpensiveì
  151. linkers, such as SLRNK and ZLINK, are not able to produce PRL files.  Laterì
  152. we will show you a method, though somewhat tedious, that allows you toì
  153. construct a reasonable approximation to a PRL file using an ordinaryì
  154. assembler (no linker at all).è
  155. SLRNK+ actually cannot produce a PRL directly using the source code asì
  156. listed.  The SLR manual discusses in a somewhat opaque way the technique forì
  157. generating a correct PRL file.  The problem is that the one-page nearlyì
  158. empty header at the beginning of the program is not generated.  Joe Wrightì
  159. invented the trick of linking in the file SLR.REL derived by assemblingì
  160. source code with the sole statement
  161.  
  162.     DS    256
  163.  
  164. This allocates one page of memory.  The PRL file is produced by the linkerì
  165. command
  166.  
  167.     SLRNK+ TEST/K,SLR,TEST,/E
  168.  
  169. The term "TEST/K" defines the output file, the term "SLR" allocates theì
  170. empty header, and the term "TEST" links in the actual program code.
  171.  
  172. You should notice in Fig. 3 the following things.  First, the PRL fileì
  173. begins with a one-page header, which is entirely zero except for a word atì
  174. address 101H (you can't tell from this example that it is a word, but itì
  175. is).  This word is the length of the code, 001BH or 27 decimal in thisì
  176. example.  The program code itself begins on the next page (200H) and is theì
  177. same as the code in Fig. 1.
  178.  
  179. The other new bytes in the PRL file are those that follow the last byte ofì
  180. the program code.  These bytes comprise the relocation bitmap that Bridgerì
  181. Mitchell described in his column in the previous issue of TCJ.  The firstì
  182. byte is 20H, which expanded to binary is 00100000.  This means that theì
  183. third byte in the program code is the high byte of an address that must beì
  184. relocated to make the program code execute at an address other than 100H. ì
  185. Indeed, the third byte is the address to which the JP instruction jumps. ì
  186. The second byte in the bitmap is 08H or 00001000 binary.  This tells us thatì
  187. the 13th byte in the program code is an address that has to be relocatedì
  188. when the program is relocated.  Indeed, this is the address of the start ofì
  189. the program in the Z-header.  The third byte in the bitmap is 01H orì
  190. 00000001 binary.  It tells us that byte 23 is an address.  If we lookì
  191. carefully, this is the address part of the "LD DE,MSG" instruction.
  192.  
  193.  
  194. How Does ZCPR34 Load and Execute a Type-4
  195.  
  196. Bridger Mitchell explained last time in some detail how a PRL file can beì
  197. relocated to run at any address.  It really is not necessary to understandì
  198. all the details.  The basic idea is that the bitmap tells a loader whichì
  199. bytes in the code to adjust.
  200.  
  201. The Z34 command processor has a special mechanism for processing type-4ì
  202. programs.  After the command processor has located a transient program, itì
  203. loads the first record of the file into the default buffer at 80h.  Here itì
  204. can examine it to see what kind of program it is.  If it is a standard CP/Mì
  205. program or a type-1 or type-2 Z-System program, it sets up the load addressìèas 100H and proceeds to load the entire file into memory, starting over withì
  206. the first record.  If it is a type-3 program, the same procedure is followedì
  207. except that the load address is extracted from the program header.
  208.  
  209. With the type-4 program things are not so simple, because the load addressì
  210. has to be calculated and the code has to be relocated.  Z34 gets these tasksì
  211. accomplished in a very clever and tricky way.  It could have done all theì
  212. work itself, but that would have added a lot of code to the commandì
  213. processor.  Instead, we took advantage of the fact that a PRL file has thatì
  214. two-record header with almost nothing in it.  To make a type-4 program, weì
  215. overlay onto this header a special loader program.  Z34 executes the codeì
  216. there to calculate the load address and then to perform the code relocation.
  217.  
  218. The loader is available in HEX format (TYP4LDR.HEX) and can be grafted ontoì
  219. the PRL file using the command
  220.  
  221.     MLOAD file=file.PRL,TYP4LDR
  222.  
  223. where 'file' is the name of the PRL file that you want to convert to a type-4 executable file.
  224.  
  225. By putting the loader code in the program rather than in the commandì
  226. processor, we provide additional flexibility.  TYP4LDR calculates theì
  227. highest address in the TPA to which a program can be loaded, but otherì
  228. loaders could return the address of the RCP or FCP and make possible self-installing modules.  Clever users will undoubtedly come up with some otherì
  229. interesting applications that use special header code.
  230.  
  231.  
  232. How Do We Make a PRL File
  233.  
  234. The easiest way to make a PRL file and from that a type-4 program is with aì
  235. capable linker like LINK from Digital Research or SLRNK+ from SLR Systems. ì
  236. LINK came with my CP/M-Plus computer; I do not know how much it costs or howì
  237. to obtain it otherwise.  SLRNK+, which offers many very useful and powerfulì
  238. features besides the ability to make PRL files, costs $195.  For someone whoì
  239. wants to experiment casually with type-4 programming, this is probably tooì
  240. much money to spend.  If you are not going to do it very often and don'tì
  241. mind a little work, you can hand craft a PRL file using a debugger like DDT. ì
  242. I will take you through the procedure using our sample program from Listingì
  243. 1.
  244.  
  245. Making the bitmap is the hard part of the procedure.  You should key in theì
  246. program called MAKEPRL.Z80 in Listing 3 and assemble it to a HEX file.  Weì
  247. will use that code in the debugger first to make a "byte-map" and then toì
  248. convert the byte-map into a bitmap.  We assume that we have alreadyì
  249. assembled versions of the program with ORGs of 100H and 200H.
  250.  
  251. To construct the PRL file, we invoke the debugger (assumed to be DDT) andì
  252. issue the commands shown in Fig. 4.  The first pair of commands loads theì
  253. utility program MAKEPRL.  The next two lines load the version of our programì
  254. that was assembled to run at 100H.  At this point we have to note the "nextì
  255. load address" reported by the debugger (I suggest you write it down).  Nowì
  256. we load the version of the program assembled to run at 200H so that itìèfollows right on the end of the 100H version.  To do this, we use an offsetì
  257. value in the "R" command that is 100H lower than the "next address" that wasì
  258. reported a moment ago.
  259.  
  260. There is one other very important step we need to perform at this point. ì
  261. MAKEPRL has to be told the address at which the second program image wasì
  262. loaded.  The value is patched in at address 10EH using the commands shown inì
  263. Fig. 4 starting with "S10E".  For our example program, the next address isì
  264. reported as 0280.  Therefore, low-nextaddr is 80 and the high-nextaddris 02.
  265.  
  266. Now we let MAKEPRL do the hard part by running it with the "G" command. ì
  267. When it is finished, we need to examine the value in the HL register, sinceì
  268. it tells us the next address after the bitmap.  After leaving DDT we have toì
  269. save the code image from 100H up to but not including that address.  For theì
  270. example program, the value in HL is reported to be 290H.  Since we areì
  271. presumably running Z34 and have the type-4 SAVE program, we save the resultì
  272. using the command
  273.  
  274.     SAVE 100-28F PRLTEST.COM
  275.  
  276. If you do not have the type-4 SAVE,you will have to calculate the number ofì
  277. sectors to save.
  278.  
  279. Fig. 4 lists one DDT command that we did not discuss.  The "F103,1FF,0"
  280. command fills the part of the header after the code size word with zeros.
  281. This makes the file look prettier, but it is not absolutely necessary,
  282. especially if you are later going to overlay the type-4 loader as described
  283. below.
  284.  
  285. The PRL files made this way can be used to make type-4 programs, and theyì
  286. can be used in Bridger Mitchell's ANYWHERE program.  However, we shouldì
  287. point out that these PRL files are not as efficient as those produced by aì
  288. linker.  We assumed that the code in the COM files extended to the end ofì
  289. the last record in the file.
  290.  
  291. Perhaps you can build on my simple method and figure out how to extend it toì
  292. produce an optimal PRL file just like the one from SLRNK+.  It would alsoì
  293. not be too difficult to write a program using routines in SYSLIB to read inì
  294. the pair of COM files and generate a PRL file from them completelyì
  295. automatically.  The most elegant method for doing this would use random-record writes.  I invite readers to send me such a program.
  296.  
  297. =============================================================================
  298.  
  299.     00 01 02 03    04 05 06 07    08 09 0A 0B    0C 0D 0E 0F
  300. -------------------------------------------------------------------
  301. 0100    C3 13 01 5A    33 45 4E 56    03 00 00 00    01 48 65 6C
  302. 0110    6C 6F 24 0E    09 11 0D 01    C3 05 00
  303.  
  304. Fig. 1.  Binary image of the sample program in Listing 1.
  305.  
  306. =============================================================================
  307. è    00 01 02 03    04 05 06 07    08 09 0A 0B    0C 0D 0E 0F
  308. -------------------------------------------------------------------
  309. 0100    C3 13 02 5A    33 45 4E 56    03 00 00 00    02 48 65 6C
  310. 0110    6C 6F 24 0E    09 11 0D 02    C3 05 00
  311.  
  312. Fig. 2.  Binary image of the sample program in Listing 1 when linked to runì
  313. at a starting address of 200H and loaded at 100H.
  314.  
  315. =============================================================================
  316.  
  317.     00 01 02 03    04 05 06 07    08 09 0A 0B    0C 0D 0E 0F
  318. -------------------------------------------------------------------
  319. 0100    00 1B 00 00    00 00 00 00    00 00 00 00    00 00 00 00
  320. 0110    00 00 00 00    00 00 00 00    00 00 00 00    00 00 00 00
  321.  
  322. 0200    C3 13 01 5A    33 45 4E 56    03 00 00 00    01 48 65 6C
  323. 0210    6C 6F 24 0E    09 11 0D 01    C3 05 00 20    08 01 00
  324.  
  325. Fig. 3.  Binary image of PRL file produced for the same test program andì
  326. loaded at address 100H.  Some memory regions containing bytes of 00 haveì
  327. been omitted from the display here.
  328.  
  329. =============================================================================
  330.  
  331.     IMAKEPRL.HEX<cr>    ; Ready to load PRL maker routine
  332.     R,<cr>            ; Load it to address 100h
  333.     ITEST100.COM<cr>    ; Ready to load program ORGed for 100h
  334.     R100<cr>        ; Load it to address 200h (offset 100)
  335.     ITEST200.COM<cr>    ; Ready to load program ORGed for 200h
  336.     R<nextaddr-100><cr>    ; Load it to proper offset
  337.     s10E<cr>        ; Ready to patch in code size
  338.     low-nextaddr<cr>    ; Low byte of code size
  339.     high-nextaddr<cr>    ; High byte of code size
  340.     .<cr>            ; End patch with period
  341.     G<cr>            ; Run MAKEPRL code at 100h
  342.     X<cr>            ; Display registers -- note value of HL
  343.     F103,1FF,0        ; Clean up the header area
  344.     G0<cr>            ; Exit from DDT
  345.  
  346. Figure 4.  Commands issued to DDT to produce a PRL file from two COM filesì
  347. assembled to run at addresses of 100h and 200h.
  348.  
  349. =============================================================================
  350.  
  351. Z80ASM SuperFast Relocating Macro Assembler     Z80ASM 1.31 Page   1
  352. PRLTEST Z80
  353.  
  354.     1         0100          org    100h
  355.     2                   
  356.     3 0100              entry:
  357.     4 0100  C3 0113         jp    start
  358.     5                   è    6 0103  5A 33 45 4E     db    'Z3ENV'
  359.     7 0108  03              db    3
  360.     8 0109  0000            dw    0
  361.     9 010B  0100            dw    entry
  362.    10                   
  363.    11 010D  48 65 6C 6C msg:    db    'Hello','$'
  364.    12                   
  365.    13 0113              start:
  366.    14 0113  0E 09           ld    c,9
  367.    15 0115  11 010D         ld    de,msg
  368.    16 0118  C3 0005         jp    0005h
  369.    17                   
  370.    18                       end
  371.  0 Error(s) Detected.
  372.  27 Absolute Bytes. 3 Symbols Detected.
  373.  
  374. Listing 1.  Simple example program assembled for a load address of 100H.
  375.  
  376. =============================================================================
  377.  
  378. Z80ASM SuperFast Relocating Macro Assembler     Z80ASM 1.31 Page   1
  379. PRLTEST Z80
  380.  
  381.     1         0200          org    200h
  382.     2                   
  383.     3 0200              entry:
  384.     4 0200  C3 0213         jp    start
  385.     5                   
  386.     6 0203  5A 33 45 4E     db    'Z3ENV'
  387.     7 0208  03              db    3
  388.     8 0209  0000            dw    0
  389.     9 020B  0200            dw    entry
  390.    10                   
  391.    11 020D  48 65 6C 6C msg:    db    'Hello','$'
  392.    12                   
  393.    13 0213              start:
  394.    14 0213  0E 09           ld    c,9
  395.    15 0215  11 020D         ld    de,msg
  396.    16 0218  C3 0005         jp    0005h
  397.    17                   
  398.    18                       end
  399.  0 Error(s) Detected.
  400.  27 Absolute Bytes. 3 Symbols Detected.
  401.  
  402. Listing 2.  Simple example program assembled for a load address of 200H.
  403.  
  404. =============================================================================
  405.  
  406. ; This code, which assists in the generation of a PRL file from a pair of COM
  407. ; files assembled for execution at 100H and 200H, is by no means optimized for
  408. ; speed or size.  I have tried to optimize it for clarity!
  409. è    org    100h
  410.  
  411.     db    0        ; Standard PRL header (and NOP)
  412. size:    dw    0        ; PRL file size (filled in by code)
  413.  
  414.     jp    start
  415.  
  416.     db    'CODE200:'    ; Identification string
  417. c200:
  418.     dw    0        ; Patch to address of code linked to 200h
  419.  
  420. start:
  421.  
  422. ; The first step is to compute the size of the code and store the value at
  423. ; address 101h as required for a PRL file.  We also put this value in BC.
  424. ; We set up DE to point to the code assembled for 200H and HL to point to
  425. ; the code assembled for 100H.
  426.  
  427.     ld    hl,(c200)    ; Start of code for 200h
  428.     ld    de,200h        ; Start of code for 100h
  429.     xor    a
  430.     sbc    hl,de        ; Difference is assumed size of code
  431.     ld    (size),hl    ; Store in proper place for PRL file
  432.     ld    b,h        ; ..and in BC
  433.     ld    c,l
  434.  
  435.     ld    hl,(c200)
  436.     ex    de,hl        ; DE -> code for 200h, HL -> code for 100h
  437.  
  438. ; Now we subtract the code for 100h from the code for 200h to generate the map
  439. ; of bytes that are addresses that have to be relocated.  There will be a byte
  440. ; of 01 corresponding to each byte in the code that is the high order byte of
  441. ; an address that must be relocated.  There will be bytes of 00 everywhere
  442. ; else.
  443.  
  444. bytemap:
  445.     ld    a,(de)        ; Get byte from 200h version
  446.     sub    (hl)        ; Subtract byte from 100h version
  447.     ld    (de),a        ; Replace 200h code with byte map
  448.     inc    hl        ; Point to next bytes
  449.     inc    de
  450.     dec    bc        ; Any more to do?
  451.     ld    a,b
  452.     or    c
  453.     jr    nz,bytemap    ; Loop until done
  454.  
  455. ; Now we have to compress the byte map into a bit map, taking each 8 bytes of
  456. ; the byte map and packing the values into a single byte in the bit map.  The
  457. ; result is written immediately following the code (i.e., at the location of
  458. ; the code linked to 200h).
  459.  
  460.     ld    hl,(size)    ; Get number of bytes in byte mapè    ld    b,3        ; Divide by 8 (2 to the 3rd power)
  461. divide:
  462.     xor    a        ; Clear carry
  463.     rr    h        ; Rotate H right, low bit to carry
  464.     rr    l        ; Rotate L right, carry into high bit
  465.     djnz    divide        ; Repeat 3 times
  466.     ld    (mapsize),hl    ; Save the value
  467.  
  468.     ld    de,(c200)    ; Point to byte map
  469.     ld    hl,(c200)    ; Point to bit map (same place!)
  470.     
  471. makemap:
  472.     ld    b,8        ; Process block of 8 bytes into 1 byte
  473.     ld    c,0        ; Initial value for byte in bit map
  474.  
  475. makebyte:
  476.     ld    a,(de)        ; Get byte from byte map
  477.     inc    de        ; Advance pointer
  478.     rr    a        ; Move relocation bit into carry flag
  479.     rl    c        ; Move carry flag into byte in C
  480.     djnz    makebyte    ; Repeat 8 times
  481.  
  482.     ld    (hl),c        ; Put result into bit map
  483.     inc    hl        ; ..and advance its pointer
  484.  
  485.     push    hl
  486.     ld    hl,(mapsize)    ; See if we are done
  487.     dec    hl
  488.     ld    (mapsize),hl
  489.     ld    a,h
  490.     or    l
  491.     pop    hl
  492.     jr    nz,makemap
  493.  
  494.     rst    38h        ; Breakpoint to end program
  495.  
  496. mapsize:
  497.     ds    2        ; Scratch area
  498.  
  499.     end
  500.  
  501. Listing 3.  Utility program to perform the hard part of making a PRL file
  502. using a debugger.
  503.  
  504. [This article was originally published in issue 34 of The Computer Journal,
  505. P.O. Box 12, South Plainfield, NJ 07080-0012 and is reproduced with the
  506. permission of the author and the publisher. Further reproduction for non-
  507. commercial purposes is authorized. This copyright notice must be retained.
  508. (c) Copyright 1988, 1991 Socrates Press and respective authors]
  509.