mirror of
				https://gitlab.com/freepascal.org/fpc/source.git
				synced 2025-10-29 07:01:44 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			364 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			364 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
		
			Executable File
		
	
	
	
	
| {
 | |
|     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.
 | 
