forked from llvm/circt
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathFirtool.cpp
More file actions
883 lines (745 loc) · 37.2 KB
/
Firtool.cpp
File metadata and controls
883 lines (745 loc) · 37.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
//===- Firtool.cpp - Definitions for the firtool pipeline setup -*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "circt/Firtool/Firtool.h"
#include "circt/Conversion/Passes.h"
#include "circt/Dialect/FIRRTL/FIRRTLOps.h"
#include "circt/Dialect/FIRRTL/Passes.h"
#include "circt/Dialect/HW/HWPasses.h"
#include "circt/Dialect/OM/OMPasses.h"
#include "circt/Dialect/SV/SVPasses.h"
#include "circt/Dialect/Seq/SeqPasses.h"
#include "circt/Dialect/Verif/VerifPasses.h"
#include "circt/Support/Passes.h"
#include "circt/Transforms/Passes.h"
#include "mlir/Transforms/Passes.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
using namespace llvm;
using namespace circt;
LogicalResult firtool::populatePreprocessTransforms(mlir::PassManager &pm,
const FirtoolOptions &opt) {
pm.nest<firrtl::CircuitOp>().addPass(
firrtl::createCheckRecursiveInstantiation());
pm.nest<firrtl::CircuitOp>().addPass(firrtl::createCheckLayers());
// Legalize away "open" aggregates to hw-only versions.
pm.nest<firrtl::CircuitOp>().addPass(firrtl::createLowerOpenAggs());
pm.nest<firrtl::CircuitOp>().addPass(firrtl::createResolvePaths());
pm.nest<firrtl::CircuitOp>().addPass(firrtl::createLowerFIRRTLAnnotations(
{/*ignoreAnnotationClassless=*/opt.shouldDisableClasslessAnnotations(),
/*ignoreAnnotationUnknown=*/opt.shouldDisableUnknownAnnotations(),
/*noRefTypePorts=*/opt.shouldLowerNoRefTypePortAnnotations()}));
if (opt.shouldEnableDebugInfo())
pm.nest<firrtl::CircuitOp>().addNestedPass<firrtl::FModuleOp>(
firrtl::createMaterializeDebugInfo());
pm.nest<firrtl::CircuitOp>().addPass(firrtl::createLowerIntmodules(
{/*fixupEICGWrapper=*/opt.shouldFixupEICGWrapper()}));
pm.nest<firrtl::CircuitOp>().nest<firrtl::FModuleOp>().addPass(
firrtl::createLowerIntrinsics());
if (auto mode = FirtoolOptions::toInferDomainsPassMode(opt.getDomainMode()))
pm.nest<firrtl::CircuitOp>().addPass(firrtl::createInferDomains({*mode}));
return success();
}
LogicalResult firtool::populateCHIRRTLToLowFIRRTL(mlir::PassManager &pm,
const FirtoolOptions &opt) {
// TODO: Ensure instance graph and other passes can handle instance choice
// then run this pass after all diagnostic passes have run.
pm.addNestedPass<firrtl::CircuitOp>(firrtl::createSpecializeOption(
{/*selectDefaultInstanceChoice*/ opt
.shouldSelectDefaultInstanceChoice()}));
pm.nest<firrtl::CircuitOp>().addPass(firrtl::createLowerSignatures());
// This pass is _not_ idempotent. It preserves its controlling annotation for
// use by ExtractInstances. This pass should be run before ExtractInstances.
//
// TODO: This pass should be deleted.
pm.nest<firrtl::CircuitOp>().addPass(firrtl::createInjectDUTHierarchy());
if (!opt.shouldDisableOptimization()) {
if (opt.shouldDisableCSEinClasses())
pm.nest<firrtl::CircuitOp>().nest<firrtl::FModuleOp>().addPass(
mlir::createCSEPass());
else
pm.nest<firrtl::CircuitOp>().nestAny().addPass(mlir::createCSEPass());
}
pm.nest<firrtl::CircuitOp>().nest<firrtl::FModuleOp>().addPass(
firrtl::createPassiveWires());
pm.nest<firrtl::CircuitOp>().nest<firrtl::FModuleOp>().addPass(
firrtl::createDropName({/*preserveMode=*/opt.getPreserveMode()}));
pm.nest<firrtl::CircuitOp>().nest<firrtl::FModuleOp>().addPass(
firrtl::createLowerCHIRRTLPass());
// Run LowerMatches before InferWidths, as the latter does not support the
// match statement, but it does support what they lower to.
pm.nest<firrtl::CircuitOp>().nest<firrtl::FModuleOp>().addPass(
firrtl::createLowerMatches());
// Width inference creates canonicalization opportunities.
pm.nest<firrtl::CircuitOp>().addPass(firrtl::createInferWidths());
pm.nest<firrtl::CircuitOp>().addPass(firrtl::createMemToRegOfVec(
{/*replSeqMem=*/opt.shouldReplaceSequentialMemories(),
/*replSeqMemFile=*/opt.shouldIgnoreReadEnableMemories()}));
pm.nest<firrtl::CircuitOp>().addPass(firrtl::createInferResets());
pm.nest<firrtl::CircuitOp>().addPass(firrtl::createDropConst());
if (opt.shouldDedup()) {
firrtl::DedupOptions opts;
opts.dedupClasses = opt.shouldDedupClasses();
pm.nest<firrtl::CircuitOp>().addPass(firrtl::createDedup(opts));
}
if (opt.shouldConvertVecOfBundle()) {
pm.addNestedPass<firrtl::CircuitOp>(firrtl::createLowerFIRRTLTypes(
{/*preserveAggregate=*/firrtl::PreserveAggregate::All,
/*preserveMemories*/ firrtl::PreserveAggregate::All}));
pm.addNestedPass<firrtl::CircuitOp>(firrtl::createVBToBV());
}
if (!opt.shouldLowerMemories())
pm.nest<firrtl::CircuitOp>().nest<firrtl::FModuleOp>().addPass(
firrtl::createFlattenMemory());
// The input mlir file could be firrtl dialect so we might need to clean
// things up.
// pm.addNestedPass<firrtl::CircuitOp>(firrtl::createLowerSignaturesPass());
pm.addNestedPass<firrtl::CircuitOp>(firrtl::createLowerFIRRTLTypes(
{/*preserveAggregate=*/opt.getPreserveAggregate(),
/*preserveMemory=*/firrtl::PreserveAggregate::None}));
{
auto &modulePM = pm.nest<firrtl::CircuitOp>().nest<firrtl::FModuleOp>();
modulePM.addPass(firrtl::createExpandWhens());
modulePM.addPass(firrtl::createSFCCompat());
}
pm.addNestedPass<firrtl::CircuitOp>(firrtl::createCheckCombLoops());
// Must run this pass after all diagnostic passes have run, otherwise it can
// hide errors.
pm.addNestedPass<firrtl::CircuitOp>(firrtl::createSpecializeLayers());
// Run after inference, layer specialization.
if (opt.shouldConvertProbesToSignals())
pm.nest<firrtl::CircuitOp>().addPass(firrtl::createProbesToSignals());
pm.nest<firrtl::CircuitOp>().addPass(firrtl::createInliner());
pm.nest<firrtl::CircuitOp>().nest<firrtl::FModuleOp>().addPass(
firrtl::createLayerMerge());
// Preset the random initialization parameters for each module. The current
// implementation assumes it can run at a time where every register is
// currently in the final module it will be emitted in, all registers have
// been created, and no registers have yet been removed.
if (opt.isRandomEnabled(FirtoolOptions::RandomKind::Reg))
pm.nest<firrtl::CircuitOp>().nest<firrtl::FModuleOp>().addPass(
firrtl::createRandomizeRegisterInit());
// If we parsed a FIRRTL file and have optimizations enabled, clean it up.
if (!opt.shouldDisableOptimization())
pm.nest<firrtl::CircuitOp>().nest<firrtl::FModuleOp>().addPass(
createSimpleCanonicalizerPass());
// Run the infer-rw pass, which merges read and write ports of a memory with
// mutually exclusive enables.
if (!opt.shouldDisableOptimization())
pm.nest<firrtl::CircuitOp>().nest<firrtl::FModuleOp>().addPass(
firrtl::createInferReadWrite());
if (opt.shouldReplaceSequentialMemories())
pm.nest<firrtl::CircuitOp>().addPass(firrtl::createLowerMemory());
if (!opt.shouldDisableOptimization())
pm.nest<firrtl::CircuitOp>().addPass(firrtl::createIMConstProp());
pm.addNestedPass<firrtl::CircuitOp>(firrtl::createAddSeqMemPorts());
pm.addPass(firrtl::createCreateSiFiveMetadata(
{/*replSeqMem=*/opt.shouldReplaceSequentialMemories(),
/*replSeqMemFile=*/opt.getReplaceSequentialMemoriesFile().str()}));
// This pass must be run after InjectDUTHierarchy.
//
// TODO: This pass should be deleted along with InjectDUTHierarchy.
pm.addNestedPass<firrtl::CircuitOp>(firrtl::createExtractInstances());
// Run SymbolDCE as late as possible, but before InnerSymbolDCE. This is for
// hierpathop's and just for general cleanup.
pm.addNestedPass<firrtl::CircuitOp>(mlir::createSymbolDCEPass());
// Run InnerSymbolDCE as late as possible, but before IMDCE.
pm.addPass(firrtl::createInnerSymbolDCE());
// The above passes, IMConstProp in particular, introduce additional
// canonicalization opportunities that we should pick up here before we
// proceed to output-specific pipelines.
if (!opt.shouldDisableOptimization()) {
if (!opt.shouldDisableWireElimination())
pm.nest<firrtl::CircuitOp>().nest<firrtl::FModuleOp>().addPass(
circt::firrtl::createEliminateWires());
pm.nest<firrtl::CircuitOp>().nest<firrtl::FModuleOp>().addPass(
createSimpleCanonicalizerPass());
pm.nest<firrtl::CircuitOp>().nest<firrtl::FModuleOp>().addPass(
circt::firrtl::createRegisterOptimizer());
// Re-run IMConstProp to propagate constants produced by register
// optimizations.
pm.nest<firrtl::CircuitOp>().addPass(firrtl::createIMConstProp());
pm.nest<firrtl::CircuitOp>().nest<firrtl::FModuleOp>().addPass(
createSimpleCanonicalizerPass());
pm.addPass(firrtl::createIMDeadCodeElim());
if (opt.shouldInlineInputOnlyModules()) {
pm.nest<firrtl::CircuitOp>().addPass(
firrtl::createAnnotateInputOnlyModules());
pm.nest<firrtl::CircuitOp>().addPass(firrtl::createInliner());
pm.nest<firrtl::CircuitOp>().nest<firrtl::FModuleOp>().addPass(
createSimpleCanonicalizerPass());
}
}
// Always run this, required for legalization.
pm.nest<firrtl::CircuitOp>().nest<firrtl::FModuleOp>().addPass(
firrtl::createMergeConnections(
{/*enableAggressiveMergin=*/!opt
.shouldDisableAggressiveMergeConnections()}));
if (!opt.shouldDisableOptimization())
pm.nest<firrtl::CircuitOp>().nest<firrtl::FModuleOp>().addPass(
firrtl::createVectorization());
return success();
}
LogicalResult firtool::populateLowFIRRTLToHW(mlir::PassManager &pm,
const FirtoolOptions &opt,
StringRef inputFilename) {
// Populate instance macros for instance choice operations before lowering to
// HW.
pm.nest<firrtl::CircuitOp>().addPass(
firrtl::createPopulateInstanceChoiceSymbols());
// Run layersink immediately before LowerXMR. LowerXMR will "freeze" the
// location of probed objects by placing symbols on them. Run layersink first
// so that probed objects can be sunk if possible.
if (!opt.shouldDisableLayerSink() && !opt.shouldDisableOptimization())
pm.nest<firrtl::CircuitOp>().addPass(firrtl::createLayerSink());
// Lower the ref.resolve and ref.send ops and remove the RefType ports.
// LowerToHW cannot handle RefType so, this pass must be run to remove all
// RefType ports and ops.
pm.nest<firrtl::CircuitOp>().addPass(firrtl::createLowerXMR());
// Layer lowering passes. Move operations into layers when possible and
// remove layers by converting them to other constructs. This lowering
// process can create a few optimization opportunities.
//
// TODO: Improve LowerLayers to avoid the need for canonicalization. See:
// https://github.com/llvm/circt/issues/7896
pm.nest<firrtl::CircuitOp>().addPass(
firrtl::createLowerLayers({opt.getEmitAllBindFiles()}));
if (!opt.shouldDisableOptimization())
pm.nest<firrtl::CircuitOp>().nest<firrtl::FModuleOp>().addPass(
createSimpleCanonicalizerPass());
auto outputFilename = opt.getOutputFilename();
if (outputFilename == "-")
outputFilename = "";
pm.nest<firrtl::CircuitOp>().addPass(firrtl::createAssignOutputDirs(
{/*outputDirOption=*/outputFilename.str()}));
// Run passes to resolve Grand Central features. This should run before
// BlackBoxReader because Grand Central needs to inform BlackBoxReader where
// certain black boxes should be placed. Note: all Grand Central Taps related
// collateral is resolved entirely by LowerAnnotations.
// Run this after output directories are (otherwise) assigned,
// so generated interfaces can be appropriately marked.
pm.addNestedPass<firrtl::CircuitOp>(
firrtl::createGrandCentral({/*companionMode=*/opt.getCompanionMode(),
/*noViews*/ opt.getNoViews()}));
// Read black box source files into the IR.
StringRef blackBoxRoot = opt.getBlackBoxRootPath().empty()
? llvm::sys::path::parent_path(inputFilename)
: opt.getBlackBoxRootPath();
pm.nest<firrtl::CircuitOp>().addPass(
firrtl::createBlackBoxReader({/*inputPrefix=*/blackBoxRoot.str()}));
// Remove TraceAnnotations and write their updated paths to an output
// annotation file.
pm.nest<firrtl::CircuitOp>().addPass(
firrtl::createResolveTraces({opt.getOutputAnnotationFilename().str()}));
pm.nest<firrtl::CircuitOp>().addPass(firrtl::createLowerDPI());
pm.nest<firrtl::CircuitOp>().addPass(firrtl::createLowerDomains());
pm.nest<firrtl::CircuitOp>().addPass(firrtl::createLowerClasses());
pm.nest<firrtl::CircuitOp>().addPass(om::createVerifyObjectFieldsPass());
// Check for static asserts.
pm.nest<firrtl::CircuitOp>().addPass(circt::firrtl::createLint(
{/*lintStaticAsserts=*/opt.getLintStaticAsserts(),
/*lintXmrsInDesign=*/opt.getLintXmrsInDesign()}));
pm.addPass(createLowerFIRRTLToHWPass(opt.shouldEnableAnnotationWarning(),
opt.getVerificationFlavor()));
if (!opt.shouldDisableOptimization()) {
auto &modulePM = pm.nest<hw::HWModuleOp>();
modulePM.addPass(mlir::createCSEPass());
modulePM.addPass(createSimpleCanonicalizerPass());
}
// Check inner symbols and inner refs.
pm.addPass(hw::createVerifyInnerRefNamespace());
// Check OM object fields.
pm.addPass(om::createVerifyObjectFieldsPass());
// Run the verif op verification pass
pm.addNestedPass<hw::HWModuleOp>(verif::createVerifyClockedAssertLikePass());
return success();
}
LogicalResult firtool::populateHWToSV(mlir::PassManager &pm,
const FirtoolOptions &opt) {
pm.nestAny().addPass(verif::createStripContractsPass());
pm.addPass(verif::createLowerTestsPass());
pm.addPass(
verif::createLowerSymbolicValuesPass({opt.getSymbolicValueLowering()}));
pm.addPass(seq::createExternalizeClockGate(opt.getClockGateOptions()));
pm.addPass(circt::createLowerSimToSVPass());
pm.addPass(circt::createLowerSeqToSVPass(
{/*disableRegRandomization=*/!opt.isRandomEnabled(
FirtoolOptions::RandomKind::Reg),
/*disableMemRandomization=*/
!opt.isRandomEnabled(FirtoolOptions::RandomKind::Mem),
/*emitSeparateAlwaysBlocks=*/
opt.shouldEmitSeparateAlwaysBlocks()}));
pm.addNestedPass<hw::HWModuleOp>(createLowerVerifToSVPass());
pm.addPass(seq::createHWMemSimImpl(
{/*disableMemRandomization=*/!opt.isRandomEnabled(
FirtoolOptions::RandomKind::Mem),
/*disableRegRandomization=*/
!opt.isRandomEnabled(FirtoolOptions::RandomKind::Reg),
/*replSeqMem=*/opt.shouldReplaceSequentialMemories(),
/*readEnableMode=*/opt.shouldIgnoreReadEnableMemories()
? seq::ReadEnableMode::Ignore
: seq::ReadEnableMode::Undefined,
/*addMuxPragmas=*/opt.shouldAddMuxPragmas(),
/*addVivadoRAMAddressConflictSynthesisBugWorkaround=*/
opt.shouldAddVivadoRAMAddressConflictSynthesisBugWorkaround()}));
// If enabled, run the optimizer.
if (!opt.shouldDisableOptimization()) {
auto &modulePM = pm.nest<hw::HWModuleOp>();
modulePM.addPass(mlir::createCSEPass());
modulePM.addPass(createSimpleCanonicalizerPass());
modulePM.addPass(mlir::createCSEPass());
modulePM.addPass(sv::createHWCleanup(
{/*mergeAlwaysBlocks=*/!opt.shouldEmitSeparateAlwaysBlocks()}));
}
// Check inner symbols and inner refs.
pm.addPass(hw::createVerifyInnerRefNamespace());
// Check OM object fields.
pm.addPass(om::createVerifyObjectFieldsPass());
return success();
}
namespace detail {
LogicalResult
populatePrepareForExportVerilog(mlir::PassManager &pm,
const firtool::FirtoolOptions &opt) {
// Run the verif op verification pass
pm.addNestedPass<hw::HWModuleOp>(verif::createVerifyClockedAssertLikePass());
// Legalize unsupported operations within the modules.
pm.nest<hw::HWModuleOp>().addPass(sv::createHWLegalizeModules());
// Tidy up the IR to improve verilog emission quality.
if (!opt.shouldDisableOptimization())
pm.nest<hw::HWModuleOp>().addPass(sv::createPrettifyVerilog());
if (opt.shouldStripFirDebugInfo())
pm.addPass(circt::createStripDebugInfoWithPredPass([](mlir::Location loc) {
if (auto fileLoc = dyn_cast<FileLineColLoc>(loc))
return fileLoc.getFilename().getValue().ends_with(".fir");
return false;
}));
if (opt.shouldStripDebugInfo())
pm.addPass(circt::createStripDebugInfoWithPredPass(
[](mlir::Location loc) { return true; }));
// Emit module and testbench hierarchy JSON files.
if (opt.shouldExportModuleHierarchy())
pm.addPass(sv::createHWExportModuleHierarchy());
// Check inner symbols and inner refs.
pm.addPass(hw::createVerifyInnerRefNamespace());
// Check OM object fields.
pm.addPass(om::createVerifyObjectFieldsPass());
return success();
}
} // namespace detail
LogicalResult
firtool::populateExportVerilog(mlir::PassManager &pm, const FirtoolOptions &opt,
std::unique_ptr<llvm::raw_ostream> os) {
if (failed(::detail::populatePrepareForExportVerilog(pm, opt)))
return failure();
pm.addPass(createExportVerilogPass(std::move(os)));
return success();
}
LogicalResult firtool::populateExportVerilog(mlir::PassManager &pm,
const FirtoolOptions &opt,
llvm::raw_ostream &os) {
if (failed(::detail::populatePrepareForExportVerilog(pm, opt)))
return failure();
pm.addPass(createExportVerilogPass(os));
return success();
}
LogicalResult firtool::populateExportSplitVerilog(mlir::PassManager &pm,
const FirtoolOptions &opt,
llvm::StringRef directory) {
if (failed(::detail::populatePrepareForExportVerilog(pm, opt)))
return failure();
pm.addPass(createExportSplitVerilogPass(directory));
return success();
}
LogicalResult firtool::populateFinalizeIR(mlir::PassManager &pm,
const FirtoolOptions &opt) {
pm.addPass(firrtl::createFinalizeIR());
pm.addPass(om::createFreezePathsPass());
return success();
}
/// BTOR2 emission pipeline, triggered with `--btor2` flag.
LogicalResult firtool::populateHWToBTOR2(mlir::PassManager &pm,
const FirtoolOptions &opt,
llvm::raw_ostream &os) {
auto &mpm = pm.nest<hw::HWModuleOp>();
// Lower all supported `ltl` ops
mpm.addPass(circt::createLowerLTLToCorePass());
// LTLToCore can generate shiftreg which should be lowered before emission
mpm.addPass(circt::seq::createLowerSeqShiftReg());
// ShiftReg Lowering generates compreg.ce, which we don't support, so lower
mpm.addPass(circt::seq::createLowerSeqCompRegCE());
// Do final formal specific lowerings, e.g. inline wires eagerly
mpm.addPass(circt::verif::createPrepareForFormalPass());
pm.addPass(circt::hw::createFlattenModules());
pm.addPass(circt::createConvertHWToBTOR2Pass(os));
return success();
}
//===----------------------------------------------------------------------===//
// FIRTOOL CommandLine Options
//===----------------------------------------------------------------------===//
namespace {
/// This struct contains command line options that can be used to initialize
/// various bits of a Firtool pipeline. This uses a struct wrapper to avoid the
/// need for global command line options.
struct FirtoolCmdOptions {
llvm::cl::opt<std::string> outputFilename{
"o",
llvm::cl::desc("Output filename, or directory for split output"),
llvm::cl::value_desc("filename"),
llvm::cl::init("-"),
};
llvm::cl::opt<bool> disableAnnotationsUnknown{
"disable-annotation-unknown",
llvm::cl::desc("Ignore unknown annotations when parsing"),
llvm::cl::init(false)};
llvm::cl::opt<bool> disableAnnotationsClassless{
"disable-annotation-classless",
llvm::cl::desc("Ignore annotations without a class when parsing"),
llvm::cl::init(false)};
llvm::cl::opt<bool> lowerAnnotationsNoRefTypePorts{
"lower-annotations-no-ref-type-ports",
llvm::cl::desc(
"Create real ports instead of ref type ports when resolving "
"wiring problems inside the LowerAnnotations pass"),
llvm::cl::init(false), llvm::cl::Hidden};
llvm::cl::opt<bool> probesToSignals{
"probes-to-signals",
llvm::cl::desc("Convert probes to non-probe signals"),
llvm::cl::init(false), llvm::cl::Hidden};
llvm::cl::opt<circt::firrtl::PreserveAggregate::PreserveMode>
preserveAggregate{
"preserve-aggregate",
llvm::cl::desc("Specify input file format:"),
llvm::cl::values(
clEnumValN(circt::firrtl::PreserveAggregate::None, "none",
"Preserve no aggregate"),
clEnumValN(circt::firrtl::PreserveAggregate::OneDimVec, "1d-vec",
"Preserve only 1d vectors of ground type"),
clEnumValN(circt::firrtl::PreserveAggregate::Vec, "vec",
"Preserve only vectors"),
clEnumValN(circt::firrtl::PreserveAggregate::All, "all",
"Preserve vectors and bundles")),
llvm::cl::init(circt::firrtl::PreserveAggregate::None),
};
llvm::cl::opt<firrtl::PreserveValues::PreserveMode> preserveMode{
"preserve-values",
llvm::cl::desc("Specify the values which can be optimized away"),
llvm::cl::values(
clEnumValN(firrtl::PreserveValues::Strip, "strip",
"Strip all names. No name is preserved"),
clEnumValN(firrtl::PreserveValues::None, "none",
"Names could be preserved by best-effort unlike `strip`"),
clEnumValN(firrtl::PreserveValues::Named, "named",
"Preserve values with meaningful names"),
clEnumValN(firrtl::PreserveValues::All, "all",
"Preserve all values")),
llvm::cl::init(firrtl::PreserveValues::None)};
llvm::cl::opt<bool> enableDebugInfo{
"g", llvm::cl::desc("Enable the generation of debug information"),
llvm::cl::init(false)};
// Build mode options.
llvm::cl::opt<firtool::FirtoolOptions::BuildMode> buildMode{
"O", llvm::cl::desc("Controls how much optimization should be performed"),
llvm::cl::values(clEnumValN(firtool::FirtoolOptions::BuildModeDebug,
"debug",
"Compile with only necessary optimizations"),
clEnumValN(firtool::FirtoolOptions::BuildModeRelease,
"release", "Compile with optimizations")),
llvm::cl::init(firtool::FirtoolOptions::BuildModeDefault)};
llvm::cl::opt<bool> disableLayerSink{"disable-layer-sink",
llvm::cl::desc("Disable layer sink"),
cl::init(false)};
llvm::cl::opt<bool> disableOptimization{
"disable-opt",
llvm::cl::desc("Disable optimizations"),
};
llvm::cl::opt<bool> vbToBV{
"vb-to-bv",
llvm::cl::desc("Transform vectors of bundles to bundles of vectors"),
llvm::cl::init(false)};
llvm::cl::opt<bool> noDedup{
"no-dedup",
llvm::cl::desc("Disable deduplication of structurally identical modules"),
llvm::cl::init(false)};
llvm::cl::opt<bool> dedupClasses{
"dedup-classes",
llvm::cl::desc(
"Deduplicate FIRRTL classes, violating their nominal typing"),
llvm::cl::init(true)};
llvm::cl::opt<firrtl::CompanionMode> companionMode{
"grand-central-companion-mode",
llvm::cl::desc("Specifies the handling of Grand Central companions"),
::llvm::cl::values(
clEnumValN(firrtl::CompanionMode::Bind, "bind",
"Lower companion instances to SystemVerilog binds"),
clEnumValN(firrtl::CompanionMode::Instantiate, "instantiate",
"Instantiate companions in the design"),
clEnumValN(firrtl::CompanionMode::Drop, "drop",
"Remove companions from the design")),
llvm::cl::init(firrtl::CompanionMode::Bind),
llvm::cl::Hidden,
};
llvm::cl::opt<bool> noViews{
"no-views",
llvm::cl::desc(
"Disable lowering of FIRRTL view intrinsics (delete them instead)"),
llvm::cl::init(false),
};
llvm::cl::opt<bool> disableAggressiveMergeConnections{
"disable-aggressive-merge-connections",
llvm::cl::desc(
"Disable aggressive merge connections (i.e. merge all field-level "
"connections into bulk connections)"),
llvm::cl::init(false)};
llvm::cl::opt<bool> lowerMemories{
"lower-memories",
llvm::cl::desc("Lower memories to have memories with masks as an "
"array with one memory per ground type"),
llvm::cl::init(false)};
llvm::cl::opt<std::string> blackBoxRootPath{
"blackbox-path",
llvm::cl::desc(
"Optional path to use as the root of black box annotations"),
llvm::cl::value_desc("path"),
llvm::cl::init(""),
};
llvm::cl::opt<bool> replSeqMem{
"repl-seq-mem",
llvm::cl::desc("Replace the seq mem for macro replacement and emit "
"relevant metadata"),
llvm::cl::init(false)};
llvm::cl::opt<std::string> replSeqMemFile{
"repl-seq-mem-file", llvm::cl::desc("File name for seq mem metadata"),
llvm::cl::init("")};
llvm::cl::opt<bool> ignoreReadEnableMem{
"ignore-read-enable-mem",
llvm::cl::desc("Ignore the read enable signal, instead of "
"assigning X on read disable"),
llvm::cl::init(false)};
llvm::cl::opt<firtool::FirtoolOptions::RandomKind> disableRandom{
llvm::cl::desc(
"Disable random initialization code (may break semantics!)"),
llvm::cl::values(
clEnumValN(firtool::FirtoolOptions::RandomKind::Mem,
"disable-mem-randomization",
"Disable emission of memory randomization code"),
clEnumValN(firtool::FirtoolOptions::RandomKind::Reg,
"disable-reg-randomization",
"Disable emission of register randomization code"),
clEnumValN(firtool::FirtoolOptions::RandomKind::All,
"disable-all-randomization",
"Disable emission of all randomization code")),
llvm::cl::init(firtool::FirtoolOptions::RandomKind::None)};
llvm::cl::opt<std::string> outputAnnotationFilename{
"output-annotation-file",
llvm::cl::desc("Optional output annotation file"),
llvm::cl::CommaSeparated, llvm::cl::value_desc("filename")};
llvm::cl::opt<bool> enableAnnotationWarning{
"warn-on-unprocessed-annotations",
llvm::cl::desc(
"Warn about annotations that were not removed by lower-to-hw"),
llvm::cl::init(false)};
llvm::cl::opt<bool> addMuxPragmas{
"add-mux-pragmas",
llvm::cl::desc("Annotate mux pragmas for memory array access"),
llvm::cl::init(false)};
llvm::cl::opt<firrtl::VerificationFlavor> verificationFlavor{
"verification-flavor",
llvm::cl::desc("Specify a verification flavor used in LowerFIRRTLToHW"),
llvm::cl::values(
clEnumValN(firrtl::VerificationFlavor::None, "none",
"Use the flavor specified by the op"),
clEnumValN(firrtl::VerificationFlavor::IfElseFatal, "if-else-fatal",
"Use Use `if(cond) else $fatal(..)` format"),
clEnumValN(firrtl::VerificationFlavor::Immediate, "immediate",
"Use immediate verif statements"),
clEnumValN(firrtl::VerificationFlavor::SVA, "sva", "Use SVA")),
llvm::cl::init(firrtl::VerificationFlavor::None)};
llvm::cl::opt<bool> emitSeparateAlwaysBlocks{
"emit-separate-always-blocks",
llvm::cl::desc(
"Prevent always blocks from being merged and emit constructs into "
"separate always blocks whenever possible"),
llvm::cl::init(false)};
llvm::cl::opt<bool> addVivadoRAMAddressConflictSynthesisBugWorkaround{
"add-vivado-ram-address-conflict-synthesis-bug-workaround",
llvm::cl::desc(
"Add a vivado specific SV attribute (* ram_style = "
"\"distributed\" *) to unpacked array registers as a workaronud "
"for a vivado synthesis bug that incorrectly modifies "
"address conflict behavivor of combinational memories"),
llvm::cl::init(false)};
//===----------------------------------------------------------------------===
// External Clock Gate Options
//===----------------------------------------------------------------------===
llvm::cl::opt<std::string> ckgModuleName{
"ckg-name", llvm::cl::desc("Clock gate module name"),
llvm::cl::init("EICG_wrapper")};
llvm::cl::opt<std::string> ckgInputName{
"ckg-input", llvm::cl::desc("Clock gate input port name"),
llvm::cl::init("in")};
llvm::cl::opt<std::string> ckgOutputName{
"ckg-output", llvm::cl::desc("Clock gate output port name"),
llvm::cl::init("out")};
llvm::cl::opt<std::string> ckgEnableName{
"ckg-enable", llvm::cl::desc("Clock gate enable port name"),
llvm::cl::init("en")};
llvm::cl::opt<std::string> ckgTestEnableName{
"ckg-test-enable",
llvm::cl::desc("Clock gate test enable port name (optional)"),
llvm::cl::init("test_en")};
llvm::cl::opt<bool> exportModuleHierarchy{
"export-module-hierarchy",
llvm::cl::desc("Export module and instance hierarchy as JSON"),
llvm::cl::init(false)};
llvm::cl::opt<bool> stripFirDebugInfo{
"strip-fir-debug-info",
llvm::cl::desc(
"Disable source fir locator information in output Verilog"),
llvm::cl::init(true)};
llvm::cl::opt<bool> stripDebugInfo{
"strip-debug-info",
llvm::cl::desc("Disable source locator information in output Verilog"),
llvm::cl::init(false)};
llvm::cl::opt<bool> fixupEICGWrapper{
"fixup-eicg-wrapper",
llvm::cl::desc("Lower `EICG_wrapper` modules into clock gate intrinsics"),
llvm::cl::init(false)};
llvm::cl::opt<bool> selectDefaultInstanceChoice{
"select-default-for-unspecified-instance-choice",
llvm::cl::desc(
"Specialize instance choice to default, if no option selected"),
llvm::cl::init(false)};
llvm::cl::opt<verif::SymbolicValueLowering> symbolicValueLowering{
"symbolic-values",
llvm::cl::desc("Control how symbolic values are lowered"),
llvm::cl::init(verif::SymbolicValueLowering::ExtModule),
verif::symbolicValueLoweringCLValues()};
llvm::cl::opt<bool> disableWireElimination{
"disable-wire-elimination", llvm::cl::desc("Disable wire elimination"),
llvm::cl::init(false)};
llvm::cl::opt<bool> emitAllBindFiles{
"emit-all-bind-files",
llvm::cl::desc("Emit bindfiles for private modules"),
llvm::cl::init(false)};
llvm::cl::opt<bool> inlineInputOnlyModules{
"inline-input-only-modules", llvm::cl::desc("Inline input-only modules"),
llvm::cl::init(false)};
llvm::cl::opt<firtool::FirtoolOptions::DomainMode> domainMode{
"domain-mode", llvm::cl::desc("Enable domain inference and checking"),
llvm::cl::init(firtool::FirtoolOptions::DomainMode::Strip),
llvm::cl::values(
clEnumValN(firtool::FirtoolOptions::DomainMode::Check, "check",
"Check domains without inference"),
clEnumValN(firtool::FirtoolOptions::DomainMode::Disable, "disable",
"Disable domain checking"),
clEnumValN(firtool::FirtoolOptions::DomainMode::Infer, "infer",
"Check domains with inference for private modules"),
clEnumValN(firtool::FirtoolOptions::DomainMode::InferAll, "infer-all",
"Check domains with inference for both public and private "
"modules"),
clEnumValN(firtool::FirtoolOptions::DomainMode::Strip, "strip",
"Erase all domain information"))};
//===----------------------------------------------------------------------===
// Lint options
//===----------------------------------------------------------------------===
llvm::cl::opt<bool> lintStaticAsserts{
"lint-static-asserts", llvm::cl::desc("Lint static assertions"),
llvm::cl::init(true)};
// TODO: Change this default to 'true' once this has been better tested and
// `-sv-extract-test-code` has been removed.
llvm::cl::opt<bool> lintXmrsInDesign{
"lint-xmrs-in-design", llvm::cl::desc("Lint XMRs in the design"),
llvm::cl::init(false)};
};
} // namespace
static llvm::ManagedStatic<FirtoolCmdOptions> clOptions;
/// Register a set of useful command-line options that can be used to configure
/// various flags within the MLIRContext. These flags are used when constructing
/// an MLIR context for initialization.
void circt::firtool::registerFirtoolCLOptions() {
// Make sure that the options struct has been initialized.
*clOptions;
}
// Initialize the firtool options with defaults supplied by the cl::opts above.
circt::firtool::FirtoolOptions::FirtoolOptions()
: outputFilename("-"), disableAnnotationsUnknown(false),
disableAnnotationsClassless(false), lowerAnnotationsNoRefTypePorts(false),
probesToSignals(false),
preserveAggregate(firrtl::PreserveAggregate::None),
preserveMode(firrtl::PreserveValues::None), enableDebugInfo(false),
buildMode(BuildModeRelease), disableLayerSink(false),
disableOptimization(false), vbToBV(false), noDedup(false),
dedupClasses(true), companionMode(firrtl::CompanionMode::Bind),
noViews(false), disableAggressiveMergeConnections(false),
lowerMemories(false), blackBoxRootPath(""), replSeqMem(false),
replSeqMemFile(""), ignoreReadEnableMem(false),
disableRandom(RandomKind::None), outputAnnotationFilename(""),
enableAnnotationWarning(false), addMuxPragmas(false),
verificationFlavor(firrtl::VerificationFlavor::None),
emitSeparateAlwaysBlocks(false),
addVivadoRAMAddressConflictSynthesisBugWorkaround(false),
ckgModuleName("EICG_wrapper"), ckgInputName("in"), ckgOutputName("out"),
ckgEnableName("en"), ckgTestEnableName("test_en"), ckgInstName("ckg"),
exportModuleHierarchy(false), stripFirDebugInfo(true),
stripDebugInfo(false), fixupEICGWrapper(false),
disableCSEinClasses(false), selectDefaultInstanceChoice(false),
symbolicValueLowering(verif::SymbolicValueLowering::ExtModule),
disableWireElimination(false), lintStaticAsserts(true),
lintXmrsInDesign(true), emitAllBindFiles(false),
inlineInputOnlyModules(false), domainMode(DomainMode::Disable) {
if (!clOptions.isConstructed())
return;
outputFilename = clOptions->outputFilename;
disableAnnotationsUnknown = clOptions->disableAnnotationsUnknown;
disableAnnotationsClassless = clOptions->disableAnnotationsClassless;
lowerAnnotationsNoRefTypePorts = clOptions->lowerAnnotationsNoRefTypePorts;
probesToSignals = clOptions->probesToSignals;
preserveAggregate = clOptions->preserveAggregate;
preserveMode = clOptions->preserveMode;
enableDebugInfo = clOptions->enableDebugInfo;
buildMode = clOptions->buildMode;
disableLayerSink = clOptions->disableLayerSink;
disableOptimization = clOptions->disableOptimization;
vbToBV = clOptions->vbToBV;
noDedup = clOptions->noDedup;
dedupClasses = clOptions->dedupClasses;
companionMode = clOptions->companionMode;
noViews = clOptions->noViews;
disableAggressiveMergeConnections =
clOptions->disableAggressiveMergeConnections;
lowerMemories = clOptions->lowerMemories;
blackBoxRootPath = clOptions->blackBoxRootPath;
replSeqMem = clOptions->replSeqMem;
replSeqMemFile = clOptions->replSeqMemFile;
ignoreReadEnableMem = clOptions->ignoreReadEnableMem;
disableRandom = clOptions->disableRandom;
outputAnnotationFilename = clOptions->outputAnnotationFilename;
enableAnnotationWarning = clOptions->enableAnnotationWarning;
addMuxPragmas = clOptions->addMuxPragmas;
verificationFlavor = clOptions->verificationFlavor;
emitSeparateAlwaysBlocks = clOptions->emitSeparateAlwaysBlocks;
addVivadoRAMAddressConflictSynthesisBugWorkaround =
clOptions->addVivadoRAMAddressConflictSynthesisBugWorkaround;
ckgModuleName = clOptions->ckgModuleName;
ckgInputName = clOptions->ckgInputName;
ckgOutputName = clOptions->ckgOutputName;
ckgEnableName = clOptions->ckgEnableName;
ckgTestEnableName = clOptions->ckgTestEnableName;
exportModuleHierarchy = clOptions->exportModuleHierarchy;
stripFirDebugInfo = clOptions->stripFirDebugInfo;
stripDebugInfo = clOptions->stripDebugInfo;
fixupEICGWrapper = clOptions->fixupEICGWrapper;
selectDefaultInstanceChoice = clOptions->selectDefaultInstanceChoice;
symbolicValueLowering = clOptions->symbolicValueLowering;
disableWireElimination = clOptions->disableWireElimination;
lintStaticAsserts = clOptions->lintStaticAsserts;
lintXmrsInDesign = clOptions->lintXmrsInDesign;
emitAllBindFiles = clOptions->emitAllBindFiles;
inlineInputOnlyModules = clOptions->inlineInputOnlyModules;
domainMode = clOptions->domainMode;
}