mirror of
				https://gitlab.com/freepascal.org/fpc/source.git
				synced 2025-11-04 14:59:37 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			266 lines
		
	
	
		
			8.7 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
			
		
		
	
	
			266 lines
		
	
	
		
			8.7 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
{
 | 
						|
    Copyright (c) 1999-2009 by Florian Klaempfl and David Zhang
 | 
						|
 | 
						|
    This unit implements an asmoutput class for MIPS assembly syntax
 | 
						|
 | 
						|
    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 cpugas;
 | 
						|
 | 
						|
{$i fpcdefs.inc}
 | 
						|
 | 
						|
  interface
 | 
						|
 | 
						|
    uses
 | 
						|
      cpubase,
 | 
						|
       aasmtai, aasmcpu, assemble, aggas;
 | 
						|
 | 
						|
    type
 | 
						|
      TMIPSGNUAssembler = class(TGNUassembler)
 | 
						|
        constructor create(smart: boolean); override;
 | 
						|
      end;
 | 
						|
 | 
						|
      TMIPSInstrWriter = class(TCPUInstrWriter)
 | 
						|
        procedure WriteInstruction(hp : tai);override;
 | 
						|
      end;
 | 
						|
 | 
						|
  implementation
 | 
						|
 | 
						|
    uses
 | 
						|
      cutils, systems,
 | 
						|
      verbose, itcpugas, cgbase, cgutils;
 | 
						|
 | 
						|
{****************************************************************************}
 | 
						|
{                         GNU MIPS  Assembler writer                           }
 | 
						|
{****************************************************************************}
 | 
						|
 | 
						|
    constructor TMIPSGNUAssembler.create(smart: boolean);
 | 
						|
      begin
 | 
						|
        inherited create(smart);
 | 
						|
        InstrWriter := TMIPSInstrWriter.create(self);
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
{****************************************************************************}
 | 
						|
{                  Helper routines for Instruction Writer                    }
 | 
						|
{****************************************************************************}
 | 
						|
 | 
						|
    function GetReferenceString(var ref: TReference): string;
 | 
						|
      begin
 | 
						|
        GetReferenceString := '';
 | 
						|
        with ref do
 | 
						|
        begin
 | 
						|
          if (base = NR_NO) and (index = NR_NO) then
 | 
						|
          begin
 | 
						|
            if assigned(symbol) then
 | 
						|
              GetReferenceString := symbol.Name;
 | 
						|
            if offset > 0 then
 | 
						|
              GetReferenceString := GetReferenceString + '+' + ToStr(offset)
 | 
						|
            else if offset < 0 then
 | 
						|
              GetReferenceString := GetReferenceString + ToStr(offset);
 | 
						|
            case refaddr of
 | 
						|
              addr_high:
 | 
						|
                GetReferenceString := '%hi(' + GetReferenceString + ')';
 | 
						|
              addr_low:
 | 
						|
                GetReferenceString := '%lo(' + GetReferenceString + ')';
 | 
						|
            end;
 | 
						|
          end
 | 
						|
          else
 | 
						|
          begin
 | 
						|
      {$ifdef extdebug}
 | 
						|
            if assigned(symbol) and
 | 
						|
              not(refaddr in [addr_pic,addr_lo]) then
 | 
						|
              internalerror(2003052601);
 | 
						|
      {$endif extdebug}
 | 
						|
            if base <> NR_NO then
 | 
						|
              GetReferenceString := GetReferenceString + '(' + gas_regname(base) + ')';
 | 
						|
            if index = NR_NO then
 | 
						|
            begin
 | 
						|
              if offset <> 0 then
 | 
						|
                GetReferenceString := ToStr(offset) + GetReferenceString;
 | 
						|
              if assigned(symbol) then
 | 
						|
              begin
 | 
						|
                if refaddr = addr_low then
 | 
						|
                  GetReferenceString := '%lo(' + symbol.Name + ')' + GetReferenceString
 | 
						|
                else
 | 
						|
                  GetReferenceString := symbol.Name + {'+' +} GetReferenceString;
 | 
						|
              end;
 | 
						|
            end
 | 
						|
            else
 | 
						|
            begin
 | 
						|
  {$ifdef extdebug}
 | 
						|
              if (Offset<>0) or assigned(symbol) then
 | 
						|
                internalerror(2003052603);
 | 
						|
  {$endif extdebug}
 | 
						|
              GetReferenceString := GetReferenceString + '(' + gas_regname(index) + ')';
 | 
						|
 | 
						|
            end;
 | 
						|
          end;
 | 
						|
        end;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    function getopstr(const Oper: TOper): string;
 | 
						|
      begin
 | 
						|
        with Oper do
 | 
						|
          case typ of
 | 
						|
            top_reg:
 | 
						|
              getopstr := gas_regname(reg);
 | 
						|
            top_const:
 | 
						|
              getopstr := tostr(longint(val));
 | 
						|
            top_ref:
 | 
						|
              if (oper.ref^.refaddr in [addr_no, addr_pic]) or ((oper.ref^.refaddr = addr_low) and ((oper.ref^.base <> NR_NO) or
 | 
						|
                (oper.ref^.index <> NR_NO))) then
 | 
						|
                getopstr := getreferencestring(ref^)
 | 
						|
              else
 | 
						|
                getopstr := getreferencestring(ref^);
 | 
						|
            else
 | 
						|
              internalerror(10001);
 | 
						|
          end;
 | 
						|
      end;
 | 
						|
 | 
						|
      function getopstr_4(const Oper: TOper): string;
 | 
						|
      var
 | 
						|
        tmpref: treference;
 | 
						|
      begin
 | 
						|
        with Oper do
 | 
						|
          case typ of
 | 
						|
            top_ref:
 | 
						|
            begin
 | 
						|
              tmpref := ref^;
 | 
						|
              Inc(tmpref.offset, 4);
 | 
						|
              getopstr_4 := getreferencestring(tmpref);
 | 
						|
            end;
 | 
						|
            else
 | 
						|
              internalerror(2007050403);
 | 
						|
          end;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TMIPSInstrWriter.WriteInstruction(hp: Tai);
 | 
						|
      var
 | 
						|
        Op: TAsmOp;
 | 
						|
        s,s1:  string;
 | 
						|
        i:  integer;
 | 
						|
        tmpfpu: string;
 | 
						|
        tmpfpu_len: longint;
 | 
						|
      begin
 | 
						|
        if hp.typ <> ait_instruction then
 | 
						|
          exit;
 | 
						|
        op := taicpu(hp).opcode;
 | 
						|
 | 
						|
        case op of
 | 
						|
          A_P_STK2:
 | 
						|
          begin
 | 
						|
            s1 := getopstr(taicpu(hp).oper[2]^);
 | 
						|
            STK2_LocalSize := align(STK2_LocalSize, 8);
 | 
						|
            if s1[1] = '-' then
 | 
						|
              str(-STK2_LocalSize, s1)
 | 
						|
            else
 | 
						|
              str(STK2_LocalSize, s1);
 | 
						|
            s := #9 + gas_op2str[A_ADDIU] + #9 + getopstr(taicpu(hp).oper[0]^)+ ',' + getopstr(taicpu(hp).oper[1]^) + ',' + s1;
 | 
						|
            owner.AsmWriteLn(s);
 | 
						|
          end;
 | 
						|
          A_P_FRAME:
 | 
						|
          begin
 | 
						|
          end;
 | 
						|
          A_P_SET_MACRO:
 | 
						|
          begin
 | 
						|
            s := #9 + '.set' + #9 + 'macro';
 | 
						|
            owner.AsmWriteLn(s);
 | 
						|
          end;
 | 
						|
          A_P_SET_REORDER:
 | 
						|
          begin
 | 
						|
            s := #9 + '.set' + #9 + 'reorder';
 | 
						|
            owner.AsmWriteLn(s);
 | 
						|
          end;
 | 
						|
          A_P_SET_NOMACRO:
 | 
						|
          begin
 | 
						|
            s := #9 + '.set' + #9 + 'nomacro';
 | 
						|
            owner.AsmWriteLn(s);
 | 
						|
          end;
 | 
						|
          A_P_SET_NOREORDER:
 | 
						|
          begin
 | 
						|
            s := #9 + '.set' + #9 + 'noreorder';
 | 
						|
            owner.AsmWriteLn(s);
 | 
						|
          end;
 | 
						|
          A_P_SW:
 | 
						|
          begin
 | 
						|
            s := #9 + gas_op2str[A_SW] + #9 + getopstr(taicpu(hp).oper[0]^)+ ',' + getopstr(taicpu(hp).oper[2]^) + '(' + getopstr(taicpu(hp).oper[1]^) + ')';
 | 
						|
            owner.AsmWriteLn(s);
 | 
						|
          end;
 | 
						|
          A_P_LW:
 | 
						|
          begin
 | 
						|
            s := #9 + gas_op2str[A_LW] + #9 + getopstr(taicpu(hp).oper[0]^)+ ',' + getopstr(taicpu(hp).oper[2]^) + '(' + getopstr(taicpu(hp).oper[1]^) + ')';
 | 
						|
            owner.AsmWriteLn(s);
 | 
						|
          end;
 | 
						|
          A_LDC1:
 | 
						|
          begin
 | 
						|
            tmpfpu := getopstr(taicpu(hp).oper[0]^);
 | 
						|
            s := #9 + gas_op2str[A_LWC1] + #9 + tmpfpu + ',' + getopstr(taicpu(hp).oper[1]^); // + '(' + getopstr(taicpu(hp).oper[1]^) + ')';
 | 
						|
            owner.AsmWriteLn(s);
 | 
						|
 | 
						|
            tmpfpu_len := length(tmpfpu);
 | 
						|
            tmpfpu[tmpfpu_len] := succ(tmpfpu[tmpfpu_len]);
 | 
						|
            s := #9 + gas_op2str[A_LWC1] + #9 + tmpfpu + ',' + getopstr_4(taicpu(hp).oper[1]^); // + '(' + getopstr(taicpu(hp).oper[1]^) + ')';
 | 
						|
            owner.AsmWriteLn(s);
 | 
						|
          end;
 | 
						|
          A_SDC1:
 | 
						|
          begin
 | 
						|
            tmpfpu := getopstr(taicpu(hp).oper[0]^);
 | 
						|
            s := #9 + gas_op2str[A_SWC1] + #9 + tmpfpu + ',' + getopstr(taicpu(hp).oper[1]^); //+ ',' + getopstr(taicpu(hp).oper[2]^) + '(' + getopstr(taicpu(hp).oper[1]^) + ')';
 | 
						|
            owner.AsmWriteLn(s);
 | 
						|
 | 
						|
            tmpfpu_len := length(tmpfpu);
 | 
						|
            tmpfpu[tmpfpu_len] := succ(tmpfpu[tmpfpu_len]);
 | 
						|
            s := #9 + gas_op2str[A_SWC1] + #9 + tmpfpu + ',' + getopstr_4(taicpu(hp).oper[1]^); //+ ',' + getopstr(taicpu(hp).oper[2]^) + '(' + getopstr(taicpu(hp).oper[1]^) + ')';
 | 
						|
            owner.AsmWriteLn(s);
 | 
						|
          end;
 | 
						|
          else
 | 
						|
          begin
 | 
						|
            s := #9 + gas_op2str[op] + cond2str[taicpu(hp).condition];
 | 
						|
            if taicpu(hp).delayslot_annulled then
 | 
						|
              s := s + ',a';
 | 
						|
            if taicpu(hp).ops > 0 then
 | 
						|
            begin
 | 
						|
              s := s + #9 + getopstr(taicpu(hp).oper[0]^);
 | 
						|
              for i := 1 to taicpu(hp).ops - 1 do
 | 
						|
                s := s + ',' + getopstr(taicpu(hp).oper[i]^);
 | 
						|
            end;
 | 
						|
            owner.AsmWriteLn(s);
 | 
						|
          end;
 | 
						|
        end;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    const
 | 
						|
      as_MIPSEL_as_info: tasminfo =
 | 
						|
        (
 | 
						|
        id: as_gas;
 | 
						|
        idtxt: 'AS';
 | 
						|
        asmbin: 'as';
 | 
						|
        asmcmd: '-mips2 -W -EL -o $OBJ $ASM';
 | 
						|
        supported_targets: [system_mips_linux,system_mipsel_linux];
 | 
						|
        flags: [af_allowdirect, af_needar, af_smartlink_sections];
 | 
						|
        labelprefix: '.L';
 | 
						|
        comment: '# ';
 | 
						|
        );
 | 
						|
 | 
						|
begin
 | 
						|
  RegisterAssembler(as_MIPSEL_as_info, TMIPSGNUAssembler);
 | 
						|
end.
 |