home *** CD-ROM | disk | FTP | other *** search
/ ProfitPress Mega CDROM2 …eeware (MSDOS)(1992)(Eng) / ProfitPress-MegaCDROM2.B6I / PROG / ASSEMBLY / MOTOASMS.ZIP / STOBIN.ASM < prev    next >
Encoding:
Assembly Source File  |  1988-06-01  |  41.5 KB  |  787 lines

  1. NAME STOBIN
  2. TITLE Motorola S-record to Binary Translator
  3. PAGE 58,110                     ;58 printed lines per page, 110 columns/page
  4.                                 ;in assembler listings
  5.  
  6. ;This program translates files from the Motorola S-record format (output by 
  7. ;motorola's freeware cross assemblers for Motorola microprocessor/microcomputer 
  8. ;chips) into binary files (the real code and data for the chip).  The Motorola 
  9. ;S-record format consists of lines of ASCII characters.  Each line starts with 
  10. ;an S, followed by a digit which seems to indicate something about the contents 
  11. ;of the line (1 for regular code and data, 9 for last line, which doesn't 
  12. ;contain code or data?).  Next, two digits give the hexadicimal number of 
  13. ;program code/data bytes represented on the line + 3. Then, 4 digits give the 
  14. ;hexadecimal address of the first program code/data byte represented on the 
  15. ;line. Then, a string of digits gives the hexadecimal values of program 
  16. ;code/data bytes in ascending address sequence (2 digits per byte).  Finally, 
  17. ;two digits give some sort of housekeeping data and these are followed by a line 
  18. ;feed and a carriage return to get to the next line.
  19.  
  20. ;Procedures:  SCRCLR, KEYSTRNG, KEYNUM, ASCTOHEX, GETKEY, DISPCHAR, DISPMSG
  21.  
  22.  
  23. DATA1      SEGMENT 'DATA'
  24. ;BUFFERS
  25.            BUFF1 DB 64,65 DUP(0) ;filename input buffer. first byte gives 1+max.
  26.                                 ;# of input characters. size set to 3 more than 
  27.                                 ;max # of input characters, as required by 
  28.                                 ;KEYSTRNG.  Max. 63 characters is the length
  29.                                 ;acceptable by DOS for filespec's (not counting
  30.                                 ;the ending null, which KEYSTRNG will supply)
  31. ;VARIABLES
  32.            INFILE DB 64 DUP(?)  ;input file name
  33.            INHNDLE DW ?         ;input file handle
  34.            OUTFILE DB 68 DUP(?) ;output file name
  35.            OUTHNDLE DW ?        ;output file handle
  36.            DEVSIZE DW ?         ;size of destination memory device
  37.            IMAGESEG DW ?        ;segment of memory image area
  38.            INSIZE DW ?          ;size of input file
  39.            INSEG DW ?           ;segment of input file area
  40.            OUTEXT DB 5,".BIN",00H  ;extension for output filename in LSTRING 
  41.                                 ;format with ending null
  42.            NUMFILL DB ?         ;fill value for unused memory locations
  43.            LINELEN DB ?         ;number of bytes represented on an input file
  44.                                 ;line
  45. ;MESSAGES
  46.            FILEPMT DB 0DH,0AH,0AH,"Please enter an input file name, or press"
  47.                    DB " <Ctrl-C> to quit.",0DH,0AH,"$"
  48.            NXTPMT DB 0DH,0AH,0AH,"Please enter the next input file name, or"
  49.                   DB " just press Enter to quit.",0DH,0AH,"$"
  50.            SIZEPMT DB 0DH,0AH,0AH,"What is the capacity (in bytes) of the "
  51.                    DB "((E)E)PROM you will transfer this program"
  52.                    DB "to?  (or press Q to quit)",0DH,0AH,"$"
  53.            FILLPMT DB 0DH,0AH,0AH,"Shall I fill unused locations with ones or"
  54.                    DB " zeroes?  (1/0)",0DH,0AH,"$"
  55.            ADJMSG DB 0DH,0AH,0AH,"Memory reallocation error.  If you do not"
  56.                    DB 0DH,0AH,0AH,"reboot your computer now, it may crash."
  57.                    DB 0DH,0AH,"$"
  58.            INFLMSG DB 0DH,0AH,0AH,"Attempt to open input file failed.",0DH,0AH,"$"
  59.            OUTFLMSG DB 0DH,0AH,0AH,"Attempt to create output file failed.",0DH,0AH
  60.                    DB "$"
  61.            WGVERMSG DB 0DH,0AH,0AH,"This program requires DOS version 3.00 or"
  62.                    DB " greater, and that's not what you're"
  63.                    DB 0DH,0AH,"using right now.",0AH,0DH,"$"
  64.            BADSZMSG DB 0DH,0AH,0AH,"The size you entered was 0 or too large.",0DH
  65.                    DB 0AH,"$"
  66.            NOMEMMSG DB 0DH,0AH,0AH,"Insufficient available memory.",0DH,0AH,"$"
  67.            NOSZMSG DB 0DH,0AH,0AH,"Unable to determine input file size.",0DH
  68.                    DB 0AH,"$"
  69.            INTOOBIG DB 0DH,0AH,0AH,"Input file is too large.",0DH,0AH,"$"
  70.            CANTREAD DB 0DH,0AH,0AH,"Can't read input file.",0DH,0AH,"$"
  71.            SIZERR DB 0DH,0AH,0AH,"Warning:  wrong number of bytes read from"
  72.                   DB " input file.",0DH,0AH,"$"
  73.            TRERRMSG DB 0DH,0AH,0AH,"Input file doesn't follow expected format;"
  74.                   DB " file ignored.",0AH,0DH,"$"
  75.            SAVERR DB 0DH,0AH,0AH,"Attempt to open output file failed.",0DH,0AH
  76.                   DB "$"
  77.            WRITERR DB 0DH,0AH,0AH,"Error writing to output file.",0DH,0AH,"$"
  78. ;LOOKUP TABLES
  79.            LINPSCRN DB 25,25,25,25,0,0,0,25,0,0,0,0,0,0,0,0,0
  80. DATA1      ENDS
  81.  
  82.  
  83. STSEG      SEGMENT STACK 'STACK'
  84.            DB 80H DUP(0) 
  85. STSEG      ENDS
  86.  
  87.  
  88. CODE1      SEGMENT 'CODE'
  89.            ASSUME CS:CODE1, DS:DATA1, SS:STSEG
  90.  
  91. ;INITIALIZE DS AND SS
  92. START:     MOV AX,DATA1         ;Obtain DATA1 segment address
  93.            MOV DS,AX            ;and put it in DS
  94.            MOV AX,STSEG         ;Obtain STSEG segment address
  95.            MOV SS,AX            ;and put it in SS.
  96.  
  97. ;MAIN PROGRAM
  98.  
  99. ;SHRINK MEMORY ALLOCATION
  100.            MOV AX,ZZZZZZZZ      ;Get segment address of dummy final segment
  101.            MOV BX,ES            ;and segment address of Program Segment Prefix.
  102.            SUB AX,BX            ;Compute size of program in paragraphs
  103.            MOV BX,AX            ;and put it in BX
  104.                                 ;ES points to Program Segment Prefix (PSP)
  105.                                 ;because we haven't messed with it yet.
  106.            MOV AX,4A00H         ;Store Set Block function number and 0 (to
  107.                                 ;allow error checking idependent of the 
  108.                                 ;carry flag.
  109.            INT 21H              ;Change memory allocation.
  110.            CMP AX,7             ;If memory control blocks were destroyed,
  111.            JE ADJFAIL           ;go respond to the failure
  112.            CMP AX,8             ;If not enough memory (not an expected error!),
  113.            JE ADJFAIL           ;go respond to the failure
  114.            CMP AX,9             ;If correct segment specified,
  115.            JNE DOSVER           ;go continue.
  116. ADJFAIL:   LEA DX,ADJMSG        ;Get address of error message
  117.            CALL DISPMSG         ;and display it.
  118.            MOV AL,1             ;Store error code in AL,
  119.            JMP QUITERR          ;then go terminate program.
  120.  
  121. ;CHECK DOS VERSION
  122. DOSVER:    MOV AH,30H           ;Get DOS version
  123.            INT 21H              ;number.
  124.            CMP AL,03H           ;If DOS version number is
  125.            JAE FRSTFILE         ;3 or greater, go run the program.
  126.            LEA DX,WGVERMSG      ;Otherwise, get the address of the "wrong
  127.            CALL DISPMSG         ;version" message and display it,
  128.            MOV AL,1             ;store an error code in AL,
  129.            JMP QUITERR          ;then go quit the program.
  130.  
  131. ;GET INPUT FILENAME AND TRY OPENING FILE
  132. FRSTFILE:  CALL SCRCLR          ;Clear screen.
  133.            LEA DX,FILEPMT       ;Get the address of the file prompt 
  134.            CALL DISPMSG         ;and display it.
  135.            LEA DX,BUFF1         ;Get buffer address and
  136.            CALL KEYSTRNG        ;get a filename.
  137.            MOV BX,DX            ;Get number of
  138.            MOV CL,[BX+1]        ;characters entered
  139.            XOR CH,CH            ;in CX,
  140.            LEA SI,BUFF1+2       ;get address of 1st character entered in DS:SI,
  141.            PUSH DS              ;get address of
  142.            POP ES               ;filename
  143.            LEA DI,INFILE        ;variable in ES:DI,
  144.            CLD                  ;set direction flag for ascending addresses,
  145.            REP MOVSB            ;and copy filename into its variable
  146.            MOVSB                ;along with its ending null.
  147.            LEA DX,INFILE        ;Get address of input filename,
  148.            MOV AL,00H           ;specify read-only, DOS-2 compatible access
  149.            MOV AH,3DH           ;and attempt
  150.            INT 21H              ;to open the file.
  151.            JNC INFILEOK         ;If no problem, go try the output file.
  152.            LEA DX,INFLMSG       ;Otherwise, get address of error message
  153.            CALL DISPMSG         ;and display it,
  154.            MOV AL,1             ;store error code
  155.            JMP QUITERR          ;and go terminate the program.
  156. INFILEOK:  MOV INHNDLE,AX       ;Save input file handle            
  157.            MOV BX,INHNDLE       ;and close
  158.            MOV AH,3EH           ;the input
  159.            INT 21H              ;file.                       
  160.  
  161. ;ATTEMPT TO CREATE OUTPUT FILE
  162.            LEA BX,BUFF1         ;Get number of
  163.            MOV CL,[BX+1]        ;characters entered
  164.            XOR CH,CH            ;in CH,
  165.            LEA SI,BUFF1+2       ;get address of 1st character entered in DS:SI,
  166.            LEA DI,OUTFILE       ;get address of filename variable in ES:DI,
  167.            CLD                  ;set direction flag for ascending addresses,
  168.            REP MOVSB            ;and copy filename into its variable
  169.            MOVSB                ;along with its ending null.
  170.            LEA DI,OUTFILE       ;Get address of output file string in ES:DI,
  171.            MOV CL,BUFF1+1       ;number of characters in string
  172.            XOR CH,CH            ;in CX,
  173.            MOV AL,"."           ;and character to search for
  174.            CLD                  ;in ascending addresses,
  175.            REPNE SCASB          ;and look for the character.
  176.            JNZ EXTADR           ;If . not found, go append file extension.
  177.            DEC DI               ;If . found, move back onto it.
  178. EXTADR:    LEA SI,OUTEXT+1      ;Get the address of output filename extension
  179.            MOV CL,OUTEXT        ;and get its length
  180.            XOR CH,CH            ;in CX,
  181.            REP MOVSB            ;then attach it to the output filename.
  182.            MOV AH,5BH           ;Store file creation function number,
  183.            MOV CX,20H           ;an "archive" attribute byte,
  184.            LEA DX,OUTFILE       ;and the output filename address
  185.            INT 21H              ;and attempt to create the output file.
  186.            JNC SAVHNDLE         ;If no problem, go continue.
  187.            LEA DX,OUTFLMSG      ;Otherwise, get error message
  188.            CALL DISPMSG         ;and display it,
  189.            MOV AL,1             ;store error code,
  190.            JMP QUITERR          ;and go terminate program.
  191. SAVHNDLE:  MOV OUTHNDLE,AX      ;Store output file handle.
  192.            MOV BX,OUTHNDLE      ;and close
  193.            MOV AH,3EH           ;the output
  194.            INT 21H              ;file.
  195.  
  196. ;GET DESTINATION DEVICE SIZE
  197. GETSIZE:   LEA DX,SIZEPMT       ;Get the device size prompt
  198.            CALL DISPMSG         ;and display it.
  199.            MOV DL,BUFF1         ;Get maximum # of BUFF1 characters
  200.            PUSH DX              ;and preserve it.
  201.            MOV BUFF1,05H        ;Store max. # of digits in device size
  202.            LEA DX,BUFF1         ;and get buffer location,
  203.            CALL KEYNUM          ;then go get device size.
  204.            POP DX               ;Restore maximum # of
  205.            MOV BUFF1,DL         ;BUFF1 characters.
  206.            CMP BUFF1+1,0        ;If digits were entered, go
  207.            JNE ASC2BIN          ;convert them to a number.
  208.            LEA DX,BADSZMSG      ;Otherwise, get address of error message
  209.            CALL DISPMSG         ;and display it,
  210.            JMP GETSIZE          ;then go try to get size again.
  211. ASC2BIN:   MOV CL,BUFF1+1       ;Get the number of digits entered
  212.            XOR CH,CH            ;in CX
  213.            MOV SI,CX            ;and the least significant digit's offset in
  214.            ADD SI,1             ;SI.
  215.            MOV DEVSIZE,00H      ;Set cumulative value to 0.
  216.            MOV BX,01H           ;Set place value for LSD to 1.
  217.            CLC                  ;Assure loop entry.
  218. NXTDIG:    JC OVERFLOW          ;If place value exceeds 16 bits, go choke
  219.            MOV AL,BUFF1[SI]     ;Get ASCII digit in AL,
  220.            XOR AH,AH            ;then AX.
  221.            SUB AL,30H           ;If it's not a digit,
  222.            JC OVERFLOW          ;go display error message and quit.
  223.            CMP AL,0AH           ;If it's too big,
  224.            JAE OVERFLOW         ;go display error message and quit.
  225.            MUL BX               ;Multiply digit by its place value.
  226.            JC OVERFLOW          ;if result more than 16 bits, go choke.
  227.            ADD AX,DEVSIZE       ;Add running sum to present digit.
  228.            JC OVERFLOW          ;if result more than 16 bits, go choke.
  229.            MOV DEVSIZE,AX       ;Otherwise, store new running sum.
  230.            MOV AX,BX            ;Get last place value
  231.            MOV BX,10            ;and place multiplier
  232.            MUL BX               ;and compute next place value.
  233.            MOV BX,AX            ;Put place value in BX,
  234.            DEC SI               ;move to next digit,
  235.            LOOP NXTDIG          ;and go process next digit.
  236.            JMP GETFILL          ;Go get fill digit
  237. OVERFLOW:  LEA DX,BADSZMSG      ;Get bad size error message address
  238.            CALL DISPMSG         ;and display message
  239.            JMP GETSIZE          ;then go try to get size again.
  240.  
  241. ;GET FILL DIGIT
  242. GETFILL:   LEA DX,FILLPMT       ;Get address of fill digit prompt
  243.            CALL DISPMSG         ;display prompt,
  244.            CALL GETKEY          ;and get response.
  245.            CMP AL,30H           ;If the response was not zero,
  246.            JNE ONECHK           ;go see if it was one.
  247.            MOV NUMFILL,00H      ;Otherwise, store fill byte
  248.            JMP GETIMMEM         ;and go continue.
  249. ONECHK:    CMP AL,31H           ;If the response was not one,
  250.            JNE GETFILL          ;go try to get fill digit again.
  251.            MOV NUMFILL,0FFH     ;Otherwise, store fill byte.
  252.  
  253. ;SET UP MEMORY BLOCK FOR DEVICE IMAGE
  254. GETIMMEM:  MOV BX,DEVSIZE       ;Get size of destination device
  255.            MOV CL,4             ;and convert
  256.            SHR BX,CL            ;it to
  257.            INC BX               ;paragraphs.
  258.            MOV AH,48H           ;Request
  259.            INT 21H              ;memory allocation.
  260.            JNC GOTIMMEM         ;If request successful, go continue.
  261.            LEA DX,NOMEMMSG      ;Otherwise, get address of error message
  262.            CALL DISPMSG         ;and go display it.
  263.            LEA DX,ADJMSG        ;Get address of memory error message
  264.            CALL DISPMSG         ;and go display it.
  265.            MOV AL,1             ;Store error code in AL,
  266.            JMP QUITERR          ;then go terminate program
  267. GOTIMMEM:  MOV IMAGESEG,AX      ;Store destination device image segment address.
  268.  
  269. ;FILL THE DESTINATION DEVICE IMAGE WITH THE FILL VALUE
  270.            MOV AL,NUMFILL       ;Get fill value
  271.            MOV CX,DEVSIZE       ;and size of destination device.
  272.            PUSH DS              ;Preserve DS, then
  273.            MOV DS,IMAGESEG      ;point it to the device image.
  274.            MOV BX,0             ;Set starting offset to 0.
  275. FILLUP:    MOV BYTE PTR [BX],AL ;Store fill value
  276.            INC BX               ;move to next byte
  277.            LOOP FILLUP          ;and go fill next byte until all done.
  278.            POP DS               ;Restore data segment address.
  279.  
  280. ;GET INPUT FILE SIZE AND REQUEST MEMORY FOR IT
  281. SIZEPREP:  LEA DX,INFILE        ;Get address of input filename,
  282.            MOV AL,00H           ;specify read-only, DOS-2 compatible access
  283.            MOV AH,3DH           ;and attempt
  284.            INT 21H              ;to open the file.
  285.            JNC INFILESZ         ;If no problem, go continue.
  286.            LEA DX,INFLMSG       ;Otherwise, get address of error message
  287.            CALL DISPMSG         ;and display it,
  288.            MOV AL,1             ;store error code               *******REPLACE?
  289.            JMP QUITERR          ;and go terminate the program.  *******REPLACE?
  290. INFILESZ:  MOV INHNDLE,AX       ;Save the input file's handle.
  291.            MOV BX,INHNDLE       ;Get input file's handle,
  292.            MOV CX,00H           ;Set offset for file pointer
  293.            MOV DX,00H           ;move to zero,
  294.            MOV AX,4202H         ;Store "move file pointer" function request
  295.                                 ;number and "end of file" code,
  296.            INT 21H              ;and move the pointer.       
  297.            JNC GOTSIZE          ;If successful, go continue
  298.            MOV BX,INHNDLE       ;Otherwise, close
  299.            MOV AH,3EH           ;the input
  300.            INT 21H              ;file.                      
  301.            LEA DX,NOSZMSG       ;Then, get error message address,
  302.            CALL DISPMSG         ;display message,
  303.            MOV AL,01H           ;store error code,            *******REPLACE?
  304.            JMP QUITERR          ;and go terminate program.    *****REPLACE?
  305. GOTSIZE:   CMP DX,0             ;If file size occupies less than 17 bits,
  306.            JE SIZEOK            ;go continue.
  307.            MOV BX,INHNDLE       ;Otherwise, close
  308.            MOV AH,3EH           ;the input
  309.            INT 21H              ;file.
  310.            LEA DX,INTOOBIG      ;Then, get error message address,
  311.            CALL DISPMSG         ;display message,
  312.            MOV AL,01H           ;store error code,         *****REPLACE?
  313.            JMP QUITERR          ;and go terminate program.  *****REPLACE?
  314. SIZEOK:    MOV INSIZE,AX        ;Store size of input file
  315.            MOV BX,INSIZE        ;Get size of input file
  316.            MOV CL,4             ;and convert
  317.            SHR BX,CL            ;it to
  318.            INC BX               ;paragraphs.
  319.            MOV AH,48H           ;Request
  320.            INT 21H              ;memory allocation.
  321.            JNC GOTINMEM         ;If request successful, go continue.
  322.            LEA DX,NOMEMMSG      ;Otherwise, get address of error message
  323.            CALL DISPMSG         ;and go display it.
  324.            LEA DX,ADJMSG        ;Get address of memory error message
  325.            CALL DISPMSG         ;and go display it.
  326.            MOV AL,1             ;Store error code in AL,
  327.            JMP QUITERR          ;then go terminate program
  328. GOTINMEM:  MOV INSEG,AX         ;Store input file area segment address.
  329.  
  330. ;READ INPUT FILE
  331.            MOV BX,INHNDLE       ;Get input file's handle,
  332.            MOV CX,00H           ;Set offset for file pointer
  333.            MOV DX,00H           ;move to zero,
  334.            MOV AX,4200H         ;Store "move file pointer" function request
  335.                                 ;number and "beginning of file" code,
  336.            INT 21H              ;and move the pointer.       
  337.            MOV BX,INHNDLE       ;Get the input file's handle
  338.            MOV CX,INSIZE        ;and size.        
  339.            PUSH DS              ;Preserve data segment address and
  340.            MOV DS,INSEG         ;get input file area
  341.            MOV DX,0             ;address in DS:DX.
  342.            MOV AH,3FH           ;Store "read handle" function number,
  343.            INT 21H              ;then read input file.
  344.            POP DS               ;Restore data segment address.
  345.            JNC READOK           ;If read successful, go continue.
  346.            LEA DX,CANTREAD      ;Otherwise, get address of error message
  347.            CALL DISPMSG         ;and display it,
  348.            MOV AL,1             ;store error code,              *****REPLACE?
  349.            JMP QUITERR          ;and go terminate the program.  *****REPLACE?
  350. READOK:    CMP AX,INSIZE        ;If the number of bytes read equals the
  351.            JE TRANPREP          ;input file's size, go continue.
  352.            LEA DX,SIZERR        ;Otherwise, get address of error message
  353.            CALL DISPMSG         ;and display it, then continue.
  354. TRANPREP:  MOV BX,INHNDLE       ;Close
  355.            MOV AH,3EH           ;the input
  356.            INT 21H              ;file.                           
  357.  
  358. ;TRANSLATE S-RECORD FILE INTO MEMORY IMAGE
  359.            PUSH DS              ;Preserve data segment address.
  360.            MOV DS,INSEG         ;Get address of input file
  361.            MOV SI,00H           ;in DS:SI
  362. SLINE:     MOV AL,[SI]          ;Get first character of line.
  363.            CMP AL,"S"           ;if it's an S,
  364.            JE LINETYPE          ;go continue.
  365.            JMP TRANERR          ;otherwise, go choke on the error.
  366. LINETYPE:  INC SI               ;Move to second character of line
  367.            MOV AL,[SI]          ;and get it.
  368.            CMP AL,"1"           ;if it's a 1,
  369.            JE GETLEN            ;go continue
  370.            CMP AL,"9"           ;if it's a 9,
  371.            JE OUTSTORE          ;you're finished, go do cleanup.
  372.            JMP TRANERR          ;Otherwise, go choke on error.
  373. GETLEN:    ADD SI,02H           ;Point DS:SI to LSD of line length
  374.            CALL ASCTOHEX        ;and get line length.
  375.            JC TRANERR           ;If there was a problem, go choke.
  376.            SUB AL,3             ;Otherwise, subtract "overhead" bytes.
  377.            JC TRANERR           ;If underflow, go choke.
  378.            MOV CL,AL            ;Otherwise, store number of bytes to convert
  379.            XOR CH,CH            ;in CX.
  380.            ADD SI,02H           ;Point DS:SI to LSD of most significant half
  381.                                 ;(MSH) of starting address
  382.            CALL ASCTOHEX        ;and get MSH of starting address
  383.            JC TRANERR           ;If there was a problem, go choke.
  384.            MOV BH,AL            ;Otherwise store MSH of starting address.
  385.            ADD SI,02H           ;Point DS:SI to LSD of least significant half
  386.                                 ;(LSH) of starting address
  387.            CALL ASCTOHEX        ;and get LSH of starting address
  388.            JC TRANERR           ;If there was a problem, go choke.
  389.            MOV BL,AL            ;Otherwise, store LSH of starting address.
  390.            POP DS               ;Restore data segment address,
  391.            MOV ES,IMAGESEG      ;get segment of image area in ES,
  392.            PUSH DS              ;preserve data segment address, and
  393.            MOV DS,INSEG         ;get segment of input file in DS.
  394.            MOV DI,BX            ;Get starting address of line in DI.
  395. TRANSLAT:  ADD SI,02H           ;Point SI to LSD of next item
  396.            CALL ASCTOHEX        ;and get item in hexadecimal
  397.            JC TRANERR           ;If there was a problem, go choke.
  398.            MOV ES:[DI],AL       ;Otherwise, store the item in the memory image,
  399.            INC DI               ;move to the next byte of image area,
  400.            LOOP TRANSLAT        ;and continue until done.
  401.            ADD SI,05H           ;Move to next line
  402.            JMP SLINE            ;and go process it.
  403. TRANERR:   POP DS               ;Restore data segment address.
  404.            LEA DX,TRERRMSG      ;Get address of translation error message
  405.            CALL DISPMSG         ;and display it,
  406.            MOV AL,1             ;store error code
  407.            JMP QUITERR          ;and go terminate program.
  408.  
  409. ;STORE OUTPUT FILE
  410. OUTSTORE:  POP DS               ;Restore data segment address to DS
  411.            LEA DX,OUTFILE       ;Get address of output filename,
  412.            MOV AL,01H           ;specify write-only, DOS-2 compatible access
  413.            MOV AH,3DH           ;and attempt
  414.            INT 21H              ;to open the file.
  415.            JNC OUTOPEN          ;If no problem, go continue.
  416.            LEA DX,SAVERR        ;Otherwise, get address of error message
  417.            CALL DISPMSG         ;and display it,
  418.            MOV AL,1             ;store error code
  419.            JMP QUITERR          ;and go terminate the program.
  420. OUTOPEN:   MOV OUTHNDLE,AX      ;Save output file handle            
  421.            MOV BX,OUTHNDLE      ;Get output file handle
  422.            MOV CX,DEVSIZE       ;number of bytes in image area.
  423.            PUSH DS              ;Preserve data segment address
  424.            MOV DS,IMAGESEG      ;and point DS:DX
  425.            MOV DX,00H           ;to the image area.
  426.            MOV AH,40H           ;And store image
  427.            INT 21H              ;area in output file.
  428.            POP DS               ;Restore data segment address.
  429.            JC BADWRITE          ;If there was a problem, go choke.
  430.            CMP AX,DEVSIZE       ;If there was no problem,
  431.            JE OUTCLOSE          ;go continue.
  432. BADWRITE:  LEA DX,WRITERR       ;Get address of error message
  433.            CALL DISPMSG         ;go display it
  434.            MOV AL,1             ;store error code in AL
  435.            JMP QUITERR          ;and go terminate the program.
  436. OUTCLOSE:  MOV BX,OUTHNDLE      ;Get output file handle
  437.            MOV AH,3EH           ;and close
  438.            INT 21H              ;output file.
  439.  
  440. ;RELEASE INPUT FILE MEMORY
  441.            MOV ES,INSEG         ;Get segment address of input file area,
  442.            MOV AH,49H           ;and release
  443.            INT 21H              ;that block of memory.
  444.            CMP AX,7             ;If memory control blocks not damaged,
  445.            JNE NXTFILE          ;then go continue.
  446.            LEA DX,ADJMSG        ;Otherwise, load error message
  447.            CALL DISPMSG         ;display it,
  448.            MOV AL,1             ;store error code in AL
  449.            JMP QUITERR          ;and go terminate the program.
  450.  
  451. ;CHECK FOR MORE INPUT FILES
  452. NXTFILE:   CALL SCRCLR          ;Clear screen.
  453.            LEA DX,NXTPMT        ;Get the address of the file prompt 
  454.            CALL DISPMSG         ;and display it.
  455.            LEA DX,BUFF1         ;Get buffer address and
  456.            CALL KEYSTRNG        ;get a filename.
  457.            MOV BX,DX            ;Get number of
  458.            MOV CL,[BX+1]        ;characters entered
  459.            XOR CH,CH            ;in CX.
  460.            CMP CX,00H           ;If no characters entered,
  461.            JE QUIT              ;go quit the program.
  462.            LEA SI,BUFF1+2       ;Get address of 1st character entered in DS:SI,
  463.            PUSH DS              ;get address of
  464.            POP ES               ;filename
  465.            LEA DI,INFILE        ;variable in ES:DI,
  466.            CLD                  ;set direction flag for ascending addresses,
  467.            REP MOVSB            ;and copy filename into its variable
  468.            MOVSB                ;along with its ending null.
  469.            LEA DX,INFILE        ;Get address of input filename,
  470.            MOV AL,00H           ;specify read-only, DOS-2 compatible access
  471.            MOV AH,3DH           ;and attempt
  472.            INT 21H              ;to open the file.
  473.            JNC NXTFILOK         ;If no problem, go try the output file.
  474.            LEA DX,INFLMSG       ;Otherwise, get address of error message
  475.            CALL DISPMSG         ;and display it,
  476.            MOV AL,1             ;store error code
  477.            JMP QUITERR          ;and go terminate the program.
  478. NXTFILOK:  MOV INHNDLE,AX       ;Save input file handle            
  479.            MOV BX,INHNDLE       ;and close
  480.            MOV AH,3EH           ;the input
  481.            INT 21H              ;file.
  482.            JMP SIZEPREP         ;Go process this input file.
  483.  
  484. QUIT:      MOV AL,0             ;Store "no error" code in AL.
  485.  
  486. QUITERR:   MOV AH,4CH
  487.            INT 21H
  488.  
  489.  
  490. ;PROCEDURE SCRCLR --- this procedure clears the screen and moves the cursor to 
  491. ;the upper left corner.
  492. ;ENTRY:  the data segment must contain lookup table LINPSCRN, a sequential list 
  493. ;of the number of lines per screen for each video mode which might be in use
  494. ;(0 for graphics or other modes for which ASCII line feeds won't work).
  495. ;STACK USAGE:  8 bytes plus one interrupt
  496. ;REGISTERS AFFECTED: if no error, none; if error AX (original AX can be 
  497. ;recovered by decrementing SP twice and POPing)
  498. ;RETURN: if error, carry flag set and error code in AX
  499.  
  500. SCRCLR     PROC
  501.            PUSH AX              ;Preserve contents
  502.            PUSH BX              ;of registers
  503.            PUSH CX              ;used by
  504.            PUSH DX              ;this routine.
  505.            MOV AH,0FH           ;Get the video mode and other assorted info 
  506.            INT 10H              ;by calling the video BIOS.
  507.            CMP AL,10H           ;If video mode is not in our table
  508.            JG BADVIDMD          ;go respond to the problem.
  509.            MOV BX,AX            ;Otherwise, put video mode 
  510.            XOR BH,BH            ;in BX and
  511.            MOV CL,LINPSCRN[BX]  ;get the number of screen lines
  512.            XOR CH,CH            ;in CX.
  513.            CMP CX,0             ;If 0 lines (a graphics mode)
  514.            JE GRAPHICS          ;go respond to the problem.
  515.            MOV AH,2             ;Store send-to-screen function number
  516.            MOV DL,0AH           ;and ASCII line feed
  517. LINEFEED:  INT 21H              ;and feed a line.
  518.            LOOP LINEFEED        ;Send more linefeeds 'til screen cleared.
  519.            MOV AH,0FH           ;Get the video mode and other assorted info
  520.            INT 10H              ;by calling the video BIOS.
  521.                                 ;Video page number now in BH and required below.
  522.            MOV DH,0             ;Store row number,
  523.            MOV DL,0             ;column number,
  524.            MOV AH,2H            ;and "set cursor position" function number,
  525.            INT 10H              ;then call video BIOS to set cursor postion.
  526.            CLC                  ;Clear carry flag to indicate no error.
  527.            JMP CLEARED          ;Go return to main program.
  528. BADVIDMD:  MOV AX,2             ;Store unrecognized video mode error number,
  529.            STC                  ;set carry flag to indicate error,
  530.            JMP CLEARED          ;and go return to main program.
  531. GRAPHICS:  MOV AX,1             ;Store graphics mode error number,
  532.            STC                  ;set carry flag to indicate error,
  533.                                 ;and go return to main program
  534. CLEARED:   POP DX               ;Restore contents
  535.            POP CX               ;of registers used
  536.            POP BX               ;by this routine
  537.            JC RETERR            ;but if error code in ax, don't restore it.
  538.            POP AX               ;If no error, restore contents of AX
  539.            RET                  ;and return to main program.
  540. RETERR:    INC SP               ;Adjust stack pointer
  541.            INC SP               ;for failure to pop AX
  542.            RET                  ;and return to main program.
  543. SCRCLR     ENDP
  544.  
  545.  
  546. ;PROCEDURE KEYSTRNG --- this procedure uses MS-DOS for buffered key-
  547. ;board input.  The input may be edited via the usual MS-DOS "template"
  548. ;editing commands (a subset of the EDLIN editing commands).
  549. ;The procedure fills any unused allowed field length with nulls (00H).
  550. ;ENTRY:  DX must contain the offset of a buffer in the data segment.
  551. ;          The first byte of the buffer must contain a number 1 greater
  552. ;             than the maximum allowable number of characters (and no
  553. ;             bigger than 2 less than the buffer's size and no bigger
  554. ;             than 255 decimal).  Thus, the maximum storage space is buffer size
  555. ;             - 3 characters.  For setting up the buffer, declare the first byte 
  556. ;             as 1+max. # of characters, then declare 2+max. # of characters
  557. ;          DS must contain the correct segment address for the buffer.
  558. ;STACK USAGE:  8 bytes, 1 DOS function call
  559. ;REGISTERS AFFECTED:  none
  560. ;VARIABLES AFFECTED:  second through nth bytes of the buffer, where n
  561. ;          is the maximum allowable number of characters + 3
  562. ;RETURN:  second byte of buffer contains the number of
  563. ;             characters entered
  564. ;          third byte & on of buffer contain characters entered
  565. ;             followed by nulls (00H) to fill unused allowed space
  566.  
  567. KEYSTRNG   PROC
  568.            PUSH AX              ;save contents of AX
  569.            PUSH CX              ;CX,
  570.            PUSH SI              ;SI,
  571.            PUSH DI              ;and DI.
  572.            MOV AH,0AH           ;store "buffered input" function #
  573.            INT 21H              ;and make the function call
  574.            MOV SI,DX            ;get address of max. # of char's + 1
  575.            CMP BYTE PTR [SI],1  ;If no characters were allowed,
  576.            JBE FULL             ;then you're done.
  577.            MOV CL,[SI]          ;Get the max. allowable # of characters + 1
  578.            INC SI               ;minus
  579.            SUB CL,[SI]          ;the number of characters entered.
  580.            XOR CH,CH            ;Get the number of nulls to
  581.                                 ;insert in CX.
  582.            MOV DI,DX            ;Get the address of
  583.            ADD DI,2             ;the first character in DI.
  584.            MOV AL,[SI]          ;Get the number of characters entered
  585.            XOR AH,AH            ;in AX.
  586.            ADD DI,AX            ;Get the address of the first unused
  587.                                 ;byte in DI.
  588. FILL:      MOV BYTE PTR [DI],00H  ;Put a null in an unused byte.
  589.            INC DI               ;Move to the next byte.
  590.            LOOP FILL            ;If not done, fill it.
  591. FULL:      POP DI               ;Restore original contents of DI,
  592.            POP SI               ;SI,
  593.            POP CX               ;CX,
  594.            POP AX               ;and AX.
  595.            RET
  596. KEYSTRNG   ENDP
  597.  
  598.  
  599. ;PROCEDURE KEYNUM --- this procedure uses two MS-DOS function calls 
  600. ;to obtain ASCII codes for the digits of a decimal number
  601. ;typed on the keyboard and stores the successive codes in ascending
  602. ;bytes of the data segment starting at DS:DX+2.  If Q or q is pressed,
  603. ;the procedure jumps to QUIT, which must be the main program's termination
  604. ;section.
  605. ;ENTRY:  DX must conatain the offset of a buffer in the data segment
  606. ;          DS:DX must contain the maximum allowable number of digits (no
  607. ;          bigger than buffer size - 3 and no bigger than 254 decimal).
  608. ;STACK USAGE: 8 bytes, 1 interrupt
  609. ;NOTE: DX is preserved in BX and restored.  Don't mess with BX!
  610. ;REGISTERS AFFECTED: none
  611. ;VARIABLES AFFECTED: DS:DX+1 to DS:DX+1+n where n is the number of
  612. ;          characters entered.
  613. ;RETURN: DS:DX+1 contains the number of characters entered.
  614. ;          DS:DX+2 to DS:DX+1+n contain the ASCII codes of the characters
  615. ;          entered.
  616.  
  617. KEYNUM     PROC
  618.            PUSH AX              ;preserve the contents of AX
  619.            PUSH BX              ;preserve the contents of BX
  620.            PUSH CX              ;preserve the contents of CX
  621.            PUSH DI              ;preserve the contents of DI
  622.            XOR DI,DI            ;zero DI (no characters entered)
  623.            MOV BX,DX            ;get buffer offset in BX
  624.            MOV BYTE PTR [BX]+1,0   ;set number of characters entered to 0
  625.            MOV CL,[BX]          ;get number of digits allowed
  626.            XOR CH,CH            ;in CX
  627. DIGIT:     MOV DL,0FFH          ;prepare to request
  628.            MOV AH,6             ;direct keyboard input
  629. KEYBD:     INT 21H              ;and make the function call
  630.            CMP AL,0             ;if no character pressed,
  631.            JE KEYBD             ;try again
  632.            CMP AL,'Q'           ;if Q pressed,
  633.            JE QUE               ;quit.
  634.            CMP AL,'q'           ;If q was pressed,
  635.            JE QUE               ;quit.
  636.            CMP AL,0DH           ;if character is a RETURN
  637.            JE DONE              ;the procedure terminates
  638.            CMP AL,08H           ;if character is a BACKSPACE
  639.            JE BACKSP            ;accomodate it
  640.            CMP CX,DI            ;if maximum # of digits already entered,
  641.            JE DIGIT             ;ignore this one
  642.            CMP AL,'0'           ;if it's inappropriate
  643.            JB DIGIT             ;ignore it
  644.            CMP AL,'9'           ;if it's not a digit
  645.            JA DIGIT             ;ignore it
  646.                                 ;if it's a digit
  647. STORE:     MOV [BX][DI]+2,AL    ;store it
  648.            INC DI               ;count it
  649.            MOV DL,AL            ;move it to DL
  650.            MOV AH,2             ;store send-to-display function #
  651.            INT 21H              ;and make the function call
  652.            JMP DIGIT            ;and go get the next character
  653. QUE:       JMP QUIT             ;If "quit", go quit.
  654. BACKSP:    CMP DI,0             ;don't backspace
  655.            JE DIGIT             ;too far
  656.            DEC DI               ;count a backspace
  657.            MOV DL,08H           ;store ASCII backspace in DL
  658.            MOV AH,2             ;store send-to-display function #
  659.            INT 21H              ;and make the function call
  660.            MOV DL,20H           ;erase the
  661.            INT 21H              ;existing character
  662.            MOV DL,08H           ;then move back onto
  663.            INT 21H              ;the space
  664. BAKDIG:    JMP DIGIT            ;and go get next character
  665. DONE:      MOV AX,DI            ;get # of characters entered in AX
  666.            MOV [BX]+1,AL        ;and in 2nd byte of buffer
  667.            MOV DX,BX            ;put buffer offset back in DX
  668.            POP DI               ;restore original contents of DI,
  669.            POP CX               ;CX,
  670.            POP BX               ;BX,
  671.            POP AX               ;and AX
  672.            RET                  ;and go back to main program
  673. KEYNUM ENDP
  674.  
  675.  
  676. ;PROCEDURE ASCTOHEX --- This procedure converts two ASCII digits to a 
  677. ;hexadecimal number returned in AL.  If there's a problem, it will return to the 
  678. ;calling program with the carry flag set.  The ASCII digits should be stored 
  679. ;with the least significant digit in the higher memory location, pointed to by 
  680. ;SI.
  681. ;ENTRY:  DS:SI points to the second (least significant) digit
  682. ;STACK USAGE:  none?
  683. ;REGISTERS AFFECTED:  AL
  684. ;RETURN:  hex number in AL, carry set if error, carry clear if OK
  685.  
  686. ASCTOHEX   PROC
  687.            PUSH BX              ;Preserve contents of BX
  688.            MOV AL,[SI]          ;Get LSD of line length,
  689.            SUB AL,30H           ;and try to make it a decimal digit.
  690.            JC ERRET             ;if it's not a digit, go choke.
  691.            CMP AL,09H           ;If it's a decimal digit
  692.            JBE STORE1           ;go store it.
  693.            SUB AL,07H           ;Otherwise, try to make it a hex digit.
  694.            JC ERRET             ;if it's not a digit, go choke.
  695.            CMP AL,0FH           ;If it's not a hex digit,
  696.            JA ERRET             ;go choke.                 
  697. STORE1:    MOV BH,AL            ;Store LSD of line length.
  698.            DEC SI               ;Move to MSD of line length.
  699.            MOV AL,[SI]          ;Get MSD of line length,
  700.            INC SI               ;put SI back where it was,
  701.            SUB AL,30H           ;and try to make it a decimal digit.
  702.            JC ERRET             ;if it's not a digit, go choke.
  703.            CMP AL,09H           ;If it's a decimal digit
  704.            JBE STORE2           ;go store it.
  705.            SUB AL,07H           ;Otherwise, try to make it a hex digit.
  706.            JC ERRET             ;if it's not a digit, go choke.
  707.            CMP AL,0FH           ;If it's not a hex digit,
  708.            JA ERRET             ;go choke.
  709. STORE2:    MOV BL,10H           ;Multiply MSD
  710.            MUL BL               ;by its place value,
  711.            ADD AL,BH            ;then add the LSD
  712.            JC ERRET             ;If overflow, go choke.
  713.            CLC                  ;Note lack of error
  714.            POP BX               ;restore contents of BX
  715.            RET                  ;and return to caller.
  716. ERRET:     STC                  ;Note error
  717.            POP BX               ;restore contents of BX
  718.            RET                  ;and return to caller.
  719. ASCTOHEX   ENDP
  720.  
  721.  
  722. ;PROCEDURE GETKEY --- this procedure uses an MS-DOS function call (via
  723. ;INT 21H) to cause the computer to wait for a character to be pressed
  724. ;on the keyboard.  When a character is pressed, it is echoed to the 
  725. ;display and its ASCII code is stored in AL.  If the character is a
  726. ;<SHIFT-BREAK> (or Ctrl-C), the program terminates and MS-DOS takes over.
  727. ;ENTRY:  no requirements.
  728. ;REGISTERS AFFECTED:  AX.
  729. ;RETURN: AL contains ASCII code for the character pressed.
  730.  
  731. GETKEY     PROC
  732.            MOV AH,1             ;store "get-from-keyboard" function #
  733.            INT 21H              ;and make the function call
  734.            RET                  ;then return to main program
  735. GETKEY     ENDP
  736.  
  737.  
  738. ;PROCEDURE DISPCHAR --- this procedure uses an MS-DOS function call (via
  739. ;INT 21H) to display a character or to send a control character to the
  740. ;display.
  741. ;ENTRY:  DL must contain the ASCII code of the character to be displayed
  742. ;STACK USAGE:  2 bytes, 1 interrupt
  743. ;REGISTERS AFFECTED:  none
  744. ;RETURN:  no data
  745.  
  746. DISPCHAR   PROC
  747.            PUSH AX              ;preserve contents of AX
  748.            MOV AH,2             ;store "send-to-display" function #
  749.            INT 21H              ;and make the function call
  750.            POP AX               ;restore original contents of AX
  751.            RET                  ;then return to main program
  752. DISPCHAR   ENDP
  753.  
  754.  
  755. ;PROCEDURE DISPMSG --- this procedure uses an MS-DOS function call (via
  756. ;INT 21H) to display a character string.  The string must end with a 
  757. ;dollar sign, which will not be sent to the display.
  758. ;ENTRY:  DS must contain the string's segment address and DX must con-
  759. ;        tain the offset of the string's first character.
  760. ;STACK USAGE:  2 bytes, 1 interrupt
  761. ;REGISTERS AFFECTED:  none
  762. ;RETURN:  no data
  763.  
  764. DISPMSG    PROC
  765.            PUSH AX              ;preserve contents of AX
  766.            MOV AH,9             ;store "display message" function #
  767.            INT 21H              ;and make the function call
  768.            POP AX               ;restore original contents of AX
  769.            RET                  ;then return to main program
  770. DISPMSG    ENDP
  771.  
  772. CODE1      ENDS
  773.  
  774.  
  775. ZZZZZZZZ   SEGMENT 'ZZZZ'
  776.            ;This segment is used when releasing memory not needed by the main 
  777.            ;program.  It should be the last segment in its source file so that
  778.            ;it will be placed last in the program file if the assembler and 
  779.            ;linker use sequential segment ordering.  The name ZZZZZZZZZ assures 
  780.            ;that this segment will be last in the program file if the assembler 
  781.            ;or linker uses alphabetic segment ordering.
  782. ZZZZZZZZ   ENDS
  783.  
  784.  
  785.            END START
  786.  
  787.