[number match level address] ASM.to.A86.translator: begin {------------------------------------------------------------- { { A program to convert CP/M ASM files into MSDOS ASM files { { This program is invoked with the following command: { { A>ASM-A86 sourcename { { Note that source-name should have NO file-type specified. { { The input file is assumed to have a file-type of .ASM { The output file will be given a filetype of .A86 { { This program does only a surface-level translation. It { does not do the exhaustive analysis that XLT-86 (from DRI) { does. You will likely need to do quite a bit of editing on { the A86 file to make it useable. Conditional jumps are not { checked to see that they are within range, etc. When the 8080 { code does a PUSH PSW, this program does a PUSH AX. This will { usually work, but will fail when the PUSH PSW was intended to { save the condition-codes rather than simply preserving the value { in the accumulator. { Still, considering the cost of XLT-86, it's not such a { bad deal. { { Copyright (C) 1986 by Shay O. Walters and Para-Soft. { { Permission is granted for this program to be used without { restriction for private non-commercial use. { {--------------------------------------------------------------------- byte source.char; string source.line 133; word source.line.num value 0; pointer to byte source.line.ptr value #source.line; string source.buf 512; file source, file1, text, disk, record source.char, buffer source.buf, value "X.ASM"; byte output.char; string output.line 133; pointer to byte output.line.ptr value #output.line; string output.buff 256; byte output.line.colm; file output.file, disk, file1, text, record output.char, buffer output.buff, value "X.A86"; {--------miscellaneous variables----------} string output.word 81; word word.length; string work.word 81; string curr.address 5; byte curr.delim; byte value 0; {-string ender-} bit flag; bit equ.flag; bit blank.address; word generated.label.num value 1000; string decimal.work 8; string gen.lbl.char 2 value "X"; string high.value.word 2; redefine high.value.word; byte value ^hff, value 0; endredef; string delimiters 24; redefine delimiters; byte value " " ,value "(" ,value "+" ,value ";" ,value ^h09 ,value ")" ,value "-" ,value "=" ,value ^h0d ,value "<" ,value "*" ,value ":" ,value ^h0a ,value ">" ,value "/" ,value "," ,value '!' ,value '[' ,value ']' ,value ^h1a ,value "'" ,value '"' ,value 0; endredef; byte wk.byte; pointer to byte wk.bp; external label entry address 5; external word bdos.ptr address 6; external byte cmd.gen.char address ^h6d; {---reserved word table---} record reserved.word.table; string 4 value 'ACI'; byte value 1; string 4 value 'ADC'; byte value 2; string 4 value 'ADD'; byte value 2; string 4 value 'ADI'; byte value 1; string 4 value 'ANA'; byte value 2; string 4 value 'ANI'; byte value 1; string 5 value 'CALL'; byte value 4; string 3 value 'CC'; byte value 9; string 3 value 'CM'; byte value 9; string 4 value 'CMA'; byte value 3; string 4 value 'CMC'; byte value 3; string 4 value 'CMP'; byte value 2; string 4 value 'CNC'; byte value 9; string 4 value 'CNZ'; byte value 9; string 3 value 'CP'; byte value 9; string 4 value 'CPE'; byte value 9; string 4 value 'CPI'; byte value 1; string 4 value 'CPO'; byte value 9; string 3 value 'CZ'; byte value 9; string 4 value 'DAA'; byte value 3; string 4 value 'DAD'; byte value 10; string 4 value 'DCR'; byte value 16; string 4 value 'DCX'; byte value 10; string 3 value 'DI'; byte value 3; string 3 value 'EI'; byte value 3; string 4 value 'HLT'; byte value 3; string 3 value 'IN'; byte value 1; string 4 value 'INR'; byte value 16; string 4 value 'INX'; byte value 10; string 3 value 'JC'; byte value 4; string 3 value 'JM'; byte value 4; string 4 value 'JMP'; byte value 4; string 4 value 'JNC'; byte value 4; string 4 value 'JNZ'; byte value 4; string 3 value 'JP'; byte value 4; string 4 value 'JPE'; byte value 4; string 4 value 'JPO'; byte value 4; string 3 value 'JZ'; byte value 4; string 4 value 'LDA'; byte value 4; string 5 value 'LDAX'; byte value 11; string 5 value 'LHLD'; byte value 4; string 4 value 'LXI'; byte value 13; string 4 value 'MOV'; byte value 7; string 4 value 'MVI'; byte value 15; string 4 value 'NOP'; byte value 3; string 4 value 'ORA'; byte value 2; string 4 value 'ORI'; byte value 1; string 4 value 'OUT'; byte value 0; {-don't bother-} string 5 value 'PCHL'; byte value 3; string 4 value 'POP'; byte value 10; string 5 value 'PUSH'; byte value 10; string 4 value 'RAL'; byte value 3; string 4 value 'RAR'; byte value 3; string 3 value 'RC'; byte value 8; string 4 value 'RET'; byte value 3; string 4 value 'RLC'; byte value 3; string 3 value 'RM'; byte value 8; string 4 value 'RNC'; byte value 8; string 4 value 'RNZ'; byte value 8; string 3 value 'RP'; byte value 8; string 4 value 'RPE'; byte value 8; string 4 value 'RPO'; byte value 8; string 4 value 'RRC'; byte value 3; string 4 value 'RST'; byte value 0; {-don't bother-} string 3 value 'RZ'; byte value 8; string 4 value 'SBB'; byte value 2; string 4 value 'SBI'; byte value 1; string 5 value 'SHLD'; byte value 6; string 5 value 'SPHL'; byte value 3; string 4 value 'STA'; byte value 5; string 4 value 'STC'; byte value 3; string 5 value 'STAX'; byte value 12; string 4 value 'SUB'; byte value 2; string 4 value 'SUI'; byte value 1; string 5 value 'XCHG'; byte value 3; string 4 value 'XRA'; byte value 2; string 4 value 'XRI'; byte value 1; string 5 value 'XTHL'; byte value 3; string 4 value 'EQU'; byte value 0; string 3 value 'DB'; byte value 0; string 3 value 'DW'; byte value 0; string 3 value 'DS'; byte value 14; string 4 value 'ORG'; byte value 0; string 4 value 'END'; byte value 0; string 5 value "~FFFFFFFF~"; endrec; pointer to string rsvd.wd.tbl.ptr; byte rsvd.wd.length; byte rsvd.word.found; byte op.class; {-------- start of procedures --------} procedure get.source.line: begin fill output.word with 0; fill source.line with 0; while source.char = ^h0a do read source; od; while source.char = ^h00 do read source; od; move #source.line to source.line.ptr; while source.char <> ^h0d and source.char <> "!" do move source.char to @source.line.ptr; add 1 to source.line.ptr; if source.char = ^h0a then read source; move ^h0a to source.char; fi; if source.char = ^h1a then move ^h00 to @source.line.ptr; move #source.line to source.line.ptr; exit; fi; read source; od; read source; {-skip c/r or "!"-} move ^h00 to @source.line.ptr; move #source.line to source.line.ptr; end; {----------------------------------} procedure put.output.char: begin write output.file; mcall entry using 2,output.char; {*debug*} end; procedure put.cr.lf: begin move ^h0d to output.char; call put.output.char; move ^h0a to output.char; call put.output.char; move 1 to output.line.colm; end; {----------------------------------------} procedure put.output.word: begin mcall entry using 11 giving ,,,wk.byte; if wk.byte <> 0 then mcall entry using 1 giving ,,,wk.byte; and wk.byte with ^h7f; if wk.byte = ^h03 then goto end; fi; fi; move #output.word to wk.bp; while @wk.bp <> 0 do if @wk.bp = "." then move "_" to @wk.bp; fi; move @wk.bp to output.char; call put.output.char; add 1 to wk.bp; od; end; {-------------------------------------------} procedure skip.white.space: begin while @source.line.ptr[bp] = " " or @source.line.ptr[bp] = ^h09 do add 1 to source.line.ptr; od; end; procedure get.next.output.word: begin call skip.white.space; scan @source.line.ptr[sp] for any " ,!;:()~090d~" giving word.length; move @source.line.ptr[sp] to output.word length word.length; add word.length to source.line.ptr; add word.length to #output.word giving wk.bp; move 0 to @wk.bp; end; procedure copy.rest.of.line: begin while @source.line.ptr[bp] <> ^h0d and @source.line.ptr[bp] <> 0 and @source.line.ptr[bp] <> ^h0a and @source.line.ptr[bp] <> ^h1a do if @source.line.ptr[bp] = '.' then move "_" to @source.line.ptr[bp]; fi; move @source.line.ptr[bp] to output.char; call put.output.char; add 1 to source.line.ptr; od; call put.cr.lf; end; procedure output.8.bit.reg: begin convert output.word to upper case; switch on output.word: "A": move "al" to output.word; "B": move "ch" to output.word; "C": move "cl" to output.word; "D": move "dh" to output.word; "E": move "dl" to output.word; "H": move "bh" to output.word; "L": move "bl" to output.word; "M": move "[bx]" to output.word; endswitch; call put.output.word; end; procedure output.16.bit.reg: begin convert output.word to upper case; switch on output.word: "H": move "bx" to output.word; "B": move "cx" to output.word; "D": move "dx" to output.word; "PSW": move "ax" to output.word; "SP": move "sp" to output.word; endswitch; call put.output.word; end; {---------- main program ----------} if cmd.gen.char <> " " then move cmd.gen.char to gen.lbl.char[byte]; fi; open source input error begin display "no source file found"; goto end; end; open output.file output error begin display "output file open error"; goto end; end; read source; get.next.source.line: call get.source.line; {-------------------------------------- { Skip over any label {-------------------------------------- restart.this.line: if @source.line.ptr[bp] = ^h1a then goto translation.finished; fi; if @source.line.ptr[bp] = 0 then goto get.next.source.line; fi; if @source.line.ptr[bp] >= "A" and @source.line.ptr[bp] <= "z" then scan @source.line.ptr[sp] for any " :;~090d0a~" giving word.length; move @source.line.ptr[sp] to output.word length word.length; add word.length to #output.word giving wk.bp; move 0 to @wk.bp; call put.output.word; add word.length to source.line.ptr; if @source.line.ptr = ":" then move ":" to output.char; call put.output.char; add 1 to source.line.ptr; if @source.line.ptr[bp] <> " " and @source.line.ptr[bp] <> 0 and @source.line.ptr[bp] <> ^h09 and @source.line.ptr[bp] <> ^h0d then subtract 1 from source.line.ptr; move ^h09 to @source.line.ptr[bp]; fi; fi; if @source.line.ptr[bp] <> " " and @source.line.ptr[bp] <> ^h09 then call put.cr.lf; fi; goto restart.this.line; fi; {------------------------------------------------ { skip any leading white space {------------------------------------------------ while @source.line.ptr[bp] = " " or @source.line.ptr[bp] = ^h09 do move @source.line.ptr[bp] to output.char; call put.output.char; add 1 to source.line.ptr; od; {----------------------------------------------- { Check for comment line {----------------------------------------------- if @source.line.ptr[bp] = ";" then call copy.rest.of.line; goto get.next.source.line; fi; {-------------------------------------------- { Check for null line {-------------------------------------------- if @source.line.ptr[bp] = ^h0d then call put.cr.lf; goto get.next.source.line; fi; {-------------------------------------------- { it's not a label, white space or comment { it must be an op-code {-------------------------------------------- scan @source.line.ptr[sp] for any " ;:()~090d~" giving word.length; move @source.line.ptr[sp] to output.word length word.length; add word.length to source.line.ptr; add word.length to #output.word giving wk.bp; move 0 to @wk.bp; move output.word to work.word; convert work.word to upper case; move "N" to rsvd.word.found; move #reserved.word.table to rsvd.wd.tbl.ptr; do if @rsvd.wd.tbl.ptr = work.word size @rsvd.wd.tbl.ptr giving rsvd.wd.length; add rsvd.wd.length to rsvd.wd.tbl.ptr; add 1 to rsvd.wd.tbl.ptr; move @rsvd.wd.tbl.ptr[bp] to op.class; move "Y" to rsvd.word.found; exitdo; fi; size @rsvd.wd.tbl.ptr giving rsvd.wd.length; add rsvd.wd.length to rsvd.wd.tbl.ptr; add 2 to rsvd.wd.tbl.ptr; od until @rsvd.wd.tbl.ptr[bp] = 0; {------------------------------------------ { don't know what it is. { output it and start over {----------------------------------------- if rsvd.word.found = "N" then call put.output.word; goto restart.this.line; fi; {------------------------------------------ { found a reserved word - translate it {------------------------------------------ switch on op.class: 1: begin {----------------------------- { ACI, ADI, etc. (also IN) {------------------------------ switch on work.word: "ACI": move "adc" to output.word; "ADI": move "add" to output.word; "ANI": move "and" to output.word; "CPI": move "cmp" to output.word; "IN": move "in" to output.word; "ORI": move "or" to output.word; "SBI": move "sbb" to output.word; "SUI": move "sub" to output.word; "XRI": move "xor" to output.word; endswitch; append "~09~al," to output.word; call put.output.word; call skip.white.space; call copy.rest.of.line; goto get.next.source.line; end; 2: begin {----------------------------- { ADC ADD etc. {------------------------------ switch on work.word: "ADC": move "adc" to output.word; "ADD": move "add" to output.word; "ANA": move "and" to output.word; "CMP": move "cmp" to output.word; "ORA": move "or" to output.word; "SBB": move "sbb" to output.word; "SUB": move "sub" to output.word; "XRA": move "xor" to output.word; endswitch; append "~09~al," to output.word; call put.output.word; call skip.white.space; call get.next.output.word; call output.8.bit.reg; call copy.rest.of.line; goto get.next.source.line; end; 3: begin {----------------------------- { op's with no arguments {------------------------------ switch on work.word: "CMA": move "not~09~al" to output.word; "CMC": move "cmc" to output.word; "DAA": move "daa" to output.word; "DI": move "cli" to output.word; "EI": move "sti" to output.word; "HLT": move "halt" to output.word; "NOP": move "nop" to output.word; "PCHL": move "jmp~09~bx" to output.word; "RAL": move "rcl~09~al,1" to output.word; "RAR": move "rcr~09~al,1" to output.word; "RET": move "ret" to output.word; "RLC": move "rol~09~al,1" to output.word; "RRC": move "ror~09~al,1" to output.word; "SPHL": move "mov~09~sp,bx" to output.word; "XCHG": move "xchg~09~bx,dx" to output.word; "XTHL": move "pop bp ! push bx ! mov bx,bp" to output.word; endswitch; call put.output.word; call copy.rest.of.line; goto get.next.source.line; end; 4: begin {----------------------------------- { op with single label {----------------------------------- switch on work.word: "CALL": move "call~09~" to output.word; "JMP": move "jmp~09~" to output.word; "JC": move "jc~09~" to output.word; "JM": move "js~09~" to output.word; "JNC": move "jnc~09~" to output.word; "JNZ": move "jnz~09~" to output.word; "JP": move "jns~09~" to output.word; "JPE": move "jpe~09~" to output.word; "JPO": move "jpo~09~" to output.word; "JZ": move "jz~09~" to output.word; "LDA": move "mov~09~al," to output.word; "LHLD": move "mov~09~bx," to output.word; endswitch; call put.output.word; call skip.white.space; call copy.rest.of.line; goto get.next.source.line; end; 5: begin {----------------------------------- { STA {----------------------------------- move "mov~09~" to output.word; call put.output.word; call skip.white.space; call get.next.output.word; call put.output.word; move ",al" to output.word; call put.output.word; call copy.rest.of.line; goto get.next.source.line; end; 6: begin {----------------------------------- { SHLD {----------------------------------- move "mov~09~" to output.word; call put.output.word; call skip.white.space; call get.next.output.word; call put.output.word; move ",bx" to output.word; call put.output.word; call copy.rest.of.line; goto get.next.source.line; end; 7: begin {--------------------- { MOV {--------------------- move "mov~09~" to output.word; call put.output.word; call skip.white.space; call get.next.output.word; call output.8.bit.reg; call skip.white.space; if @source.line.ptr[bp] <> "," then {--error--} call copy.rest.of.line; goto get.next.source.line; fi; move ',' to output.char; call put.output.char; add 1 to source.line.ptr; call get.next.output.word; call output.8.bit.reg; call copy.rest.of.line; goto get.next.source.line; end; 8: begin {-------------------------------------- { conditional RETURN {-------------------------------------- switch on work.word: "RC": move "jnc" to output.word; "RM": move "jns" to output.word; "RNC": move "jc" to output.word; "RNZ": move "jz" to output.word; "RP": move "js" to output.word; "RPE": move "jpo" to output.word; "RPO": move "jpe" to output.word; "RZ": move "jnz" to output.word; endswitch; append "~09~" to output.word; append gen.lbl.char to output.word; convert generated.label.num to decimal.work; append decimal.work to output.word; call put.output.word; call put.cr.lf; move "~09~ret" to output.word; call put.output.word; call copy.rest.of.line; move gen.lbl.char[byte] to output.word[byte]; move decimal.work to output.word[+1]; append ":" to output.word; call put.output.word; call put.cr.lf; add 1 to generated.label.num; goto get.next.source.line; end; 9: begin {-------------------------------------- { conditional CALL {-------------------------------------- switch on work.word: "CC": move "jnc" to output.word; "CM": move "jns" to output.word; "CNC": move "jc" to output.word; "CNZ": move "jz" to output.word; "CP": move "js" to output.word; "CPE": move "jpo" to output.word; "CPO": move "jpe" to output.word; "CZ": move "jnz" to output.word; endswitch; append "~09~" to output.word; append gen.lbl.char to output.word; convert generated.label.num to decimal.work; append decimal.work to output.word; call put.output.word; call put.cr.lf; move "~09~call" to output.word; call put.output.word; call copy.rest.of.line; move gen.lbl.char[byte] to output.word[byte]; move decimal.work to output.word[+1]; append ":" to output.word; call put.output.word; call put.cr.lf; add 1 to generated.label.num; goto get.next.source.line; end; 10: begin {------------------------------ { op with single double-reg arg {------------------------------ switch on work.word: "DAD": move "add~09~bx," to output.word; "DCX": move "dec~09~" to output.word; "INX": move "inc~09~" to output.word; "POP": move "pop~09~" to output.word; "PUSH": move "push~09~" to output.word; endswitch; call put.output.word; call skip.white.space; call get.next.output.word; call output.16.bit.reg; call copy.rest.of.line; goto get.next.source.line; end; 11: begin {----------------- { LDAX {----------------- call skip.white.space; move "mov~09~si," to output.word; call put.output.word; call get.next.output.word; call output.16.bit.reg; move " ! mov al,[si]" to output.word; call put.output.word; call copy.rest.of.line; goto get.next.source.line; end; 12: begin {----------------- { STAX {----------------- call skip.white.space; move "mov~09~di," to output.word; call put.output.word; call get.next.output.word; call output.16.bit.reg; move " ! mov [di],al" to output.word; call put.output.word; call copy.rest.of.line; goto get.next.source.line; end; 13: begin {----------------- { LXI {----------------- call skip.white.space; move "mov~09~" to output.word; call put.output.word; call get.next.output.word; call output.16.bit.reg; if @source.line.ptr[bp] <> "," then call copy.rest.of.line; goto get.next.source.line; fi; add 1 to source.line.ptr; move "," to output.char; call put.output.char; call skip.white.space; if @source.line.ptr <> "-" then if @source.line.ptr[bp] < "0" or @source.line.ptr[bp] > "9" then move " offset " to output.word; call put.output.word; fi; fi; call copy.rest.of.line; goto get.next.source.line; end; 14: begin {------------------------ { DS {------------------------ move "rs" to output.word; call put.output.word; call copy.rest.of.line; goto get.next.source.line; end; 15: begin {----------------------------- { MVI {------------------------------ move "mov~09~" to output.word; call put.output.word; call skip.white.space; call get.next.output.word; call output.8.bit.reg; call skip.white.space; call copy.rest.of.line; goto get.next.source.line; end; 16: begin {----------------------------- { INR DCR {------------------------------ switch on work.word: "DCR": move "dec" to output.word; "INR": move "inc" to output.word; endswitch; append "~09~" to output.word; call put.output.word; call skip.white.space; call get.next.output.word; call output.8.bit.reg; call copy.rest.of.line; goto get.next.source.line; end; endswitch; call put.output.word; call copy.rest.of.line; goto get.next.source.line; translation.finished: close output.file; display "finished"; end;