summaryrefslogtreecommitdiff
path: root/closures/compiler/arm/agarmgas.pas
diff options
context:
space:
mode:
Diffstat (limited to 'closures/compiler/arm/agarmgas.pas')
-rw-r--r--closures/compiler/arm/agarmgas.pas326
1 files changed, 326 insertions, 0 deletions
diff --git a/closures/compiler/arm/agarmgas.pas b/closures/compiler/arm/agarmgas.pas
new file mode 100644
index 0000000000..af037b2ab8
--- /dev/null
+++ b/closures/compiler/arm/agarmgas.pas
@@ -0,0 +1,326 @@
+{
+ Copyright (c) 2003 by Florian Klaempfl
+
+ This unit implements an asm for the ARM
+
+ 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.
+
+ ****************************************************************************
+}
+{ This unit implements the GNU Assembler writer for the ARM
+}
+
+unit agarmgas;
+
+{$i fpcdefs.inc}
+
+ interface
+
+ uses
+ globtype,
+ aasmtai,aasmdata,
+ aggas,
+ cpubase;
+
+ type
+ TARMGNUAssembler=class(TGNUassembler)
+ constructor create(smart: boolean); override;
+ function MakeCmdLine: TCmdStr; override;
+ procedure WriteExtraHeader; override;
+ end;
+
+ TArmInstrWriter=class(TCPUInstrWriter)
+ procedure WriteInstruction(hp : tai);override;
+ end;
+
+ TArmAppleGNUAssembler=class(TAppleGNUassembler)
+ constructor create(smart: boolean); override;
+ end;
+
+
+ const
+ gas_shiftmode2str : array[tshiftmode] of string[3] = (
+ '','lsl','lsr','asr','ror','rrx');
+
+ implementation
+
+ uses
+ cutils,globals,verbose,
+ systems,
+ assemble,
+ cpuinfo,aasmcpu,
+ itcpugas,
+ cgbase,cgutils;
+
+{****************************************************************************}
+{ GNU Arm Assembler writer }
+{****************************************************************************}
+
+ constructor TArmGNUAssembler.create(smart: boolean);
+ begin
+ inherited create(smart);
+ InstrWriter := TArmInstrWriter.create(self);
+ end;
+
+
+ function TArmGNUAssembler.MakeCmdLine: TCmdStr;
+ begin
+ result:=inherited MakeCmdLine;
+ if (current_settings.fputype = fpu_soft) then
+ result:='-mfpu=softvfp '+result;
+
+ if current_settings.cputype = cpu_armv7m then
+ result:='-march=armv7m -mthumb -mthumb-interwork '+result;
+ end;
+
+ procedure TArmGNUAssembler.WriteExtraHeader;
+ begin
+ inherited WriteExtraHeader;
+ if current_settings.cputype in cpu_thumb2 then
+ AsmWriteLn(#9'.syntax unified');
+ end;
+
+{****************************************************************************}
+{ GNU/Apple ARM Assembler writer }
+{****************************************************************************}
+
+ constructor TArmAppleGNUAssembler.create(smart: boolean);
+ begin
+ inherited create(smart);
+ InstrWriter := TArmInstrWriter.create(self);
+ end;
+
+
+{****************************************************************************}
+{ Helper routines for Instruction Writer }
+{****************************************************************************}
+
+ function getreferencestring(var ref : treference) : string;
+ var
+ s : string;
+ begin
+ with ref do
+ begin
+{$ifdef extdebug}
+ // if base=NR_NO then
+ // internalerror(200308292);
+
+ // if ((index<>NR_NO) or (shiftmode<>SM_None)) and ((offset<>0) or (symbol<>nil)) then
+ // internalerror(200308293);
+{$endif extdebug}
+
+ if assigned(symbol) then
+ begin
+ if (base<>NR_NO) and not(is_pc(base)) then
+ internalerror(200309011);
+ s:=symbol.name;
+ if offset<0 then
+ s:=s+tostr(offset)
+ else if offset>0 then
+ s:=s+'+'+tostr(offset);
+ end
+ else
+ begin
+ s:='['+gas_regname(base);
+ if addressmode=AM_POSTINDEXED then
+ s:=s+']';
+ if index<>NR_NO then
+ begin
+ if signindex<0 then
+ s:=s+', -'
+ else
+ s:=s+', ';
+
+ s:=s+gas_regname(index);
+
+ if shiftmode<>SM_None then
+ s:=s+', '+gas_shiftmode2str[shiftmode]+' #'+tostr(shiftimm);
+ end
+ else if offset<>0 then
+ s:=s+', #'+tostr(offset);
+
+ case addressmode of
+ AM_OFFSET:
+ s:=s+']';
+ AM_PREINDEXED:
+ s:=s+']!';
+ end;
+ end;
+
+ end;
+ getreferencestring:=s;
+ end;
+
+
+ const
+ shiftmode2str: array[tshiftmode] of string[3] = ('','lsl','lsr','asr','ror','rrx');
+
+ function getopstr(const o:toper) : string;
+ var
+ hs : string;
+ first : boolean;
+ r : tsuperregister;
+ begin
+ case o.typ of
+ top_reg:
+ getopstr:=gas_regname(o.reg);
+ top_shifterop:
+ begin
+ if (o.shifterop^.rs<>NR_NO) and (o.shifterop^.shiftimm=0) then
+ getopstr:=shiftmode2str[o.shifterop^.shiftmode]+' '+gas_regname(o.shifterop^.rs)
+ else if (o.shifterop^.rs=NR_NO) then
+ getopstr:=shiftmode2str[o.shifterop^.shiftmode]+' #'+tostr(o.shifterop^.shiftimm)
+ else internalerror(200308282);
+ end;
+ top_const:
+ getopstr:='#'+tostr(longint(o.val));
+ top_regset:
+ begin
+ getopstr:='{';
+ first:=true;
+ for r:=RS_R0 to RS_R15 do
+ if r in o.regset^ then
+ begin
+ if not(first) then
+ getopstr:=getopstr+',';
+ getopstr:=getopstr+gas_regname(newreg(o.regtyp,r,o.subreg));
+ first:=false;
+ end;
+ getopstr:=getopstr+'}';
+ end;
+ top_conditioncode:
+ getopstr:=cond2str[o.cc];
+ top_modeflags:
+ begin
+ getopstr:='';
+ if mfA in o.modeflags then getopstr:=getopstr+'a';
+ if mfI in o.modeflags then getopstr:=getopstr+'i';
+ if mfF in o.modeflags then getopstr:=getopstr+'f';
+ end;
+ top_ref:
+ if o.ref^.refaddr=addr_full then
+ begin
+ hs:=o.ref^.symbol.name;
+ if o.ref^.offset>0 then
+ hs:=hs+'+'+tostr(o.ref^.offset)
+ else
+ if o.ref^.offset<0 then
+ hs:=hs+tostr(o.ref^.offset);
+ getopstr:=hs;
+ end
+ else
+ getopstr:=getreferencestring(o.ref^);
+ else
+ internalerror(2002070604);
+ end;
+ end;
+
+
+ Procedure TArmInstrWriter.WriteInstruction(hp : tai);
+ var op: TAsmOp;
+ postfix,s: string;
+ i: byte;
+ sep: string[3];
+ begin
+ op:=taicpu(hp).opcode;
+ if current_settings.cputype in cpu_thumb2 then
+ begin
+ postfix:='';
+ if taicpu(hp).wideformat then
+ postfix:='.w';
+
+ if taicpu(hp).ops = 0 then
+ s:=#9+gas_op2str[op]+' '+cond2str[taicpu(hp).condition]+oppostfix2str[taicpu(hp).oppostfix]
+ else
+ s:=#9+gas_op2str[op]+oppostfix2str[taicpu(hp).oppostfix]+postfix+cond2str[taicpu(hp).condition]; // Conditional infixes are deprecated in unified syntax
+ end
+ else
+ s:=#9+gas_op2str[op]+cond2str[taicpu(hp).condition]+oppostfix2str[taicpu(hp).oppostfix];
+ if taicpu(hp).ops<>0 then
+ begin
+ sep:=#9;
+ for i:=0 to taicpu(hp).ops-1 do
+ begin
+ // debug code
+ // writeln(s);
+ // writeln(taicpu(hp).fileinfo.line);
+
+ { LDM and STM use references as first operand but they are written like a register }
+ if (i=0) and (op in [A_LDM,A_STM,A_FSTM,A_FLDM]) then
+ begin
+ case taicpu(hp).oper[0]^.typ of
+ top_ref:
+ begin
+ s:=s+sep+gas_regname(taicpu(hp).oper[0]^.ref^.index);
+ if taicpu(hp).oper[0]^.ref^.addressmode=AM_PREINDEXED then
+ s:=s+'!';
+ end;
+ top_reg:
+ s:=s+sep+gas_regname(taicpu(hp).oper[0]^.reg);
+ else
+ internalerror(200311292);
+ end;
+ end
+ { register count of SFM and LFM is written without # }
+ else if (i=1) and (op in [A_SFM,A_LFM]) then
+ begin
+ case taicpu(hp).oper[1]^.typ of
+ top_const:
+ s:=s+sep+tostr(taicpu(hp).oper[1]^.val);
+ else
+ internalerror(200311292);
+ end;
+ end
+ else
+ s:=s+sep+getopstr(taicpu(hp).oper[i]^);
+
+ sep:=',';
+ end;
+ end;
+ owner.AsmWriteLn(s);
+ end;
+
+
+ const
+ as_arm_gas_info : tasminfo =
+ (
+ id : as_gas;
+
+ idtxt : 'AS';
+ asmbin : 'as';
+ asmcmd : '-o $OBJ $ASM';
+ supported_targets : [system_arm_linux,system_arm_wince,system_arm_gba,system_arm_palmos,system_arm_nds,system_arm_embedded,system_arm_symbian];
+ flags : [af_allowdirect,af_needar,af_smartlink_sections];
+ labelprefix : '.L';
+ comment : '# ';
+ );
+
+ as_arm_gas_darwin_info : tasminfo =
+ (
+ id : as_darwin;
+ idtxt : 'AS-Darwin';
+ asmbin : 'as';
+ asmcmd : '-o $OBJ $ASM -arch $ARCH';
+ supported_targets : [system_arm_darwin];
+ flags : [af_allowdirect,af_needar,af_smartlink_sections,af_supports_dwarf,af_stabs_use_function_absolute_addresses];
+ labelprefix : 'L';
+ comment : '# ';
+ );
+
+
+begin
+ RegisterAssembler(as_arm_gas_info,TARMGNUAssembler);
+ RegisterAssembler(as_arm_gas_darwin_info,TArmAppleGNUAssembler);
+end.