• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Nic30 / hwtBuildsystem / cc0b2e8e-a681-493b-a982-c825a54bf943

05 May 2026 12:42PM UTC coverage: 55.065% (-0.5%) from 55.574%
cc0b2e8e-a681-493b-a982-c825a54bf943

push

circleci

Nic30
style(tests): assertEqual->assertMultiLineEqual

207 of 562 branches covered (36.83%)

Branch coverage included in aggregate %.

1500 of 2538 relevant lines covered (59.1%)

0.59 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

48.51
/hwtBuildsystem/examples/synthetizeHwModule.py
1
#!/usr/bin/env python3
2
# -*- coding: utf-8 -*-
3

4
import datetime
1✔
5
import hashlib
1✔
6
import json
1✔
7
import os
1✔
8
from pathlib import Path
1✔
9
import socket
1✔
10
import sqlite3
1✔
11
import subprocess
1✔
12
from typing import Tuple
1✔
13

14
from hwt.hwModule import HwModule
1✔
15
from hwt.serializer.store_manager import SaveToFilesFlat
1✔
16
from hwt.serializer.verilog import VerilogSerializer
1✔
17
from hwt.serializer.vhdl import Vhdl2008Serializer
1✔
18
from hwt.synth import to_rtl
1✔
19
from hwt.synthesizer.dummyPlatform import DummyPlatform
1✔
20
from hwtBuildsystem.common.executor import ToolExecutor
1✔
21
from hwtBuildsystem.common.project import SynthesisToolProject
1✔
22
from hwtBuildsystem.examples.example_HwModule import ExampleTop0
1✔
23
from hwtBuildsystem.fakeTool.recordingExecutor import RecordingExecutor
1✔
24
from hwtBuildsystem.quartus.api.project import QuartusProject
1✔
25
from hwtBuildsystem.quartus.executor import QuartusExecutor
1✔
26
from hwtBuildsystem.quartus.part import IntelPart
1✔
27
from hwtBuildsystem.vivado.api.project import VivadoProject
1✔
28
from hwtBuildsystem.vivado.executor import VivadoExecutor
1✔
29
from hwtBuildsystem.vivado.part import XilinxPart
1✔
30
from hwtBuildsystem.yosys.executor import YosysExecutor
1✔
31
from hwtBuildsystem.yosys.part import LatticePart
1✔
32

33

34
def buildHwModule(exe: ToolExecutor, module: HwModule, root:str, part:tuple,
1✔
35
              targetPlatform=DummyPlatform(),
36
              synthesize:bool=True, implement:bool=True, writeBitstream:bool=True,
37
              openGui:bool=False) -> Tuple[SynthesisToolProject, datetime.datetime, datetime.datetime]:
38
    """
39
    Synthetize unit using bitstream synthesis tool like Xilinx Vivado or Intel Quartus
40

41
    :param synthesize: if True the synthtesis/mapping compilation stage will be performed
42
    :param implement: if True the implementation stage of compilation will be performed
43
    :param writeBitstream: if True the final bitstream will be generated
44
    :param openGui: if True the GUI of the tool will be opened on task end
45
    """
46
    uName = module._getDefaultName()
1✔
47
    p = exe.project(root, uName)
1✔
48
    # generate project
49
    if p._exists():
1!
50
        p._remove()
×
51

52
    p.create()
1✔
53
    p.setPart(part)
1✔
54

55
    # generate files
56
    if isinstance(exe, (QuartusExecutor, YosysExecutor)) or (isinstance(exe, RecordingExecutor) and
1!
57
                                                             isinstance(exe.executor, (QuartusExecutor, YosysExecutor))):
58
        serializer = VerilogSerializer
×
59
    else:
60
        serializer = Vhdl2008Serializer
1✔
61
    hwt_build_start = datetime.datetime.now()
1✔
62
    store_manager = SaveToFilesFlat(serializer, root=os.path.join(p.path, 'src'))
1✔
63
    to_rtl(module, store_manager=store_manager, target_platform=targetPlatform)
1✔
64
    hwt_build_end = datetime.datetime.now()
1✔
65
    p.addFiles(store_manager.files)
1✔
66
    p.setTop(module._name)
1✔
67

68
    if synthesize:
1!
69
        p.synthAll()
1✔
70

71
    if implement:
1!
72
        p.implemAll()
×
73

74
    if writeBitstream:
1!
75
        p.writeBitstream()
×
76

77
    if openGui:
1!
78
        exe.openGui()
×
79

80
    return p, hwt_build_start, hwt_build_end
1✔
81

82

83
SQL_COMMON_BUILD_REPORT_COLUMNS = """
1✔
84
    component_name TEXT NOT NULL,
85
    component_configuration TEXT NOT NULL,
86
    revision TEXT NOT NULL,
87
    build_start timestamp,
88
    build_srcgen_start timestamp,
89
    build_srcgen_end timestamp,
90
    build_end timestamp,
91
    tool_version TEXT NOT NULL,
92
    machine_name TEXT NOT NULL,
93
    part TEXT NOT NULL,
94
    md5_of_inputs TEXT NOT NULL"""
95
SQL_COMMON_BUILD_REPORT_COLUMNS_QUESTIONMARKS = "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?"
1✔
96

97

98
def calculateSrcChecksum(project: SynthesisToolProject):
1✔
99
    """
100
    Calculate md5 checksum of all input source files
101
    """
102
    src_files = sorted((Path(project.path) / "src").rglob("*"))
×
103
    assert src_files
×
104
    h = hashlib.md5()
×
105
    for fn in src_files:
×
106
        h.update(open(fn, "rb").read())
×
107
    return h.hexdigest()
×
108

109

110
def collect_common_build_report_values(component_name: str,
1✔
111
                                       component_configuration: dict,
112
                                       build_start:datetime.datetime,
113
                                       build_srcgen_start:datetime.datetime,
114
                                       build_srcgen_end:datetime.datetime,
115
                                       project: SynthesisToolProject):
116
    """
117
    :return: tuple of table values as defined in :var:`SQL_COMMON_BUILD_REPORT_COLUMNS`
118
    """
119
    machine_name = socket.gethostname()
×
120
    tool_version = project.executor.getVersion()
×
121
    revision = subprocess.check_output(["git", "rev-parse", "HEAD"]).decode()
×
122
    now = datetime.datetime.now()
×
123
    conf = json.dumps(component_configuration)
×
124
    part = str(project.part)
×
125
    md5_of_inputs = calculateSrcChecksum(project)
×
126

127
    return (component_name, conf, revision, build_start, build_srcgen_start, build_srcgen_end,
×
128
            now, tool_version, machine_name, part, md5_of_inputs)
129

130

131
def parse_reports(project: SynthesisToolProject, printReports=False):
1✔
132
    report = project.report()
×
133
    synth_report = report.parseUtilizationSynth()
×
134
    resources = synth_report.getBasicResourceReport()
×
135
    if printReports:
×
136
        print(resources)
×
137
        print("Bitstream is in file %s" % (report.bitstreamFile))
×
138
    return resources
×
139

140

141
def is_report_build(db_cursor: sqlite3.Cursor, table_name:str, name: str):
1✔
142
    try:
×
143
        for (isBuild,) in db_cursor.execute(f'SELECT EXISTS(SELECT 1 FROM {table_name:s} WHERE component_name="{name:s}");'):
×
144
            if isBuild:
×
145
                return True
×
146
        return False
×
147
    except sqlite3.OperationalError as e:
×
148
        if "no such table" in e.args[0]:
×
149
            return False
×
150
        else:
151
            raise e
×
152

153

154
def store_yosys_report_in_db(db_cursor: sqlite3.Cursor, build_start:datetime.datetime,
1✔
155
                             build_srcgen_start:datetime.datetime,
156
                             build_srcgen_end:datetime.datetime,
157
                             project: VivadoProject, component_name: str):
158
    db_cursor.execute(f'''
×
159
    CREATE TABLE IF NOT EXISTS yosys_builds
160
        ({SQL_COMMON_BUILD_REPORT_COLUMNS:s},
161
         lut int, ff int, latch int, bram DECIMAL(10, 2), uram DECIMAL(10, 2), dsp int)''')
162

163
    r = parse_reports(project)
×
164
    common = collect_common_build_report_values(component_name, {}, build_start, build_srcgen_start, build_srcgen_end, project)
×
165
    db_cursor.execute(f'''
×
166
        INSERT INTO yosys_builds
167
            VALUES({SQL_COMMON_BUILD_REPORT_COLUMNS_QUESTIONMARKS:s}, ?, ?, ?, ?, ?, ?)''',
168
        (*common, r['lut'], r['ff'], r['latch'], r['bram'], r['uram'], r['dsp']),
169
    )
170
    return r
×
171

172

173
def is_yosys_report_build(db_cursor: sqlite3.Cursor, name: str):
1✔
174
    return is_report_build(db_cursor, "yosys_builds", name)
×
175

176

177
def store_vivado_report_in_db(db_cursor: sqlite3.Cursor, build_start:datetime.datetime,
1✔
178
                              build_srcgen_start:datetime.datetime,
179
                              build_srcgen_end:datetime.datetime,
180
                              project: VivadoProject, component_name: str):
181
    db_cursor.execute(f'''
×
182
    CREATE TABLE IF NOT EXISTS xilinx_vivado_builds
183
        ({SQL_COMMON_BUILD_REPORT_COLUMNS:s},
184
         lut int, ff int, latch int, bram DECIMAL(10, 2), uram DECIMAL(10, 2), dsp int)''')
185

186
    r = parse_reports(project)
×
187
    common = collect_common_build_report_values(component_name, {}, build_start, build_srcgen_start, build_srcgen_end, project)
×
188
    db_cursor.execute(f'''
×
189
        INSERT INTO xilinx_vivado_builds
190
            VALUES({SQL_COMMON_BUILD_REPORT_COLUMNS_QUESTIONMARKS:s}, ?, ?, ?, ?, ?, ?)''',
191
        (*common, r['lut'], r['ff'], r['latch'], r['bram'], r['uram'], r['dsp']),
192
    )
193
    return r
×
194

195

196
def is_vivado_report_build(db_cursor: sqlite3.Cursor, name: str):
1✔
197
    return is_report_build(db_cursor, "xilinx_vivado_builds", name)
×
198

199

200
def store_quartus_report_in_db(db_cursor: sqlite3.Cursor, build_start:datetime.datetime,
1✔
201
                               build_srcgen_start:datetime.datetime,
202
                               build_srcgen_end:datetime.datetime,
203
                               project: QuartusProject,
204
                               component_name: str):
205
    db_cursor.execute(f'''
×
206
    CREATE TABLE IF NOT EXISTS intel_quartus_builds
207
        ({SQL_COMMON_BUILD_REPORT_COLUMNS:s},
208
         alm int, lut int, ff int, latch int, bram_bits DECIMAL(10, 2), dsp int)''')
209
    common = collect_common_build_report_values(component_name, {}, build_start, build_srcgen_start, build_srcgen_end, project)
×
210
    r = parse_reports(project)
×
211
    db_cursor.execute(f'''
×
212
        INSERT INTO intel_quartus_builds
213
            VALUES({SQL_COMMON_BUILD_REPORT_COLUMNS_QUESTIONMARKS:s}, ?, ?, ?, ?, ?, ?)''',
214
        (*common, r['alm'], r['lut'], r['ff'], r['latch'], r['bram_bits'], r['dsp']),
215
    )
216
    return r
×
217

218

219
def is_quartus_report_build(db_cursor: sqlite3.Cursor, name: str):
1✔
220
    return is_report_build(db_cursor, "intel_quartus_builds", name)
×
221

222

223
if __name__ == "__main__":
224
    """
225
    :note: An example of usage
226
    """
227
    TEST_TRACES = os.path.join(os.path.dirname(__file__), '..', '..', 'tests')
228
    # from hwtBuildsystem.fakeTool.recordingExecutor import RecordingExecutor
229
    # from hwtBuildsystem.fakeTool.replayingExecutor import ReplayingExecutor
230

231
    def component_constructor():
232
        return ExampleTop0()
233

234
    conn = sqlite3.connect('build_report.db')
235
    try:
236
        c = conn.cursor()
237
        logComunication = True
238

239
        # start = datetime.datetime.now()
240
        # with RecordingExecutor(YosysExecutor(logComunication=logComunication),
241
        #                       [],
242
        #                       os.path.join(TEST_TRACES, "ExampleTop0_synth_trace.yosys_ice40.json")
243
        #                       ) as executor:
244
        # # with YosysExecutor(logComunication=logComunication) as executor:
245
        #    m = component_constructor()
246
        #    # part = IntelPart("Cyclone V", "5CGXFC7C7F23C8")
247
        #    # part = IntelPart("Arria 10", "10AX048H1F34E1HG")
248
        #    part = LatticePart('iCE40', 'up5k', 'sg48')
249
        #    project, build_srcgen_start, build_srcgen_end = buildHwModule(executor, m, "tmp/yosys", part,
250
        #                  synthesize=True,
251
        #                  implement=False,
252
        #                  writeBitstream=False,
253
        #                  # openGui=True,
254
        #                  )
255
        #    name = ".".join([m.__class__.__module__, m.__class__.__qualname__])
256
        #    store_yosys_report_in_db(c, start, build_srcgen_start, build_srcgen_end, project, name)
257
        #    conn.commit()
258

259
        start = datetime.datetime.now()
260
        with RecordingExecutor(
261
            VivadoExecutor(logComunication=logComunication),
262
            ['tmp/vivado/ExampleTop0/ExampleTop0.xpr',
263
             'tmp/vivado/ExampleTop0/ExampleTop0.runs/synth_1/ExampleTop0_utilization_synth.rpt'],
264
             os.path.join(TEST_TRACES, "ExampleTop0_synth_trace.vivado_kintex7.json"),
265
            removeAllTracedFilesFirst=True) as executor:
266
        # with ReplayingExecutor(os.path.join(os.path.dirname(__file__), "../../../tests/ExampleTop0_synth_trace.json")) as v:
267
        # with VivadoExecutor(logComunication=logComunication) as executor:
268
            m = component_constructor()
269
            __pb = XilinxPart
270
            part = XilinxPart(
271
                    __pb.Family.kintex7,
272
                    __pb.Size._160t,
273
                    __pb.Package.ffg676,
274
                    __pb.Speedgrade._2)
275
            project, build_srcgen_start, build_srcgen_end = buildHwModule(executor, m, "tmp/vivado", part,
276
                          synthesize=True,
277
                          implement=False,
278
                          writeBitstream=False,
279
                          # openGui=True,
280
                          )
281
            name = ".".join([m.__class__.__module__, m.__class__.__qualname__])
282
            store_vivado_report_in_db(c, start, build_srcgen_start, build_srcgen_end, project, name)
283
            conn.commit()
284

285
        # start = datetime.datetime.now()
286
        # with RecordingExecutor(QuartusExecutor(logComunication=logComunication),
287
        #                       ['tmp/quartus/ExampleTop0/ExampleTop0.map.rpt'],
288
        #                       os.path.join(TEST_TRACES, "ExampleTop0_synth_trace.quartus_arria10.json"),
289
        #                       removeAllTracedFilesFirst=True) as executor:
290
        # #with QuartusExecutor(logComunication=logComunication) as executor:
291
        #    m = component_constructor()
292
        #    # part = IntelPart("Cyclone V", "5CGXFC7C7F23C8")
293
        #    part = IntelPart("Arria 10", "10AX048H1F34E1HG")
294
        #    project, build_srcgen_start, build_srcgen_end = buildHwModule(executor, m, "tmp/quartus", part,
295
        #                  synthesize=True,
296
        #                  implement=False,
297
        #                  writeBitstream=False,
298
        #                  # openGui=True,
299
        #                  )
300
        #    name = ".".join([m.__class__.__module__, m.__class__.__qualname__])
301
        #    store_quartus_report_in_db(c, start, build_srcgen_start, build_srcgen_end, project, name)
302
        #    conn.commit()
303
        print("All done")
304
    finally:
305
        conn.close()
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc