1 {
2     Copyright (c) 1999-2003 by Florian Klaempfl
3 
4     This unit implements an asmoutput class for SPARC AT&T syntax
5 
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10 
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15 
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 
20  ****************************************************************************
21 }
22 unit cpugas;
23 
24 {$i fpcdefs.inc}
25 
26 interface
27 
28     uses
29       cpubase,systems,
30       aasmtai,aasmdata,aasmcpu,assemble,aggas,
31       cgutils,globtype;
32 
33     type
34       TGasSPARC=class(TGnuAssembler)
35         constructor CreateWithWriter(info: pasminfo; wr: TExternalAssemblerOutputFile; freewriter, smart: boolean); override;
36         {# Constructs the command line for calling the assembler }
MakeCmdLinenull37         function MakeCmdLine: TCmdStr; override;
38       end;
39 
40      TSPARCInstrWriter=class(TCPUInstrWriter)
41        procedure WriteInstruction(hp:Tai);override;
GetReferenceStringnull42        function GetReferenceString(var ref : TReference):string;
getopstrnull43        function getopstr(const Oper:TOper):string;
44      end;
45 
46 implementation
47 
48     uses
49       cutils,globals,cpuinfo,procinfo,
50       verbose,itcpugas,cgbase;
51 
52 
53 {****************************************************************************}
54 {                         GNU PPC Assembler writer                           }
55 {****************************************************************************}
56 
57     constructor TGasSPARC.CreateWithWriter(info: pasminfo; wr: TExternalAssemblerOutputFile; freewriter, smart: boolean);
58       begin
59         inherited;
60         InstrWriter := TSPARCInstrWriter.create(self);
61       end;
62 
63 
TGasSPARC.MakeCmdLinenull64     function TGasSPARC.MakeCmdLine: TCmdStr;
65       begin
66          result := Inherited MakeCmdLine;
67 
68          { ARCH selection }
69          // Note for casual readers: gas (GNU as) uses -Av7, -Av8, -Av9 etc. on SPARC,
70          // rather than variants of the -m option used by most other CPUs. Solaris as
71          // uses -xarch=v7, -xarch=v8 etc., that form is not supported here since there
72          // are probably other incompatibilties between the GNU and Solaris binutils
73          // that need to be reviewed.
74          //
75          // v9 is required as the default since the RTL started using membar at 2.2.2.
76          case current_settings.cputype of
77 {$ifdef SPARC}
78            cpu_SPARC_V7: Replace(result,'$ARCH','-Av7');
79            cpu_SPARC_V8: Replace(result,'$ARCH','-Av8');
80 {$endif SPARC}
81            cpu_SPARC_V9: Replace(result,'$ARCH','-Av9');
82          else
83            Replace(result,'$ARCH','-Av9')
84          end
85       end;
86 
87 
TSPARCInstrWriter.GetReferenceStringnull88     function TSPARCInstrWriter.GetReferenceString(var ref:TReference):string;
89       begin
90         result:='';
91         if assigned(ref.symbol) then
92           begin
93             result:=ref.symbol.name;
94             if assigned(ref.relsymbol) then
95               result:=result+'-'+ref.relsymbol.name;
96           end;
97         if (ref.offset<0) then
98           result:=result+tostr(ref.offset)
99         else if (ref.offset>0) then
100           begin
101             if assigned(ref.symbol) then
102               result:=result+'+';
103             result:=result+tostr(ref.offset);
104           end
105         { asmreader appears to treat literal numbers as references }
106         else if (ref.symbol=nil) and (ref.base=NR_NO) and (ref.index=NR_NO) then
107           result:='0';
108 
109         case ref.refaddr of
110           addr_high:
111             result:='%hi('+result+')';
112           addr_low:
113             result:='%lo('+result+')';
114         end;
115 
116         if assigned(ref.symbol) or (ref.offset<>0) then
117           begin
118             if (ref.base<>NR_NO) then
119               begin
120                 if (ref.index<>NR_NO) then
121                   InternalError(2013013001);
122                 if (result[1]='-') then
123                   result:=gas_regname(ref.base)+result
124                 else
125                   result:=gas_regname(ref.base)+'+'+result;
126               end
127             else if (ref.index<>NR_NO) then
128               InternalError(2013122501);
129           end
130         else
131           begin
132             if (ref.base<>NR_NO) then
133               begin
134                 result:=gas_regname(ref.base);
135                 if (ref.index<>NR_NO) then
136                   result:=result+'+'+gas_regname(ref.index);
137               end
138             else if (ref.index<>NR_NO) then
139               result:=gas_regname(ref.index);
140           end;
141       end;
142 
143 
TSPARCInstrWriter.getopstrnull144     function TSPARCInstrWriter.getopstr(const Oper:TOper):string;
145       begin
146         with Oper do
147           case typ of
148             top_reg:
149               getopstr:=gas_regname(reg);
150             top_const:
151               getopstr:=tostr(longint(val));
152             top_ref:
153               if (oper.ref^.refaddr in [addr_no,addr_pic]) or
154                  ((oper.ref^.refaddr=addr_low) and ((oper.ref^.base<>NR_NO) or
155                   (oper.ref^.index<>NR_NO))) then
156                 getopstr:='['+getreferencestring(ref^)+']'
157               else
158                 getopstr:=getreferencestring(ref^);
159             else
160               internalerror(10001);
161           end;
162         end;
163 
164 
165     procedure TSPARCInstrWriter.WriteInstruction(hp:Tai);
166 
167       procedure writePseudoInstruction(opc: TAsmOp);
168         begin
169           if (taicpu(hp).ops<>2) or
170              (taicpu(hp).oper[0]^.typ<>top_reg) or
171              (taicpu(hp).oper[1]^.typ<>top_reg) then
172             internalerror(200401045);
173           { Fxxxs %f<even>,%f<even> }
174           owner.writer.AsmWriteln(#9+std_op2str[opc]+#9+getopstr(taicpu(hp).oper[0]^)+','+getopstr(taicpu(hp).oper[1]^));
175           { FMOVs %f<odd>,%f<odd> }
176           inc(taicpu(hp).oper[0]^.reg);
177           inc(taicpu(hp).oper[1]^.reg);
178           owner.writer.AsmWriteln(#9+std_op2str[A_FMOVs]+#9+getopstr(taicpu(hp).oper[0]^)+','+getopstr(taicpu(hp).oper[1]^));
179           dec(taicpu(hp).oper[0]^.reg);
180           dec(taicpu(hp).oper[1]^.reg);
181         end;
182 
183       var
184         Op:TAsmOp;
185         s:String;
186         i:Integer;
187       begin
188         if hp.typ<>ait_instruction then
189           exit;
190         op:=taicpu(hp).opcode;
191         if (op=A_Bxx) and (taicpu(hp).condition in floatAsmConds) then
192           op:=A_FBxx;
193         { translate pseudoops, this should be move to a separate pass later, so it's done before
194           peephole optimization }
195         case op of
196           A_FABSd:
197             writePseudoInstruction(A_FABSs);
198 
199           A_FMOVd:
200             writePseudoInstruction(A_FMOVs);
201 
202           A_FNEGd:
203             writePseudoInstruction(A_FNEGs);
204 
205           else
206             begin
207               { call maybe not translated to call }
208               s:=#9+std_op2str[op]+cond2str[taicpu(hp).condition];
209               if taicpu(hp).delayslot_annulled then
210                 s:=s+',a';
211               if taicpu(hp).ops>0 then
212                 begin
213                   s:=s+#9+getopstr(taicpu(hp).oper[0]^);
214                   for i:=1 to taicpu(hp).ops-1 do
215                     s:=s+','+getopstr(taicpu(hp).oper[i]^);
216                 end;
217               owner.writer.AsmWriteLn(s);
218             end;
219         end;
220       end;
221 
222 
223     const
224       as_sparc_as_info : tasminfo =
225          (
226            id     : as_gas;
227            idtxt  : 'AS';
228            asmbin : 'as';
229 {$ifdef FPC_SPARC_V8_ONLY}
230            asmcmd : '$PIC -o $OBJ $EXTRAOPT $ASM';
231 {$else}
232            asmcmd : '$ARCH $PIC -32 -o $OBJ $EXTRAOPT $ASM';
233 {$endif}
234            supported_targets : [system_sparc_solaris,system_sparc_linux,system_sparc_embedded];
235            flags : [af_needar,af_smartlink_sections];
236            labelprefix : '.L';
237            comment : '# ';
238            dollarsign: '$';
239          );
240 
241       as_sparc_gas_info : tasminfo =
242          (
243            id     : as_ggas;
244            idtxt  : 'GAS';
245            asmbin : 'gas';
246            asmcmd : '$ARCH $PIC -o $OBJ $EXTRAOPT $ASM';
247            supported_targets : [system_sparc_solaris,system_sparc_linux,system_sparc_embedded];
248            flags : [af_needar,af_smartlink_sections];
249            labelprefix : '.L';
250            comment : '# ';
251            dollarsign: '$';
252          );
253 
254       as_sparc64_as_info : tasminfo =
255          (
256            id     : as_gas;
257            idtxt  : 'AS';
258            asmbin : 'as';
259 {$ifdef FPC_SPARC_V8_ONLY}
260            asmcmd : '$PIC -o $OBJ $EXTRAOPT $ASM';
261 {$else}
262            asmcmd : '$ARCH $PIC -o $OBJ $EXTRAOPT $ASM';
263 {$endif}
264            supported_targets : [system_sparc64_linux];
265            flags : [af_needar,af_smartlink_sections];
266            labelprefix : '.L';
267            comment : '# ';
268            dollarsign: '$';
269          );
270 
271       as_sparc64_gas_info : tasminfo =
272          (
273            id     : as_ggas;
274            idtxt  : 'GAS';
275            asmbin : 'gas';
276            asmcmd : '$ARCH $PIC -o $OBJ $EXTRAOPT $ASM';
277            supported_targets : [system_sparc64_linux];
278            flags : [af_needar,af_smartlink_sections];
279            labelprefix : '.L';
280            comment : '# ';
281            dollarsign: '$';
282          );
283 
284 begin
285 {$ifdef SPARC}
286   RegisterAssembler(as_SPARC_as_info,TGasSPARC);
287   RegisterAssembler(as_SPARC_gas_info,TGasSPARC);
288 {$else SPARC}
289   RegisterAssembler(as_SPARC64_as_info,TGasSPARC);
290   RegisterAssembler(as_SPARC64_gas_info,TGasSPARC);
291 {$endif SPARC}
292 end.
293