xref: /freebsd/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/Mips.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
1 //===--- Mips.cpp - Tools Implementations -----------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "Mips.h"
10 #include "clang/Driver/CommonArgs.h"
11 #include "clang/Driver/Driver.h"
12 #include "clang/Driver/Options.h"
13 #include "llvm/ADT/StringSwitch.h"
14 #include "llvm/Option/ArgList.h"
15 
16 using namespace clang::driver;
17 using namespace clang::driver::tools;
18 using namespace clang;
19 using namespace llvm::opt;
20 
21 // Get CPU and ABI names. They are not independent
22 // so we have to calculate them together.
getMipsCPUAndABI(const ArgList & Args,const llvm::Triple & Triple,StringRef & CPUName,StringRef & ABIName)23 void mips::getMipsCPUAndABI(const ArgList &Args, const llvm::Triple &Triple,
24                             StringRef &CPUName, StringRef &ABIName) {
25   const char *DefMips32CPU = "mips32r2";
26   const char *DefMips64CPU = "mips64r2";
27 
28   // MIPS32r6 is the default for mips(el)?-img-linux-gnu and MIPS64r6 is the
29   // default for mips64(el)?-img-linux-gnu.
30   if (Triple.getVendor() == llvm::Triple::ImaginationTechnologies &&
31       Triple.isGNUEnvironment()) {
32     DefMips32CPU = "mips32r6";
33     DefMips64CPU = "mips64r6";
34   }
35 
36   if (Triple.getSubArch() == llvm::Triple::MipsSubArch_r6) {
37     DefMips32CPU = "mips32r6";
38     DefMips64CPU = "mips64r6";
39   }
40 
41   // MIPS3 is the default for mips64*-unknown-openbsd.
42   if (Triple.isOSOpenBSD())
43     DefMips64CPU = "mips3";
44 
45   // MIPS2 is the default for mips(el)?-unknown-freebsd.
46   // MIPS3 is the default for mips64(el)?-unknown-freebsd.
47   if (Triple.isOSFreeBSD()) {
48     DefMips32CPU = "mips2";
49     DefMips64CPU = "mips3";
50   }
51 
52   if (Arg *A = Args.getLastArg(clang::driver::options::OPT_march_EQ,
53                                options::OPT_mcpu_EQ))
54     CPUName = A->getValue();
55 
56   if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) {
57     ABIName = A->getValue();
58     // Convert a GNU style Mips ABI name to the name
59     // accepted by LLVM Mips backend.
60     ABIName = llvm::StringSwitch<llvm::StringRef>(ABIName)
61                   .Case("32", "o32")
62                   .Case("64", "n64")
63                   .Default(ABIName);
64   }
65 
66   // Setup default CPU and ABI names.
67   if (CPUName.empty() && ABIName.empty()) {
68     switch (Triple.getArch()) {
69     default:
70       llvm_unreachable("Unexpected triple arch name");
71     case llvm::Triple::mips:
72     case llvm::Triple::mipsel:
73       CPUName = DefMips32CPU;
74       break;
75     case llvm::Triple::mips64:
76     case llvm::Triple::mips64el:
77       CPUName = DefMips64CPU;
78       break;
79     }
80   }
81 
82   if (ABIName.empty() && Triple.isABIN32())
83     ABIName = "n32";
84 
85   if (ABIName.empty() &&
86       (Triple.getVendor() == llvm::Triple::MipsTechnologies ||
87        Triple.getVendor() == llvm::Triple::ImaginationTechnologies)) {
88     ABIName = llvm::StringSwitch<const char *>(CPUName)
89                   .Case("mips1", "o32")
90                   .Case("mips2", "o32")
91                   .Case("mips3", "n64")
92                   .Case("mips4", "n64")
93                   .Case("mips5", "n64")
94                   .Case("mips32", "o32")
95                   .Case("mips32r2", "o32")
96                   .Case("mips32r3", "o32")
97                   .Case("mips32r5", "o32")
98                   .Case("mips32r6", "o32")
99                   .Case("mips64", "n64")
100                   .Case("mips64r2", "n64")
101                   .Case("mips64r3", "n64")
102                   .Case("mips64r5", "n64")
103                   .Case("mips64r6", "n64")
104                   .Case("octeon", "n64")
105                   .Case("p5600", "o32")
106                   .Case("i6400", "n64")
107                   .Case("i6500", "n64")
108                   .Default("");
109   }
110 
111   if (ABIName.empty()) {
112     // Deduce ABI name from the target triple.
113     ABIName = Triple.isMIPS32() ? "o32" : "n64";
114   }
115 
116   if (CPUName.empty()) {
117     // Deduce CPU name from ABI name.
118     CPUName = llvm::StringSwitch<const char *>(ABIName)
119                   .Case("o32", DefMips32CPU)
120                   .Cases("n32", "n64", DefMips64CPU)
121                   .Default("");
122   }
123 
124   // FIXME: Warn on inconsistent use of -march and -mabi.
125 }
126 
getMipsABILibSuffix(const ArgList & Args,const llvm::Triple & Triple)127 std::string mips::getMipsABILibSuffix(const ArgList &Args,
128                                       const llvm::Triple &Triple) {
129   StringRef CPUName, ABIName;
130   tools::mips::getMipsCPUAndABI(Args, Triple, CPUName, ABIName);
131   return llvm::StringSwitch<std::string>(ABIName)
132       .Case("o32", "")
133       .Case("n32", "32")
134       .Case("n64", "64");
135 }
136 
137 // Convert ABI name to the GNU tools acceptable variant.
getGnuCompatibleMipsABIName(StringRef ABI)138 StringRef mips::getGnuCompatibleMipsABIName(StringRef ABI) {
139   return llvm::StringSwitch<llvm::StringRef>(ABI)
140       .Case("o32", "32")
141       .Case("n64", "64")
142       .Default(ABI);
143 }
144 
145 // Select the MIPS float ABI as determined by -msoft-float, -mhard-float,
146 // and -mfloat-abi=.
getMipsFloatABI(const Driver & D,const ArgList & Args,const llvm::Triple & Triple)147 mips::FloatABI mips::getMipsFloatABI(const Driver &D, const ArgList &Args,
148                                      const llvm::Triple &Triple) {
149   mips::FloatABI ABI = mips::FloatABI::Invalid;
150   if (Arg *A =
151           Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float,
152                           options::OPT_mfloat_abi_EQ)) {
153     if (A->getOption().matches(options::OPT_msoft_float))
154       ABI = mips::FloatABI::Soft;
155     else if (A->getOption().matches(options::OPT_mhard_float))
156       ABI = mips::FloatABI::Hard;
157     else {
158       ABI = llvm::StringSwitch<mips::FloatABI>(A->getValue())
159                 .Case("soft", mips::FloatABI::Soft)
160                 .Case("hard", mips::FloatABI::Hard)
161                 .Default(mips::FloatABI::Invalid);
162       if (ABI == mips::FloatABI::Invalid && !StringRef(A->getValue()).empty()) {
163         D.Diag(clang::diag::err_drv_invalid_mfloat_abi) << A->getAsString(Args);
164         ABI = mips::FloatABI::Hard;
165       }
166     }
167   }
168 
169   // If unspecified, choose the default based on the platform.
170   if (ABI == mips::FloatABI::Invalid) {
171     if (Triple.isOSFreeBSD()) {
172       // For FreeBSD, assume "soft" on all flavors of MIPS.
173       ABI = mips::FloatABI::Soft;
174     } else {
175       // Assume "hard", because it's a default value used by gcc.
176       // When we start to recognize specific target MIPS processors,
177       // we will be able to select the default more correctly.
178       ABI = mips::FloatABI::Hard;
179     }
180   }
181 
182   assert(ABI != mips::FloatABI::Invalid && "must select an ABI");
183   return ABI;
184 }
185 
getMIPSTargetFeatures(const Driver & D,const llvm::Triple & Triple,const ArgList & Args,std::vector<StringRef> & Features)186 void mips::getMIPSTargetFeatures(const Driver &D, const llvm::Triple &Triple,
187                                  const ArgList &Args,
188                                  std::vector<StringRef> &Features) {
189   StringRef CPUName;
190   StringRef ABIName;
191   getMipsCPUAndABI(Args, Triple, CPUName, ABIName);
192   ABIName = getGnuCompatibleMipsABIName(ABIName);
193 
194   // Historically, PIC code for MIPS was associated with -mabicalls, a.k.a
195   // SVR4 abicalls. Static code does not use SVR4 calling sequences. An ABI
196   // extension was developed by Richard Sandiford & Code Sourcery to support
197   // static code calling PIC code (CPIC). For O32 and N32 this means we have
198   // several combinations of PIC/static and abicalls. Pure static, static
199   // with the CPIC extension, and pure PIC code.
200 
201   // At final link time, O32 and N32 with CPIC will have another section
202   // added to the binary which contains the stub functions to perform
203   // any fixups required for PIC code.
204 
205   // For N64, the situation is more regular: code can either be static
206   // (non-abicalls) or PIC (abicalls). GCC has traditionally picked PIC code
207   // code for N64. Since Clang has already built the relocation model portion
208   // of the commandline, we pick add +noabicalls feature in the N64 static
209   // case.
210 
211   // The is another case to be accounted for: -msym32, which enforces that all
212   // symbols have 32 bits in size. In this case, N64 can in theory use CPIC
213   // but it is unsupported.
214 
215   // The combinations for N64 are:
216   // a) Static without abicalls and 64bit symbols.
217   // b) Static with abicalls and 32bit symbols.
218   // c) PIC with abicalls and 64bit symbols.
219 
220   // For case (a) we need to add +noabicalls for N64.
221 
222   bool IsN64 = ABIName == "64";
223   bool IsPIC = false;
224   bool NonPIC = false;
225   bool HasNaN2008Opt = false;
226 
227   Arg *LastPICArg = Args.getLastArg(options::OPT_fPIC, options::OPT_fno_PIC,
228                                     options::OPT_fpic, options::OPT_fno_pic,
229                                     options::OPT_fPIE, options::OPT_fno_PIE,
230                                     options::OPT_fpie, options::OPT_fno_pie);
231   if (LastPICArg) {
232     Option O = LastPICArg->getOption();
233     NonPIC =
234         (O.matches(options::OPT_fno_PIC) || O.matches(options::OPT_fno_pic) ||
235          O.matches(options::OPT_fno_PIE) || O.matches(options::OPT_fno_pie));
236     IsPIC =
237         (O.matches(options::OPT_fPIC) || O.matches(options::OPT_fpic) ||
238          O.matches(options::OPT_fPIE) || O.matches(options::OPT_fpie));
239   }
240 
241   bool UseAbiCalls = false;
242 
243   Arg *ABICallsArg =
244       Args.getLastArg(options::OPT_mabicalls, options::OPT_mno_abicalls);
245   UseAbiCalls =
246       !ABICallsArg || ABICallsArg->getOption().matches(options::OPT_mabicalls);
247 
248   if (IsN64 && NonPIC && (!ABICallsArg || UseAbiCalls)) {
249     D.Diag(diag::warn_drv_unsupported_pic_with_mabicalls)
250         << LastPICArg->getAsString(Args) << (!ABICallsArg ? 0 : 1);
251   }
252 
253   if (ABICallsArg && !UseAbiCalls && IsPIC) {
254     D.Diag(diag::err_drv_unsupported_noabicalls_pic);
255   }
256 
257   if (CPUName == "i6500" || CPUName == "i6400") {
258     // MIPS cpu i6400 and i6500 support MSA (Mips SIMD Architecture)
259     // by default.
260     Features.push_back("+msa");
261   }
262 
263   if (!UseAbiCalls)
264     Features.push_back("+noabicalls");
265   else
266     Features.push_back("-noabicalls");
267 
268   if (Arg *A = Args.getLastArg(options::OPT_mlong_calls,
269                                options::OPT_mno_long_calls)) {
270     if (A->getOption().matches(options::OPT_mno_long_calls))
271       Features.push_back("-long-calls");
272     else if (!UseAbiCalls)
273       Features.push_back("+long-calls");
274     else
275       D.Diag(diag::warn_drv_unsupported_longcalls) << (ABICallsArg ? 0 : 1);
276   }
277 
278   if (Arg *A = Args.getLastArg(options::OPT_mxgot, options::OPT_mno_xgot)) {
279     if (A->getOption().matches(options::OPT_mxgot))
280       Features.push_back("+xgot");
281     else
282       Features.push_back("-xgot");
283   }
284 
285   mips::FloatABI FloatABI = mips::getMipsFloatABI(D, Args, Triple);
286   if (FloatABI == mips::FloatABI::Soft) {
287     // FIXME: Note, this is a hack. We need to pass the selected float
288     // mode to the MipsTargetInfoBase to define appropriate macros there.
289     // Now it is the only method.
290     Features.push_back("+soft-float");
291   }
292 
293   if (Arg *A = Args.getLastArg(options::OPT_mnan_EQ)) {
294     StringRef Val = StringRef(A->getValue());
295     if (Val == "2008") {
296       if (mips::getIEEE754Standard(CPUName) & mips::Std2008) {
297         Features.push_back("+nan2008");
298         HasNaN2008Opt = true;
299       } else {
300         Features.push_back("-nan2008");
301         D.Diag(diag::warn_target_unsupported_nan2008) << CPUName;
302       }
303     } else if (Val == "legacy") {
304       if (mips::getIEEE754Standard(CPUName) & mips::Legacy)
305         Features.push_back("-nan2008");
306       else {
307         Features.push_back("+nan2008");
308         D.Diag(diag::warn_target_unsupported_nanlegacy) << CPUName;
309       }
310     } else
311       D.Diag(diag::err_drv_unsupported_option_argument)
312           << A->getSpelling() << Val;
313   }
314 
315   if (Arg *A = Args.getLastArg(options::OPT_mabs_EQ)) {
316     StringRef Val = StringRef(A->getValue());
317     if (Val == "2008") {
318       if (mips::getIEEE754Standard(CPUName) & mips::Std2008) {
319         Features.push_back("+abs2008");
320       } else {
321         Features.push_back("-abs2008");
322         D.Diag(diag::warn_target_unsupported_abs2008) << CPUName;
323       }
324     } else if (Val == "legacy") {
325       if (mips::getIEEE754Standard(CPUName) & mips::Legacy) {
326         Features.push_back("-abs2008");
327       } else {
328         Features.push_back("+abs2008");
329         D.Diag(diag::warn_target_unsupported_abslegacy) << CPUName;
330       }
331     } else {
332       D.Diag(diag::err_drv_unsupported_option_argument)
333           << A->getSpelling() << Val;
334     }
335   } else if (HasNaN2008Opt) {
336     Features.push_back("+abs2008");
337   }
338 
339   AddTargetFeature(Args, Features, options::OPT_msingle_float,
340                    options::OPT_mdouble_float, "single-float");
341   AddTargetFeature(Args, Features, options::OPT_mips16, options::OPT_mno_mips16,
342                    "mips16");
343   AddTargetFeature(Args, Features, options::OPT_mmicromips,
344                    options::OPT_mno_micromips, "micromips");
345   AddTargetFeature(Args, Features, options::OPT_mdsp, options::OPT_mno_dsp,
346                    "dsp");
347   AddTargetFeature(Args, Features, options::OPT_mdspr2, options::OPT_mno_dspr2,
348                    "dspr2");
349   AddTargetFeature(Args, Features, options::OPT_mmsa, options::OPT_mno_msa,
350                    "msa");
351   if (Arg *A = Args.getLastArg(
352           options::OPT_mstrict_align, options::OPT_mno_strict_align,
353           options::OPT_mno_unaligned_access, options::OPT_munaligned_access)) {
354     if (A->getOption().matches(options::OPT_mstrict_align) ||
355         A->getOption().matches(options::OPT_mno_unaligned_access))
356       Features.push_back(Args.MakeArgString("+strict-align"));
357     else
358       Features.push_back(Args.MakeArgString("-strict-align"));
359   }
360 
361   // Add the last -mfp32/-mfpxx/-mfp64, if none are given and the ABI is O32
362   // pass -mfpxx, or if none are given and fp64a is default, pass fp64 and
363   // nooddspreg.
364   if (Arg *A = Args.getLastArg(options::OPT_mfp32, options::OPT_mfpxx,
365                                options::OPT_mfp64)) {
366     if (A->getOption().matches(options::OPT_mfp32))
367       Features.push_back("-fp64");
368     else if (A->getOption().matches(options::OPT_mfpxx)) {
369       Features.push_back("+fpxx");
370       Features.push_back("+nooddspreg");
371     } else
372       Features.push_back("+fp64");
373   } else if (mips::shouldUseFPXX(Args, Triple, CPUName, ABIName, FloatABI)) {
374     Features.push_back("+fpxx");
375     Features.push_back("+nooddspreg");
376   } else if (Arg *A = Args.getLastArg(options::OPT_mmsa)) {
377     if (A->getOption().matches(options::OPT_mmsa))
378       Features.push_back("+fp64");
379   }
380 
381   AddTargetFeature(Args, Features, options::OPT_mno_odd_spreg,
382                    options::OPT_modd_spreg, "nooddspreg");
383   AddTargetFeature(Args, Features, options::OPT_mno_madd4, options::OPT_mmadd4,
384                    "nomadd4");
385   AddTargetFeature(Args, Features, options::OPT_mmt, options::OPT_mno_mt, "mt");
386   AddTargetFeature(Args, Features, options::OPT_mcrc, options::OPT_mno_crc,
387                    "crc");
388   AddTargetFeature(Args, Features, options::OPT_mvirt, options::OPT_mno_virt,
389                    "virt");
390   AddTargetFeature(Args, Features, options::OPT_mginv, options::OPT_mno_ginv,
391                    "ginv");
392 
393   if (Arg *A = Args.getLastArg(options::OPT_mindirect_jump_EQ)) {
394     StringRef Val = StringRef(A->getValue());
395     if (Val == "hazard") {
396       Arg *B =
397           Args.getLastArg(options::OPT_mmicromips, options::OPT_mno_micromips);
398       Arg *C = Args.getLastArg(options::OPT_mips16, options::OPT_mno_mips16);
399 
400       if (B && B->getOption().matches(options::OPT_mmicromips))
401         D.Diag(diag::err_drv_unsupported_indirect_jump_opt)
402             << "hazard" << "micromips";
403       else if (C && C->getOption().matches(options::OPT_mips16))
404         D.Diag(diag::err_drv_unsupported_indirect_jump_opt)
405             << "hazard" << "mips16";
406       else if (mips::supportsIndirectJumpHazardBarrier(CPUName))
407         Features.push_back("+use-indirect-jump-hazard");
408       else
409         D.Diag(diag::err_drv_unsupported_indirect_jump_opt)
410             << "hazard" << CPUName;
411     } else
412       D.Diag(diag::err_drv_unknown_indirect_jump_opt) << Val;
413   }
414 }
415 
getIEEE754Standard(StringRef & CPU)416 mips::IEEE754Standard mips::getIEEE754Standard(StringRef &CPU) {
417   // Strictly speaking, mips32r2 and mips64r2 do not conform to the
418   // IEEE754-2008 standard. Support for this standard was first introduced
419   // in Release 3. However, other compilers have traditionally allowed it
420   // for Release 2 so we should do the same.
421   return (IEEE754Standard)llvm::StringSwitch<int>(CPU)
422       .Case("mips1", Legacy)
423       .Case("mips2", Legacy)
424       .Case("mips3", Legacy)
425       .Case("mips4", Legacy)
426       .Case("mips5", Legacy)
427       .Case("mips32", Legacy)
428       .Case("mips32r2", Legacy | Std2008)
429       .Case("mips32r3", Legacy | Std2008)
430       .Case("mips32r5", Legacy | Std2008)
431       .Case("mips32r6", Std2008)
432       .Case("mips64", Legacy)
433       .Case("mips64r2", Legacy | Std2008)
434       .Case("mips64r3", Legacy | Std2008)
435       .Case("mips64r5", Legacy | Std2008)
436       .Case("mips64r6", Std2008)
437       .Default(Std2008);
438 }
439 
hasCompactBranches(StringRef & CPU)440 bool mips::hasCompactBranches(StringRef &CPU) {
441   // mips32r6 and mips64r6 have compact branches.
442   return llvm::StringSwitch<bool>(CPU)
443       .Case("mips32r6", true)
444       .Case("mips64r6", true)
445       .Default(false);
446 }
447 
hasMipsAbiArg(const ArgList & Args,const char * Value)448 bool mips::hasMipsAbiArg(const ArgList &Args, const char *Value) {
449   Arg *A = Args.getLastArg(options::OPT_mabi_EQ);
450   return A && (A->getValue() == StringRef(Value));
451 }
452 
isUCLibc(const ArgList & Args)453 bool mips::isUCLibc(const ArgList &Args) {
454   Arg *A = Args.getLastArg(options::OPT_m_libc_Group);
455   return A && A->getOption().matches(options::OPT_muclibc);
456 }
457 
isNaN2008(const Driver & D,const ArgList & Args,const llvm::Triple & Triple)458 bool mips::isNaN2008(const Driver &D, const ArgList &Args,
459                      const llvm::Triple &Triple) {
460   if (Arg *NaNArg = Args.getLastArg(options::OPT_mnan_EQ))
461     return llvm::StringSwitch<bool>(NaNArg->getValue())
462         .Case("2008", true)
463         .Case("legacy", false)
464         .Default(false);
465 
466   // NaN2008 is the default for MIPS32r6/MIPS64r6.
467   return llvm::StringSwitch<bool>(getCPUName(D, Args, Triple))
468       .Cases("mips32r6", "mips64r6", true)
469       .Default(false);
470 }
471 
isFPXXDefault(const llvm::Triple & Triple,StringRef CPUName,StringRef ABIName,mips::FloatABI FloatABI)472 bool mips::isFPXXDefault(const llvm::Triple &Triple, StringRef CPUName,
473                          StringRef ABIName, mips::FloatABI FloatABI) {
474   if (ABIName != "32")
475     return false;
476 
477   // FPXX shouldn't be used if either -msoft-float or -mfloat-abi=soft is
478   // present.
479   if (FloatABI == mips::FloatABI::Soft)
480     return false;
481 
482   return llvm::StringSwitch<bool>(CPUName)
483       .Cases("mips2", "mips3", "mips4", "mips5", true)
484       .Cases("mips32", "mips32r2", "mips32r3", "mips32r5", true)
485       .Cases("mips64", "mips64r2", "mips64r3", "mips64r5", true)
486       .Default(false);
487 }
488 
shouldUseFPXX(const ArgList & Args,const llvm::Triple & Triple,StringRef CPUName,StringRef ABIName,mips::FloatABI FloatABI)489 bool mips::shouldUseFPXX(const ArgList &Args, const llvm::Triple &Triple,
490                          StringRef CPUName, StringRef ABIName,
491                          mips::FloatABI FloatABI) {
492   bool UseFPXX = isFPXXDefault(Triple, CPUName, ABIName, FloatABI);
493 
494   // FPXX shouldn't be used if -msingle-float is present.
495   if (Arg *A = Args.getLastArg(options::OPT_msingle_float,
496                                options::OPT_mdouble_float))
497     if (A->getOption().matches(options::OPT_msingle_float))
498       UseFPXX = false;
499   // FP64 should be used for MSA.
500   if (Arg *A = Args.getLastArg(options::OPT_mmsa))
501     if (A->getOption().matches(options::OPT_mmsa))
502       UseFPXX = llvm::StringSwitch<bool>(CPUName)
503                     .Cases("mips32r2", "mips32r3", "mips32r5", false)
504                     .Cases("mips64r2", "mips64r3", "mips64r5", false)
505                     .Default(UseFPXX);
506 
507   return UseFPXX;
508 }
509 
supportsIndirectJumpHazardBarrier(StringRef & CPU)510 bool mips::supportsIndirectJumpHazardBarrier(StringRef &CPU) {
511   // Supporting the hazard barrier method of dealing with indirect
512   // jumps requires MIPSR2 support.
513   return llvm::StringSwitch<bool>(CPU)
514       .Case("mips32r2", true)
515       .Case("mips32r3", true)
516       .Case("mips32r5", true)
517       .Case("mips32r6", true)
518       .Case("mips64r2", true)
519       .Case("mips64r3", true)
520       .Case("mips64r5", true)
521       .Case("mips64r6", true)
522       .Case("octeon", true)
523       .Case("p5600", true)
524       .Case("i6400", true)
525       .Case("i6500", true)
526       .Default(false);
527 }
528