@@ -43,32 +43,26 @@ def run_tcl_template(ctx, template, substitutions, xilinx_env, input_files, outp
43
43
44
44
return [
45
45
DefaultInfo (files = depset (outputs )),
46
+ vivado_log ,
47
+ vivado_journal ,
46
48
]
47
49
48
- def create_and_synth (
49
- ctx ,
50
- with_synth ,
51
- synth_checkpoint = None ,
52
- timing_summary_report = None ,
53
- util_report = None ,
54
- synth_strategy = None ):
55
- """Create a project and optionally synthesize.
50
+ def generate_file_load_tcl (module ):
51
+ """Generate the strings needed for tcl.
56
52
57
- Due to IP issues, it makes sense to do synthesis in project mode.
58
- This function can also be used to generate a vivado project from the input sources .
53
+ Look at all the sources for a verilog module and make the needed commands
54
+ to get xilinx tools to load all the files needed .
59
55
60
56
Args:
61
- ctx: Context from a rule
62
- with_synth: A flag indicating if synthesis should be run too.
63
- synth_checkpoint: Optionally define the output synthesis checkpoint. Not used when creating a project only.
64
- timing_summary_report: Optionally define the timing summary report output. Not used when creating a project only.
65
- util_report: Optionally define the utilization report output. Not used when creating a project only.
66
- synth_strategy: Optionally define the synthesis strategy to use. Not used when creating a project only.
57
+ module: The top level verilog module
67
58
68
59
Returns:
69
- DefaultInfo - Files generated by the project.
60
+ all_files: All file objects that the module depends on.
61
+ hdl_source_content: A string to load any hdl files in xilinx tools.
62
+ constraints_content: A string to load any constraints in xilinx tools.
63
+ tcl_content: A string to load any other tcl in xilinx tools.
70
64
"""
71
- transitive_srcs = depset ([], transitive = [ctx . attr . module [VerilogInfo ].dag ])
65
+ transitive_srcs = depset ([], transitive = [module [VerilogInfo ].dag ])
72
66
all_srcs = [verilog_info_struct .srcs for verilog_info_struct in transitive_srcs .to_list ()]
73
67
all_files = [src for sub_tuple in all_srcs for src in sub_tuple ]
74
68
@@ -92,6 +86,38 @@ def create_and_synth(
92
86
else :
93
87
fail ("Unknown file type: " + file .path )
94
88
89
+ return [
90
+ all_files ,
91
+ hdl_source_content ,
92
+ constraints_content ,
93
+ tcl_content ,
94
+ ]
95
+
96
+ def create_and_synth (
97
+ ctx ,
98
+ with_synth ,
99
+ synth_checkpoint = None ,
100
+ timing_summary_report = None ,
101
+ util_report = None ,
102
+ synth_strategy = None ):
103
+ """Create a project and optionally synthesize.
104
+
105
+ Due to IP issues, it makes sense to do synthesis in project mode.
106
+ This function can also be used to generate a vivado project from the input sources.
107
+
108
+ Args:
109
+ ctx: Context from a rule
110
+ with_synth: A flag indicating if synthesis should be run too.
111
+ synth_checkpoint: Optionally define the output synthesis checkpoint. Not used when creating a project only.
112
+ timing_summary_report: Optionally define the timing summary report output. Not used when creating a project only.
113
+ util_report: Optionally define the utilization report output. Not used when creating a project only.
114
+ synth_strategy: Optionally define the synthesis strategy to use. Not used when creating a project only.
115
+
116
+ Returns:
117
+ DefaultInfo - Files generated by the project.
118
+ """
119
+ all_files , hdl_source_content , constraints_content , tcl_content = generate_file_load_tcl (ctx .attr .module )
120
+
95
121
project_dir = ctx .actions .declare_directory (ctx .label .name )
96
122
97
123
if with_synth :
@@ -134,7 +160,8 @@ def create_and_synth(
134
160
)
135
161
136
162
def _vivado_create_project_impl (ctx ):
137
- return create_and_synth (ctx , 0 )
163
+ default_info = create_and_synth (ctx , 0 )
164
+ return [default_info [0 ]]
138
165
139
166
vivado_create_project = rule (
140
167
implementation = _vivado_create_project_impl ,
@@ -145,7 +172,7 @@ vivado_create_project = rule(
145
172
mandatory = True ,
146
173
),
147
174
"module_top" : attr .string (
148
- doc = "The name of the verilog module to verilate ." ,
175
+ doc = "The name of the top level verilog module ." ,
149
176
mandatory = True ,
150
177
),
151
178
"part_number" : attr .string (
@@ -160,7 +187,7 @@ vivado_create_project = rule(
160
187
),
161
188
"jobs" : attr .int (
162
189
doc = "Jobs to pass to vivado which defines the amount of parallelism." ,
163
- default = 4
190
+ default = 4 ,
164
191
),
165
192
"_create_project_tcl_template" : attr .label (
166
193
doc = "The create project tcl template" ,
@@ -198,7 +225,7 @@ vivado_synthesize = rule(
198
225
mandatory = True ,
199
226
),
200
227
"module_top" : attr .string (
201
- doc = "The name of the verilog module to verilate ." ,
228
+ doc = "The name of the top level verilog module ." ,
202
229
mandatory = True ,
203
230
),
204
231
"part_number" : attr .string (
@@ -217,7 +244,7 @@ vivado_synthesize = rule(
217
244
),
218
245
"jobs" : attr .int (
219
246
doc = "Jobs to pass to vivado which defines the amount of parallelism." ,
220
- default = 4
247
+ default = 4 ,
221
248
),
222
249
"_create_project_tcl_template" : attr .label (
223
250
doc = "The create project tcl template" ,
@@ -285,7 +312,7 @@ vivado_synthesis_optimize = rule(
285
312
),
286
313
"threads" : attr .int (
287
314
doc = "Threads to pass to vivado which defines the amount of parallelism." ,
288
- default = 8
315
+ default = 8 ,
289
316
),
290
317
"_synthesis_optimize_template" : attr .label (
291
318
doc = "The synthesis optimzation tcl template" ,
@@ -351,7 +378,7 @@ vivado_placement = rule(
351
378
),
352
379
"threads" : attr .int (
353
380
doc = "Threads to pass to vivado which defines the amount of parallelism." ,
354
- default = 8
381
+ default = 8 ,
355
382
),
356
383
"_placement_template" : attr .label (
357
384
doc = "The placement tcl template" ,
@@ -417,7 +444,7 @@ vivado_place_optimize = rule(
417
444
),
418
445
"threads" : attr .int (
419
446
doc = "Threads to pass to vivado which defines the amount of parallelism." ,
420
- default = 8
447
+ default = 8 ,
421
448
),
422
449
"_place_optimize_template" : attr .label (
423
450
doc = "The placement tcl template" ,
@@ -499,7 +526,7 @@ vivado_routing = rule(
499
526
),
500
527
"threads" : attr .int (
501
528
doc = "Threads to pass to vivado which defines the amount of parallelism." ,
502
- default = 8
529
+ default = 8 ,
503
530
),
504
531
"_route_template" : attr .label (
505
532
doc = "The placement tcl template" ,
@@ -526,14 +553,15 @@ def _vivado_write_bitstream_impl(ctx):
526
553
527
554
outputs = [bitstream ]
528
555
529
- return run_tcl_template (
556
+ default_info = run_tcl_template (
530
557
ctx ,
531
558
ctx .file ._write_bitstream_template ,
532
559
substitutions ,
533
560
ctx .file .xilinx_env ,
534
561
[checkpoint_in ],
535
562
outputs ,
536
563
)
564
+ return [default_info [0 ]]
537
565
538
566
vivado_write_bitstream = rule (
539
567
implementation = _vivado_write_bitstream_impl ,
@@ -618,3 +646,97 @@ def vivado_flow(name, module, module_top, part_number, xilinx_env, tags = []):
618
646
xilinx_env = xilinx_env ,
619
647
tags = tags ,
620
648
)
649
+
650
+ def _xsim_test_impl (ctx ):
651
+ all_files , hdl_source_content , constraints_content , tcl_content = generate_file_load_tcl (ctx .attr .module )
652
+
653
+ project_dir = ctx .actions .declare_directory ("{}_prj" .format (ctx .label .name ))
654
+ if (ctx .attr .with_waveform ):
655
+ with_waveform_str = "1"
656
+ wave_db = ctx .actions .declare_file ("{}.wdb" .format (ctx .label .name ))
657
+ wave_db_path = wave_db .path
658
+ outputs = [project_dir , wave_db ]
659
+ else :
660
+ with_waveform_str = "0"
661
+ wave_db_path = ""
662
+ outputs = [project_dir ]
663
+
664
+ substitutions = {
665
+ "{{PART_NUMBER}}" : ctx .attr .part_number ,
666
+ "{{HDL_SOURCE_CONTENT}}" : hdl_source_content ,
667
+ "{{TCL_CONTENT}}" : tcl_content ,
668
+ "{{CONSTRAINTS_CONTENT}}" : constraints_content ,
669
+ "{{MODULE_TOP}}" : ctx .attr .module_top ,
670
+ "{{PROJECT_DIR}}" : project_dir .path ,
671
+ "{{WITH_WAVEFORM}}" : with_waveform_str ,
672
+ "{{WAVE_DB}}" : wave_db_path ,
673
+ }
674
+
675
+ _ , vivado_log , vivado_journal = run_tcl_template (
676
+ ctx ,
677
+ ctx .file ._xsim_test_template ,
678
+ substitutions ,
679
+ ctx .file .xilinx_env ,
680
+ all_files ,
681
+ outputs ,
682
+ )
683
+
684
+ outputs .append (vivado_log )
685
+ outputs .append (vivado_journal )
686
+
687
+ log_runfiles = ctx .runfiles (files = [vivado_log ])
688
+
689
+ error_parser = "if grep -q Error {}; then\n " .format (vivado_log .short_path )
690
+ error_parser += "cat {}\n " .format (vivado_log .short_path )
691
+ error_parser += "exit 64\n "
692
+ error_parser += "fi"
693
+
694
+ ctx .actions .write (
695
+ output = ctx .outputs .executable ,
696
+ content = error_parser ,
697
+ is_executable = True ,
698
+ )
699
+
700
+ return [
701
+ DefaultInfo (
702
+ files = depset (outputs ),
703
+ runfiles = log_runfiles ,
704
+ executable = ctx .outputs .executable ,
705
+ ),
706
+ ]
707
+
708
+ xsim_test = rule (
709
+ implementation = _xsim_test_impl ,
710
+ doc = "Use the vivado tool xsim to test." ,
711
+ test = True ,
712
+ attrs = {
713
+ "module" : attr .label (
714
+ doc = "The top level build." ,
715
+ providers = [VerilogInfo ],
716
+ mandatory = True ,
717
+ ),
718
+ "module_top" : attr .string (
719
+ doc = "The name of the top level verilog module." ,
720
+ mandatory = True ,
721
+ ),
722
+ "part_number" : attr .string (
723
+ doc = "The targeted xilinx part." ,
724
+ mandatory = True ,
725
+ ),
726
+ "with_waveform" : attr .bool (
727
+ doc = "Generate with a waveform" ,
728
+ default = False ,
729
+ ),
730
+ "xilinx_env" : attr .label (
731
+ doc = "A shell script to source the vivado environment and " +
732
+ "point to license server" ,
733
+ mandatory = True ,
734
+ allow_single_file = [".sh" ],
735
+ ),
736
+ "_xsim_test_template" : attr .label (
737
+ doc = "The tcl template to run on vivado." ,
738
+ default = "@rules_hdl//vivado:xsim_test.tcl.template" ,
739
+ allow_single_file = [".template" ],
740
+ ),
741
+ },
742
+ )
0 commit comments