;************************************************************************ ;* * ;* UNLOAD86.A86 This is a MS-DOS unload program. See the help * ;* screen at the end of this file for details on its use. * ;* Written by: Mark D. Pickerill for Pro-Log Corp. 9 Aug. 1988 * ;* Assemble with the 2500 A.D. X8086 assembler. * ;* * ;************************************************************************ ; CR: EQU 0DH ; Carriage return LF: EQU 0AH ; Line feed EOF: EQU 1AH ; End of file ; CHIP 8086 ; 8086 mode ; ORG 0100H ; Start of tpa ; UNLOAD: JMP SHORT START ; Skip data area ; FILDAT: ; DB 0FFH ; Data to fill empty space in rom (if selected) BNPFTYP: ; DB 'PN' ; Pn for bnpf, hl for bhlf, or 10 for b10f FTYPE: ; DB '.HEX',00H ; File type FTYPE1: ; DB '.BNP',00H ; File type for bnpf files OUTTYPE: ; DB 00H ; 00 for hex, non-zero for bnpf USEEXT: ; DB 00H ; 00 for no extended address records DOFILL: ; DB 00H ; 00 not to fill to end of rom OVERRIDE: ; DB 00H ; Ff if overriding forced extended addressing ENDSEG: ; DW 0000H ; Space to store end segment for rom fill ENDADDR: ; DW 0000H ; Space to store end address for rom fill OOD: ; DB 00H ; Flag 0 for read from disk, ff to use fildat NOPARMS:JMP HELP ; Extend short jump ; START: PUSH CS ; Set data segment POP DS ; It's set PUSH DS ; Get this segment POP ES ; And set es as well CALL ILPRT ; Print signon message DB CR,LF,'UNLOAD86 ver. 1.2',00H MOV SI,0080H ; Point to parameter field in psp LODSB ; Get parameter length MOV CL,AL ; Into cl OR CL,CL ; Force flags JZ NOPARMS ; Print help screen MOV CH,00H ; Zero ch LOOP1: LODSB ; Get byte from parameter field CMP AL,' ' ; Space? LOOPZ LOOP1 ; Wait until you get a non-space char JZ NOPARMS ; Just spaces, print help screen CMP AL,'/' ; Switch char? JZ NOPARMS ; No filename!, print help screen CMP AL,'-' ; Alt switch for unix types JZ NOPARMS ; No filename!, print help screen CMP AL,'[' ; Alt switch for cp/m types JZ NOPARMS ; No filename!, print help screen LEA DI,INFN ; Point to input filename area STOSB ; Stuff this char LOOP2: LODSB ; Get byte CMP AL,' ' ; Space? JZ NOSP ; Yes,ignore CMP AL,'/' ; Or switch char? JZ SWITCH ; Yes CMP AL,'-' ; Alt switch for unix types JZ SWITCH ; Yes CMP AL,'[' ; Alt switch for cp/m types JZ SWITCH ; Yes STOSB ; Stuff char NOSP: LOOP LOOP2 ; Nope JMP SHORT CONT ; No more SWITCH: LODSB ; Get switch options AND AL,5FH ; Make upper case as ibm types ; Usualy use lower case! CMP AL,'B' ; Bnpf option? JZ SETBNPF ; Yes CMP AL,'O' ; Override forced extended address records? JZ SETOVR ; Yes CMP AL,'E' ; Use extended addressing? JZ SETEXT ; Yes CMP AL,'P' ; Set eprom type? JZ SETROM ; Yes LOOP SWITCH ; Look for more options JMP CONT ; No more ; SETOVR: XOR AL,AL ; Turn off extended addressing MOV [USEEXT],AL ; Do it DEC AL ; Indicate override of extended addressing MOV [OVERRIDE],AL ; Flag it as such LOOP SWITCH ; Look for more options JMP CONT ; No more ; SETEXT: MOV AL,0FFH ; Indicate use of extended addressing MOV [USEEXT],AL ; Flag it as such LOOP SWITCH ; Look for more options JMP CONT ; No more ; SETBNPF:MOV AL,0FFH ; Indicate bnpf option MOV [OUTTYPE],AL ; Set it ; LOOKMOR:LOOP SWITCH ; If more, look for additional options JMP CONT ; No more ; SETROM: DEC CX ; Decrement loop counter LODSB ; Get char CMP AL,'0' ; At least a zero? JC LOOKMOR ; No,ignore CMP AL,'A' ; At least an a? JC NUM ; Numeric AND AL,5FH ; Force upper case CMP AL,'G' ; More garbage? JNC LOOKMOR ; Yes, ignore SUB AL,37H ; Remove alpha bias JMP SHORT FOUNDIT ; And continue NUM: CMP AL,3AH ; Above numeric? JNC LOOKMOR ; Yes, ignore SUB AL,30H ; Remove numeric bias FOUNDIT:CMP AL,0CH ; Big rom? JC SMALL ; No CALL CHKOVR ; Unless user has overridden SMALL: PUSH SI ; Save pointer LEA SI,ATABLE ; Point to address table ADD AL,AL ; Multiply by two ADD AL,AL ; And by four XOR AH,AH ; Clear ah ADD SI,AX ; Add in offset LODSW ; Get segment address MOV [ENDSEG],AX ; Stuff it LODSW ; Get offset address MOV [ENDADDR],AX ; Stuff it MOV [DOFILL],BYTE PTR 0FFH ; Flag fillrom operation POP SI ; Restore si JMP LOOKMOR ; Go look for more options ; CONT: MOV [DI],BYTE PTR 00H ; Terminate string LEA SI,INFN ; Copy input to output fn LEA DI,OUTFN ; Pointing to output filename MOV CX,60D ; 64-4 for 'hex0' is 60 LOOP3: MOV AL,[SI] ; Get byte MOV [DI],AL ; Go ahead & move it INC SI ; Increment source INC DI ; And destination CMP AL,'.' ; Looking for that file extension JZ DONE ; Found the dot CMP AL,00H ; End? LOOPNZ LOOP3 ; Continue DONE: DEC DI ; Backup over dot or zero MOV CX,0005H ; Five bytes to move MOV AL,[OUTTYPE] ; Hex or bnpf? OR AL,AL ; Force flags JZ OHEX ; Hex LEA SI,FTYPE1 ; Point to file type for bnpf JMP SHORT ALL ; And continue OHEX: LEA SI,FTYPE ; Point to file type for hex ALL: REP MOVSB ; Move the rest ; MOV AL,00H ; Read access code MOV AH,3DH ; Open file function LEA DX,INFN ; Point to input file name INT 21H ; Open the file MOV [INHDL],AX ; Save handle JNC OK ; Ok CALL ILPRT ; Print this... DB CR,LF,'Failure to Open Input file',00H JMP FINIS ; Go to error handler ; OK: MOV BX,AX ; Handle in bx MOV AX,4202H ; Move to end of file XOR CX,CX ; Clear offsets MOV DX,CX ; Inc. dx INT 21H ; Do it OR DX,DX ; Longer than 64k? JZ LT64K ; No CALL CHKOVR ; Check extended addressing override ; LT64K: XOR CX,CX ; Clear offsets MOV DX,CX ; All 32 bits MOV AX,4200H ; Move back to start of file MOV BX,[INHDL] ; Get handle INT 21H ; Moved back MOV CL,00H ; Normal addributes MOV AH,3CH ; Create file function LEA DX,OUTFN ; Point to file name INT 21H ; Open the file JNC OK1 ; Ok CALL ILPRT ; Print this... DB CR,LF,'Failure to Open output file',00H JMP FINIS ; Go to error handler OK1: MOV [OUTHDL],AX ; Save handle MOV AL,[OUTTYPE] ; Get output format OR AL,AL ; Force flags JZ READ ; Don't do start char for bnpf LEA DX,CNTRLB ; Point to start byte MOV BX,[OUTHDL] ; Get output handle MOV AH,40H ; Write function MOV CX,0003H ; One byte + crlf INT 21H ; Do it JNC READ ; Ok JMP BADWR ; Error ; READ: LEA DI,INBUF ; Point to input buffer MOV CX,16D ; Fill entire buffer MOV AL,[FILDAT] ; Get fill data MOV AH,AL ; Dup into ah REP STOSW ; Do it ; MOV AL,[OOD] ; Already out of data? OR AL,AL ; Force flags JNZ FILLIT ; Yup LEA DX,INBUF ; Point to buffer MOV CX,32D ; Process 32 bytes at a time MOV BX,[INHDL] ; Get handle MOV AH,3FH ; Read function INT 21H ; Do it JNC ROK ; Ok CALL ILPRT ; Print this... DB CR,LF,'Error Reading Input file',00H JMP FINIS ; Go to error handler ; CNTRLB: ; DB 02H,CR,LF ; Bnpf start ; ROK: CMP AX,0000H ; Completely finished? JNZ NOPE ; Nope MOV AL,[OUTTYPE] ; Check for bnpf OR AL,AL ; Force flags JNZ EXIT ; Bnpf ignores all this... MOV AL,0FFH ; Indicate we're finished reading from disk MOV [OOD],AL ; Flag it MOV AL,[DOFILL] ; Check for fillrom function OR AL,AL ; Force flags JZ EXIT ; Not selected FILLIT: MOV AX,[EXTEND] ; Get current segment SUB AX,1000H ; Compensate to what is in use CMP [ENDSEG],AX ; Check against selected end segment JC TOOBIG ; Warn operator that his data won't fit JNZ NOPE ; Segment hasn't been reached yet, continue MOV AX,[ADDRESS] ; Get current address DEC AX ; To last location, not next avail loc CMP [ENDADDR],AX ; Check against selected end address JC TOOBIG ; Warn oerator that his data won't fit JNZ NOPE ; Address hasn't been reached yet ; EXIT: JMP FINISHUP ; Yes, finish up & terminate TOOBIG: JMP WARN ; Tell operator NOPE: MOV AL,[OUTTYPE] ; Get output format OR AL,AL ; Force flags JZ HEX ; Do hex ; Drop through to bnpf LEA SI,INBUF ; Point to input buffer MOV CX,32D ; 32 bytes to process BNPF: LEA DI,OUTBUF ; Output buffer MOV [DI],BYTE PTR 'B' ; The b for begin INC DI ; Next location BIGLP: MOV AL,[SI] ; Get byte PUSH CX ; Save byte loop MOV CX,0008H ; 8 bits in a byte BNPFLP: RCL AL,1 ; Rotate through carry JC P ; High MOV AH,[BNPFTYP+1] ; Get the byte for low MOV [DI],AH ; Put in buffer INC DI ; Next location LOOP BNPFLP ; Do entire byte JMP ONEBYTE ; Complete & write P: MOV AH,[BNPFTYP] ; Get the byte for high MOV [DI],AH ; Put in buffer INC DI ; Next location LOOP BNPFLP ; Do entire byte ONEBYTE:MOV [DI],BYTE PTR 'F' ; The f for finish POP CX ; Recover byte loop INC SI ; Next byte INC DI ; Next dest MOV [DI],BYTE PTR 0DH ; Send a cr INC DI ; Next MOV [DI],BYTE PTR 0AH ; Send a lf INC DI ; Next PUSH CX ; Save loop counter PUSH SI ; Save input counter MOV CX,12D ; Twelve bytes every time CALL WRITE ; Write byte POP SI ; Recover input counter POP CX ; Recover loop counter LOOP BNPF ; Do next byte JMP READ ; Read next 32 bytes ; HEX: XOR BX,BX ; Output counter MOV CX,32D ; Input counter XOR DX,DX ; Dl is checksum reg MOV AX,[ADDRESS] ; Get current load address OR AX,AX ; Force flags JNZ NOEXT ; No extended address record needed CALL EAR ; Do extended addressing if selected NOEXT: LEA SI,INBUF ; Point to input buffer LEA DI,OUTBUF ; Point to output buffer MOV [DI],BYTE PTR ':' ; Stuff that colon INC DI ; And point to next INC BX ; And increment counter MOV AL,20H ; All are 32 byte records CALL BITE ; Stuff it MOV AX,[ADDRESS] ; Get load address XCHG AL,AH ; Do high byte first CALL BITE ; Send it XCHG AH,AL ; Now do low byte CALL BITE ; Send it MOV AX,[ADDRESS] ; Get load address ADD AX,20H ; Increment to next MOV [ADDRESS],AX ; Put back MOV AL,00H ; Record type 00 CALL BITE ; Send it LOOP4: MOV AL,[SI] ; Get input CALL BITE ; Process INC SI ; Point to next LOOP LOOP4 ; Until done MOV AL,DL ; Get checksum CALL BITE ; Process, [clobbering dl] MOV [DI], WORD PTR 0A0DH ; Append crlf ADD BX,02H ; Bump output counter appropiately MOV CX,BX ; Get count into cx CALL WRITE ; Write output JMP READ ; Read more ; WRITE: LEA DX,OUTBUF ; Point to beginning of output buffer MOV BX,[OUTHDL] ; Get output handle MOV AH,40H ; Write function INT 21H ; Do it JNC WOK ; Ok BADWR: CALL ILPRT ; Print this... DB CR,LF,'Error Writing Output file',00H JMP FINIS ; Go to error handler WOK: RET ; Near ; EAR: PUSH AX ; Save everything MOV AL,[USEEXT] ; Get extended address flag OR AL,AL ; Force flags JNZ GOAHEAD ; Yes, do extended addressing MOV AX,[EXTEND] ; Get extended address anyway ADD AX,1000H ; Increment to next 64k block MOV [EXTEND],AX ; Put back for consistancy POP AX ; Restore ax RET ; Go home ; GOAHEAD:PUSH DI ; PUSH CX ; PUSH DX ; PUSH SI ; PUSH BX ; LEA DI,OUTBUF ; Point to output buffer MOV [DI],BYTE PTR ':' ; Stuff that colon INC DI ; And point to next INC BX ; And increment counter MOV AL,02H ; Two bytes of data in extended record CALL BITE ; Stuff it MOV AX,0000H ; Extended address records have load addr of 0 XCHG AL,AH ; Do high byte first CALL BITE ; Send it XCHG AH,AL ; Now do low byte CALL BITE ; Send it MOV AL,02H ; Record type 02 CALL BITE ; Send it MOV AX,[EXTEND] ; Get current extended address XCHG AL,AH ; Do high byte first CALL BITE ; Send it XCHG AH,AL ; Now do low byte CALL BITE ; Send it MOV AX,[EXTEND] ; Get extended address again ADD AX,1000H ; Increment to next 64k block MOV [EXTEND],AX ; Put back MOV AL,DL ; Get checksum CALL BITE ; Process, [clobbering dl] MOV [DI], WORD PTR 0A0DH ; Append crlf ADD BX,02H ; Bump output counter appropiately MOV CX,BX ; Get count into cx CALL WRITE ; Write output POP BX ; Recover everything POP SI ; POP DX ; POP CX ; POP DI ; POP AX ; RET ; Go home ; CHKOVR: PUSH AX ; Save ax MOV AL,[OVERRIDE] ; Check to see if extended override selected OR AL,AL ; Force flags JNZ OVR ; Overridden by user MOV AL,0FFH ; Otherwise flag extended addressing MOV [USEEXT],AL ; Flagged OVR: POP AX ; Restore ax RET ; Go home ; FINISHUP: ; CALL ILPRT ; Print this... DB CR,LF,'Function Complete.',00H MOV AL,[OUTTYPE] ; Get output format OR AL,AL ; Force flags JZ HEXEND ; Do hex ; Drop through to bnpf ; BNPFEND:LEA DX,CNTRLC ; Point to eof marker MOV BX,[OUTHDL] ; Get output handle MOV AH,40H ; Write function MOV CX,0003H ; One byte INT 21H ; Do it JNC WOKK ; Ok JMP BADWR ; Error ; WARN: CALL ILPRT ; Print this... DB CR,LF,LF,'WARNING: Input data file too large for output size' DB ' selected.',07H,LF,00H ; JMP FINISHUP ; Terminate ; CNTRLC: ; DB 03H,CR,LF ; Termination for bnpf ; HEXEND: LEA DX,EOFREC ; Point to eof record MOV BX,[OUTHDL] ; Get output handle MOV AH,40H ; Write function MOV CX,0014H ; Fourteen bytes INT 21H ; Do it JNC WOKK ; Ok JMP BADWR ; Error ; WOKK: MOV AH,3EH ; Close the file now MOV BX,[OUTHDL] ; Close output INT 21H ; Close the damn thing JNC CLOK ; Closed ok CALL ILPRT ; Print this... DB CR,LF,'Error Closing Output file!',00H ; CLOK: MOV AH,3EH ; Close the file now MOV BX,[INHDL] ; Close input INT 21H ; Close the damn thing JNC FINISH ; Closed ok CALL ILPRT ; Print this... DB CR,LF,'Error Closing Input file!',00H ; FINISH: MOV AX,4C00H ; No-error termination INT 21H ; Bye-bye ; FINIS: MOV AX,4CFFH ; Error termination INT 21H ; Bye-bye ; EOFREC: ; DB ':00000001FF',CR,LF,EOF ; End of file record ; ;************************************************************************ ;* * ;* ILPRT: This is an 8088 in-line print routine. It will print * ;* the string following the CALL NEAR instruction until a 00H is * ;* encountered. Accepts: Data string to print in memory following* ;* the CALL NEAR used to invoke this routine. Returns: Nothing. * ;* Calls: CONOUT. Clobbers: ES,SI * ;* * ;************************************************************************ ; ILPRT: PUSH CS ; Get code segment POP ES ; Into es POP SI ; Get offset PUSH AX ; Save ax PUSH DX ; And dx ILLP: MOV AL,ES:[SI] ; Get char OR AL,AL ; Force flags JZ ILEXIT ; Exit if last CALL CONOUT ; Send char INC SI ; Point to next JMP SHORT ILLP ; Loop til done ILEXIT: INC SI ; Point to next instruction POP DX ; Restore dx POP AX ; And ax PUSH SI ; And return offset RET ; Near ; CONOUT: MOV AH,02H ; Conout call MOV DL,AL ; Get char INT 21H ; Do it RET ; Near ; BITE: SUB DL,AL ; Generate checksum PUSH AX ; Save AND AL,0F0H ; Mask out lower nybble ROR AL,1 ; Get msn into lower nybble ROR AL,1 ; ROR AL,1 ; ROR AL,1 ; Now it's there CALL NYB ; Process nybble MOV [DI],AL ; Save in disk buffer INC BX ; Increment count INC DI ; Next location in buffer POP AX ; Recover byte AND AL,0FH ; Mask lsn CALL NYB ; Process nybble MOV [DI],AL ; Save in disk buffer INC BX ; Increment count INC DI ; Next location in buffer RET ; Near ; ; Converts lower nybble in al to ascii hex NYB: CMP AL,0AH ; Letter? JNC NYB1 ; Yes ADD AL,30H ; Add in numeric bias RET ; Go home (near) NYB1: ADD AL,37H ; Add in letter bias RET ; Go home (near) ; INHDL: ; BLKB 2 ; Storage for input file handle OUTHDL: ; BLKB 2 ; Storage for output file handle ADDRESS: ; DW 0000H ; Current address EXTEND: ; DW 0000H ; Current extended address INFN: ; BLKB 64D ; Plenty of room for a filename & path OUTFN: ; BLKB 64D ; Output filename INBUF: ; BLKB 32D ; Thirty two byte input buffer OUTBUF: EQU $ ; Output buffer ; HELP: ; Called only if nothing is going to happen ; Otherwise, this routine is overwritten CALL ILPRT ; Print help screen DB CR,LF,'Usage: UNLOAD86 FILENAME.TYP [/OPTIONS]' DB CR,LF,LF,'Where Options are:' DB CR,LF,' B for BNPF instead of INTeL hex.' DB ' (Overrides all other options!)' DB CR,LF,' E to use extended addressing on files <=64K' DB CR,LF,' O to override forced extended addressing.' DB CR,LF,' P to fill output file to end of EPROM.' DB CR,LF,' Uses the following subcommands:' DB CR,LF,' 0 32 Bytes 1 64 Bytes' DB CR,LF,' 2 128 Bytes 3 256 Bytes' DB CR,LF,' 4 512 Bytes 5 1K Bytes' DB CR,LF,' 6 2K Bytes 7 4K Bytes' DB CR,LF,' 8 8K Bytes 9 16K Bytes' DB CR,LF,' A 32K Bytes B 64K Bytes' DB CR,LF,' C *128K Bytes D *256K Bytes' DB CR,LF,' E *512K Bytes F *1Meg Bytes' DB CR,LF,LF,' * Forces extended addressing' DB CR,LF,LF,'INTeL hex output files are .HEX' DB CR,LF,'BNPF output files are .BNP' DB CR,LF,'Note: - or [ may be used instead of / for switches.' DB CR,LF,00H ; JMP FINIS ; Terminate ; ATABLE: ; Table of rom sizes for fillrom option DW 0000H ; Segment for 32 byter DW 001FH ; Address for 32 byter DW 0000H ; Segment for 64 byter DW 003FH ; Address for 64 byter DW 0000H ; Segment for 128 byter DW 007FH ; Address for 128 byter DW 0000H ; Segment for 256 byter DW 00FFH ; Address for 256 byter DW 0000H ; Segment for 512 byter DW 01FFH ; Address for 512 byter DW 0000H ; Segment for 1k byter DW 03FFH ; Address for 1k byter DW 0000H ; Segment for 2k byter DW 07FFH ; Address for 2k byter DW 0000H ; Segment for 4k byter DW 0FFFH ; Address for 4k byter DW 0000H ; Segment for 8k byter DW 1FFFH ; Address for 8k byter DW 0000H ; Segment for 16k byter DW 3FFFH ; Address for 16k byter DW 0000H ; Segment for 32k byter DW 7FFFH ; Address for 32k byter DW 0000H ; Segment for 64k byter DW 0FFFFH ; Address for 64k byter DW 1000H ; Segment for 128k byter DW 0FFFFH ; Address for 128k byter DW 3000H ; Segment for 256k byter DW 0FFFFH ; Address for 256k byter DW 7000H ; Segment for 512k byter DW 0FFFFH ; Address for 512k byter DW 0F000H ; Segment for 1m byter DW 0FFFFH ; Address for 1m byter ; END ;