Skip to content

Commit 38fb743

Browse files
Merge pull request #805 from hs-apotell/cmp
Introducing uhdm-cmp tool to topographically compare two uhdm binaries
2 parents 30936ad + 90357c8 commit 38fb743

File tree

3 files changed

+123
-16
lines changed

3 files changed

+123
-16
lines changed

CMakeLists.txt

+5-1
Original file line numberDiff line numberDiff line change
@@ -243,8 +243,12 @@ if (UHDM_BUILD_TESTS)
243243
endif()
244244

245245
# Useful utilities
246+
add_executable(uhdm-cmp ${PROJECT_SOURCE_DIR}/util/uhdm-cmp.cpp)
247+
target_link_libraries(uhdm-cmp PRIVATE uhdm)
248+
246249
add_executable(uhdm-dump ${PROJECT_SOURCE_DIR}/util/uhdm-dump.cpp)
247250
target_link_libraries(uhdm-dump PRIVATE uhdm)
251+
248252
add_executable(uhdm-hier ${PROJECT_SOURCE_DIR}/util/uhdm-hier.cpp)
249253
target_link_libraries(uhdm-hier PRIVATE uhdm)
250254

@@ -270,7 +274,7 @@ target_link_libraries(test_inst PRIVATE
270274

271275
# Installation target
272276
install(
273-
TARGETS uhdm capnp kj uhdm-dump uhdm-hier
277+
TARGETS uhdm capnp kj uhdm-cmp uhdm-dump uhdm-hier
274278
ARCHIVE DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/uhdm
275279
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_PREFIX}/include/uhdm)
276280
install(DIRECTORY ${GENDIR}/uhdm/

scripts/classes.py

+13-15
Original file line numberDiff line numberDiff line change
@@ -526,16 +526,13 @@ def _get_GetVpiPropertyValue_implementation(model):
526526
def _get_Compare_implementation(model):
527527
vpi_blacklist = [
528528
'uhdmId',
529-
'uhdmParentType',
530529
'uhdmType',
531530
'vpiColumnNo',
532531
'vpiEndColumnNo',
533532
'vpiEndLineNo',
534533
'vpiFile',
535534
'vpiFullName',
536-
'vpiInstance',
537535
'vpiLineNo',
538-
'vpiParent',
539536
]
540537

541538
classname = model['name']
@@ -544,18 +541,21 @@ def _get_Compare_implementation(model):
544541
includes = set()
545542
content = [
546543
f'int {classname}::Compare(const BaseClass *const other, AnySet& visited) const {{',
547-
' int r = 0;',
548-
' if (!visited.insert(this).second) return r;',
549-
'',
550-
' AnySet local;',
551-
' if ((r = basetype_t::Compare(other, local)) != 0) return r;',
552-
' visited.merge(local);',
553-
''
544+
' int r = 0;'
554545
]
555546

547+
if not model['subclasses']:
548+
# Mark self visited (and check) only for the most derived sub-class
549+
content.append(' if (!visited.insert(this).second) return r;')
550+
551+
content.extend([
552+
' if ((r = basetype_t::Compare(other, visited)) != 0) return r;',
553+
''
554+
])
555+
556556
var_declared = False
557557
for key, value in model.allitems():
558-
if key not in ['property', 'obj_ref', 'class_ref']:
558+
if key not in ['property', 'obj_ref', 'class_ref', 'class']:
559559
continue
560560

561561
vpi = value.get('vpi')
@@ -591,8 +591,7 @@ def _get_Compare_implementation(model):
591591
f' auto lhs_{name} = lhs->{Name}();',
592592
f' auto rhs_{name} = rhs->{Name}();',
593593
f' if ((lhs_{name} != nullptr) && (rhs_{name} != nullptr)) {{',
594-
f' if ((r = lhs_{name}->Compare(rhs_{name}, local)) != 0) return r;',
595-
' visited.merge(local);',
594+
f' if ((r = lhs_{name}->Compare(rhs_{name}, visited)) != 0) return r;',
596595
f' }} else if ((lhs_{name} != nullptr) && (rhs_{name} == nullptr)) {{',
597596
' return 1;',
598597
f' }} else if ((lhs_{name} == nullptr) && (rhs_{name} != nullptr)) {{',
@@ -613,8 +612,7 @@ def _get_Compare_implementation(model):
613612
f' if ((r = static_cast<int>(lhs_{name}->size() - rhs_{name}->size())) != 0) return r;',
614613
'',
615614
f' for (size_t i = 0, n = lhs_{name}->size(); i < n; ++i) {{',
616-
f' if ((r = lhs_{name}->at(i)->Compare(rhs_{name}->at(i), local)) != 0) return r;',
617-
' visited.merge(local);',
615+
f' if ((r = lhs_{name}->at(i)->Compare(rhs_{name}->at(i), visited)) != 0) return r;',
618616
' }',
619617
f' }} else if ((lhs_{name} != nullptr) && (rhs_{name} == nullptr)) {{',
620618
' return 1;',

util/uhdm-cmp.cpp

+105
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
/*
2+
* Copyright 2019 Alain Dargelas
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#include <uhdm/uhdm.h>
18+
19+
#include <algorithm>
20+
#include <filesystem>
21+
#include <iostream>
22+
#include <memory>
23+
#include <string>
24+
25+
namespace fs = std::filesystem;
26+
27+
static int32_t usage(const char *progName) {
28+
std::cerr << "Usage:" << std::endl
29+
<< " " << progName << " <uhdm-file> <uhdm-file>" << std::endl
30+
<< std::endl
31+
<< "Reads input uhdm binary representations of two files and "
32+
"compares them topographically."
33+
<< std::endl
34+
<< std::endl
35+
<< "Exits with code" << std::endl
36+
<< " = 0, if input files are equal" << std::endl
37+
<< " < 0, if input files are not equal" << std::endl
38+
<< " > 0, for any failures" << std::endl;
39+
return 1;
40+
}
41+
42+
int32_t main(int32_t argc, char **argv) {
43+
if (argc != 3) {
44+
return usage(argv[0]);
45+
}
46+
47+
fs::path fileA = argv[1];
48+
fs::path fileB = argv[2];
49+
50+
std::error_code ec;
51+
if (!fs::is_regular_file(fileA, ec) || ec) {
52+
std::cerr << fileA << ": File does not exist!" << std::endl;
53+
return usage(argv[0]);
54+
}
55+
56+
if (!fs::is_regular_file(fileB, ec) || ec) {
57+
std::cerr << fileB << ": File does not exist!" << std::endl;
58+
return usage(argv[0]);
59+
}
60+
61+
std::unique_ptr<UHDM::Serializer> serializerA(new UHDM::Serializer);
62+
std::vector<vpiHandle> handlesA = serializerA->Restore(fileA);
63+
64+
std::unique_ptr<UHDM::Serializer> serializerB(new UHDM::Serializer);
65+
std::vector<vpiHandle> handlesB = serializerB->Restore(fileB);
66+
67+
if (handlesA.empty()) {
68+
std::cerr << fileA << ": Failed to load." << std::endl;
69+
return 1;
70+
}
71+
72+
if (handlesB.empty()) {
73+
std::cerr << fileB << ": Failed to load." << std::endl;
74+
return 1;
75+
}
76+
77+
if (handlesA.size() != handlesB.size()) {
78+
std::cerr << "Number of designs mismatch." << std::endl;
79+
return -1;
80+
}
81+
82+
std::function<const UHDM::design *(vpiHandle handle)> to_design =
83+
[](vpiHandle handle) {
84+
return (const UHDM::design *)((const uhdm_handle *)handle)->object;
85+
};
86+
87+
std::vector<const UHDM::design *> designsA;
88+
designsA.reserve(handlesA.size());
89+
std::transform(handlesA.begin(), handlesA.end(), std::back_inserter(designsA),
90+
to_design);
91+
92+
std::vector<const UHDM::design *> designsB;
93+
designsB.reserve(handlesB.size());
94+
std::transform(handlesB.begin(), handlesB.end(), std::back_inserter(designsB),
95+
to_design);
96+
97+
for (size_t i = 0, n = designsA.size(); i < n; ++i) {
98+
UHDM::AnySet visited;
99+
if (designsA[i]->Compare(designsB[i], visited) != 0) {
100+
return -1;
101+
}
102+
}
103+
104+
return 0;
105+
}

0 commit comments

Comments
 (0)