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 / PROGPACK / TYP4LDR1.Z80 < prev    next >
Text File  |  2000-06-30  |  13KB  |  404 lines

  1. ; Program:    TYP4LDR.Z80
  2. ; Authors:    Joe Wright, Bridger Mitchell, Jay Sage
  3. ; Date:        June 18, 1988
  4. ; Version:    1.0
  5. vers    equ    11        ; August 11, 1988, Bruce Morgen.
  6.                 ; Saved a byte in the file size
  7.                 ; calculation and another in
  8.                 ; the relocator module.
  9.  
  10. ;vers    equ    10        ; 20 Jun 88  jww
  11.  
  12. ; Checks file size against memory allocation earlier
  13. ; and therefore eliminates two calls to ADJADDR.
  14. ; Shorten ADJADDR routine.
  15. ; Place record count in DE before LOAD:
  16.  
  17. no    equ    0
  18. yes    equ    not no
  19.  
  20. prl    equ    yes        ; If not PRL, DRI SPR is assumed
  21. align    equ    no        ; If yes, force page alignment for load
  22. test    equ    no        ; If yes, no .phase/.dephase
  23.  
  24. tbuff    equ    80h        ; Always executes from the default buffer
  25.  
  26.  
  27. ; This file contains the overlay loader code that is placed into the page-0
  28. ; header of a PRL or SPR program file to make a type-4 Z-System program that
  29. ; will be loaded automatically by the ZCPR34 or Z3PLUS command processor to
  30. ; the highest possible address in the TPA.  SPR and PRL files are much the
  31. ; same except that the code segment in PRL files is relative to 0100h while
  32. ; in SPR files it is relative to 0000h.  Assuming that the program has been
  33. ; assembled and then linked to PRL by either DRI's LINK or SLR's SLRNK+, the
  34. ; type-4 program would be created using Ron Fowler's MLOAD (version 2.1 or
  35. ; later) with the command:
  36. ;
  37. ;    MLOAD <file>[.COM]=<file>.PRL,TYP4LDR[.HEX]
  38. ;
  39. ; where <file> is the name of the program and the items in square brackets
  40. ; are optional.
  41.  
  42. ; The header in a PRL or SPR file occupies one page or two records.  TYP4LDR
  43. ; comprises two pieces of code, one in the first record of the file and one
  44. ; in the second record.  These two pieces of code are executed by the
  45. ; command processor from the default buffer at 80h.
  46.  
  47. ; The command processor first calls the routine in record 0.  This code
  48. ; calculates where the actual program code beginning with record 2 should be
  49. ; loaded and reports the result back to the command processor.  The command
  50. ; processor then loads the second routine in record 1 into the default
  51. ; buffer at 80h and the actual program code beginning with record 2
  52. ; (including the bitmap) to the calculated load address.  The command
  53. ; processor then returns to the second TYP4LDR routine, which performs the
  54. ; relocation of the program code and then returns to the CCP.
  55.  
  56. ;--------------------------------------------------
  57.  
  58. ; PRTVAL macro(s) to print text and value during assembly
  59.  
  60. prtval2    macro m1,v1,m2            ; \
  61.     .printx    m1 v1 m2        ;  +- this is the print value macro
  62.     endm                ; /
  63.  
  64. prtval    macro r,msg1,val,msg2        ; \
  65.     .radix r            ;   passing the radix value
  66.     prtval2 <msg1>,%val,<msg2>    ;   requires the uses of 2 macros
  67.     endm                ; /
  68.  
  69. ;=============================================================================
  70.  
  71. ; Record 0 Routine  --  Load Address Calculator
  72.  
  73. ; Record 0 of the loader code begins with a Z-System header that identifies
  74. ; the program to the command processor as a type-4 program.  The first byte
  75. ; contains a RST 0 instruction that will cause a warmboot if an attempt is
  76. ; made to execute the program with a command processor that is not
  77. ; compatible with ZCPR34 or later.  The next two bytes would normally
  78. ; contain the entry address to the program code.  In the PRL and SPR file
  79. ; format, they contain the length of the program.  This value is used to
  80. ; locate the bitmap and to compute the size of the program.
  81.  
  82. ; ZCPR34 calls the code in this record at location TBUFF+9.  It is called
  83. ; from a point inside the command processor's MLOAD3 routine where the load
  84. ; address is being computed.  On entry, the registers contain the following
  85. ; information:
  86.  
  87. ;     HL  =    Z3ENV, environment descriptor address
  88. ;     DE  =    ENTRY, address of beginning of CCP
  89. ;     BC  =    PROGSIZE, program size from program header in record 2
  90. ;      A  =    FULLGET flag
  91.  
  92. ; The value in HL is not used here but could be used, for example, by a
  93. ; different loader designed to load a routine into the RCP module.  The
  94. ; Z3ENV address would be needed to determine the address and size of the RCP
  95. ; buffer.
  96.  
  97. ; The value in DE is used to determine the address of the top of the TPA.
  98.  
  99. ; The value reported in BC is extracted by the CCP from the load-address
  100. ; word of the type-3 header in the actual program code.  This will normally
  101. ; be 0100h for a PRL file or 0000h for an SPR file.  However, if the program
  102. ; uses dynamically allocated buffer space after the end of its own code,
  103. ; then the type-4 program must be loaded to a correspondingly lower address. 
  104. ; In that case, the value at offset 11 (0Bh) in record 2 should be patched
  105. ; to contain the address of the end of the required buffer space relative to
  106. ; the nominal load address (100h for PRL, 000h for SPR).  The value thus
  107. ; includes the code segment, data segment, and the dynamic buffer space, and
  108. ; the nominal load address.
  109.  
  110. ; The value in A is the FULLGET flag that tells whether or not the command
  111. ; processor supports the fullget option.  If it does not, the CCP always
  112. ; performs a test to make sure that code is never loaded to an address above
  113. ; the beginning of the CCP.  Because it does not know in advance how big a
  114. ; file is, it actually has to protect one extra page below the CCP.  If the
  115. ; CCP supports the fullget option, this checking is disabled.  Since during
  116. ; type-4 loading we know the size of the code, we can load it one page
  117. ; higher in memory.
  118.  
  119. ; When the loader routine here is called, the top of the stack contains the
  120. ; return address to the point in MLOAD3 from which the loader was called.
  121.  
  122.     org    100h        ; ORG HEX file at 100h
  123.  
  124.      if    not test
  125.     .phase    tbuff        ; Program actually runs at 80h
  126.      endif
  127.  
  128.  
  129. rec0:    rst    0        ; Only a ZCPR34-compatible CCP
  130.                 ; ..can execute this file
  131. length:    ds    2        ; Length of the code module (SPR or PRL)
  132.  
  133.     db    'Z3ENV'
  134.     db    4        ; A Type 4 program
  135.  
  136. start:    ex    (sp),hl        ; Get return address from stack
  137.                 ; ..and put Z3ENV on the stack
  138.     ld    (load+1),hl    ; Set in-line jump to the return address
  139.     ld    hl,(length)    ; Length of this PRL/SPR code
  140.     push    hl        ; Save on stack for sector 1 routine ;(+2)
  141.     push    de        ; Save CCP address ;(+4)
  142.     or    a        ; Test FULLGET
  143.     push    af        ; Save result ;(+6)
  144.  
  145.      if    prl        ; If PRL file, we have to adjust PROGSIZE
  146.     dec    b        ; ..for the 100h address offset
  147.      endif
  148.  
  149. ; We now calculate the size of the file to be loaded by the CCP.  It will be
  150. ; the length of the program plus the length of the bitmap (1/8 the code size)
  151. ; adjusted to an integer number of records.
  152.  
  153.     ex    de,hl        ; PRL length into DE
  154.     ld    hl,7        ; Make sure we count any fractional byte
  155.     add    hl,de
  156.     ld    a,3        ; Divisor (2^3=8)
  157.  
  158. div:    srl    h        ; 0 to H7, H0 to carry
  159.     rr    l        ; Carry to L7
  160.     dec    a
  161.     jr    nz,div        ; Divide by 8
  162.  
  163.     add    hl,de        ; PRL/8 + PRL to HL
  164.     ld    de,127
  165.     add    hl,de
  166.     ld    a,128
  167.     and    l
  168.     ld    l,a
  169.  
  170. ; If fullget is false, the CCP file loader will perform tests to prevent the
  171. ; load from overwriting either the CCP or an RSX.  Because the CCP cannot
  172. ; detect the end of a file until an attempt to read the next record fails,
  173. ; no attempted read is allowed in the top page of memory.  To account for this,
  174. ; the effective file size is taken to be 101h bytes longer than the actual
  175. ; size.
  176.  
  177.     pop    af        ; Get fullget status back ;(+4)
  178.     pop    de        ; CCP address (+2)
  179.     push    hl        ; Save file size (+4)
  180.     push    de        ; Save CCP address (+6)
  181.     push    af        ; Save fullget again ;(+8)
  182.     jr    nz,noadj1    ; If fullget is true, no adjustment needed
  183.  
  184.     ld    de,101h
  185.     add    hl,de
  186. noadj1:    ex    de,hl        ; Load size to DE
  187.  
  188. ; Place the larger of Load size and Memory size in DE
  189.  
  190.     ld    a,e
  191.     sub    c
  192.     ld    a,d
  193.     sbc    b
  194.     jr    nc,noadj2    ; DE is larger
  195.     ld    d,b
  196.     ld    e,c
  197.  
  198. ; Calculate possible load address assuming RSX defines top of TPA and DE
  199. ; defines memory required.  If fullget is false, a further adjustment
  200. ; is required because the CCP file load checking code uses the RSX lower
  201. ; page boundary as the upper address.
  202.  
  203. noadj2:    ld    hl,(6)        ; DOS/RSX pointer to HL
  204.     pop    af        ; We need fullget test again ;(+6)
  205.     jr    nz,noadj3
  206.     ld    l,0        ; If fullget false, use beginning of page
  207.  
  208. noadj3:    push    de        ; Save memory size ;(+8)
  209.     call    adjaddr        ; Calculate address with DOS/RSX
  210.  
  211. ; Now calculate possible load address assuming CCP defines top of TPA
  212.  
  213.     pop    de        ; Memory size into DE ;(+6)
  214.     pop    hl        ; CCP address ;(+4)
  215.     call    adjaddr        ; Calculate address and keep lowest
  216.  
  217. ; Get ready to return to CCP
  218.  
  219. loadaddr equ    $+1
  220.  
  221.     ld    de,-1        ; Get final value of load address
  222.  
  223.      if    align
  224.     ld    e,a        ; Force page alignment (A=0)
  225.      endif
  226.  
  227.     pop    hl        ; Get file size ;(+2)
  228.     push    de        ; Pass load address to record-1 routine ;(+4)
  229.     push    de        ; Hold a copy on the stack for now ;(+6)
  230.  
  231.     add    hl,hl
  232.     ld    e,h
  233.     ld    d,a        ; A remains zero from last call to ADJADDR:
  234.  
  235.     ld    hl,tbuff    ; Set for for CCP to call second record
  236.     ex    (sp),hl        ; Load address to HL, tbuff to top of stack
  237.  
  238.      if    test
  239.     rst    38h        ; DDT breakpoint
  240.      endif
  241.  
  242. load:    jp    0        ; Return to CCP (hot-patched above)
  243.                 ; Command processor loads record 1 to tbuff
  244.                 ; ..and records 2+ to load address, then
  245.                 ; ..'returns' to tbuff
  246.  
  247. ;--------------------------------------------------
  248.  
  249. ; This subroutine takes the address of the top of TPA in HL and the amount of
  250. ; memory required in DE and computes the proper load address.  It then compares
  251. ; it to the value stored at LOADADDR and replaces the value there if the new
  252. ; value is lower.
  253.  
  254. adjaddr:
  255.     xor    a        ; Clear carry flag
  256.     sbc    hl,de        ; Compute lower memory address
  257.     ex    de,hl        ; ..and put it in DE
  258.     ld    hl,(loadaddr)    ; Get previously computed load address
  259.     sbc    hl,de        ; Compare HL and DE
  260.     ret    c        ; HL is lower, nothing to do
  261.     ld    (loadaddr),de    ; New lower address 
  262.     ret
  263.  
  264. space    defl    80h - ($-rec0)    ; Space remaining in this record
  265.  
  266.     .printx                ; Skip line on screen
  267.  
  268.      if    space < 80h
  269.  
  270.     prtval    10,<Space remaining in 1st routine:>,space,bytes
  271.     rept    space
  272.     db    0        ; Zero fill
  273.      endm
  274.  
  275.      else            ; Code too long
  276.  
  277. space    defl    -space
  278.     prtval    10,<1st routine too long by>,space,bytes
  279.  
  280.      endif
  281.  
  282.      if    not test
  283.     .dephase
  284.      endif
  285.  
  286. ;=============================================================================
  287.  
  288. ; Record 1 Routine  --  Code Relocator
  289.  
  290. ; This code is loaded to tbuff by the command processor. It is executed
  291. ; after the command processor has loaded the program code/data to the load
  292. ; address and relogged the current DU.  On entry, the stack contains the
  293. ; following data:
  294. ;
  295. ;    (sp)    load address
  296. ;    (sp+2)    PRL/SPR code size
  297. ;    (sp+4)    Z3ENV address
  298. ;    (sp+6)    return address of command processor routine
  299. ;        that called MLOAD3
  300.  
  301.      if    not test
  302.     .phase    tbuff
  303.      endif
  304.  
  305. rec1:    pop    de        ; Load address to DE
  306.     pop    bc        ; PRL/SPR code size to BC
  307.     pop    hl        ; Toss out Z3ENV (not needed here)
  308.  
  309. ; The loaded module may have been assembled as a Type 3.
  310. ; We change it here to Type 4.
  311.  
  312.     ld    hl,8        ; Offset to type byte
  313.     add    hl,de        ; Add the offset
  314.     ld    (hl),4        ; Make it type 4
  315.  
  316. ; Bridger Mitchell's  Word-wide relocator starts here..
  317.  
  318.     push    de        ; Save load address on stack
  319.     exx            ; Select alternate registers
  320.     pop    de        ; Load address to DE'
  321.      if    prl
  322.     dec    d        ; -100h if PRL assembly
  323.      endif
  324.     exx            ; Select main registers
  325.  
  326.     ld    ix,0        ; Clear IX
  327.     add    ix,sp        ; Save SP in IX
  328.     ex    de,hl        ; Load address to HL
  329.  
  330. ; The relocator uses SP as a memory pointer and so we must disable
  331. ; the interrupt system until we get it right again.
  332.  
  333.     di            ; Disable interrupt system
  334.     ld    sp,hl        ; Sp -> start of code, lag 1 byte
  335.     dec    sp        ; ..because prl marks the high byte
  336.     add    hl,bc        ; Add code length, hl ->prl bitmap
  337.     ld    e,1        ; Init the rotation byte
  338.                 ; It will set CY every 8 bytes
  339. ; Main relocation loop..
  340.  
  341. rloop:    ld    a,b        ; Check byte count
  342.     or    c
  343.     jr    z,rdone        ; Return to MLOAD caller
  344.  
  345.     dec    bc        ; Reduce byte count
  346.     rrc    e        ; Every 8 bits the CY is set
  347.     jr    nc,same        ; ..not set
  348.  
  349.     ld    d,(hl)        ; Set d = next byte from bitmap
  350.     inc    hl        ; And advance bitmap pointer
  351.  
  352. same:    rlc    d        ; Shift bitmap byte left into CY
  353.     jr    nc,noof        ; No relocation needed
  354.  
  355.     exx            ; Alternate registers
  356.     pop    hl        ; Get word to relocate from 'stack'
  357.     add    hl,de        ; Add the load address in DE'
  358.     push    hl        ; Put it back
  359.     exx            ; Main registers
  360.  
  361. noof:    inc    sp        ; -> next byte of code
  362.     jr    rloop
  363.  
  364. rdone:    ld    sp,ix        ; Restore the stack pointer
  365.     ei            ; And permit interrupts again
  366.  
  367.      if    test
  368.     rst    38h        ; DDT breakpoint
  369.      else
  370.     ret            ; Return to MLOAD3's caller in ZCPR34
  371.      endif
  372.  
  373. space    defl    80h - ($-rec1)    ; Space remaining in this record
  374.  
  375.      if    space < 80h
  376.  
  377.     prtval    10,<Space remaining in 2nd routine:>,space,bytes
  378.  
  379.      if    space > 16    ; Include ID if there is room
  380.     db    ' TYP4LDR Ver ',vers/10+'0','.',vers mod 10+'0'
  381. space    defl    space - 16
  382.      endif
  383.  
  384.     rept    space
  385.     db    0        ; Zero fill
  386.      endm
  387.  
  388.      else            ; Code too long
  389.  
  390. space    defl    -space
  391.     prtval    10,<2nd routine too long by>,space,bytes
  392.  
  393.      endif
  394.  
  395.     .printx                ; Skip line on screen
  396.  
  397.      if    not test
  398.     .dephase        ; Good Housekeeping
  399.      endif
  400.  
  401.     end
  402.  
  403. ; End of TYP4LDR.Z80 Relocator
  404.