fpc/compiler/m68k/ra68k.pas
2014-08-20 13:49:47 +00:00

372 lines
13 KiB
ObjectPascal

{
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,aasmdata,aasmcpu,
cpubase,rautils,cclasses;
type
Tm68kOperand=class(TOperand)
end;
Tm68kInstruction=class(TInstruction)
opsize : topsize;
function ConcatInstruction(p : TAsmList):tai;override;
function ConcatLabeledInstr(p : TAsmList):tai;
end;
implementation
uses
verbose,cgbase;
{*****************************************************************************
TM68kInstruction
*****************************************************************************}
function TM68kInstruction.ConcatInstruction(p : TAsmList):tai;
begin
result:=inherited ConcatInstruction(p);
if assigned(result) then
taicpu(result).opsize:=opsize;
end;
(*
function TM68kInstruction.ConcatInstruction(p : TAsmList):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 : TAsmList):tai;
begin
result:=nil;
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.