mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-08 17:48:01 +02:00
372 lines
13 KiB
ObjectPascal
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.
|