Skip to content

Commit 37dfd5a

Browse files
Merge pull request #50 from alainmarcel/fix_tests
Fix tests - attributes
2 parents d5672a2 + 76d7bfa commit 37dfd5a

23 files changed

Lines changed: 1506 additions & 85 deletions

CLAUDE.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,13 @@ When working with UHDM objects, you need to know where to find type definitions:
125125
- Main include: `#include <uhdm/uhdm.h>`
126126
- This pulls in all necessary UHDM types and the visitor pattern
127127

128+
4. **Inspecting UHDM Content**:
129+
- **Important**: To inspect the actual UHDM content for a test, look at the `uhdm_path.log` file
130+
- This file contains the textual representation of the UHDM tree that shows all objects and their properties
131+
- Located at: `test/<test_name>/uhdm_path.log`
132+
- Alternatively, use: `uhdm-dump slpp_all/surelog.uhdm` to manually dump UHDM content
133+
- The uhdm-dump tool is at: `build/third_party/Surelog/third_party/UHDM/bin/uhdm-dump`
134+
128135
### Adding New Features
129136
1. Identify UHDM node type in the UHDM dump (use `-d uhdm` with Surelog)
130137
2. Find the VPI type constant in `vpi_user.h` and object class in `generated/uhdm/`

src/frontends/uhdm/module.cpp

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -388,19 +388,22 @@ void UhdmImporter::import_net(const net* uhdm_net, const UHDM::instance* inst) {
388388

389389
// Check if net is signed
390390
if (auto ref_typespec = uhdm_net->Typespec()) {
391+
log("UHDM: Checking signed attribute for net '%s'\n", netname.c_str());
391392
// Check if typespec indicates signed
392393
bool is_signed = false;
393394
const UHDM::typespec* actual_typespec = nullptr;
394395

395396
if (ref_typespec->Actual_typespec()) {
396397
actual_typespec = ref_typespec->Actual_typespec();
398+
log("UHDM: Found Actual_typespec, UhdmType=%d\n", actual_typespec->UhdmType());
397399
}
398400

399401
if (actual_typespec) {
400402
switch (actual_typespec->UhdmType()) {
401403
case uhdmlogic_typespec:
402404
if (auto logic_ts = dynamic_cast<const UHDM::logic_typespec*>(actual_typespec)) {
403405
is_signed = logic_ts->VpiSigned();
406+
log("UHDM: logic_typespec VpiSigned=%d\n", is_signed);
404407
}
405408
break;
406409
case uhdmint_typespec:
@@ -409,15 +412,38 @@ void UhdmImporter::import_net(const net* uhdm_net, const UHDM::instance* inst) {
409412
case uhdmshort_int_typespec:
410413
case uhdmlong_int_typespec:
411414
is_signed = true; // These are signed by default
415+
log("UHDM: Integer type, signed by default\n");
412416
break;
413417
default:
414418
// Other typespec types are not handled
419+
log("UHDM: Unknown typespec type %d\n", actual_typespec->UhdmType());
415420
break;
416421
}
417422

418423
if (is_signed) {
419-
log("UHDM: Net '%s' is signed\n", netname.c_str());
424+
log("UHDM: Net '%s' is signed, setting is_signed=true\n", netname.c_str());
420425
w->is_signed = true;
426+
} else {
427+
log("UHDM: Net '%s' is not signed\n", netname.c_str());
428+
}
429+
} else {
430+
log("UHDM: No actual typespec found for net '%s'\n", netname.c_str());
431+
}
432+
} else {
433+
log("UHDM: Net '%s' has no typespec\n", netname.c_str());
434+
}
435+
436+
// Import attributes (e.g., (* keep *))
437+
if (auto net = any_cast<const UHDM::net*>(uhdm_net)) {
438+
if (net->Attributes()) {
439+
for (auto attr : *net->Attributes()) {
440+
std::string attr_name = std::string(attr->VpiName());
441+
if (!attr_name.empty()) {
442+
// Set the attribute to 1 (standard practice for boolean attributes like keep)
443+
w->attributes[RTLIL::escape_id(attr_name)] = RTLIL::Const(1);
444+
if (mode_debug)
445+
log("UHDM: Added attribute '%s' to net '%s'\n", attr_name.c_str(), netname.c_str());
446+
}
421447
}
422448
}
423449
}

src/frontends/uhdm/uhdm2rtlil.cpp

Lines changed: 142 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1145,30 +1145,156 @@ void UhdmImporter::import_module(const module_inst* uhdm_module) {
11451145
name_map[var_name] = wire;
11461146
add_src_attribute(wire->attributes, var);
11471147

1148-
// Add wiretype attribute for struct types
1148+
// Import attributes (e.g., (* keep *))
1149+
if (auto variables = any_cast<const UHDM::variables*>(var)) {
1150+
if (variables->Attributes()) {
1151+
for (auto attr : *variables->Attributes()) {
1152+
std::string attr_name = std::string(attr->VpiName());
1153+
if (!attr_name.empty()) {
1154+
// Set the attribute to 1 (standard practice for boolean attributes like keep)
1155+
wire->attributes[RTLIL::escape_id(attr_name)] = RTLIL::Const(1);
1156+
if (mode_debug)
1157+
log("UHDM: Added attribute '%s' to variable '%s'\n", attr_name.c_str(), var_name.c_str());
1158+
}
1159+
}
1160+
}
1161+
}
1162+
1163+
// Add wiretype and signed attributes
11491164
if (auto logic_var = dynamic_cast<const UHDM::logic_var*>(var)) {
11501165
if (auto ref_typespec = logic_var->Typespec()) {
1166+
// First check if we have a typedef name to use as wiretype
1167+
std::string wiretype_name;
1168+
1169+
// Check if the actual_typespec has a name (typedef name)
11511170
if (auto actual_typespec = ref_typespec->Actual_typespec()) {
1152-
if (actual_typespec->UhdmType() == uhdmstruct_typespec) {
1153-
// Get the struct type name
1154-
std::string type_name;
1155-
if (!ref_typespec->VpiName().empty()) {
1156-
type_name = ref_typespec->VpiName();
1157-
} else if (!actual_typespec->VpiName().empty()) {
1158-
type_name = actual_typespec->VpiName();
1159-
}
1160-
1161-
if (!type_name.empty()) {
1162-
wire->attributes[RTLIL::escape_id("wiretype")] = RTLIL::escape_id(type_name);
1163-
log("UHDM: Added wiretype attribute '\\%s' to wire '%s'\n", type_name.c_str(), wire->name.c_str());
1171+
if (!actual_typespec->VpiName().empty()) {
1172+
wiretype_name = actual_typespec->VpiName();
1173+
} else if (!ref_typespec->VpiName().empty()) {
1174+
wiretype_name = ref_typespec->VpiName();
1175+
}
1176+
1177+
// Add wiretype attribute for any typedef'd type
1178+
if (!wiretype_name.empty()) {
1179+
wire->attributes[RTLIL::escape_id("wiretype")] = RTLIL::escape_id(wiretype_name);
1180+
log("UHDM: Added wiretype attribute '\\%s' to wire '%s'\n", wiretype_name.c_str(), wire->name.c_str());
1181+
}
1182+
1183+
// Check for signed attribute
1184+
bool is_signed = false;
1185+
switch (actual_typespec->UhdmType()) {
1186+
case uhdmlogic_typespec:
1187+
if (auto logic_ts = dynamic_cast<const UHDM::logic_typespec*>(actual_typespec)) {
1188+
is_signed = logic_ts->VpiSigned();
1189+
log("UHDM: Variable '%s' logic_typespec VpiSigned=%d\n", var_name.c_str(), is_signed);
1190+
}
1191+
break;
1192+
case uhdmint_typespec:
1193+
if (auto int_ts = dynamic_cast<const UHDM::int_typespec*>(actual_typespec)) {
1194+
is_signed = int_ts->VpiSigned();
1195+
log("UHDM: Variable '%s' int_typespec VpiSigned=%d\n", var_name.c_str(), is_signed);
1196+
}
1197+
break;
1198+
default:
1199+
break;
1200+
}
1201+
1202+
if (is_signed) {
1203+
wire->is_signed = true;
1204+
log("UHDM: Variable '%s' is signed, setting is_signed=true\n", var_name.c_str());
1205+
}
1206+
}
1207+
}
1208+
1209+
// Handle initial expression if present
1210+
if (logic_var->Expr()) {
1211+
log("UHDM: Variable '%s' has initial expression\n", var_name.c_str());
1212+
RTLIL::SigSpec init_value = import_expression(logic_var->Expr());
1213+
if (init_value.size() > 0) {
1214+
// Resize the init_value to match the wire width
1215+
RTLIL::SigSpec lhs(wire);
1216+
if (init_value.size() != lhs.size()) {
1217+
int orig_size = init_value.size();
1218+
// Need to resize - check if wire is signed for proper extension
1219+
if (wire->is_signed && init_value.size() < lhs.size()) {
1220+
// Sign extend
1221+
init_value.extend_u0(lhs.size(), true);
1222+
} else {
1223+
// Zero extend or truncate
1224+
init_value.extend_u0(lhs.size(), false);
11641225
}
1226+
log("UHDM: Resized initial value from %d bits to %d bits for variable '%s'\n",
1227+
orig_size, lhs.size(), var_name.c_str());
11651228
}
1229+
1230+
// Create an initial process to assign the value
1231+
RTLIL::Process* proc = module->addProcess(NEW_ID);
1232+
proc->root_case.actions.push_back(RTLIL::SigSig(lhs, init_value));
1233+
proc->root_case.compare.clear();
1234+
proc->root_case.switches.clear();
1235+
1236+
// Add sync rule for initial
1237+
RTLIL::SyncRule* sync = new RTLIL::SyncRule;
1238+
sync->type = RTLIL::STa; // Always
1239+
sync->signal = RTLIL::SigSpec();
1240+
sync->actions.push_back(RTLIL::SigSig(lhs, init_value));
1241+
proc->syncs.push_back(sync);
1242+
1243+
add_src_attribute(proc->attributes, var);
1244+
log("UHDM: Created initial assignment for variable '%s'\n", var_name.c_str());
11661245
}
11671246
}
11681247
}
11691248

11701249
log("UHDM: Created wire '%s' for variable\n", wire->name.c_str());
11711250
} else {
1251+
// Wire already exists, but check if we need to handle initial expression
1252+
RTLIL::Wire* existing_wire = module->wire(wire_id);
1253+
if (existing_wire) {
1254+
wire_map[var] = existing_wire;
1255+
name_map[var_name] = existing_wire;
1256+
1257+
// Handle initial expression for existing wire
1258+
if (auto logic_var = dynamic_cast<const UHDM::logic_var*>(var)) {
1259+
if (logic_var->Expr()) {
1260+
log("UHDM: Existing variable '%s' has initial expression\n", var_name.c_str());
1261+
RTLIL::SigSpec init_value = import_expression(logic_var->Expr());
1262+
if (init_value.size() > 0) {
1263+
// Resize the init_value to match the wire width
1264+
RTLIL::SigSpec lhs(existing_wire);
1265+
if (init_value.size() != lhs.size()) {
1266+
int orig_size = init_value.size();
1267+
// Need to resize - check if wire is signed for proper extension
1268+
if (existing_wire->is_signed && init_value.size() < lhs.size()) {
1269+
// Sign extend
1270+
init_value.extend_u0(lhs.size(), true);
1271+
} else {
1272+
// Zero extend or truncate
1273+
init_value.extend_u0(lhs.size(), false);
1274+
}
1275+
log("UHDM: Resized initial value from %d bits to %d bits for existing variable '%s'\n",
1276+
orig_size, lhs.size(), var_name.c_str());
1277+
}
1278+
1279+
// Create an initial process to assign the value
1280+
RTLIL::Process* proc = module->addProcess(NEW_ID);
1281+
proc->root_case.actions.push_back(RTLIL::SigSig(lhs, init_value));
1282+
proc->root_case.compare.clear();
1283+
proc->root_case.switches.clear();
1284+
1285+
// Add sync rule for initial
1286+
RTLIL::SyncRule* sync = new RTLIL::SyncRule;
1287+
sync->type = RTLIL::STa; // Always
1288+
sync->signal = RTLIL::SigSpec();
1289+
sync->actions.push_back(RTLIL::SigSig(lhs, init_value));
1290+
proc->syncs.push_back(sync);
1291+
1292+
add_src_attribute(proc->attributes, var);
1293+
log("UHDM: Created initial assignment for existing variable '%s'\n", var_name.c_str());
1294+
}
1295+
}
1296+
}
1297+
}
11721298
log("UHDM: Variable '%s' already exists as wire, skipping\n", var_name.c_str());
11731299
}
11741300
}
@@ -1403,12 +1529,9 @@ void UhdmImporter::import_module(const module_inst* uhdm_module) {
14031529
// Finalize module
14041530
module->fixup_ports();
14051531

1406-
// Check if module is empty (no processes, cells, or memories) and mark as blackbox if so
1407-
if (module->processes.empty() && module->cells_.empty() && module->memories.empty()) {
1408-
// This is an empty module, mark it as blackbox
1409-
module->set_bool_attribute(ID::blackbox);
1410-
log("UHDM: Module %s has no implementation, marking as blackbox\n", module->name.c_str());
1411-
}
1532+
// NOTE: Blackbox detection is done after hierarchy import in import_design()
1533+
// We don't mark modules as blackbox here because cells may be added later
1534+
// during hierarchy traversal
14121535

14131536
// Restore saved instance context
14141537
current_instance = saved_instance;

0 commit comments

Comments
 (0)