1 //=- ARMScheduleM7.td - ARM Cortex-M7 Scheduling Definitions -*- tablegen -*-=//
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
7 //===----------------------------------------------------------------------===//
9 // This file defines the SchedRead/Write data for the ARM Cortex-M7 processor.
11 //===----------------------------------------------------------------------===//
13 def CortexM7Model : SchedMachineModel {
14 let IssueWidth = 2; // Dual issue for most instructions.
15 let MicroOpBufferSize = 0; // The Cortex-M7 is in-order.
16 let LoadLatency = 2; // Best case for load-use case.
17 let MispredictPenalty = 4; // Mispredict cost for forward branches is 6,
19 let CompleteModel = 0;
22 let SchedModel = CortexM7Model in {
24 //===--------------------------------------------------------------------===//
25 // The Cortex-M7 has two ALU, two LOAD, a STORE, a MAC, a BRANCH and a VFP
26 // pipe. The stages relevant to scheduling are as follows:
28 // EX1: address generation shifts
29 // EX2: fast load data ALUs FP operation
30 // EX3: slow load data integer writeback FP operation
31 // EX4: store data FP writeback
33 // There are shifters in both EX1 and EX2, and some instructions can be
34 // flexibly allocated between them. EX2 is used as the "zero" point
35 // for scheduling, so simple ALU operations executing in EX2 will have
36 // ReadAdvance<0> (the default) for their source operands and Latency = 1.
38 def M7UnitLoadL : ProcResource<1> { let BufferSize = 0; }
39 def M7UnitLoadH : ProcResource<1> { let BufferSize = 0; }
40 def M7UnitLoad : ProcResGroup<[M7UnitLoadL,M7UnitLoadH]> { let BufferSize = 0; }
41 def M7UnitStore : ProcResource<1> { let BufferSize = 0; }
42 def M7UnitALU : ProcResource<2>;
43 def M7UnitShift1 : ProcResource<1> { let BufferSize = 0; }
44 def M7UnitShift2 : ProcResource<1> { let BufferSize = 0; }
45 def M7UnitMAC : ProcResource<1> { let BufferSize = 0; }
46 def M7UnitBranch : ProcResource<1> { let BufferSize = 0; }
47 def M7UnitVFP : ProcResource<1> { let BufferSize = 0; }
48 def M7UnitVPortL : ProcResource<1> { let BufferSize = 0; }
49 def M7UnitVPortH : ProcResource<1> { let BufferSize = 0; }
50 def M7UnitVPort : ProcResGroup<[M7UnitVPortL,M7UnitVPortH]> { let BufferSize = 0; }
51 def M7UnitSIMD : ProcResource<1> { let BufferSize = 0; }
53 //===---------------------------------------------------------------------===//
54 // Subtarget-specific SchedWrite types with map ProcResources and set latency.
56 def : WriteRes<WriteALU, [M7UnitALU]> { let Latency = 1; }
58 // Basic ALU with shifts.
60 def : WriteRes<WriteALUsi, [M7UnitALU, M7UnitShift1]>;
61 def : WriteRes<WriteALUsr, [M7UnitALU, M7UnitShift1]>;
62 def : WriteRes<WriteALUSsr, [M7UnitALU, M7UnitShift1]>;
66 def : WriteRes<WriteCMP, [M7UnitALU]> { let Latency = 1; }
67 def : WriteRes<WriteCMPsi, [M7UnitALU, M7UnitShift1]> { let Latency = 2; }
68 def : WriteRes<WriteCMPsr, [M7UnitALU, M7UnitShift1]> { let Latency = 2; }
72 def : WriteRes<WriteMUL16, [M7UnitMAC]>;
73 def : WriteRes<WriteMUL32, [M7UnitMAC]>;
74 def : WriteRes<WriteMUL64Lo, [M7UnitMAC]>;
75 def : WriteRes<WriteMUL64Hi, []> { let NumMicroOps = 0; }
78 // Multiply-accumulates.
80 def : WriteRes<WriteMAC16, [M7UnitMAC]>;
81 def : WriteRes<WriteMAC32, [M7UnitMAC]>;
82 def : WriteRes<WriteMAC64Lo, [M7UnitMAC]> { let Latency = 2; }
83 def : WriteRes<WriteMAC64Hi, []> { let NumMicroOps = 0; }
87 // These cannot be dual-issued with any instructions.
88 def : WriteRes<WriteDIV, [M7UnitALU]> {
94 def : WriteRes<WriteLd, [M7UnitLoad]> { let Latency = 1; }
95 def : WriteRes<WritePreLd, [M7UnitLoad]> { let Latency = 2; }
96 def : WriteRes<WriteST, [M7UnitStore]> { let Latency = 2; }
99 def : WriteRes<WriteBr, [M7UnitBranch]> { let Latency = 2; }
100 def : WriteRes<WriteBrL, [M7UnitBranch]> { let Latency = 2; }
101 def : WriteRes<WriteBrTbl, [M7UnitBranch]> { let Latency = 2; }
104 def : WriteRes<WriteNoop, []> { let Latency = 0; }
106 //===---------------------------------------------------------------------===//
107 // Sched definitions for floating-point instructions
109 // Floating point conversions.
110 def : WriteRes<WriteFPCVT, [M7UnitVFP, M7UnitVPort]> { let Latency = 3; }
111 def : WriteRes<WriteFPMOV, [M7UnitVPort]> { let Latency = 3; }
112 def M7WriteFPMOV64 : SchedWriteRes<[M7UnitVPortL, M7UnitVPortH]> {
116 // The FP pipeline has a latency of 3 cycles.
117 // ALU operations (32/64-bit). These go down the FP pipeline.
118 def : WriteRes<WriteFPALU32, [M7UnitVFP, M7UnitVPort]> { let Latency = 3; }
119 def : WriteRes<WriteFPALU64, [M7UnitVFP, M7UnitVPortL, M7UnitVPortH]> {
125 def : WriteRes<WriteFPMUL32, [M7UnitVFP, M7UnitVPort]> { let Latency = 3; }
126 def : WriteRes<WriteFPMUL64, [M7UnitVFP, M7UnitVPortL, M7UnitVPortH]> {
131 // Multiply-accumulate. FPMAC goes down the FP Pipeline.
132 def : WriteRes<WriteFPMAC32, [M7UnitVFP, M7UnitVPort]> { let Latency = 6; }
133 def : WriteRes<WriteFPMAC64, [M7UnitVFP, M7UnitVPortL, M7UnitVPortH]> {
138 // Division. Effective scheduling latency is 3, though real latency is larger
139 def : WriteRes<WriteFPDIV32, [M7UnitVFP, M7UnitVPort]> { let Latency = 16; }
140 def : WriteRes<WriteFPDIV64, [M7UnitVFP, M7UnitVPortL, M7UnitVPortH]> {
145 // Square-root. Effective scheduling latency is 3; real latency is larger
146 def : WriteRes<WriteFPSQRT32, [M7UnitVFP, M7UnitVPort]> { let Latency = 16; }
147 def : WriteRes<WriteFPSQRT64, [M7UnitVFP, M7UnitVPortL, M7UnitVPortH]> {
152 def M7WriteShift2 : SchedWriteRes<[M7UnitALU, M7UnitShift2]> {}
154 // Not used for M7, but needing definitions anyway
155 def : WriteRes<WriteVLD1, []>;
156 def : WriteRes<WriteVLD2, []>;
157 def : WriteRes<WriteVLD3, []>;
158 def : WriteRes<WriteVLD4, []>;
159 def : WriteRes<WriteVST1, []>;
160 def : WriteRes<WriteVST2, []>;
161 def : WriteRes<WriteVST3, []>;
162 def : WriteRes<WriteVST4, []>;
164 def M7SingleIssue : SchedWriteRes<[]> {
168 def M7Slot0Only : SchedWriteRes<[]> {
173 // What pipeline stage operands need to be ready for depending on
174 // where they come from.
175 def : ReadAdvance<ReadALUsr, 0>;
176 def : ReadAdvance<ReadMUL, 0>;
177 def : ReadAdvance<ReadMAC, 1>;
178 def : ReadAdvance<ReadALU, 0>;
179 def : ReadAdvance<ReadFPMUL, 0>;
180 def : ReadAdvance<ReadFPMAC, 3>;
181 def M7Read_ISS : SchedReadAdvance<-1>; // operands needed at EX1
182 def M7Read_EX2 : SchedReadAdvance<1>; // operands needed at EX3
183 def M7Read_EX3 : SchedReadAdvance<2>; // operands needed at EX4
185 // Non general purpose instructions may not be dual issued. These
186 // use both issue units.
187 def M7NonGeneralPurpose : SchedWriteRes<[]> {
188 // Assume that these will go down the main ALU pipeline.
189 // In reality, many look likely to stall the whole pipeline.
194 // List the non general purpose instructions.
195 def : InstRW<[M7NonGeneralPurpose], (instregex "t2MRS", "tSVC", "tBKPT",
196 "t2MSR", "t2DMB", "t2DSB", "t2ISB",
197 "t2HVC", "t2SMC", "t2UDF", "ERET",
198 "tHINT", "t2HINT", "t2CLREX", "BUNDLE")>;
200 //===---------------------------------------------------------------------===//
201 // Sched definitions for load/store
203 // Mark whether the loads/stores must be single-issue
204 // Address operands are needed earlier
205 // Data operands are needed later
207 def M7BaseUpdate : SchedWriteRes<[]> {
208 let Latency = 0; // Update is bypassable out of EX1
211 def M7LoadLatency1 : SchedWriteRes<[]> {
215 def M7SlowLoad : SchedWriteRes<[M7UnitLoad]> { let Latency = 2; }
217 // Byte and half-word loads should have greater latency than other loads.
218 // So should load exclusive.
220 def : InstRW<[M7SlowLoad],
221 (instregex "t2LDR(B|H|SB|SH)pc")>;
222 def : InstRW<[M7SlowLoad, M7Read_ISS],
223 (instregex "t2LDR(B|H|SB|SH)T", "t2LDR(B|H|SB|SH)i",
225 def : InstRW<[M7SlowLoad, M7Read_ISS, M7Read_ISS],
226 (instregex "t2LDR(B|H|SB|SH)s", "tLDR(B|H)r", "tLDR(SB|SH)")>;
227 def : InstRW<[M7SlowLoad, M7BaseUpdate, M7Read_ISS],
228 (instregex "t2LDR(B|H|SB|SH)_(POST|PRE)")>;
230 // Exclusive loads/stores cannot be dual-issued
231 def : InstRW<[WriteLd, M7Slot0Only, M7Read_ISS],
232 (instregex "t2LDREX$")>;
233 def : InstRW<[M7SlowLoad, M7Slot0Only, M7Read_ISS],
234 (instregex "t2LDREX(B|H)")>;
235 def : InstRW<[WriteST, M7SingleIssue, M7Read_EX2, M7Read_ISS],
236 (instregex "t2STREX(B|H)?$")>;
238 // Load/store multiples cannot be dual-issued. Note that default scheduling
239 // occurs around read/write times of individual registers in the list; read
240 // time for STM cannot be overridden because it is a variadic source operand.
242 def : InstRW<[WriteLd, M7SingleIssue, M7Read_ISS],
243 (instregex "(t|t2)LDM(DB|IA)$")>;
244 def : InstRW<[WriteST, M7SingleIssue, M7Read_ISS],
245 (instregex "(t|t2)STM(DB|IA)$")>;
246 def : InstRW<[M7BaseUpdate, WriteLd, M7SingleIssue, M7Read_ISS],
247 (instregex "(t|t2)LDM(DB|IA)_UPD$", "tPOP")>;
248 def : InstRW<[M7BaseUpdate, WriteST, M7SingleIssue, M7Read_ISS],
249 (instregex "(t|t2)STM(DB|IA)_UPD$", "tPUSH")>;
251 // Load/store doubles cannot be dual-issued.
253 def : InstRW<[M7BaseUpdate, WriteST, M7SingleIssue,
254 M7Read_EX2, M7Read_EX2, M7Read_ISS],
255 (instregex "t2STRD_(PRE|POST)")>;
256 def : InstRW<[WriteST, M7SingleIssue, M7Read_EX2, M7Read_EX2, M7Read_ISS],
257 (instregex "t2STRDi")>;
258 def : InstRW<[WriteLd, M7LoadLatency1, M7SingleIssue, M7BaseUpdate, M7Read_ISS],
259 (instregex "t2LDRD_(PRE|POST)")>;
260 def : InstRW<[WriteLd, M7LoadLatency1, M7SingleIssue, M7Read_ISS],
261 (instregex "t2LDRDi")>;
263 // Word load / preload
264 def : InstRW<[WriteLd],
265 (instregex "t2LDRpc", "t2PL[DI]pci", "tLDRpci")>;
266 def : InstRW<[WriteLd, M7Read_ISS],
267 (instregex "t2LDR(i|T)", "t2PL[DI](W)?i", "tLDRi", "tLDRspi")>;
268 def : InstRW<[WriteLd, M7Read_ISS, M7Read_ISS],
269 (instregex "t2LDRs", "t2PL[DI](w)?s", "tLDRr")>;
270 def : InstRW<[WriteLd, M7BaseUpdate, M7Read_ISS],
271 (instregex "t2LDR_(POST|PRE)")>;
274 def : InstRW<[M7BaseUpdate, WriteST, M7Read_EX2, M7Read_ISS],
275 (instregex "t2STR(B|H)?_(POST|PRE)")>;
276 def : InstRW<[WriteST, M7Read_EX2, M7Read_ISS, M7Read_ISS],
277 (instregex "t2STR(B|H)?s$", "tSTR(B|H)?r$")>;
278 def : InstRW<[WriteST, M7Read_EX2, M7Read_ISS],
279 (instregex "t2STR(B|H)?(i|T)", "tSTR(B|H)?i$", "tSTRspi")>;
281 // TBB/TBH - single-issue only; takes two cycles to issue
283 def M7TableLoad : SchedWriteRes<[M7UnitLoad]> {
288 def : InstRW<[M7TableLoad, M7Read_ISS, M7Read_ISS], (instregex "t2TB")>;
290 // VFP loads and stores
292 def M7LoadSP : SchedWriteRes<[M7UnitLoad, M7UnitVPort]> { let Latency = 1; }
293 def M7LoadDP : SchedWriteRes<[M7UnitLoadL, M7UnitLoadH, M7UnitVPortL, M7UnitVPortH]> {
297 def M7StoreSP : SchedWriteRes<[M7UnitStore, M7UnitVPort]>;
298 def M7StoreDP : SchedWriteRes<[M7UnitStore, M7UnitVPortL, M7UnitVPortH]> {
302 def : InstRW<[M7LoadSP, M7Read_ISS], (instregex "VLDR(S|H)$")>;
303 def : InstRW<[M7LoadDP, M7Read_ISS], (instregex "VLDRD$")>;
304 def : InstRW<[M7StoreSP, M7Read_EX3, M7Read_ISS], (instregex "VSTR(S|H)$")>;
305 def : InstRW<[M7StoreDP, M7Read_EX3, M7Read_ISS], (instregex "VSTRD$")>;
307 // Load/store multiples cannot be dual-issued.
309 def : InstRW<[WriteLd, M7SingleIssue, M7Read_ISS],
310 (instregex "VLDM(S|D|Q)(DB|IA)$")>;
311 def : InstRW<[WriteST, M7SingleIssue, M7Read_ISS],
312 (instregex "VSTM(S|D|Q)(DB|IA)$")>;
313 def : InstRW<[M7BaseUpdate, WriteLd, M7SingleIssue, M7Read_ISS],
314 (instregex "VLDM(S|D|Q)(DB|IA)_UPD$")>;
315 def : InstRW<[M7BaseUpdate, WriteST, M7SingleIssue, M7Read_ISS],
316 (instregex "VSTM(S|D|Q)(DB|IA)_UPD$")>;
318 //===---------------------------------------------------------------------===//
319 // Sched definitions for ALU
322 // Shifted ALU operands are read a cycle early.
323 def M7Ex1ReadNoFastBypass : SchedReadAdvance<-1, [WriteLd, M7LoadLatency1]>;
325 def : InstRW<[WriteALUsi, M7Ex1ReadNoFastBypass, M7Read_ISS],
326 (instregex "t2(ADC|ADDS|ADD|BIC|EOR|ORN|ORR|RSBS|RSB|SBC|SUBS)rs$",
327 "t2(SUB|CMP|CMNz|TEQ|TST)rs$",
329 def : InstRW<[WriteALUsi, M7Read_ISS],
330 (instregex "t2MVNs")>;
332 // Treat pure shift operations (except for RRX) as if they used the EX1
333 // shifter but have timing as if they used the EX2 shifter as they usually
334 // can choose the EX2 shifter when needed. Will miss a few dual-issue cases,
335 // but the results prove to be better than trying to get them exact.
337 def : InstRW<[M7WriteShift2, M7Read_ISS], (instregex "t2RRX$")>;
338 def : InstRW<[WriteALUsi], (instregex "(t|t2)(LSL|LSR|ASR|ROR)")>;
340 // Instructions that use the shifter, but have normal timing.
342 def : InstRW<[WriteALUsi,M7Slot0Only], (instregex "t2(BFC|BFI)$")>;
344 // Instructions which are slot zero only but otherwise normal.
346 def : InstRW<[WriteALU, M7Slot0Only], (instregex "t2CLZ")>;
348 // MAC operations that don't have SchedRW set.
350 def : InstRW<[WriteMAC32, ReadMUL, ReadMUL, ReadMAC], (instregex "t2SML[AS]D")>;
352 // Divides are special because they stall for their latency, and so look like a
353 // single-cycle as far as scheduling opportunities go. By putting WriteALU
354 // first, we make the operand latency 1, but keep the instruction latency 7.
356 def : InstRW<[WriteALU, WriteDIV], (instregex "t2(S|U)DIV")>;
358 // DSP extension operations
360 def M7WriteSIMD1 : SchedWriteRes<[M7UnitSIMD, M7UnitALU]> {
364 def M7WriteSIMD2 : SchedWriteRes<[M7UnitSIMD, M7UnitALU]> {
368 def M7WriteShSIMD1 : SchedWriteRes<[M7UnitSIMD, M7UnitALU, M7UnitShift1]> {
372 def M7WriteShSIMD0 : SchedWriteRes<[M7UnitSIMD, M7UnitALU, M7UnitShift1]> {
373 let Latency = 0; // Bypassable out of EX1
376 def M7WriteShSIMD2 : SchedWriteRes<[M7UnitSIMD, M7UnitALU, M7UnitShift1]> {
381 def : InstRW<[M7WriteShSIMD2, M7Read_ISS],
382 (instregex "t2(S|U)SAT")>;
383 def : InstRW<[M7WriteSIMD1, ReadALU],
384 (instregex "(t|t2)(S|U)XT(B|H)")>;
385 def : InstRW<[M7WriteSIMD1, ReadALU, ReadALU],
386 (instregex "t2(S|SH|U|UH)(ADD16|ADD8|ASX|SAX|SUB16|SUB8)",
388 def : InstRW<[M7WriteSIMD2, ReadALU, ReadALU],
389 (instregex "t2(Q|UQ)(ADD|ASX|SAX|SUB)", "t2USAD8")>;
390 def : InstRW<[M7WriteShSIMD2, M7Read_ISS, M7Read_ISS],
391 (instregex "t2QD(ADD|SUB)")>;
392 def : InstRW<[M7WriteShSIMD0, M7Read_ISS],
393 (instregex "t2(RBIT|REV)", "tREV")>;
394 def : InstRW<[M7WriteShSIMD1, M7Read_ISS],
395 (instregex "t2(SBFX|UBFX)")>;
396 def : InstRW<[M7WriteShSIMD1, ReadALU, M7Read_ISS],
397 (instregex "t2PKH(BT|TB)", "t2(S|U)XTA")>;
398 def : InstRW<[M7WriteSIMD2, ReadALU, ReadALU, M7Read_EX2],
399 (instregex "t2USADA8")>;
402 def : InstRW<[M7NonGeneralPurpose], (instregex "MSR", "MRS")>;
404 //===---------------------------------------------------------------------===//
405 // Sched definitions for FP operations
408 // Effective scheduling latency is really 3 for nearly all FP operations,
409 // even if their true latency is higher.
410 def M7WriteVFPLatOverride : SchedWriteRes<[]> {
414 def M7WriteVFPExtraVPort : SchedWriteRes<[M7UnitVPort]> {
419 // Instructions which are missing default schedules.
420 def : InstRW<[WriteFPALU32],
421 (instregex "V(ABS|CVT.*|NEG|FP_VMAX.*|FP_VMIN.*|RINT.*)S$")>;
422 def : InstRW<[M7WriteVFPLatOverride, WriteFPALU64],
423 (instregex "V(ABS|CVT.*|NEG|FP_VMAX.*|FP_VMIN.*|RINT.*)D$")>;
426 def M7WriteVCMPS : SchedWriteRes<[M7UnitVFP, M7UnitVPort]> { let Latency = 0; }
427 def M7WriteVCMPD : SchedWriteRes<[M7UnitVFP, M7UnitVPort, M7UnitVPort]> {
431 def : InstRW<[M7WriteVCMPS], (instregex "VCMPS$")>;
432 def : InstRW<[M7WriteVCMPD], (instregex "VCMPD$")>;
435 def M7VMRS : SchedWriteRes<[M7UnitVFP, M7UnitVPort]> { let SingleIssue = 1; }
436 def M7VMSR : SchedWriteRes<[M7UnitVFP, M7UnitVPort]> { let SingleIssue = 1; }
437 def : InstRW<[M7VMRS], (instregex "FMSTAT")>;
438 def : InstRW<[M7VMSR], (instregex "VMSR")>;
440 // VSEL cannot bypass in its implied $cpsr operand; model as earlier read
441 def : InstRW<[WriteFPALU32, M7Slot0Only, ReadALU, ReadALU, M7Read_ISS],
442 (instregex "VSEL.*S$")>;
443 def : InstRW<[M7WriteVFPLatOverride, WriteFPALU64, M7Slot0Only,
444 ReadALU, ReadALU, M7Read_ISS],
445 (instregex "VSEL.*D$")>;
448 def : InstRW<[WriteFPMOV],
449 (instregex "VMOV(H|S)$", "FCONST(H|S)")>;
450 def : InstRW<[WriteFPMOV, M7WriteVFPExtraVPort, M7Slot0Only],
451 (instregex "VMOVD$")>;
452 def : InstRW<[WriteFPMOV, M7WriteVFPExtraVPort, M7Slot0Only],
453 (instregex "FCONSTD")>;
454 def : InstRW<[WriteFPMOV, M7WriteVFPExtraVPort, M7SingleIssue],
455 (instregex "VMOV(DRR|RRD|RRS|SRR)")>;
457 // Larger-latency overrides.
459 def : InstRW<[M7WriteVFPLatOverride, WriteFPDIV32], (instregex "VDIVS")>;
460 def : InstRW<[M7WriteVFPLatOverride, WriteFPDIV64], (instregex "VDIVD")>;
461 def : InstRW<[M7WriteVFPLatOverride, WriteFPSQRT32], (instregex "VSQRTS")>;
462 def : InstRW<[M7WriteVFPLatOverride, WriteFPSQRT64], (instregex "VSQRTD")>;
463 def : InstRW<[M7WriteVFPLatOverride, WriteFPMUL64],
464 (instregex "V(MUL|NMUL)D")>;
465 def : InstRW<[M7WriteVFPLatOverride, WriteFPALU64],
466 (instregex "V(ADD|SUB)D")>;
468 // Multiply-accumulate. Chained SP timing is correct; rest need overrides
469 // Double-precision chained MAC stalls the pipeline behind it for 3 cycles,
470 // making it appear to have 3 cycle latency for scheduling.
472 def : InstRW<[M7WriteVFPLatOverride, WriteFPMAC64,
473 ReadFPMAC, ReadFPMUL, ReadFPMUL],
474 (instregex "V(N)?ML(A|S)D$")>;
476 // Single-precision fused MACs look like latency 5 with advance of 2.
478 def M7WriteVFPLatOverride5 : SchedWriteRes<[]> {
482 def M7ReadFPMAC2 : SchedReadAdvance<2>;
484 def : InstRW<[M7WriteVFPLatOverride5, WriteFPMAC32,
485 M7ReadFPMAC2, ReadFPMUL, ReadFPMUL],
486 (instregex "VF(N)?M(A|S)S$")>;
488 // Double-precision fused MAC stalls the pipeline behind it for 2 cycles, making
489 // it appear to have 3 cycle latency for scheduling.
491 def : InstRW<[M7WriteVFPLatOverride, WriteFPMAC64,
492 ReadFPMAC, ReadFPMUL, ReadFPMUL],
493 (instregex "VF(N)?M(A|S)D$")>;
495 } // SchedModel = CortexM7Model