|
@@ -0,0 +1,363 @@
|
|
|
|
+{
|
|
|
|
+ Copyright (c) 1998-2003 by Carl Eric Codere and Peter Vreman
|
|
|
|
+
|
|
|
|
+ Handles the common 68k assembler reader routines
|
|
|
|
+
|
|
|
|
+ This program is free software; you can redistribute it and/or modify
|
|
|
|
+ it under the terms of the GNU General Public License as published by
|
|
|
|
+ the Free Software Foundation; either version 2 of the License, or
|
|
|
|
+ (at your option) any later version.
|
|
|
|
+
|
|
|
|
+ This program is distributed in the hope that it will be useful,
|
|
|
|
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
+ GNU General Public License for more details.
|
|
|
|
+
|
|
|
|
+ You should have received a copy of the GNU General Public License
|
|
|
|
+ along with this program; if not, write to the Free Software
|
|
|
|
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
+
|
|
|
|
+ ****************************************************************************
|
|
|
|
+}
|
|
|
|
+unit ra68k;
|
|
|
|
+
|
|
|
|
+{$i fpcdefs.inc}
|
|
|
|
+
|
|
|
|
+ interface
|
|
|
|
+
|
|
|
|
+ uses
|
|
|
|
+ aasmbase,aasmtai,aasmcpu,
|
|
|
|
+ cpubase,rautils,cclasses;
|
|
|
|
+
|
|
|
|
+ type
|
|
|
|
+ Tm68kOperand=class(TOperand)
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ Tm68kInstruction=class(TInstruction)
|
|
|
|
+ opsize : topsize;
|
|
|
|
+ function ConcatInstruction(p : taasmoutput):tai;override;
|
|
|
|
+ function ConcatLabeledInstr(p : taasmoutput):tai;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ implementation
|
|
|
|
+
|
|
|
|
+ uses
|
|
|
|
+ verbose,cgbase;
|
|
|
|
+
|
|
|
|
+{*****************************************************************************
|
|
|
|
+ TM68kInstruction
|
|
|
|
+*****************************************************************************}
|
|
|
|
+
|
|
|
|
+ function TM68kInstruction.ConcatInstruction(p : taasmoutput):tai;
|
|
|
|
+ var
|
|
|
|
+ fits : boolean;
|
|
|
|
+ begin
|
|
|
|
+ result:=nil;
|
|
|
|
+ fits := FALSE;
|
|
|
|
+ { setup specific opcodetions for first pass }
|
|
|
|
+
|
|
|
|
+ { Setup special operands }
|
|
|
|
+ { Convert to general form as to conform to the m68k opcode table }
|
|
|
|
+ if (opcode = A_ADDA) or (opcode = A_ADDI)
|
|
|
|
+ then opcode := A_ADD
|
|
|
|
+ else
|
|
|
|
+ { CMPM excluded because of GAS v1.34 BUG }
|
|
|
|
+ if (opcode = A_CMPA) or
|
|
|
|
+ (opcode = A_CMPI) then
|
|
|
|
+ opcode := A_CMP
|
|
|
|
+ else
|
|
|
|
+ if opcode = A_EORI then
|
|
|
|
+ opcode := A_EOR
|
|
|
|
+ else
|
|
|
|
+ if opcode = A_MOVEA then
|
|
|
|
+ opcode := A_MOVE
|
|
|
|
+ else
|
|
|
|
+ if opcode = A_ORI then
|
|
|
|
+ opcode := A_OR
|
|
|
|
+ else
|
|
|
|
+ if (opcode = A_SUBA) or (opcode = A_SUBI) then
|
|
|
|
+ opcode := A_SUB;
|
|
|
|
+
|
|
|
|
+ { Setup operand types }
|
|
|
|
+
|
|
|
|
+(*
|
|
|
|
+ in opcode <> A_MOVEM then
|
|
|
|
+ begin
|
|
|
|
+
|
|
|
|
+ while not(fits) do
|
|
|
|
+ begin
|
|
|
|
+ { set the opcodetion cache, if the opcodetion }
|
|
|
|
+ { occurs the first time }
|
|
|
|
+ if (it[i].i=opcode) and (ins_cache[opcode]=-1) then
|
|
|
|
+ ins_cache[opcode]:=i;
|
|
|
|
+
|
|
|
|
+ if (it[i].i=opcode) and (instr.ops=it[i].ops) then
|
|
|
|
+ begin
|
|
|
|
+ { first fit }
|
|
|
|
+ case instr.ops of
|
|
|
|
+ 0 : begin
|
|
|
|
+ fits:=true;
|
|
|
|
+ break;
|
|
|
|
+ end;
|
|
|
|
+ 1 :
|
|
|
|
+ begin
|
|
|
|
+ if (optyp1 and it[i].o1)<>0 then
|
|
|
|
+ begin
|
|
|
|
+ fits:=true;
|
|
|
|
+ break;
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
|
|
+ 2 : if ((optyp1 and it[i].o1)<>0) and
|
|
|
|
+ ((optyp2 and it[i].o2)<>0) then
|
|
|
|
+ begin
|
|
|
|
+ fits:=true;
|
|
|
|
+ break;
|
|
|
|
+ end
|
|
|
|
+ 3 : if ((optyp1 and it[i].o1)<>0) and
|
|
|
|
+ ((optyp2 and it[i].o2)<>0) and
|
|
|
|
+ ((optyp3 and it[i].o3)<>0) then
|
|
|
|
+ begin
|
|
|
|
+ fits:=true;
|
|
|
|
+ break;
|
|
|
|
+ end;
|
|
|
|
+ end; { end case }
|
|
|
|
+ end; { endif }
|
|
|
|
+ if it[i].i=A_NONE then
|
|
|
|
+ begin
|
|
|
|
+ { NO MATCH! }
|
|
|
|
+ Message(asmr_e_invalid_combination_opcode_and_operand);
|
|
|
|
+ exit;
|
|
|
|
+ end;
|
|
|
|
+ inc(i);
|
|
|
|
+ end; { end while }
|
|
|
|
+ *)
|
|
|
|
+ fits:=TRUE;
|
|
|
|
+
|
|
|
|
+ { We add the opcode to the opcode linked list }
|
|
|
|
+ if fits then
|
|
|
|
+ begin
|
|
|
|
+ case ops of
|
|
|
|
+ 0:
|
|
|
|
+ if opsize <> S_NO then
|
|
|
|
+ result:=(taicpu.op_none(opcode,opsize))
|
|
|
|
+ else
|
|
|
|
+ result:=(taicpu.op_none(opcode,S_NO));
|
|
|
|
+ 1: begin
|
|
|
|
+ case operands[1].opr.typ of
|
|
|
|
+ OPR_SYMBOL:
|
|
|
|
+ begin
|
|
|
|
+ result:=(taicpu.op_sym_ofs(opcode,
|
|
|
|
+ opsize, operands[1].opr.symbol,operands[1].opr.symofs));
|
|
|
|
+ end;
|
|
|
|
+ OPR_CONSTANT:
|
|
|
|
+ begin
|
|
|
|
+ result:=(taicpu.op_const(opcode,
|
|
|
|
+ opsize, operands[1].opr.val));
|
|
|
|
+ end;
|
|
|
|
+ OPR_REGISTER:
|
|
|
|
+ result:=(taicpu.op_reg(opcode,opsize,operands[1].opr.reg));
|
|
|
|
+ OPR_REFERENCE:
|
|
|
|
+ if opsize <> S_NO then
|
|
|
|
+ begin
|
|
|
|
+ result:=(taicpu.op_ref(opcode,
|
|
|
|
+ opsize,operands[1].opr.ref));
|
|
|
|
+ end
|
|
|
|
+ else
|
|
|
|
+ begin
|
|
|
|
+ { special jmp and call case with }
|
|
|
|
+ { symbolic references. }
|
|
|
|
+ if opcode in [A_BSR,A_JMP,A_JSR,A_BRA,A_PEA] then
|
|
|
|
+ begin
|
|
|
|
+ result:=(taicpu.op_ref(opcode,
|
|
|
|
+ S_NO,operands[1].opr.ref));
|
|
|
|
+ end
|
|
|
|
+ else
|
|
|
|
+ Message(asmr_e_invalid_opcode_and_operand);
|
|
|
|
+ end;
|
|
|
|
+ OPR_NONE:
|
|
|
|
+ Message(asmr_e_invalid_opcode_and_operand);
|
|
|
|
+ else
|
|
|
|
+ begin
|
|
|
|
+ Message(asmr_e_invalid_opcode_and_operand);
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
|
|
+ 2: begin
|
|
|
|
+ { source }
|
|
|
|
+ case operands[1].opr.typ of
|
|
|
|
+ { reg,reg }
|
|
|
|
+ { reg,ref }
|
|
|
|
+ OPR_REGISTER:
|
|
|
|
+ begin
|
|
|
|
+ case operands[2].opr.typ of
|
|
|
|
+ OPR_REGISTER:
|
|
|
|
+ begin
|
|
|
|
+ result:=(taicpu.op_reg_reg(opcode,
|
|
|
|
+ opsize,operands[1].opr.reg,operands[2].opr.reg));
|
|
|
|
+ end;
|
|
|
|
+ OPR_REFERENCE:
|
|
|
|
+ result:=(taicpu.op_reg_ref(opcode,
|
|
|
|
+ opsize,operands[1].opr.reg,operands[2].opr.ref));
|
|
|
|
+ else { else case }
|
|
|
|
+ begin
|
|
|
|
+ Message(asmr_e_invalid_opcode_and_operand);
|
|
|
|
+ end;
|
|
|
|
+ end; { end second operand case for OPR_REGISTER }
|
|
|
|
+ end;
|
|
|
|
+ { regset, ref }
|
|
|
|
+ OPR_regset:
|
|
|
|
+ begin
|
|
|
|
+ case operands[2].opr.typ of
|
|
|
|
+ OPR_REFERENCE :
|
|
|
|
+ result:=(taicpu.op_regset_ref(opcode,
|
|
|
|
+ opsize,operands[1].opr.regset,operands[2].opr.ref));
|
|
|
|
+ else
|
|
|
|
+ begin
|
|
|
|
+ Message(asmr_e_invalid_opcode_and_operand);
|
|
|
|
+ end;
|
|
|
|
+ end; { end second operand case for OPR_regset }
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ { const,reg }
|
|
|
|
+ { const,const }
|
|
|
|
+ { const,ref }
|
|
|
|
+ OPR_CONSTANT:
|
|
|
|
+ case operands[2].opr.typ of
|
|
|
|
+ { constant, constant does not have a specific size. }
|
|
|
|
+ OPR_CONSTANT:
|
|
|
|
+ result:=(taicpu.op_const_const(opcode,
|
|
|
|
+ S_NO,operands[1].opr.val,operands[2].opr.val));
|
|
|
|
+ OPR_REFERENCE:
|
|
|
|
+ begin
|
|
|
|
+ result:=(taicpu.op_const_ref(opcode,
|
|
|
|
+ opsize,operands[1].opr.val,
|
|
|
|
+ operands[2].opr.ref))
|
|
|
|
+ end;
|
|
|
|
+ OPR_REGISTER:
|
|
|
|
+ begin
|
|
|
|
+ result:=(taicpu.op_const_reg(opcode,
|
|
|
|
+ opsize,operands[1].opr.val,
|
|
|
|
+ operands[2].opr.reg))
|
|
|
|
+ end;
|
|
|
|
+ else
|
|
|
|
+ begin
|
|
|
|
+ Message(asmr_e_invalid_opcode_and_operand);
|
|
|
|
+ end;
|
|
|
|
+ end; { end second operand case for OPR_CONSTANT }
|
|
|
|
+ { ref,reg }
|
|
|
|
+ { ref,ref }
|
|
|
|
+ OPR_REFERENCE:
|
|
|
|
+ case operands[2].opr.typ of
|
|
|
|
+ OPR_REGISTER:
|
|
|
|
+ begin
|
|
|
|
+ result:=(taicpu.op_ref_reg(opcode,
|
|
|
|
+ opsize,operands[1].opr.ref,
|
|
|
|
+ operands[2].opr.reg));
|
|
|
|
+ end;
|
|
|
|
+ OPR_regset:
|
|
|
|
+ begin
|
|
|
|
+ result:=(taicpu.op_ref_regset(opcode,
|
|
|
|
+ opsize,operands[1].opr.ref,
|
|
|
|
+ operands[2].opr.regset));
|
|
|
|
+ end;
|
|
|
|
+ OPR_REFERENCE: { special opcodes }
|
|
|
|
+ result:=(taicpu.op_ref_ref(opcode,
|
|
|
|
+ opsize,operands[1].opr.ref,
|
|
|
|
+ operands[2].opr.ref));
|
|
|
|
+ else
|
|
|
|
+ begin
|
|
|
|
+ Message(asmr_e_invalid_opcode_and_operand);
|
|
|
|
+ end;
|
|
|
|
+ end; { end second operand case for OPR_REFERENCE }
|
|
|
|
+ OPR_SYMBOL: case operands[2].opr.typ of
|
|
|
|
+ OPR_REFERENCE:
|
|
|
|
+ begin
|
|
|
|
+ result:=(taicpu.op_sym_ofs_ref(opcode,
|
|
|
|
+ opsize,operands[1].opr.symbol,operands[1].opr.symofs,
|
|
|
|
+ operands[2].opr.ref))
|
|
|
|
+ end;
|
|
|
|
+ OPR_REGISTER:
|
|
|
|
+ begin
|
|
|
|
+ result:=(taicpu.op_sym_ofs_reg(opcode,
|
|
|
|
+ opsize,operands[1].opr.symbol,operands[1].opr.symofs,
|
|
|
|
+ operands[2].opr.reg))
|
|
|
|
+ end;
|
|
|
|
+ else
|
|
|
|
+ begin
|
|
|
|
+ Message(asmr_e_invalid_opcode_and_operand);
|
|
|
|
+ end;
|
|
|
|
+ end; { end second operand case for OPR_SYMBOL }
|
|
|
|
+ else
|
|
|
|
+ begin
|
|
|
|
+ Message(asmr_e_invalid_opcode_and_operand);
|
|
|
|
+ end;
|
|
|
|
+ end; { end first operand case }
|
|
|
|
+ end;
|
|
|
|
+ 3: begin
|
|
|
|
+ if (opcode = A_DIVSL) or (opcode = A_DIVUL) or (opcode = A_MULU)
|
|
|
|
+ or (opcode = A_MULS) or (opcode = A_DIVS) or (opcode = A_DIVU) then
|
|
|
|
+ begin
|
|
|
|
+ if (operands[1].opr.typ <> OPR_REGISTER)
|
|
|
|
+ or (operands[2].opr.typ <> OPR_REGISTER)
|
|
|
|
+ or (operands[3].opr.typ <> OPR_REGISTER) then
|
|
|
|
+ begin
|
|
|
|
+ Message(asmr_e_invalid_opcode_and_operand);
|
|
|
|
+ end
|
|
|
|
+ else
|
|
|
|
+ begin
|
|
|
|
+ result:=(taicpu. op_reg_reg_reg(opcode,opsize,
|
|
|
|
+ operands[1].opr.reg,operands[2].opr.reg,operands[3].opr.reg));
|
|
|
|
+ end;
|
|
|
|
+ end
|
|
|
|
+ else
|
|
|
|
+ Message(asmr_e_invalid_opcode_and_operand);
|
|
|
|
+ end;
|
|
|
|
+ end; { end case }
|
|
|
|
+ end;
|
|
|
|
+ if assigned(result) then
|
|
|
|
+ p.concat(result);
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ function TM68kInstruction.ConcatLabeledInstr(p : taasmoutput):tai;
|
|
|
|
+ begin
|
|
|
|
+ if ((opcode >= A_BCC) and (opcode <= A_BVS)) or
|
|
|
|
+ (opcode = A_BRA) or (opcode = A_BSR) or
|
|
|
|
+ (opcode = A_JMP) or (opcode = A_JSR) or
|
|
|
|
+ ((opcode >= A_FBEQ) and (opcode <= A_FBNGLE)) then
|
|
|
|
+ begin
|
|
|
|
+ if ops > 2 then
|
|
|
|
+ Message(asmr_e_invalid_opcode_and_operand)
|
|
|
|
+ else if operands[1].opr.typ <> OPR_SYMBOL then
|
|
|
|
+ Message(asmr_e_invalid_opcode_and_operand)
|
|
|
|
+ else if (operands[1].opr.typ = OPR_SYMBOL) and
|
|
|
|
+ (ops = 1) then
|
|
|
|
+ if assigned(operands[1].opr.symbol) and
|
|
|
|
+ (operands[1].opr.symofs=0) then
|
|
|
|
+ result:=taicpu.op_sym(opcode,S_NO,
|
|
|
|
+ operands[1].opr.symbol)
|
|
|
|
+ else
|
|
|
|
+ Message(asmr_e_invalid_opcode_and_operand);
|
|
|
|
+ end
|
|
|
|
+ else if ((opcode >= A_DBCC) and (opcode <= A_DBF))
|
|
|
|
+ or ((opcode >= A_FDBEQ) and (opcode <= A_FDBNGLE)) then
|
|
|
|
+ begin
|
|
|
|
+ if (ops<>2) or
|
|
|
|
+ (operands[1].opr.typ <> OPR_REGISTER) or
|
|
|
|
+ (operands[2].opr.typ <> OPR_SYMBOL) or
|
|
|
|
+ (operands[2].opr.symofs <> 0) then
|
|
|
|
+ Message(asmr_e_invalid_opcode_and_operand)
|
|
|
|
+ else
|
|
|
|
+ result:=taicpu.op_reg_sym(opcode,opsize,operands[1].opr.reg,
|
|
|
|
+ operands[2].opr.symbol);
|
|
|
|
+ end
|
|
|
|
+ else
|
|
|
|
+ Message(asmr_e_invalid_opcode_and_operand);
|
|
|
|
+ if assigned(result) then
|
|
|
|
+ p.concat(result);
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+end.
|