summaryrefslogtreecommitdiff
path: root/compiler/m68k/ra68k.pas
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/m68k/ra68k.pas')
-rwxr-xr-xcompiler/m68k/ra68k.pas363
1 files changed, 363 insertions, 0 deletions
diff --git a/compiler/m68k/ra68k.pas b/compiler/m68k/ra68k.pas
new file mode 100755
index 0000000000..3b7c24dc8d
--- /dev/null
+++ b/compiler/m68k/ra68k.pas
@@ -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.