CNVZ80B1 { (C) Copyright 1982 by Motorola Inc. } {**********convert Z80 to MC68000 source utility **********} ÿ{ subroutines } subprogram convert (input,output,infile,outfile); const imagelen = 100; {input line length} labellen = 7; { label length (+:) } charlen = 80; { general character length } type labels = string[labellen]; chars = string[charlen]; oprtype = (Dreg,Areg, { registers } Dindirect,Aindirect,{ indirect reference } Aindpointer, { pointer on stack } IXdisp,IYdisp, { pointer in Dreg with displacement } imaddr, { immediate address } immed,none); { immediate data, not set } size = (unknown,byte,word); var image: string[imagelen]; { input image } copyimage: string[imagelen]; { print image string } lbl: labels; { label field } opc: chars; { opcode field } opr1,opr2: chars; { operands } comment: string[imagelen]; { comment } opr1type,opr2type: oprtype; { operand types } datalen: size; { byte or word operation } lines: integer; { input lines read } msgs: integer; { diagnostic count } linesout: integer; { assembler lines into output file } linesunmatched: integer; { unconverted lines copied over } infile,outfile: text; { in and out files } passthis: boolean; { pass this record thru unaltered } passmode: boolean; { pass flag for pass mode } errormsg: chars; { error message } newEA: chars; { replacement EA for data loads } ccop: string[2]; { CC operation } baseaddr: chars; { loaddata primary address } freshccr: boolean; { CCR is fresh } MC68010: boolean; { MC68010 target machine } procedure convert; type errortype = (warning,error); var spaces: chars; { blank fill for output control } { diagnostic message procedure } procedure diagnostic(severity:errortype; message:chars); begin if severity=warning then writeln(outfile,'******** WARNING *** ',message) else writeln(outfile,' FAIL 0 **** ',message); writeln('input line',lines:5,' output line',linesout:5,' ',message); linesout := linesout + 1; msgs := msgs + 1; if severity=error then freshccr := false end; { output 68000 assembly language statement } procedure emit(opcode,opr1,opr2: chars); var spclbl,spcopc,spccmnt: integer; { format spacing } { return indication of ccr transparancy } function ccrclobbered: boolean; var rawopcode: string[10]; destisAn: boolean; work: integer; begin ccrclobbered := true; work := pos(opcode,'.'); { strip length specification } if work > 0 then rawopcode := copy(opcode,1,work-1) else rawopcode := opcode; destisAn := false; if length(opr2)=2 then if (opr2[1]='A') and (opr2[2] in ['0'..'7']) then destisAn := true; if pos('EXG LEA LINK MOVEM MOVEP PEA UNLK NOP ', concat(rawopcode,' ')) > 0 then ccrclobbered := false; if ((rawopcode='ADD') or (rawopcode='SUB') or (rawopcode='MOVE')) and destisAn then ccrclobbered := false; if (rawopcode='MOVE') and (opr1='SR') then ccrclobbered := false; if length(rawopcode)=3 then if rawopcode[1]='B' then ccrclobbered := false end; begin comment := ''; { do not print duplicate comment field } if length(opr2) > 0 then opr2 := concat(',',opr2); spclbl := 10 - length(lbl); if spclbl < 1 then spclbl := 1; spcopc := 10 - length(opcode); if spcopc < 1 then spcopc := 1; spccmnt := 19 - length(opr1) - length(opr2) -1; if spccmnt < 1 then spccmnt := 1; writeln(outfile,lbl,copy(spaces,1,spclbl), { label field } opcode,copy(spaces,1,spcopc), { opcode field } opr1,opr2,copy(spaces,1,spccmnt), { comment field } ' ',comment); if ccrclobbered then freshccr := false; linesout := linesout + 1; comment := ''; lbl := '' end; { procedure to emit with size specification added } procedure emitsz(opcode,opr1,opr2: chars); begin if datalen=byte then emit(concat(opcode,'B'),opr1,opr2) else emit(concat(opcode,'W'),opr1,opr2) end; { procedure to set psuedo carry to x bit of CCR } procedure refreshccr; begin if not freshccr then emit('MOVE.W','D1','CCR') end; { procedure to update psuedo Z80 condition code } procedure saveccr; begin if MC68010 then emit('MOVE.W','CCR','D1') else emit('MOVE.W','SR','D1'); freshccr := true end; { procedure to set S, Z, and V CC bits (all but C) } procedure setszv; begin emit('BSR','...SETSZV',''); freshccr := true end; { procedure to set only C CC bit } procedure setc; begin emit('BSR','...SETC',''); freshccr := true end; { procedure to clear C CC bit } procedure clearc; begin emit('AND.B','D5','D1') end; { procedure to setup operand addressability } procedure loadaddr(addr:chars; addrtype:oprtype); begin case addrtype of Dreg,Areg,Aindirect,imaddr: newEA := addr; Dindirect,Aindpointer: begin emit('MOVE.W',addr,'A0'); newEA := '(A0)' end; IXdisp: begin emit('MOVE.W','D6','A0'); newEA := concat(addr,'(A0)') end; IYdisp: begin emit('MOVE.W','D7','A0'); newEA := concat(addr,'(A0)') end; immed: newEA := concat('#',addr) end; end; { procedure to load data into data register } procedure loaddata(source,dest:chars; srctype:oprtype); begin if srctype=Dreg then begin newEA := source; baseaddr := source end else begin loadaddr(source,srctype); baseaddr := newEA; emitsz('MOVE.',newEA,dest); newEA := dest end end; { procedure to store register into destination } procedure storedata(source,dest:chars; desttype:oprtype); begin loadaddr(dest,desttype); emitsz('MOVE.',source,newEA) end; { procedure to store register back to original load } procedure storeback(source: chars); begin if source<>baseaddr then emitsz('MOVE.',source,baseaddr) end; { procedure to convert CC into opposite condition code format } procedure scancc; begin if opr1='(A2)' then opr1 := 'C '; { taken as a register } if opr1='C ' then begin emit('BTST.L','#4','D1'); ccop := 'EQ' { carry set } end else if opr1='NC' then begin emit('BTST.L','#4','D1'); ccop := 'NE' { carry clear } end else if opr1='M ' then ccop := 'PL' { minus } else if opr1='P ' then ccop := 'MI' { plus } else if opr1='Z ' then ccop := 'NE' { zero } else if opr1='NZ' then ccop := 'EQ' { not zero } else if opr1='PE' then ccop := 'VC' { overflow set } else if opr1='PO' then ccop := 'VS'; { overflow clear } if not ((opr1='C ') or (opr1='NC')) then refreshccr; if (opr1='PO') or (opr1='PE') then diagnostic(warning,'P/V branch test unsupported if for parity') end; { procedure to emit branch } procedure emitbranch; begin if opr2type=none then emit('BRA',opr1,'') else begin scancc; if ccop='CC' then ccop := 'CS' else if ccop='CS' then ccop := 'CC' else if ccop='PL' then ccop := 'MI' else if ccop='MI' then ccop := 'PL' else if ccop='VC' then ccop := 'VS' else if ccop='VS' then ccop := 'VC' else if ccop='EQ' then ccop := 'NE' else if ccop='NE' then ccop := 'EQ'; emit(concat('B',ccop),opr2,''); end end; { function to return low byte register pair pointer given pair } function lowbyte(pair:chars): chars; begin if pair='(A1)' then lowbyte := '(A2)' else if pair='(A3)' then lowbyte := '(A4)' else if pair='(SP)' then lowbyte := '(A5)' end; { procedure to handle DEFB } procedure DEFB; var x,y: integer; inrange: boolean; begin x := pos(image,concat(' ',opr1)) + 1; y := x-1; inrange := true; while inrange do begin y := y + 1; if image[y]='''' then repeat y:=y+1 until image[y]=''''; if image[y] in [' ',';'] then begin inrange := false; y := y - 1 end; if y=length(image) then inrange := false end; emit('DC.B',copy(image,x,y-x+1),'') end; {DEFB} { procedure to handle DEFW supporting optional multiple fields } procedure DEFW; var x: integer; parse: string[imagelen]; begin x := pos(image,concat(' ',opr1)) + 1; parse := delete(image,1,x-1); while length(parse) > 0 do begin { emit subgroups } opr1 := ''; x := 0; while length(opr1) = 0 do begin { scan for terminator } x := x + 1; case parse[x] of '''': repeat x:=x + 1 until parse[x]=''''; ',': begin opr1 := copy(parse,1,x-1); parse := delete(parse,1,x) end; ' ',';': begin opr1 := copy(parse,1,x-1); parse := '' end; otherwise if x=length(parse) then begin opr1 := parse; parse := '' end end {case} end; {scan terminator} emit('DC.B',concat( '(',opr1,')-((',opr1,')/256)*256,(',opr1,')/256') ,'') end {emit subgroups} end; {DEFW} begin {convert} spaces := ' '; if (length(errormsg)=0) and (not passthis) then begin writeln(outfile,'* ',copyimage); linesout := linesout + 1; if lbl <> ' ' then freshccr := false end else begin { do not process statement } passthis := true; linesout := linesout + 1; writeln(outfile,image); if length(errormsg)>0 then diagnostic(error,errormsg); end; if not passthis then if opc = 'ADC' then begin if opr1='D0' then begin { A destination } loaddata(opr2,'D2',opr2type); refreshccr; emit('ADDX.B',newEA,'D0'); saveccr end else if opr2='A6' then begin {SP to HL} loaddata(opr1,'D2',opr1type); emit('MOVE.W','A6','D3'); refreshccr; emit('ADDX.W','D3',newEA); saveccr; storedata(newEA,opr1,opr1type) end else begin {BC,DE,HL to HL} emit('LEA',opr2,'A0'); refreshccr; emit('ADDX.W','-(A0)','-(SP)'); saveccr; emit('ADD.W','#2','SP') end end else if opc = 'ADD' then begin if opr1='D0' then begin { destination is A } loadaddr(opr2,opr2type); emitsz('ADD.',newEA,opr1); saveccr end else begin { destination must be HL,IX,IY } if opr1type=Dreg then loadaddr(opr2,opr2type) else loaddata(opr2,'D2',opr2type); emit('ADD.W',newEA,opr1); setc end end else if opc = 'AND' then begin loadaddr(opr1,opr1type); emit('AND.B',newEA,'D0'); saveccr; clearc end else if opc = 'BIT' then begin loadaddr(opr2,opr2type); refreshccr; if opr2type=Dreg then emit('BTST.L',concat('#',opr1),newEA) else emit('BTST.B',concat('#',opr1),newEA); saveccr end else if opc = 'CALL' then begin if opr2type=none then emit('LEA',opr1,'A0') else begin emit('LEA',opr2,'A0'); scancc; emit(concat('B',ccop,'.S'),'*+6','') end; emit('BSR','...CALL',''); freshccr := false end else if opc = 'CCF' then emit('EOR.B','#$11','D1') else if opc = 'CP' then begin emit('MOVE.B','D0','D2'); loadaddr(opr1,opr1type); emit('SUB.B',newEA,'D2'); saveccr end else if opc = 'CPIR' then emit('BSR','...CPIR','') else if opc = 'CPI' then emit('BSR','...CPI','') else if opc = 'CPD' then emit('BSR','...CPD','') else if opc = 'CPDR' then emit('BSR','...CPDR','') else if opc = 'CPL' then emit('NOT.B','D0','') else if opc = 'DAA' then diagnostic(error,'DAA cannot be converted') else if opc = 'DEC' then case datalen of byte: begin loadaddr(opr1,opr1type); emit('SUB.B','#1',newEA); setszv end; word: emit('SUB.W','#1',opr1); end else if opc = 'DEFB' then DEFB else if opc = 'DEFM' then emit('DC.B',opr1,'') else if opc = 'DEFL' then emit('SET',opr1,'') else if opc = 'DEFS' then emit('DS.B',opr1,'') else if opc = 'DEFW' then DEFW else if (opc = 'DI') or (opc = 'EI') then diagnostic(error,'DI/EI interrupts require rewrite') else if opc = 'DJNZ' then begin emit('SUB.B','#1','(A1)'); emit('BNE',opr1,'') end else if opc = 'EJECT' then emit('PAGE','','') else if opc = 'END' then begin if opr1[1] in ['0'..'9'] then diagnostic(error,'fixed address untranslatable'); if length(opr1)>1 then if ((opr1[1] in ['$','@','%']) and (opr1[2] in ['0'..'9'])) then diagnostic(error,'fixed address untranslatable'); emit('END',opr1,'') end else if opc = 'EQU' then emit('EQU',opr1,'') else if opc = 'EX' then begin if opr1='(A6)' then begin { (SP),XX } if opr2='(SP)' then emit('BSR','...EXHL','') else if opr2='D6' then emit('BSR','...EXIX','') else if opr2='D7' then emit('BSR','...EXIY','') end else if opr1='(A3)' then begin { DE,HL } emit('MOVE.W',opr1,'D2'); emit('MOVE.W',opr2,opr1); emit('MOVE.W','D2',opr2) end else if opr1='AF' then begin { AF,AF' } emit('SWAP.W','D0',''); emit('SWAP.W','D1','') end end else if opc = 'EXX' then emit('BSR','...EXX','') else if opc = 'HALT' then begin emit('STOP','#0',''); diagnostic(warning,'HALT simulated with STOP instruction') end else if opc = 'IM' then diagnostic(error, 'IM - set interrupt mode not convertable') else if opc = 'IN' then diagnostic(error,'IN instruction unconvertable') else if opc = 'INC' then case datalen of byte: begin loadaddr(opr1,opr1type); emit('ADD.B','#1',newEA); setszv end; word: emit('ADD.W','#1',opr1); end else if (opc='IND') or (opc='INDR') or (opc='INI') or (opc='INIR') then diagnostic(error,'IND/INDR/INI/INIR I/O untranslatable') else if opc = 'JP' then begin if opr1type in [Aindpointer,Dindirect] then begin loadaddr(opr1,opr1type); emit('JMP','(A0)','') end else if opr2type=none then emit('BRA',opr1,'') { conditional jump } else emitbranch end else if opc = 'JR' then begin emitbranch; if pos(concat(opr1,opr2),'-$') > 0 then diagnostic(error, 'absolute branch displacements untranslatable') end else if opc = 'LD' then begin case datalen of { byte moves } byte: case opr1type of IXdisp,IYdisp,Aindpointer,Dindirect: begin loadaddr(opr1,opr1type); if opr2type=immed then opr2 := concat('#',opr2); emit('MOVE.B',opr2,newEA) end; otherwise begin loadaddr(opr2,opr2type); emit('MOVE.B',newEA,opr1) end end; { word moves } word: case opr1type of imaddr: case opr2type of { opr1 is address } Dreg,Areg: begin { opr2 in register } emit('MOVE.W',opr2,'-(SP)'); emit('MOVE.B','1(SP)',opr1); emit('MOVE.B','(SP)+',concat(opr1,'+1')) end; otherwise begin { create a pointer } loadaddr(opr2,opr2type); emit('MOVE.B',lowbyte(opr2),opr1); emit('MOVE.B',opr2,concat(opr1,'+1')) end end; Aindirect: case opr2type of imaddr: begin emit('MOVE.B',opr2,lowbyte(opr1)); emit('MOVE.B',concat(opr2,'+1'),opr1) end; otherwise begin loadaddr(opr2,opr2type); emit('MOVE.W',newEA,opr1) end end; { indirect } Dreg,Areg: case opr2type of imaddr: begin emit('MOVE.B',concat(opr2,'+1'),'-(SP)'); emit('MOVE.B',opr2,'1(SP)'); emit('MOVE.W','(SP)+',opr1) end; otherwise begin loadaddr(opr2,opr2type); emit('MOVE.W',newEA,opr1) end end { Dreg,Areg } end { word } end { case } end { LD } else if opc = 'LDIR' then emit('BSR','...LDIR','') else if opc = 'LDI' then emit('BSR','...LDI','') else if opc = 'LDD' then emit('BSR','...LDD','') else if opc = 'LDDR' then emit('BSR','...LDDR','') else if opc = 'NEG' then begin emit('NEG.B','D0',''); saveccr end else if opc = 'NOP' then emit('NOP','','') else if opc = 'OR' then begin loadaddr(opr1,opr1type); emit('OR.B',newEA,'D0'); saveccr; clearc end else if opc = 'ORG' then begin emit('ORG',opr1,''); diagnostic(warning,'''ORG'' encountered') end else if opc = 'OUT' then diagnostic(error,'OUT I/O untranslatable') else if (opc='OUTD') or (opc='OTDR') or (opc='OUTI') or (opc='OTIR') then diagnostic(error,'OUTD/OTDR/OUTI/OTIR I/O untranslatable') else if opc = 'POP' then case opr1type of Dreg: begin emit('MOVE.B','1(A6)','-(SP)'); emit('MOVE.B','(A6)','1(SP)'); emit('MOVE.W','(SP)+',opr1); emit('ADD.W','#2','A6') end; Aindirect: begin emit('MOVE.B','(A6)+',lowbyte(opr1)); emit('MOVE.B','(A6)+',opr1) end; otherwise begin diagnostic(warning,'flags read as MC68000 CCR format'); emit('MOVE.B','(A6)+','D1'); emit('MOVE.B','(A6)+','D0') end; end else if opc = 'PUSH' then case opr1type of Dreg: begin emit('MOVE.W',opr1,'-(SP)'); emit('MOVE.B','1(SP)','-(A6)'); emit('MOVE.B','(SP)+','-(A6)') end; Aindirect: begin emit('MOVE.B',opr1,'-(A6)'); emit('MOVE.B',lowbyte(opr1),'-(A6)') end; otherwise begin diagnostic(warning,'flags stored as MC68000 CCR format'); emit('MOVE.B','D0','-(A6)'); emit('MOVE.B','D1','-(A6)'); end; end else if opc = 'RES' then begin loadaddr(opr2,opr2type); refreshccr; if opr2type=Dreg then emit('BCLR.L',concat('#',opr1),newEA) else emit('BCLR.B',concat('#',opr1),newEA); saveccr end else if opc = 'RET' then begin if opr1type=none then opr1 := '...RET' else begin opr2 := '...RET'; opr2type := imaddr end; emitbranch end else if (opc = 'RETI') or (opc = 'RETN') then diagnostic(error,'RETI/RETN interrupt returns untranslatable') else if opc = 'RL' then begin loaddata(opr1,'D2',opr1type); refreshccr; emit('ADDX.B',newEA,newEA); saveccr; storeback(newEA) end else if opc = 'RLA' then begin refreshccr; emit('ADDX.B','D0','D0'); setc end else if opc = 'RLC' then begin loaddata(opr1,'D2',opr1type); emit('ROL.B','#1',newEA); saveccr; storeback(newEA) end else if opc = 'RLCA' then begin emit('ROL.B','#1','D0'); setc end else if opc = 'RLD' then emit('BSR','...RLD','') else if opc = 'RR' then begin loaddata(opr1,'D2',opr1type); refreshccr; emit('ROXR.B','#1',newEA); saveccr; storeback(newEA) end else if opc = 'RRA' then begin refreshccr; emit('ROXR.B','#1','D0'); setc end else if opc = 'RRC' then begin loaddata(opr1,'D2',opr1type); refreshccr; emit('ROR.B','#1',newEA); saveccr; storeback(newEA) end else if opc = 'RRCA' then begin emit('ROR.B','#1','D0'); setc end else if opc = 'RRD' then emit('BSR','...RRD','') else if opc = 'RST' then diagnostic(error,'RST restart untranslatable') else if opc = 'SBC' then begin if opr1='D0' then begin { A destination } loaddata(opr2,'D2',opr2type); refreshccr; emit('SUBX.B',newEA,'D0'); saveccr end else if opr2='A6' then begin {SP to HL} loaddata(opr1,'D2',opr1type); emit('MOVE.W','A6','D3'); refreshccr; emit('SUBX.W','D3',newEA); saveccr; storedata(newEA,opr1,opr1type) end else begin {BC,DE,HL to HL} emit('LEA',opr2,'A0'); refreshccr; emit('SUBX.W','-(A0)','-(SP)'); saveccr; emit('ADD.W','#2','SP') end end else if opc = 'SCF' then emit('OR.B','#$10','D1') else if opc = 'SET' then begin loadaddr(opr2,opr2type); refreshccr; if opr2type=Dreg then emit('BSET.L',concat('#',opr1),newEA) else emit('BSET.B',concat('#',opr1),newEA); saveccr end else if opc = 'SLA' then begin loaddata(opr1,'D2',opr1type); emit('ADD.B',newEA,newEA); saveccr; storeback(newEA) end else if opc = 'SRA' then begin loaddata(opr1,'D2',opr1type); emit('ASR.B','#1',newEA); saveccr; storeback(newEA) end else if opc = 'SRL' then begin loaddata(opr1,'D2',opr1type); emit('LSR.B','#1','D2'); saveccr; storeback(newEA) end else if opc = 'SUB' then begin loadaddr(opr1,opr1type); emit('SUB.B',newEA,'D0'); saveccr end else if opc = 'XOR' then begin loaddata(opr1,'D2',opr1type); emit('EOR.B',newEA,'D0'); saveccr; clearc end else if (length(opc)=0) and (length(lbl)>0) then begin { only label on stmt } lbl := concat(lbl,':'); emit('EQU','*',''); diagnostic(warning,'label may need word alignment') end else begin linesout := linesout + 1; writeln(outfile,image); diagnostic(error,'this statement unidentified'); linesunmatched := linesunmatched + 1 end; end.