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 / LINKPRL1.LBR / LINKPRL.ZZ0 / LINKPRL.Z80
Text File  |  1989-08-19  |  25KB  |  939 lines

  1.     TITLE    "LINKPRL Map-generating linker"
  2. ;================================================================
  3. VER    EQU    33
  4. ; Copyright (C) 1989 by Harold F. Bower
  5. ;----------------------------------------------------------------
  6. ; Link MicroSoft .REL files to .PRL-type with Relocation bit map.
  7. ; Originally developed in 1983 in a crude form to produce bit
  8. ; maps for small relocatable utilities. This version implements
  9. ; the standard RSX format with header record, object with ORG of
  10. ; 100H, followed by bit map.
  11. ;
  12. ;            Harold F. Bower
  13. ;            P.O. Box 313
  14. ;            Ft. Meade, MD  20755
  15. ;----------------------------------------------------------------
  16. ; Standard equates
  17.  
  18. BELL    EQU    07H        ; Bell character
  19. HT    EQU    09H        ; Tab character
  20. LF    EQU    0AH        ; Line Feed
  21. CR    EQU    0DH        ; Carriage Return
  22.  
  23. ; BDOS function calls
  24.  
  25. CONOUT    EQU    2        ; Console output
  26. PTSTR    EQU    9        ; Print string
  27. RDSTR    EQU    10        ; Read console string
  28. OPENF    EQU    15        ; Open file
  29. CLOSEF    EQU    16        ; Close file
  30. DELF    EQU    19        ; Delete file
  31. READSQ    EQU    20        ; Read sequential
  32. WRITSQ    EQU    21        ; Write sequential
  33. MAKEF    EQU    22        ; Make file
  34. SETDMA    EQU    26        ; Set dma address
  35.  
  36. ; Default memory locations
  37.  
  38. WBOOT    EQU    0000H        ; CP/M Warm Boot entry
  39. BDOS    EQU    0005H        ; CP/M Bdos entry point
  40. FCB    EQU    005CH        ; Default file control block
  41. BUFF    EQU    0080H        ; Default CP/M sector buffer
  42.  
  43. ; Miscellaneous    Values
  44.  
  45. KYBLEN    EQU    32        ; Length of keyboard buffer
  46.  
  47. ; Begin program by checking for valid file name from command line
  48.  
  49. BEGIN:    LD    (STACK),SP    ; Save entry stack for Help return
  50.     LD    SP,STACK    ; Set local stack
  51.     CALL    PRT001        ; Print opening banner
  52.     DEFB    CR,LF,'Bit-map Linker V',VER/10+'0','.'
  53.     DEFB    VER MOD 10+'0',HT,'19 Aug 89'
  54.     DEFB    '  (C) H.F.Bower',CR,LF,LF,'$'
  55. PRT001:    POP    DE
  56.     CALL    PRTMSG
  57.     LD    A,(FCB+1)    ; Check for filename
  58.     CP    ' '
  59.     JP    Z,NONAME    ; ..jump Error and abort if none
  60.     CP    '/'        ; Is it a Help request?
  61.     JP    NZ,BEGIN0    ; ..jump if not and continue
  62.     CALL    PRT002
  63.     DEFB    CR,LF,'LINKPRL',CR,LF,LF
  64.     DEFB    ' Purpose:',CR,LF
  65.     DEFB    HT,'Produce COM or PRL file from MicroSoft REL'
  66.     DEFB    CR,LF,LF,' Usage:',CR,LF
  67.     DEFB    HT,'LINKPRL //    - Print this message',CR,LF
  68.     DEFB    HT,'LINKPRL FOO    - Link FOO.REL',CR,LF,LF,'$'
  69. PRT002:    POP    DE        ; Else print help
  70.     CALL    PRTMSG
  71.     LD    SP,(STACK)    ; Restore entry stack
  72.     RET            ; ..and quit here
  73.  
  74. BEGIN0:    LD    HL,FCB+9    ; Check for filetype
  75.     LD    A,(HL)
  76.     CP    ' '        ; If none
  77.     JR    NZ,START1    ; .assume .REL
  78.     LD    HL,RELTYP    ; ..and load FCB
  79.     CALL    MOVTYP
  80. START1:    CALL    OPENFILE    ; Open source .REL file
  81.  
  82. ; Now the program starts...
  83.  
  84. ;  Internal Register Useage:
  85. ;    B = bit count for source byte
  86. ;    C = source byte shifted, b7=current
  87. ;    D = General Purpose counter
  88. ;    E = output byte for map
  89. ;    HL = pointer to input file
  90. ;    BC' = Program 'ORG' location
  91. ;    DE' = Data 'ORG' location
  92. ;    HL' = 16-bit accumulator for
  93. ;        displacement calculations
  94. ;    IX = physical load location
  95. ;    IY = points to flags
  96.  
  97. ; Calculate available memory and zero storage
  98. ; locations up to the BDOS base page
  99.  
  100.     LD    HL,(BDOS+1)    ; Get BDOS starting address
  101.     LD    L,0        ; ..and set page boundary
  102.     DEC    HL        ; ...down one for safety
  103.     LD    DE,TEMP        ; Get first address
  104.     PUSH    DE        ; ..and save
  105.     OR    A
  106.     SBC    HL,DE        ; ..and calculate difference
  107.     LD    C,L
  108.     LD    B,H
  109.     POP    HL        ; Restore starting addr
  110.     LD    (HL),0        ; ..zero first spot
  111.     LD    E,L
  112.     LD    D,H        ; Copy addr
  113.     INC    DE        ; ..plus one
  114.     LDIR            ; ..move the 0 along
  115.  
  116. ; Set initial values in storage since memory was set to
  117. ; zero by action above
  118.  
  119.     LD    A,128        ; Set pointer to trigger
  120.     LD    (INPTR),A    ; initial read
  121.     LD    IX,OUTFIL    ; Set IX for load
  122.     LD    IY,FLAGS    ; Set IY to flags byte
  123. MODE:    CALL    PRT003        ; Prompt for operation mode
  124.     DEFB    CR,LF,'Link to .COM or .PRL (C/P) :$'
  125. PRT003:    POP    DE
  126.     CALL    PRTMSG
  127.     LD    A,KYBLEN    ; Set buffer length
  128.     CALL    GETINP
  129.     LD    A,(HL)        ; Just look at the first
  130.     CALL    UPPER
  131.     CP    03H        ; Crtl-C?
  132.     JP    Z,WBOOT
  133.     CP    'C'        ; Check operating mode
  134.     RES    3,(IY+0)    ; ..clear Map generation flag for COM
  135.     LD    DE,0100H    ; Set default load addr for files
  136.     JR    Z,ADRLOP    ; ..jump if .COM
  137.     CP    'P'        ; Is it a PRL request?
  138.     JR    NZ,MODE        ; ..jump If not 'C' or 'P', error
  139.     SET    3,(IY+0)    ; Else set PRL Map generation flag
  140. ADRLOP:    PUSH    DE        ; Save address
  141.     CALL    PRT004
  142.     DEFB    CR,LF,'Enter Hex load addr (Default = $'
  143. PRT004:    POP    DE
  144.     CALL    PRTMSG
  145.     POP    HL        ; Bring address back..
  146.     CALL    PRTHEX        ; ..and print it
  147.     PUSH    HL        ; Now save address again
  148.     CALL    PRT005        ; ..and print end of prompt line
  149.     DEFB    'H) :$'
  150. PRT005:    POP    DE
  151.     CALL    PRTMSG
  152.     LD    A,KYBLEN    ; Set line length
  153.     CALL    GETINP        ; ..and get a line
  154.     DEC    HL        ; Get count
  155.     LD    B,(HL)        ; ..to B
  156.     INC    HL
  157.     EX    DE,HL
  158.     LD    A,B
  159.     OR    A        ; Cnt = 0 for default
  160.     JR    Z,DEFAULT
  161.     LD    HL,0000        ; Start with clear register
  162.     CALL    GETNUM
  163.     EX    (SP),HL        ; Swap new number for stack
  164.     LD    A,B        ; Check for valid Hex address
  165.     OR    A
  166.     JR    Z,DEFAULT    ; Jump if Ok
  167.     EX    (SP),HL        ; If bad, swap back again
  168.     CALL    PRT006
  169.     DEFB    CR,LF,BELL,'++ Hex Digit Error ++',CR,LF,'$'
  170. PRT006:    POP    DE
  171.     CALL    PRTMSG        ; ..print error msg
  172.     POP    DE        ; Restore default address
  173.     JR    ADRLOP        ; ..and try again
  174.  
  175. DEFAULT: POP    HL        ; Get address from stack
  176.     LD    (ORGADR),HL
  177.     LD    HL,BUFF
  178.     CALL    READ        ; Set bit position
  179.     JR    LOOP0        ; ..and jump to test bit
  180.  
  181. ;===============================================;
  182. ;     M a i n    P r o g r a m    L o o p    ;
  183. ;===============================================;
  184.  
  185. LOOP:    CALL    GETBIT        ; Get a source bit into position
  186. LOOP0:    JR    NZ,LOOP1    ; ..jump if 1x form and test next
  187.     CALL    BYTE0        ; 0 = load 8 bits absolute
  188.     JR    LOOP        ; ..and back for more
  189.  
  190. ; We have 1x form.  Check the second bit
  191.  
  192. LOOP1:    CALL    GETBIT        ; Get a source bit into position
  193.     JR    Z,LOOP2        ; ..jump if it is 10x form
  194.     CALL    GETBIT        ; We have 11x, Check 3rd bit
  195.     JR    NZ,COMREL    ; 1 = Common, 0 = Data
  196.  
  197. ; We have 110 = Data Relative.
  198.  
  199.     CALL    ADDR16        ; Get 16 bits, data relative
  200.     EXX            ; Do the math in alternate regs
  201.     LD    HL,(TEMP)    ; Load the offset
  202.     ADD    HL,DE        ; ..and add DSEG base from DE'
  203.     JR    OUTV        ; Write a 01 to Bit Map
  204.  
  205. ; We have 111 = Common Relative.
  206.  
  207. COMREL:    CALL    ADDR16        ; Get 16 bits, common rel
  208.     PUSH    HL        ; Write 01 to map
  209.     PUSH    DE
  210.     LD    DE,(COMMAD)    ; Add Common Base address
  211.     LD    HL,(TEMP)    ; ..to accumulated offset
  212.     ADD    HL,DE
  213.     POP    DE
  214.     EX    (SP),HL
  215.     EXX
  216.     POP    HL
  217.     JR    OUTV        ; Save value & write 01 to Bit Map
  218.  
  219. ; We have 10x form.  Check the third bit
  220.  
  221. LOOP2:    CALL    GETBIT        ; Get a bit in position
  222.     JR    Z,SPECL        ; ..jump if 100 (Special Link Item)
  223.  
  224. ; We have 101 = Program Relative.
  225.  
  226.     CALL    ADDR16        ; Get 16 bits, prog relative
  227.     EXX            ; ..writing 01 in bit map
  228.     LD    HL,(TEMP)
  229.     ADD    HL,BC
  230. OUTV:    LD    A,L        ; Vector here to output
  231.     EXX            ; ..relative addresses
  232.     CALL    BYTE0V        ; Low byte has 0 Map Bit
  233.     EXX
  234.     LD    A,H        ; Get Hi byte
  235.     EXX
  236.     CALL    BYTE1V        ; ..write with 1 Map Bit
  237.     JR    LOOP
  238.  
  239. ; Arrive here if special link (100xxxxxxxx)
  240. ; We don't do much with these, most just print information
  241.  
  242. SPECL:    CALL    GETTYP        ; Get 4 bit type
  243.     EXX            ; Swap to alternates to get free HL'
  244.     LD    HL,SPLTBL    ; Offset from table start
  245.     ADD    A,A        ; Double value for 2-byte entries
  246.     ADD    A,L
  247.     LD    L,A
  248.     JR    NC,SPECL0    ; Bypass next if no Overflow
  249.     INC    H
  250. SPECL0:    LD    A,(HL)        ; Addr.low to A..
  251.     INC    HL
  252.     LD    H,(HL)        ; Addr.high to H
  253.     LD    L,A        ; Complete address to HL
  254.     PUSH    HL        ; Address to stack to simulate CALL
  255.     EXX            ; ..back to primary registers
  256.     RET            ; Jump to Address on stack
  257.  
  258. SPLTBL:    DEFW    ENTRY        ; 0 = Entry Symbol
  259.     DEFW    COMNAM        ; 1 = Common Block Name
  260.     DEFW    PGNAME        ; 2 = Program Name
  261.     DEFW    SEARCH        ; 3 = Library Search
  262.     DEFW    UNDEF0        ; 4 = (undefined)
  263.     DEFW    COMMON        ; 5 = Common Size
  264.     DEFW    CHNEXT        ; 6 = Chain External
  265.     DEFW    ENTRPOINT    ; 7 = Entry Point
  266.     DEFW    UNDEF1        ; 8 = (undefined)
  267.     DEFW    EXTOFF        ; 9 = External + offset
  268.     DEFW    DATSIZ        ; 10 = Data Size
  269.     DEFW    LODLOC        ; 11 = Load Location
  270.     DEFW    CHNADDR        ; 12 = Chain Address
  271.     DEFW    PRGSIZ        ; 13 = Program Size
  272.     DEFW    FINI        ; 14 = End of Program
  273.     DEFW    FINI        ; 15 = Module End
  274.  
  275. ; End of activity, so wind it up and exit.
  276.  
  277. FINI:    BIT    3,(IY+0)    ; Are we generating a Bit Map?
  278.     JR    Z,FINI0A    ; ..jump if not
  279.  
  280.     LD    A,(COUNT)    ; Else do we have any Map Bits left?
  281.     OR    A
  282.     JR    Z,FINI0        ; ..jump if not
  283. FINLOP:    OR    A        ; Insure Zero bit shifted
  284.     RL    E        ; ..to fill last byte
  285.     INC    A        ; Bump map bit count
  286.     CP    8        ; End of a byte yet?
  287.     JR    C,FINLOP    ; ..loop if not
  288.     LD    HL,(BITMAP)    ; Save the final Map Byte
  289.     LD    (HL),E
  290.     INC    HL        ; ..and bump last byte pointer
  291.     LD    (BITMAP),HL    ; Save highest byte address
  292. FINI0:    CALL    PRT007
  293.     DEFB    CR,LF,'Bit Map begins @ ORG + $'
  294. PRT007:    POP    DE
  295.     CALL    PRTMSG        ; Print Start of Map message
  296. FINI0A:    LD    DE,(PROGSZ)    ; Calculate CSEG+DSEG size
  297.     LD    HL,(DATASZ)
  298.     ADD    HL,DE
  299.     BIT    3,(IY+0)    ; Are we generating a map?
  300.     JR    Z,SMALL        ; ..jump if not to save just CSEG+DSEG
  301.     CALL    PRTHEX        ; Else Print 16-bit Hex value
  302.     LD    HL,(BITMAP)    ; Get ending address
  303.     DEC    H        ; ..compensating for Size Page
  304.     LD    DE,OUTFIL    ; Now get starting addr
  305.     OR    A
  306.     SBC    HL,DE        ; Calculate size
  307.     CALL    PRT008
  308.     DEFB    CR,LF,'Bit Map ends @ ORG + $'
  309. PRT008:    POP    DE
  310.     CALL    PRTMSG        ; Print Map Ending message..
  311.     CALL    PRTHEX        ; ..and HEX address
  312.     INC    H        ; ..(correcting size for save)
  313. SMALL:    LD    A,L        ; Check for partial page
  314.     AND    7FH
  315.     PUSH    AF        ; ..save result in Z flag
  316.  
  317. ; Divide HL by 128.  This code is shorter than 7 shifts right
  318. ; with Zero fill.
  319.  
  320.     RL    L        ; MSB of L to carry flag
  321.     LD    L,H        ; Move high byte to low
  322.     LD    H,0        ; ..and null high byte
  323.     ADC    HL,HL        ; Shift all left, carry to LSB of L
  324.  
  325.     POP    AF        ; Return partial page flag (Z)
  326.     JR    Z,SMALL0    ; ..jump if no partial page
  327.     INC    HL        ; Else compensate by bumping count
  328. SMALL0:    LD    C,L        ; Move sector count to BC
  329.     LD    B,H
  330.     CALL    WRITEIT        ; Write the file to disk
  331.     LD    DE,FCB
  332.     LD    C,CLOSEF    ; ..and close it
  333.     CALL    BDOS
  334.     INC    A
  335.     JR    NZ,FINI2    ; Jump if Close OK
  336.     CALL    PRT009        ; ..else print error message
  337.     DEFB    CR,LF,'Cannot Close .PRL file !',BELL,CR,LF,'$'
  338. PRT009:    POP    DE
  339.     CALL    PRTMSG
  340. FINI2:    JP    0000H        ; Quit with warm boot
  341.  
  342.  
  343. ENTRY:    PUSH    DE        ; Print entry name(s) when found
  344.     CALL    PTEXIT
  345.     DEFB    'Entry point    : $'
  346.  
  347. COMNAM:    PUSH    DE        ; Print common block when found
  348.     CALL    PTEXIT
  349.     DEFB    'Common name    : $'
  350.  
  351. PGNAME:    PUSH    DE        ; Print program name when found
  352.     CALL    PTEXIT
  353.     DEFB    CR,LF,'Program Name    : $'
  354.  
  355. SEARCH:    PUSH    DE        ; Print library to search
  356.     CALL    PTEXIT
  357.     DEFB    'Search Library    : $'
  358.  
  359. UNDEF0:    PUSH    DE        ; Print reserved error if found
  360.     CALL    PTEXIT
  361.     DEFB    CR,LF,'UNDEFINED    : $'
  362. PTEXIT:    POP    DE        ; Restore string start addr
  363.     CALL    PRTMSG        ; .and print the string
  364.     POP    DE
  365.     CALL    PNAME        ; ..followed by item name
  366.     JP    SZEXIT        ; ...and size/address
  367.  
  368. ; Define COMMON if found
  369.  
  370. COMMON:    CALL    GET16        ; Get the value
  371.     PUSH    DE        ; While temp has value
  372.     CALL    ABVCTR        ; ..print label & name
  373.     DEFB    'COMMON        : $'
  374. ABVCTR:    POP    DE        ; Restore string start addr
  375.     CALL    PRTMSG
  376.     CALL    PNAME        ; Print item name
  377.     CALL    PRT010
  378.     DEFB    ' = $'
  379. PRT010:    POP    DE
  380.     CALL    PRTMSG        ; ..and equate string
  381.     POP    DE
  382.     CALL    PRT16        ; Now print value
  383.     LD    HL,(TEMP)    ; Get common address
  384.     LD    (COMMAD),HL    ; ..and save it
  385.     JP    VECTOR
  386.  
  387. ; List external chain references when found
  388.  
  389. CHNEXT:    CALL    GET16        ; Get the address
  390.     PUSH    DE        ; While temp has value
  391.     CALL    ABVCTR        ; Go print label name & value
  392.     DEFB    'Chain EXTERNAL    : $'
  393.  
  394. ; List entry points when found
  395.  
  396. ENTRPOINT:
  397.     CALL    GET16        ; Get the address
  398.     PUSH    DE        ; While temp has value
  399.     CALL    ABVCTR        ; Go print label name & value
  400.     DEFB    'Entry Point    : $'
  401.  
  402. ; Print A & B error if found
  403.  
  404. UNDEF1:    CALL    GET16        ; Get address
  405.     PUSH    DE        ; Print label & name
  406.     CALL    ABVCTR        ; Go print label name & value
  407.     DEFB    'Undefined !!!    : $'
  408.  
  409. ; Print External + Offset if found
  410.  
  411. EXTOFF:    PUSH    DE
  412.     CALL    CHNAD0        ; Print message
  413.     DEFB    'External + Offset = $'
  414.  
  415. ; Print Chain Address if found
  416.  
  417. CHNADDR: PUSH    DE
  418.     CALL    CHNAD0
  419.     DEFB    'Chain Address    = $'
  420. CHNAD0:    POP    DE
  421.     CALL    PRTMSG        ; Print the addressed message
  422.     POP    DE
  423.     CALL    PVAL        ; ..and its value
  424.     JR    SZEXIT
  425.  
  426. ; Print data area size when found
  427.  
  428. DATSIZ:    PUSH    DE
  429.     CALL    PRT011
  430.     DEFB    'Data Area Size    : $'
  431. PRT011:    POP    DE
  432.     CALL    PRTMSG        ; Print the text message
  433.     POP    DE
  434.     CALL    PVAL        ; ..and the value/address
  435.     LD    (DATASZ),HL
  436.     SET    0,(IY+0)    ; Show data area OK
  437.     JR    SZEXIT
  438.  
  439. ; Print program size when found
  440.  
  441. PRGSIZ:    PUSH    DE
  442.     CALL    PRT012
  443.     DEFB    'Program Size    : $'
  444. PRT012:    POP    DE
  445.     CALL    PRTMSG        ; Print the text message
  446.     POP    DE
  447.     CALL    PVAL        ; ..and its value
  448.     LD    (PROGSZ),HL
  449.     SET    1,(IY+0)    ; Show data area OK
  450. SZEXIT:    CALL    SETSTAT
  451. VECTOR:    CALL    CRLF        ; Wind up on a new line
  452.     JP    LOOP
  453.  
  454. ; Print load location when found
  455.  
  456. LODLOC:    CALL    GET16        ; Get a 16-bit address
  457.     LD    (LODPTR),HL    ; ..store
  458.     BIT    7,(IY+0)    ; Is this first reference?
  459.     JR    NZ,LOD1        ; ..jump if not, only print 1st Load
  460.     BIT    3,(IY+0)    ; Is this a PRL operation?
  461.     JR    Z,LOD1        ; ..jump and don't print if .COM
  462.     PUSH    DE
  463.     CALL    PRT013
  464.     DEFB    'Load Location    : $'
  465. PRT013:    POP    DE
  466.     CALL    PRTMSG        ; Else Print Load Location msg
  467.     CALL    PRT16        ; ..and 16-bit value
  468.     POP    DE
  469.     CALL    CRLF        ; Move to a new line
  470. LOD1:    JP    CHECKLOAD    ; Pad to location with Nulls
  471.  
  472. ;.....
  473. ; Subroutine for name/value retrieval
  474.  
  475. PNAME:    LD    D,3        ; Get char count
  476.     XOR    A
  477.     CALL    GBITS        ; Assemble 3-bits for count
  478.     OR    A        ; Is it 0 for 8 chars?
  479.     JR    NZ,PNAME0    ; ..jump if not
  480.     LD    A,8        ; Else set to desired eight
  481. PNAME0:    LD    D,A        ; Move cc to counter
  482. PNAME1:    PUSH    DE        ; Get & print 1 char
  483.     LD    D,8        ; ..8 bits/char
  484.     CALL    GBITS
  485.     CALL    PRINTC        ; Print it
  486.     POP    DE
  487.     DEC    D
  488.     JR    NZ,PNAME1    ; Go back for more
  489.     RET
  490.  
  491. PVAL:    CALL    GET16        ; Get 16 bit value
  492. PRT16:    LD    HL,(TEMP)    ; Retrieve 16-bit value
  493. PRTHEX:    LD    A,H
  494.     CALL    HEXOUT        ; Print hi-byte in HEX..
  495.     LD    A,L
  496.     JP    HEXOUT        ; ..then lo-byte and quit
  497.  
  498. ;-------------------------------------------------------------
  499. ;  L o w e r - l e v e l    B i t    M a n i p u l a t i o n
  500. ;-------------------------------------------------------------
  501.  
  502. ; Get a bit from the input file, reading disk file as necessary
  503.  
  504. GETBIT:    RL    C        ; Rotate byte for test
  505.     DJNZ    READX        ; ..jump if new byte not necessary
  506.  
  507. ; Need another byte from the file, so fall thru..
  508.  
  509. READ:    PUSH    AF        ; Set up addresses and
  510.     PUSH    DE        ; ..read a byte
  511.     LD    A,(INPTR)    ; Check pointer for disk read
  512.     CP    128
  513.     CALL    NC,DISKRD    ; Read disk if pointer > 127
  514.     LD    E,A        ; Set pointer for offset
  515.     LD    D,0
  516.     LD    HL,BUFF        ; Start from base
  517.     ADD    HL,DE
  518.     INC    A        ; Bump pointer
  519.     LD    (INPTR),A    ; ..and save
  520.     LD    C,(HL)        ; Get a byte
  521.     LD    B,8        ; ..and set counter
  522.     POP    DE
  523.     POP    AF
  524. READX:    BIT    7,C        ; Set Zero flag to MSB of subject byte
  525.     RET
  526.  
  527. ; Accumulate 16-bits from input file as pointer.
  528. ;  EXIT: Variable TEMP contains 16-bit value
  529.  
  530. GET16:    XOR    A
  531.     LD    D,2        ; Get number type
  532.     CALL    GBITS        ; ..but don't do anything with it
  533.     LD    (TYPLOD),A    ; Save load type
  534. ADDR16:    CALL    GETBYT        ; Get low byte
  535.     EX    AF,AF'        ; ..and temporarily save
  536.     CALL    GETBYT        ; Now get hi byte
  537.     LD    H,A        ; Prepare to save 16-bit value & return
  538.     EX    AF,AF'        ; Get Low byte back
  539.     LD    L,A
  540.     LD    (TEMP),HL    ; Save the Word if needed
  541.     RET
  542.  
  543. ;.....
  544. ; Output a byte with a 1 Map Bit
  545.  
  546. BYTE1V:    SCF            ; Set Carry flag for 1 in Bit Map
  547.     JR    CHKWRT        ; ..and do it
  548.  
  549. ;.....
  550. ; Accumulate 8 bits into a byte and output with a 0 Map Bit
  551.  
  552. BYTE0:    CALL    GETBYT        ; Gather 8 bits into a byte
  553. BYTE0V:    OR    A        ; Reset varry for 0 in Bit Map
  554.             ;..fall thru to..
  555. ;.....
  556. ; Check for output write status on Map Bit
  557. ;  Carry Flag unaffected until shifted into E Register
  558.  
  559. CHKWRT:    BIT    2,(IY+0)    ; Check ok-to-load
  560.     JR    Z,CHKWR2    ; ..Error if flag = 0
  561.  
  562.     LD    (IX+0),A    ; Save Code byte
  563.     INC    IX        ; ..and bump code pointer
  564.  
  565.     PUSH    HL        ; Preserve regs
  566.     LD    HL,(PCNTR)
  567.     INC    HL        ; Increment Pseudo-Program Counter
  568.     LD    (PCNTR),HL
  569.  
  570.     RL    E        ; Rotate Map from Carry into E
  571.     LD    HL,COUNT
  572.     INC    (HL)        ; Bump count..
  573.     BIT    3,(HL)        ; ..check = 8?
  574.     JR    Z,CHKWR1    ; Exit if < 8
  575.     LD    (HL),0        ; ..else reset counter to 0
  576.     LD    HL,(BITMAP)    ; Write 8 Map bits out
  577.     LD    (HL),E
  578.     INC    HL        ; ..bumping address
  579.     LD    (BITMAP),HL
  580.     LD    E,0        ; Preset next map byte to 0
  581. CHKWR1:    POP    HL        ; Restore regs
  582.     RET
  583.  
  584. CHKWR2:    CALL    ERRV        ; Print message & Abort
  585.     DEFB    CR,LF,BELL,'Write attempt before areas sized !$'
  586.  
  587. ;.....
  588. ; Get 4-bit designator for Special Link Type
  589.  
  590. GETTYP:    LD    D,4        ; Get type of spec link
  591.     XOR    A        ; ..into A register
  592.     JR    GBITS        ; Jump to do the work
  593.  
  594. ;.....
  595. ; Get 8-bit byte into the accumulator
  596.  
  597. GETBYT:    LD    D,8        ; 8 bits to a byte
  598. GBITS:    CALL    GETBIT        ; Get one of the little buggers
  599.     SCF            ; Prepare to shift in "1" bit
  600.     JR    NZ,GBITS0    ; ..jump if MSB is a "1"
  601.     CCF            ; Else complement carry for "0" bit
  602. GBITS0:    RLA            ; Rotate bit into accumulator
  603.     DEC    D        ; Count down number of loops
  604.     JR    NZ,GBITS    ; ..and continue til no more bits
  605.     RET
  606.  
  607. ;.....
  608. ; Compare new load location with internal counter and
  609. ;  fill bit map with 0 to new location
  610.  
  611. CHECKLOAD:
  612.     PUSH    HL
  613.     PUSH    BC        ; Save registers
  614.     PUSH    DE
  615.     LD    HL,(LODPTR)    ; Get new load address
  616.     LD    A,(TYPLOD)    ; Check type of load
  617.     CP    2        ; Type 1 = prog seg.
  618.     JR    C,CHECK2
  619.     JR    Z,CHECK1    ; Type 2 = data seg.
  620.     LD    DE,(DATASZ)    ; Must be common
  621.     ADD    HL,DE
  622. CHECK1:    LD    DE,(PROGSZ)    ; Data area starts at end of prog.
  623.     ADD    HL,DE
  624. CHECK2:    SET    7,(IY+0)    ; Set to show not init load
  625.     LD    DE,(PCNTR)    ; Get internal location
  626.     OR    A
  627.     SBC    HL,DE        ; Now we have the difference
  628.     POP    DE        ; Restore output byte
  629. CHECK0:    LD    A,H        ; Ready for exit?
  630.     OR    L
  631.     JR    Z,CHECKEND
  632.     CALL    BYTE0V        ; Write a zero & increment IX
  633.     DEC    HL
  634.     JR    CHECK0        ; ..back for more
  635.  
  636. CHECKEND:
  637.     POP    BC        ; Restore registers
  638.     POP    HL
  639.     JP    LOOP        ; ..and start again
  640.  
  641. ;  Check status of area set flags.  If Program and Data areas are sized,
  642. ;  Set OK-to-Load flag, and load registers and pointers
  643.  
  644. SETSTAT: BIT    0,(IY+0)    ; Data size set?
  645.     RET    Z        ; ..Ret if not
  646.     BIT    1,(IY+0)    ; Program size set?
  647.     RET    Z        ; ..Ret if not
  648.     SET    2,(IY+0)    ; Ready, so set ok-to-load
  649.     PUSH    HL        ; Save registers
  650.     PUSH    DE
  651.     EXX            ; Store in alternage regs
  652.     LD    BC,(ORGADR)    ; Set program 'ORG'
  653.     LD    HL,(PROGSZ)
  654.     ADD    HL,BC
  655.     EX    DE,HL        ; Data 'ORG' in de
  656.     EXX            ; Now back again
  657.     LD    DE,(PROGSZ)    ; Calculate combined CSEG/DSEG size
  658.     LD    HL,(DATASZ)
  659.     ADD    HL,DE
  660.     BIT    3,(IY+0)    ; Are we doing a PRL link?
  661.     JR    Z,SETST0    ; ..jump if not
  662.     LD    (IX+1),L    ; Else save size in output file Page 0
  663.     LD    (IX+2),H
  664.     LD    IX,OUTFIL+100H    ; ..and Reset output to Page 1 for code
  665.     LD    DE,100H        ; Increase size for PRL header page
  666.     ADD    HL,DE
  667. SETST0:    LD    DE,OUTFIL    ; Calculate start of bit map
  668.     ADD    HL,DE
  669.     LD    (BITMAP),HL
  670.     POP    DE        ; Restore registers
  671.     POP    HL
  672.     RET
  673.  
  674. ;---------------------------------------------------------------;
  675. ;    C P / M      I n t e r f a c e      R o u t i n e s    ;
  676. ;---------------------------------------------------------------;
  677.  
  678. ; Open a disk file specified in the File Control Block
  679. ;  Print error and abort to CP/M if unable to open.
  680.  
  681. OPENFILE:
  682.     LD    DE,FCB        ; Open file whose name is
  683.     LD    C,OPENF        ; ..in FCB
  684.     CALL    BDOS
  685.     CP    0FFH        ; Good open?
  686.     RET    NZ        ; ..return if so
  687.     CALL    ERRV        ; Print message and finish
  688.     DEFB    '++ Cannot Open File ++',CR,LF,BELL,'$'
  689.  
  690. ; Read a 128-byte sector into the program buffer from the file
  691. ; specified in the FCB.
  692. ;   Print error message and abort to CP/M if error in reading.
  693.  
  694. DISKRD:    LD    DE,BUFF        ; Read a sector into input buffer
  695.     LD    C,SETDMA
  696.     CALL    BDOS        ; Set DMA address to buffer area
  697.     LD    C,READSQ
  698.     LD    DE,FCB        ; ..and read a sector
  699.     CALL    BDOS
  700.     OR    A        ; Good read?
  701.     RET    Z        ; ..return to caller if good
  702.     JR    WRTERR        ; Else print msg and abort
  703.  
  704. WRITEIT: PUSH    BC        ; Save count
  705.     BIT    3,(IY+0)    ; Is this a .COM file?
  706.     LD    HL,COMTYP    ; .get set
  707.     JR    Z,WRTGO        ; ..jump if .COM
  708.     LD    HL,PRLTYP    ; No, must be .PRL
  709. WRTGO:    CALL    MOVTYP
  710.     EX    DE,HL
  711.     LD    B,24        ; Clear 24 places in FCB
  712. WR0:    LD    (HL),0        ; ..to Zero
  713.     INC    HL
  714.     DJNZ    WR0
  715.     LD    DE,FCB        ; Point to the File Control Block
  716.     PUSH    DE
  717.     LD    C,DELF        ; ..and kill any old copies
  718.     CALL    BDOS
  719.     POP    DE
  720.     LD    C,MAKEF        ; Make new file
  721.     CALL    BDOS
  722.     POP    BC        ; Restore count
  723.     INC    A        ; Was Make ok?
  724.     JR    Z,MAKERR
  725.     LD    DE,128        ; Set block size
  726.     LD    HL,OUTFIL    ; Get start address
  727. WRTLOP:    LD    A,B        ; Check count for end
  728.     OR    C
  729.     RET    Z
  730.     PUSH    HL        ; Save registers
  731.     PUSH    DE
  732.     PUSH    BC
  733.     EX    DE,HL
  734.     LD    C,SETDMA    ; Set transfer addr
  735.     CALL    BDOS
  736.     LD    DE,FCB
  737.     LD    C,WRITSQ    ; Write a sector
  738.     CALL    BDOS
  739.     OR    A        ; Were there any errors?
  740.     JR    NZ,WRTERR    ; ..jump if so
  741.     POP    BC        ; Restore registers
  742.     POP    DE
  743.     POP    HL
  744.     DEC    BC        ; Decrease block counter
  745.     ADD    HL,DE        ; Set next block address
  746.     JR    WRTLOP
  747.  
  748. WRTERR:    CALL    ERRV
  749.     DEFB    CR,LF,'++ ERROR writing file ++',BELL
  750.     DEFB    CR,LF,'...Aborting !$'
  751. ERRV:    POP    DE        ; Restore message address
  752.     CALL    PRTMSG        ; Print error message
  753.     JP    FINI2
  754.  
  755. MAKERR:    CALL    ERRV        ; Say that we have Creation Problems
  756.     DEFB    CR,LF,BELL,'Directory Full - Abort !$'
  757.  
  758. NONAME:    CALL    ERRV        ; No name in FCB
  759.     DEFB    CR,LF,'No File Name !',CR,LF,BELL,'$'
  760.  
  761. ;.....
  762. ; Set character count in 'A' to keyboard buffer
  763. ; max length and get up to that many characters
  764. ;   ENTER: A has maximum buffer length
  765. ;   EXIT:  HL points to 1st char in buffer
  766.  
  767. GETINP:    LD    DE,BUFF
  768.     PUSH    DE        ; Save address
  769.     LD    (DE),A
  770.     LD    C,RDSTR
  771.     CALL    BDOS        ; Get the string
  772.     POP    HL        ; ..restore the pointer
  773.     INC    HL
  774.     INC    HL        ; ...to the 1st char
  775.     RET
  776.  
  777. ; Print message addressed by DE to console
  778. ;  Preserve BC and HL registers
  779.  
  780. PRTMSG:    PUSH    HL        ; Preserve registers
  781.     PUSH    BC
  782.     LD    C,PTSTR        ; Write string w/BDOS function
  783.     CALL    BDOS
  784.     POP    BC        ; ..restore regs
  785.     POP    HL
  786.     RET
  787.  
  788. ; Print character in A-register to Console
  789. ;  Preserve BC and HL register pairs
  790.  
  791. PRINTC:    PUSH    HL        ; Preserve registers
  792.     PUSH    BC
  793.     LD    E,A
  794.     LD    C,CONOUT    ; Print with BDOS function
  795.     CALL    BDOS
  796.     POP    BC        ; ..restore regs
  797.     POP    HL
  798.     RET
  799.  
  800. ;-------------------------------------------------------;
  801. ;    U T I L I T Y    S u b r o u t i n e s        ;
  802. ;-------------------------------------------------------;
  803.  
  804. MOVTYP:    LD    DE,FCB+9    ; Load 3 byte filetype
  805.     LD    BC,3        ; ..to FCB
  806.     LDIR
  807.     RET
  808.  
  809. ;.....
  810. ; Convert 'B' bytes in string addressed by DE to binary in HL.
  811. ;  RETURN:  Zero flag set = Ok.
  812.  
  813. GETNUM:    LD    A,(DE)        ; Get a character
  814.     CALL    UPPER        ; ..in uppercase
  815.     CALL    CV2BIN        ; Convert to Binary
  816.     JR    C,GETERR    ; ..going error if not digit
  817.     PUSH    DE
  818.     LD    E,A
  819.     LD    D,0
  820.     ADD    HL,HL        ; Multiply by 16
  821.     ADD    HL,HL
  822.     ADD    HL,HL
  823.     ADD    HL,HL
  824.     ADD    HL,DE        ; ..add in new digit
  825.     POP    DE
  826.     INC    DE
  827.     DJNZ    GETNUM
  828.     RET            ; Zero set if ok
  829.  
  830. GETERR:    OR    0FFH        ; Set error return status
  831.     RET
  832.  
  833. ;.....
  834. ; Convert character in 'A' to uppercase
  835.  
  836. UPPER:    CP    'a'        ; Is it Less than "a"?
  837.     RET    C        ; ..quit if so
  838.     CP    'z'+1        ; Less than "z"+1?
  839.     RET    NC        ; ..Return if not
  840.     AND    5FH        ; Else convert lower to uppercase
  841.     RET
  842.  
  843. ;.....
  844. ; Convert ascii char in 'A' to Hex.  Return carry
  845. ;  RETURN: Carry set = invalid hex digit.
  846. ;       Carry clear = legal Hex digit
  847.  
  848. CV2BIN:    SUB    '0'        ; Subtract number bias
  849.     RET    C        ; ..return if bad
  850.     CP    10        ; Is it in 0..9?
  851.     CCF
  852.     RET    NC        ; ..return if so w/Carry Clear
  853.     SUB    7        ; A-F?
  854.     CP    10
  855.     RET    C        ; ..return Carry set if not
  856.     CP    16        ; Less than "G"?
  857.     CCF            ; ..return w/Carry Clear if so
  858.     RET
  859.  
  860. ;.....
  861. ; Write CRLF sequence to Console
  862. ;  Preserve BC, DE, and HL register pairs
  863.  
  864. CRLF:    PUSH    HL        ; Save registers
  865.     PUSH    DE
  866.     PUSH    BC
  867.     LD    A,CR
  868.     CALL    PRINTC        ; Send a Carriage Return
  869.     LD    A,LF
  870.     CALL    PRINTC        ; ..and Line Feed
  871.     POP    BC        ; Restore regs
  872.     POP    DE
  873.     POP    HL
  874.     RET
  875.  
  876. ;.....
  877. ; Print character in A-register to Console as two Hex digits
  878. ;  Preserve all registers
  879.  
  880. HEXOUT:    PUSH    HL        ; Preserve registers
  881.     PUSH    DE
  882.     PUSH    BC
  883.     PUSH    AF
  884.     RRCA            ; Move Hi Nybble to Low
  885.     RRCA
  886.     RRCA
  887.     RRCA
  888.     CALL    HEXDIG        ; ..Print Nybble as Hex digit
  889.     POP    AF        ; Restore Low Nybble
  890.     CALL    HEXDIG        ; ..and print as Hex digit
  891.     POP    BC
  892.     POP    DE
  893.     POP    HL
  894.     RET
  895.  
  896. HEXDIG:    AND    0FH        ; Print '0'-'9', 'A'-'F'
  897.     ADD    A,90H
  898.     DAA
  899.     ADC    A,40H
  900.     DAA
  901.     JR    PRINTC
  902.  
  903. ;.....
  904. ; File Type fields for Input/Output Names
  905.  
  906. RELTYP:    DEFB    'REL'
  907. COMTYP:    DEFB    'COM'
  908. PRLTYP:    DEFB    'PRL'
  909.  
  910. ;-------------------------------------------------------;
  911. ;    V A R I A B L E        S T O R A G E        ;
  912. ;-------------------------------------------------------;
  913.     DSEG            ; Put data in the right segment
  914.  
  915.     DEFS    64        ; Room for stack
  916. STACK:    DEFS    2        ; Storage for entry stack
  917. TEMP:    DEFS    2        ; Temporary working storage
  918. COMMAD:    DEFS    2        ; Start address of COMMON area
  919. COMMSZ:    DEFS    2        ; COMMON size
  920. PROGSZ:    DEFS    2        ; PROGRAM size
  921. DATASZ:    DEFS    2        ; DATA size
  922. COUNT:    DEFS    1        ; Output bit count
  923. BITMAP:    DEFS    2        ; Bit map address
  924. PCNTR:    DEFS    2        ; Program relative counter
  925. LODPTR:    DEFS    2        ; Load location storage
  926. TYPLOD:    DEFS    1        ; Type of load operation
  927. FLAGS:    DEFS    1        ; Flags for operations:
  928.                 ; B7 - 0 = no load loc set
  929.                 ;  3 - 0 = COM (No Map), 1 = PRL (Map)
  930.                 ;  2 - 1 = OK to load
  931.                 ;  1 - 0 = No pgm size set
  932.                 ;  0 - 0 = No data size set
  933. ORGADR:    DEFS    2        ; Address to 'ORG'
  934. INPTR:    DEFS    1        ; Input pointer to next byte
  935.  
  936. OUTFIL:                ; ++ Assembled code starts here ++
  937.  
  938.     END
  939.