home *** CD-ROM | disk | FTP | other *** search
- ;UNLOAD.MAC - A program to turn COM files into HEX.
- ; Disassembled and commented by Ted Harper
- ;
- .Z80
- ;
- BDOS EQU 0005
- InFCB EQU 005Ch
- InputFileName EQU 005Dh
- InFCBExt EQU 0065h ;Location of .EXT part of name of input file
- InFCBExtent EQU 0068h ;Location where current file extent is stored
- InFCBRecCount EQU 006Ah ;Location where current record count is held
- InFCBD0 EQU 006Dh ;Location of D0 byte in input FCB
- InFCBCurrRecNum EQU 007Ch ;Current record number
- TPAStart equ 0100h
- ;
- CR equ 0Dh ;ASCII character equates
- LF equ 0Ah
- ;
- ; BDOS functions
- ;
- BDOSPrintString equ 09
- BDOSOpenFile equ 0Fh
- BDOSCloseFile equ 10h
- BDOSDeleteFile equ 13h
- BDOSReadSector equ 14h
- BDOSWriteSector equ 15h
- BDOSMakeFile equ 16h
- BDOSSetDMA equ 1Ah
- ;
- aseg
- org 0100h
- ;
- CALL Start
- DB 'UNLOAD Version 2.03'
- DB 0Dh,0Ah
- DB '$'
- ;
- Start:
- POP DE ;Restore pointer to message
- LD (StackPtrSave),SP ;Save entry stack pointer
- LD SP,LocalStackTop ;Set up local stack
- ;
- LD C,BDOSPrintString ;Print signon message above
- CALL BDOS
- ;
- CALL CheckInputFiletype ;Check the filetype for the input
- ;file and return start address
- ;
- PUSH HL ;Save start address of output file
- ;
- LD HL,InFCB ;Move "FILENAME" part of filename to output
- LD DE,OutFCB ;FCB
- LD BC,0009 ;9 bytes to move
- LDIR
- ;Move "HEX" to "ext" part of filename in output FCB
- LD HL,OutFileType ;Move "HEX" to ".EXT" part of filename in
- LD DE,OutFCBExt ;output FCB
- LD BC,0003 ;3 bytes to move
- LDIR
- ;
- CALL OpenInputFile ;Open both the input and output files
- CALL OpenOutputFile
- ;
- LD B,08 ;Output the "filename" part of the filename
- LD HL,InputFileName ;to the hex file (8 characters)
- OutputFNLoop:
- LD A,(HL)
- CALL OutputCharToHEXFile
- INC HL
- DJNZ OutputFNLoop
- ;
- CALL OutputCRLFtoHEXFile ;Output CR and LF to HEX file
- ;
- POP HL ;Restore start address of output file
- ;
- Unload32Bytes:
- ;This code writes one "line" of the HEX file out. It
- ;usually consists of a colon, then the address of
- ;the start of the line, then 32 hex numbers, then
- ;a checksum. It ends with a CR+LF pair
- ;
- LD B,32 ;Set loop index to 32 bytes to process
- ;
- LD A,':' ;Start each line with a ':'
- CALL OutputCharToHEXFile
- ;
- CALL GetAByteFromInput ;Read a byte in from the COM file
- JR C,InputEOFReached ;Carry is set if last byte done
- PUSH AF
- LD C,00 ;Initialise checksum to 00
- ;
- LD A,B ;Output 20h (number of bytes this line)
- CALL Output2HexNibbles
- ;
- LD A,H ;Output start address for this line
- CALL Output2HexNibbles
- LD A,L
- CALL Output2HexNibbles
- ;
- XOR A ;Output a zero after the address
- CALL Output2HexNibbles
- ;
- POP AF ;Restore the first byte read
- JR Proc32ByteEntry ;Enter the processing loop
-
- ;The following loop outputs the next 32 bytes from
- ;the input file as hex numbers in ascii format.
- ;
- Proc32ByteLoop:
- CALL GetAByteFromInput ;Read a byte from the input file
- ;
- Proc32ByteEntry:
- CALL Output2HexNibbles ;Output the byte in A in hex.
- INC HL ;Bump index to next byte
- DJNZ Proc32ByteLoop ;Loop to process 32 bytes
- ;
- ;Now the checksum must be output. It was maintained
- ;in the C-reg during the above processing loop.
- ;
- LD A,C ;Put the checksum into the acc.
- NEG ;Invert all bits??
- CALL Output2HexNibbles ;Output it to the HEX file
- ;
- CALL OutputCRLFtoHEXFile ;Finish each line with CR+LF pair
- ;
- JR Unload32Bytes ;Loop back to process another 32 bytes
- ;
- InputEOFReached:
- ;Finish off by writing 5 zero bytes to the hex file
- ;
- LD B,5 ;Finish off by writing 5 '0' bytes to hex file
- OutputZerosLoop:
- XOR A
- CALL Output2HexNibbles
- DJNZ OutputZerosLoop
- ;
- CALL OutputCRLFtoHEXFile ;Finish off with CR+LF
- ;
- CALL CloseOutputFile ;Write some ^Z's to output & close up
- ;
- LD SP,(StackPtrSave) ;Restore stack pointer and return to CP/M
- ;
- RET
- ;
- PrintAndExit:
- LD C,BDOSPrintString ;Print a message (DE points to it)
- CALL BDOS
- JP 0000 ;and warm boot to CP/M
- ;
- OutputCRLFtoHEXFile:
- LD A,CR ;Write a CR and an LF to the hex file
- CALL OutputCharToHEXFile
- LD A,LF
- JP OutputCharToHEXFile
- ;
- Output2HexNibbles:
- ;Output the character in A as two ASCII hex nibbles
- PUSH AF
- ADD A,C
- LD C,A
- POP AF
- PUSH AF
- RRCA
- RRCA
- RRCA
- RRCA
- CALL OutputANibble
- POP AF
- OutputANibble:
- AND 0Fh
- ADD A,90h
- DAA
- ADC A,'@'
- DAA
- JP OutputCharToHEXFile
- ;
- AddAtoHL:
- ;Adds the value in A to that in HL
- ADD A,L
- LD L,A
- RET NC
- INC H
- RET
- ;
- CheckInputFiletype:
- LD DE,InFCBD0
- LD HL,0000
- ;
- LD A,(InFCBExt) ;Check the first byte of input filename ".EXT"
- AND 7Fh ;Mask the attribute bit off
- CP 'C' ;Is it a 'C'
- JR NZ,NotCOM ;If not, things get more difficult
- ;
- LD A,(InFCBExt+1) ;Check if second byte is 'O' in same manner
- AND 7Fh
- CP 'O'
- JR NZ,NotCOM
- ;
- LD A,(InFCBExt+2) ;Check if third byte is 'M' in same manner
- AND 7Fh
- CP 'M'
- JR NZ,NotCOM
- ;
- LD HL,TPAStart ;It is a COM file so return HL = 100h
- ;
- NotCOM:
- ;The filetype is not COM, work a bit harder to get load address
- LD A,(DE)
- CP ' '
- RET Z
- LD HL,0000
- GrungeLoop1:
- LD A,(DE)
- INC DE
- SUB '0'
- RET C
- CP 0Ah
- JR C,LessThan10
- SUB 07
- CP 0Ah
- RET C
- CP 10h
- RET NC
- LessThan10:
- ADD HL,HL
- ADD HL,HL
- ADD HL,HL
- ADD HL,HL
- ADD A,L
- LD L,A
- JR GrungeLoop1
- ;
- OpenInputFile:
- LD HL,0000
- LD (InFCBExtent),HL ;Zero "current extent number"
- LD (InFCBRecCount),HL ;zero record count for extent
- XOR A ;Set "Current record to read" to zero
- LD (InFCBCurrRecNum),A
- ;
- ;Initialise counter to force sector read when first
- ;byte requested by main processing loop
- ;
- LD A,80h
- LD (BytesReadFromBuffer),A
- ;
- LD DE,InFCB ;Open the input file
- LD C,BDOSOpenFile
- CALL BDOS
- ;
- ;Return if file opened OK, otherwise exit with error msg
- LD DE,FileNotExistMsg ;Return if file opened OK, otherwise
- INC A ;exit with error message
- JP Z,PrintAndExit
- RET
- ;
- GetAByteFromInput:
- PUSH HL ;Save the current "work" pointer
- ;
- LD HL,InputDMABuffer
- LD A,(BytesReadFromBuffer) ;Find how many bytes we've used up
- INC A
- ;Result is +ve if < 128 (i.e. not all bytes used yet)
- JP P,InBufferNotExhausted
- ;
- PUSH BC ;No bytes left in buffer, read another sector
- PUSH DE
- PUSH HL
- ;
- EX DE,HL ;Set DMA address to input file buffer
- LD C,BDOSSetDMA
- CALL BDOS
- ;Read a sector from the input file into the DMA area
- LD DE,InFCB ;Read a sector from the input file into the
- LD C,BDOSReadSector ;DMA area
- CALL BDOS
- ;
- POP HL
- POP DE
- POP BC
- AND A
- LD A,1Ah ;Put a CTRL-Z into acc (just in case)
- ;
- SCF ;Set Carry flag and exit if EOF reached
- JR NZ,EOFInputReached
- ;
- XOR A ;EOF not reached, zero "bytes used" counter
- ;
- InBufferNotExhausted:
- LD (BytesReadFromBuffer),A ;Save number of bytes read from buffer
- CALL AddAtoHL ;Set HL to point to the right byte to get
- LD A,(HL) ;Get a byte out of the buffer
- AND A ;Set whatever flags
- ;
- EOFInputReached:
- POP HL ;Common exit point for this routine
- RET
- ;
- OpenOutputFile:
- LD HL,0000
- LD (OutFCBExtent),HL ;Zero "current extent" field in FCB
- LD (OutFCBRecCount),HL ;zero record count for extent
- XOR A ;Set "current record to write" to zero
- LD (OutFCBCurrRecNum),A
- ;
- LD (BytesHeldForOutput),A ;zero counter of "held" bytes
- ;
- LD DE,OutFCB ;Set DE to point to output FCB
- PUSH DE
- ;
- LD C,BDOSDeleteFile ;Delete the file if it exists
- CALL BDOS
- ;
- POP DE ;Make the file (like "rewrite" in Pascal)
- LD C,BDOSMakeFile
- CALL BDOS
- ;if BDOS returned FF, then couldn't find directory space
- LD DE,DirectoryFullMsg ;If BDOS returned 0FFh, then couldn't
- INC A ;make file, so exit
- JP Z,PrintAndExit ;otherwise just return
- RET
-
- OutputCharToHEXFile:
- ;Output a character to the HEX file being created.
- ;Actually, the routine holds 128 characters, then
- ;writes a whole sector when it needs to.
- PUSH HL
- PUSH AF
- ;Get address to store the byte in by adding the start
- ;address of the buffer to the number of bytes already
- ;held there.
- LD HL,OutputBuffer
- LD A,(BytesHeldForOutput)
- CALL AddAtoHL
- POP AF
- ;Save the byte in the output buffer
- LD (HL),A
- ;Add 1 to the tally of bytes held awaiting output
- LD A,(BytesHeldForOutput)
- INC A
- ;If a is +ve, then < 128 bytes are held, so sector is
- ;not full & doesn't need to be written
- JP P,OutputSectorNotFull
- ;Output buffer is full...write buffer to disk
- PUSH BC
- PUSH DE
- ;Set DMA address to output DMA area
- LD DE,OutputBuffer
- LD C,BDOSSetDMA
- CALL BDOS
- ;Write a sector to the output file
- LD DE,OutFCB
- LD C,BDOSWriteSector
- CALL BDOS
- ;Cancel program if error returned, otherwise continue
- LD DE,DiskFullMsg
- AND A
- JP NZ,PrintAndExit
- ;no write error, life can continue
- ;A contains zero here (conveniently), so doesn't need
- ;to be zeroed before saving as "held" count
- POP DE
- POP BC
- ;
- OutputSectorNotFull:
- ;Save the number of bytes held in the buffer
- LD (BytesHeldForOutput),A
- POP HL
- RET
- ;
- CloseOutputFile:
- ;Output a number of ctrl-Z characters to the output
- ;file until the current sector has been filled.
- OutputCtrlZLoop:
- LD A,1Ah ;^Z character (used as eof padding)
- CALL OutputCharToHEXFile
- AND A
- JR NZ,OutputCtrlZLoop
- ;Close the output file
- LD DE,OutFCB
- LD C,BDOSCloseFile
- CALL BDOS
- ;If 0FFh returned, close failed, so abort with error msg
- LD DE,FileNotExistMsg
- INC A
- JP Z,PrintAndExit
- RET
-
- DirectoryFullMsg:
- DB 'Directory Full$'
- DiskFullMsg:
- DB 'Disk Full$'
- FileNotExistMsg:
- DB 'File does not exist$'
- OutFileType:
- DB 'HEX'
- BytesReadFromBuffer:
- DB 0
- InputDMABuffer:
- DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
- DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
- DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
- DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
- ;
- OutFCB EQU 0388h
- OutFCBExt EQU 0391h
- OutFCBExtent EQU 0394h
- OutFCBRecCount EQU 0396h
- OutFCBCurrRecNum EQU 03A8h
- BytesHeldForOutput EQU 03A9h
- OutputBuffer EQU 03AAh
- StackPtrSave EQU 042Ah
- LocalStackTop EQU 046Ch
- ;
- END
- um EQU 03A8h
- BytesHeldForOutput EQU 03A