'=========================================================================== ' Subject: ABSOLUTE ASSEMBLY V2.0 Date: 06-17-97 (11:12) ' Author: Petter Holmberg Code: QB, QBasic, PDS ' Origin: petter.holmberg@usa.net Packet: ASMCODE.ABC '=========================================================================== ' -------------------------------------------------------------------------- ' ' Absolute Assembly 2.0 by Petter Holmberg, -97. ' ' ' ' Since the release of Absolute Assembly 1.1beta, I've had some ideas for ' ' new program features. Also, a friend of mine who recently started learning ' ' Assembler have given me a couple of bug reports and suggestions. So I made ' ' this new version for all of you who found Absolute Assembly 1.1 useful. ' ' For those of you who haven't used AbsAsm 1.1, here's what it does: ' ' ' ' This program will let you choose a text file with Assembly source code, ' ' a destination file name and a string variable name. The result will be a ' ' set of commented BASIC string declaration lines in the destination file, ' ' ready to be executed with CALL ABSOLUTE. ' ' For example, you have a text file looking like this: ' ' ' ' ; A Useless Program example ' ' ' ' XOR AX, AX ; Set AX to 0 ' ' Loopinit: ' ' MOV CX, 4 ; Prepare for a loop ' ' Increase: INC AX ; Incease AX by 1 ' ' LOOP Increase ; Loop 8 times ' ' CMP AX, 8 ; Is AX 8? ' ' JNZ Loopinit ; No. Go back to Loopinit ' ' RETF ; Back to BASIC ' ' ' ' Run it through this program and you will get these lines moved into a ' ' selected BASIC program: ' ' ' ' asm$ = "" ' ' asm$ = asm$ + CHR$(&H31) + CHR$(&HC0) ' XOR AX,AX ' ' asm$ = asm$ + CHR$(&HB9) + CHR$(&H4) + CHR$(&H0) ' Loopinit: MOV CX,0004 ' ' asm$ = asm$ + CHR$(&H40) ' Increase: INC AX ' ' asm$ = asm$ + CHR$(&HE2) + CHR$(&HFD) ' LOOP Increase ' ' asm$ = asm$ + CHR$(&H3D) + CHR$(&H8) + CHR$(&H0) ' CMP AX,0008 ' ' asm$ = asm$ + CHR$(&H75) + CHR$(&HF5) ' JNZ Loopinit ' ' asm$ = asm$ + CHR$(&HCB) ' RETF ' ' ' ' Absolute Assembly takes use of DEBUG, the program shipped with MS-DOS. ' ' DEBUG only supports 8088/8086 instructions, but it's still a good tool for ' ' getting machine language out of Assembly instructions. ' ' ' ' News: ' ' * Support for blank lines and lines with just comments or lables. ' ' * Support for double Assembly commands, like REP STOSB. ' ' * Option to automatically add CALL ABSOLUTE lines to output file. ' ' * All Assembly source lines printed to BASIC file in the same column. ' ' * Option to merge lines directly into a BASIC file. ' ' * Auto-detection of QuickBASIC binary files to ensure safe merging. ' ' * A better handling of errors and bugs in the sourcefile. ' ' ' ' Notes: ' ' Comments must start with a semicolon, (;). ' ' The maximum number of labels are 256. You shouldn't need half as much. ' ' The maximum number of letters for a label are 16. It's easy to change ' ' the program to accept a larger number, but it's probably not necessary. ' ' A line label must be immediately followed by a colon, (:). Do NOT use a ' ' colon after the label name in jump-instructions. ' ' Never use Assembly opcodes, numbers or single letters as labels. ' ' Do not name labels so that the name includes the letters REP, REPE or ' ' REPZ after each other, for example RepeatLoop: ' ' "Label:" and "label:" are processed as the same label. ' ' This program was made in QB45, but you should be able to run it in ' ' QBASIC, PDS, VBDOS and PB as well. ' ' If the program locks up, it's probably while running DEBUG. If this ' ' happens; reboot your computer and check your source code for lines with ' ' other things than Assembly instrucions, comments, labels or spaces. ' ' I haven't really tested this program for bugs, so please be patient with ' ' me. :) ' ' You may use this program freely; distribute it, modify it, learn from it ' ' or erase it from your hard drive. ;) Just be sure to credit me in the ' ' programs where you have used Absolute Assembly for some of the code. ' ' That is, if your program isn't used for illegal business like ' ' destroying secret military computer networks. Then you can take all the ' ' credits yourself. ;) Please also mail me and tell me about the programs ' ' where you have had use for Absolute Assembly! ' ' Any comments/suggestions can be sent to: petter.holmberg@usa.net ' ' The source code is still crappy and not very much commented, but I wrote ' ' this in just a couple of hours. The whole program is basically a very ' ' large and complex string handler - in fact, the most advanced I've ever ' ' written! Maybe I'll add some more functions later... ' ' Enjoy the program and have fun! Petter Holmberg, Sweden. ' ' -------------------------------------------------------------------------- ' ON ERROR GOTO ErrorHandler ' -------------------------------------------------------------------------- ' ' Declaration of constants and arrays: ' ' -------------------------------------------------------------------------- ' CONST rundebug$ = "C:\DOS\DEBUG.EXE" ' Change this if you have DEBUG on ' another location. CONST tempfile1$ = "TEMPFIL1.TXT" ' Change this if the filename already ' is in use. CONST tempfile2$ = "TEMPFIL2.TXT" ' Change this if the filename already ' is in use. CONST tempfile3$ = "TEMPFIL3.TXT" ' Change this if the filename already ' is in use. CONST tempfile4$ = "TEMPFIL4.TXT" ' Change this if the filename already ' is in use. CONST errorfile$ = "ERRORS.TXT" ' Change this if the filename already ' is in use. TYPE labeltype ' Usertype for storing of labels. labelname AS STRING * 16 ' Change this if you want longer labels. labelpos AS STRING * 4 labelnum AS INTEGER END TYPE DIM label(1 TO 256) AS labeltype ' Array for storing of labels. Start: numlabels% = 0 ' Label counter. linecounter% = 1 ' Line counter. errorcounter% = 0 ' Error counter. ' -------------------------------------------------------------------------- ' ' Ask for settings: ' ' -------------------------------------------------------------------------- ' CLS PRINT "Absolute Assembly 2.0 by Petter Holmberg, -97." PRINT INPUT "Assembly source text file : ", sourcefilename$ INPUT "BASIC destination file : ", destfilename$ INPUT "Name of code string : ", codestring$ codestring$ = LTRIM$(RTRIM$(codestring$)) IF codestring$ = "" THEN codestring$ = "asm$" IF RIGHT$(codestring$, 1) <> "$" THEN codestring$ = codestring$ + "$" PRINT "Append to destfile? (y/n) : "; DO kbd$ = INKEY$ IF LCASE$(kbd$) = "n" THEN writemethod% = 0 IF LCASE$(kbd$) = "y" THEN writemethod% = 1 LOOP UNTIL LCASE$(kbd$) = "n" OR LCASE$(kbd$) = "y" PRINT LCASE$(kbd$) PRINT "Add CALL ABSOLUTE lines? (y/n) : "; DO kbd$ = INKEY$ IF LCASE$(kbd$) = "n" THEN callabs% = 0 IF LCASE$(kbd$) = "y" THEN callabs% = 1 LOOP UNTIL LCASE$(kbd$) = "n" OR LCASE$(kbd$) = "y" PRINT LCASE$(kbd$) PRINT ' -------------------------------------------------------------------------- ' ' Warn the user if the BASIC destination file is a QuickBASIC binary file: ' ' -------------------------------------------------------------------------- ' IF writemethod% = 1 THEN DIM readstring AS STRING * 3 OPEN destfilename$ FOR BINARY AS #1 GET #1, , readstring IF readstring = CHR$(252) + CHR$(0) + CHR$(1) THEN PRINT "BASIC destination file is probably a QuickBASIC binary file" PRINT "Continue anyway? (y/n) : " DO kbd$ = INKEY$ IF UCASE$(kbd$) = "N" THEN END LOOP UNTIL UCASE$(kbd$) = "Y" END IF CLOSE #1 END IF ' -------------------------------------------------------------------------- ' ' Get rid of blank lines, comments and double instructions in sourcefile: ' ' -------------------------------------------------------------------------- ' conversiontime! = TIMER PRINT "Modifying source file..." OPEN sourcefilename$ FOR INPUT AS #1 OPEN tempfile1$ FOR OUTPUT AS #2 DO LINE INPUT #1, readline$ sourceline$ = sourceline$ + UCASE$(readline$) IF INSTR(sourceline$, ";") THEN sourceline$ = LEFT$(sourceline$, INSTR(sourceline$, ";") - 1) END IF sourceline$ = LTRIM$(RTRIM$(sourceline$)) IF INSTR(sourceline$, "REPE") THEN PRINT #2, LEFT$(sourceline$, INSTR(sourceline$, "REPE") + 2) + "Z" sourceline$ = RIGHT$(sourceline$, LEN(sourceline$) - INSTR(sourceline$, "REPE") - 3) sourceline$ = LTRIM$(RTRIM$(sourceline$)) ELSEIF INSTR(sourceline$, "REPZ") THEN PRINT #2, LEFT$(sourceline$, INSTR(sourceline$, "REPZ") + 3) sourceline$ = RIGHT$(sourceline$, LEN(sourceline$) - INSTR(sourceline$, "REPZ") - 3) sourceline$ = LTRIM$(RTRIM$(sourceline$)) ELSEIF INSTR(sourceline$, "REP") THEN PRINT #2, LEFT$(sourceline$, INSTR(sourceline$, "REP") + 2) + "Z" sourceline$ = RIGHT$(sourceline$, LEN(sourceline$) - INSTR(sourceline$, "REP") - 2) sourceline$ = LTRIM$(RTRIM$(sourceline$)) END IF IF RIGHT$(sourceline$, 1) <> ":" THEN IF LEN(sourceline$) > 0 THEN PRINT #2, sourceline$ sourceline$ = "" END IF LOOP UNTIL EOF(1) CLOSE #2 CLOSE #1 ' -------------------------------------------------------------------------- ' ' Insert DEBUG instructions and Assembly source code into tempfile and take ' ' care of lables: ' ' -------------------------------------------------------------------------- ' OPEN tempfile1$ FOR INPUT AS #1 OPEN tempfile2$ FOR OUTPUT AS #2 DO LINE INPUT #1, sourceline$ IF INSTR(sourceline$, ":") THEN numlabels% = numlabels% + 1 label(numlabels%).labelname = LEFT$(sourceline$, INSTR(sourceline$, ":") - 1) sourceline$ = MID$(sourceline$, INSTR(sourceline$, ":") + 1) label(numlabels%).labelnum = linecounter% END IF sourceline$ = LTRIM$(RTRIM$(sourceline$)) PRINT #2, sourceline$ linecounter% = linecounter% + 1 LOOP UNTIL EOF(1) CLOSE #2 CLOSE #1 OPEN tempfile2$ FOR INPUT AS #1 OPEN tempfile3$ FOR OUTPUT AS #2 PRINT #2, "a" DO LINE INPUT #1, sourceline$ FOR labelscan% = 1 TO numlabels% IF INSTR(sourceline$, LTRIM$(RTRIM$(label(labelscan%).labelname))) THEN sourceline$ = LEFT$(sourceline$, INSTR(sourceline$, LTRIM$(RTRIM$(label(labelscan%).labelname))) - 1) + "100" END IF NEXT labelscan% PRINT #2, sourceline$ LOOP UNTIL EOF(1) CLOSE #1 PRINT #2, "" PRINT #2, "u 100, 100" PRINT #2, "q" CLOSE #2 ' -------------------------------------------------------------------------- ' ' Run DEBUG to find machine language code length in bytes and then update ' ' the tempfile with the correct byte length: ' ' All errors detected will be written to the file specified in errorfile$ ' ' -------------------------------------------------------------------------- ' PRINT "Detecting machine language code length..." SHELL rundebug$ + "<" + tempfile3$ + ">" + tempfile3$ OPEN tempfile3$ FOR INPUT AS #1 OPEN errorfile$ FOR OUTPUT AS #2 linecounter% = 0 DO oldline$ = midline$ midline$ = newline$ LINE INPUT #1, newline$ SEEK #1, SEEK(1) + 2 IF INSTR(newline$, "^") THEN PRINT PRINT "Error in line"; RTRIM$(STR$(linecounter% - 1)); ":" PRINT midline$ PRINT newline$ PRINT #2, "Error in line"; RTRIM$(STR$(linecounter% - 1)); ":" PRINT #2, midline$ PRINT #2, newline$ errorcounter% = errorcounter% + 1 linecounter% = linecounter% - 1 END IF linecounter% = linecounter% + 1 LOOP UNTIL newline$ = "-u 100, 100" CLOSE #2 CLOSE #1 IF errorcounter% > 0 THEN KILL tempfile1$ KILL tempfile2$ KILL tempfile3$ KILL tempfile4$ PRINT PRINT "Error(s) in source code detected. Look in "; errorfile$; " for information." END END IF asmlength$ = MID$(oldline$, INSTR(oldline$, ":") + 1, 4) PRINT "Source code byte length detected." OPEN tempfile3$ FOR INPUT AS #1 OPEN tempfile4$ FOR OUTPUT AS #2 SEEK #1, SEEK(1) + 5 PRINT #2, "a" DO LINE INPUT #1, sourceline$ SEEK #1, SEEK(1) + 2 sourceline$ = RIGHT$(sourceline$, LEN(sourceline$) - 10) IF LEN(sourceline$) > 0 THEN PRINT #2, sourceline$ LOOP UNTIL sourceline$ = "" CLOSE #1 PRINT #2, "" PRINT #2, "u 100, "; asmlength$ PRINT #2, "q" CLOSE #2 ' -------------------------------------------------------------------------- ' ' Run DEBUG again to create a full output file: ' ' -------------------------------------------------------------------------- ' SHELL rundebug$ + "<" + tempfile4$ + ">" + tempfile3$ ' -------------------------------------------------------------------------- ' ' Scan through DEBUG output file to get the byte offsets for the lines with ' ' labels in the sourcefile: ' ' -------------------------------------------------------------------------- ' OPEN tempfile3$ FOR INPUT AS #1 DO LINE INPUT #1, readline$ LOOP UNTIL INSTR(readline$, "-u 100,") SEEK #1, SEEK(1) + 2 labelcounter% = 1 linecounter% = 1 DO LINE INPUT #1, readline$ IF label(labelcounter%).labelnum = linecounter% THEN label(labelcounter%).labelpos = MID$(readline$, 6, 4) labelcounter% = labelcounter% + 1 END IF linecounter% = linecounter% + 1 LOOP UNTIL readline$ = "-q" CLOSE #1 ' -------------------------------------------------------------------------- ' ' Update tempfile with the correct byte offset numbers for lines with labels ' ' in the sourcefile: ' ' -------------------------------------------------------------------------- ' OPEN tempfile2$ FOR INPUT AS #1 OPEN tempfile3$ FOR OUTPUT AS #2 PRINT #2, "a" DO LINE INPUT #1, sourceline$ FOR labelscan% = 1 TO numlabels% IF INSTR(sourceline$, LTRIM$(RTRIM$(label(labelscan%).labelname))) THEN sourceline$ = LEFT$(sourceline$, INSTR(sourceline$, LTRIM$(RTRIM$(label(labelscan%).labelname))) - 1) + label(labelscan%).labelpos END IF NEXT labelscan% PRINT #2, sourceline$ LOOP UNTIL EOF(1) CLOSE #1 PRINT #2, "" PRINT #2, "u 100, "; asmlength$ PRINT #2, "q" CLOSE #2 PRINT "Label conversion completed." ' -------------------------------------------------------------------------- ' ' Make a final pass through DEBUG to create final output file: ' ' -------------------------------------------------------------------------- ' SHELL rundebug$ + "<" + tempfile3$ + ">" + tempfile3$ PRINT "DEBUG output file successfully created." ' -------------------------------------------------------------------------- ' ' Calculate the longest possible BASIC string declaration line ' ' -------------------------------------------------------------------------- ' linecounter% = 1 longestline% = 0 maxsourcelength% = 0 maxcodelength% = 0 OPEN tempfile3$ FOR INPUT AS #1 DO LINE INPUT #1, readline$ LOOP UNTIL INSTR(readline$, "-u 100,") SEEK #1, SEEK(1) + 2 DO LINE INPUT #1, readline$ linelength% = LEN(RTRIM$(MID$(readline$, 11, 14))) IF linelength% >= longestline% THEN codelength% = 0 FOR findcodelength% = 1 TO linelength% STEP 2 IF MID$(RTRIM$(MID$(readline$, 11, 14)), findcodelength%, 1) = "0" THEN codelength% = codelength% + 1 ELSE codelength% = codelength% + 2 END IF NEXT findcodelength% IF maxsourcelength% < codelength% THEN maxsourcelength% = codelength% longestline% = linelength% END IF linecounter% = linecounter + 1 LOOP UNTIL readline$ = "-q" maxcodelength% = LEN(codestring$) + 3 + LEN(codestring$) + (longestline% \ 2) * 11 + maxsourcelength% CLOSE #1 ' -------------------------------------------------------------------------- ' ' Transform the source code to BASIC string declaration lines: ' ' -------------------------------------------------------------------------- ' FOR modifylabels% = 1 TO numlabels% MID$(label(modifylabels%).labelname, 2, 16) = LCASE$(RIGHT$(label(modifylabels%).labelname, 15)) NEXT modifylabels% OPEN tempfile3$ FOR INPUT AS #1 OPEN tempfile1$ FOR INPUT AS #2 IF writemethod% = 1 THEN OPEN destfilename$ FOR APPEND AS #3 ELSE OPEN destfilename$ FOR OUTPUT AS #3 END IF DO LINE INPUT #1, readline$ LOOP UNTIL INSTR(readline$, "-u 100,") SEEK #1, SEEK(1) + 2 PRINT #3, "" PRINT #3, "' ------ Created with Absolute Assembly 2.0 by Petter Holmberg, -97. ------- '" PRINT #3, "" PRINT #3, codestring$ + " = " + CHR$(34) + CHR$(34) linecounter% = 1 labelcounter% = 1 DO LINE INPUT #1, readline$ readline$ = RTRIM$(readline$) IF NOT EOF(2) THEN LINE INPUT #2, sourceline$ ELSE sourceline$ = "" IF readline$ <> "-q" THEN sourcedata$ = RTRIM$(MID$(readline$, 11, 14)) basicline$ = codestring$ + " = " + codestring$ FOR makebasicline% = 1 TO LEN(sourcedata$) STEP 2 IF MID$(RTRIM$(MID$(readline$, 11, 14)), makebasicline%, 1) = "0" THEN basicline$ = basicline$ + " + CHR$(&H" + MID$(sourcedata$, makebasicline% + 1, 1) + ")" ELSE basicline$ = basicline$ + " + CHR$(&H" + MID$(sourcedata$, makebasicline%, 2) + ")" END IF NEXT makebasicline% IF LEN(basicline$) < maxcodelength% THEN basicline$ = basicline$ + SPACE$(maxcodelength% - LEN(basicline$)) basicline$ = basicline$ + " ' " IF label(labelcounter%).labelnum = linecounter% THEN basicline$ = basicline$ + RTRIM$(label(labelcounter%).labelname) + ": " labelcounter% = labelcounter% + 1 END IF asmline$ = (RIGHT$(readline$, (LEN(readline$) - 24))) IF INSTR(asmline$, CHR$(9)) THEN MID$(asmline$, INSTR(asmline$, CHR$(9))) = " " asmline$ = RTRIM$(asmline$) basicline$ = basicline$ + asmline$ FOR labelscan% = 1 TO numlabels% IF INSTR(sourceline$, UCASE$(RTRIM$(label(labelscan%).labelname))) AND INSTR(sourceline$, ":") = 0 THEN basicline$ = LEFT$(basicline$, LEN(basicline$) - 4) basicline$ = basicline$ + RTRIM$(label(labelscan%).labelname) END IF NEXT labelscan% PRINT #3, basicline$ END IF linecounter% = linecounter% + 1 LOOP UNTIL readline$ = "-q" IF writemethod% = 1 THEN PRINT #3, "" PRINT #3, "offset% = VARPTR("; codestring$; ")" PRINT #3, "DEF SEG = VARSEG("; codestring$; ")" PRINT #3, "CALL ABSOLUTE(offset%)" PRINT #3, "DEF SEG" END IF PRINT #3, "" PRINT #3, "' ------ Created with Absolute Assembly 2.0 by Petter Holmberg, -97. ------- '" CLOSE #3 CLOSE #2 CLOSE #1 PRINT "Source code successfully moved to BASIC destination file." KILL tempfile1$ KILL tempfile2$ KILL tempfile3$ KILL tempfile4$ PRINT PRINT "Time of conversion:"; TIMER - conversiontime!; "seconds." PRINT PRINT "Convert another file? (y/n) : "; DO kbd$ = INKEY$ IF LCASE$(kbd$) = "n" THEN PRINT LCASE$(kbd$) END END IF IF LCASE$(kbd$) = "y" THEN PRINT LCASE$(kbd$) GOTO Start END IF LOOP END ' -------------------------------------------------------------------------- ' ' Error handler: ' ' -------------------------------------------------------------------------- ' ErrorHandler: CLEAR PRINT PRINT "Whoops! An error occured during program execution." PRINT "Check the spelling of your filenames and check the sourcefile for illegal lines." PRINT PRINT "Press any key to end program..." DO: LOOP WHILE INKEY$ = "" END