Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions merge.lists
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Test file list for merge
# This is a comment and should be ignored
test_db1.yaml

# Another comment
test_db2.yaml
5 changes: 4 additions & 1 deletion src/ucis/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,12 @@ def get_parser():
help="Specifies the format of the input databases. Defaults to 'xml'")
merge.add_argument("--output-format", "-of",
help="Specifies the format of the input databases. Defaults to 'xml'")
merge.add_argument("--file-list", "-f",
help="File containing list of databases to merge (one per line)")
merge.add_argument("--libucis", "-l",
help="Specifies the name/path of the UCIS shared library")
merge.add_argument("db", nargs="+")
merge.add_argument("db", nargs="*",
help="Database files to merge (can be combined with --file-list)")
merge.set_defaults(func=cmd_merge.merge)

list_db_formats = subparser.add_parser("list-db-formats",
Expand Down
48 changes: 36 additions & 12 deletions src/ucis/cmd/cmd_merge.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,32 +22,56 @@ def merge(args):
if not rgy.hasDatabaseFormat(args.output_format):
raise Exception("Output format %s not recognized" % args.output_format)

# Build list of databases to merge
db_files = list(args.db) if args.db else []

# Read from file list if provided
if args.file_list:
import os
if not os.path.exists(args.file_list):
raise Exception("File list not found: %s" % args.file_list)

with open(args.file_list, 'r') as f:
for line in f:
line = line.strip()
# Skip comments and blank lines
if line and not line.startswith('#'):
db_files.append(line)

# Validate we have at least one database
if len(db_files) == 0:
raise Exception("No input databases specified. Use --file-list or provide database arguments.")

input_desc : FormatDescDb = rgy.getDatabaseDesc(args.input_format)
output_desc : FormatDescDb = rgy.getDatabaseDesc(args.output_format)

db_l : List[UCIS] = []
for input in args.db:
db_if : FormatIfDb = input_desc.fmt_if()
out_if = output_desc.fmt_if()
out_db : UCIS = out_if.create()
db_if : FormatIfDb = input_desc.fmt_if()
merger = DbMerger()

for input in db_files:
print("read and merge: ", input)
out_db_ref : UCIS = out_if.create()
db_l : List[UCIS] = []
try:
db = db_if.read(input)
db_l.append(db)
db_l.append(out_db)
except Exception as e:
raise Exception("Failed to read input file %s: %s" % (
input,
str(e)
))

out_if = output_desc.fmt_if()
out_db : UCIS = out_if.create()
try:
merger.merge(out_db_ref, db_l)
except Exception as e:
raise Exception("Merge operation failed: %s" % str(e))

merger = DbMerger()
try:
merger.merge(out_db, db_l)
except Exception as e:
raise Exception("Merge operation failed: %s" % str(e))
out_db = out_db_ref
db.close()

out_db.write(args.out)
for db in db_l:
db.close()


29 changes: 29 additions & 0 deletions test_combined.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<UCIS xmlns:ucis="http://www.w3.org/2001/XMLSchema-instance" writtenBy="HaPham" writtenTime="2025-11-25T00:00:00" ucisVersion="1.0">
<sourceFiles fileName="__null__file__" id="1"/>
<historyNodes historyNodeId="0" logicalName="dummy" physicalName="dummy" kind="dummy" testStatus="true" simtime="0" timeunit="0" runCwd="" cpuTime="0" seed="0" cmd="" args="" date="2025-11-25T21:42:38" userName="dummy" toolCategory="unknown" ucisVersion="1.0" vendorId="unknown" vendorTool="PyUCIS" vendorToolVersion="unknown"/>
<instanceCoverages name="cg_inst" key="0">
<id file="1" line="1" inlineCount="1"/>
<covergroupCoverage>
<cgInstance name="inst1" key="0">
<options/>
<cgId cgName="cvg1" moduleName="cvg1">
<cginstSourceId file="1" line="1" inlineCount="1"/>
<cgSourceId file="1" line="1" inlineCount="1"/>
</cgId>
<coverpoint name="cp1" key="0">
<options/>
<coverpointBin name="b0" type="bins" key="0">
<range from="-1" to="-1">
<contents coverageCount="2"/>
</range>
</coverpointBin>
<coverpointBin name="b1" type="bins" key="0">
<range from="-1" to="-1">
<contents coverageCount="1"/>
</range>
</coverpointBin>
</coverpoint>
</cgInstance>
</covergroupCoverage>
</instanceCoverages>
</UCIS>
12 changes: 12 additions & 0 deletions test_coverage_example.waive.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?xml version='1.0' encoding='UTF-8'?>
<WaiveData version="1.0" coverageFile="test_coverage_example.xml">
<Waive path="TYPE:transaction_cg" waived="true" timestamp="2026-01-01T09:43:14.346044">
<Message>unused


abc


xyz</Message>
</Waive>
</WaiveData>
169 changes: 169 additions & 0 deletions test_coverage_example.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
<?xml version="1.0" encoding="UTF-8"?>
<UCIS xmlns:ucis="http://www.w3.org/2001/XMLSchema-instance" writtenBy="TestUser" writtenTime="2025-12-06T16:43:45" ucisVersion="1.0">
<sourceFiles fileName="test_design.sv" id="1"/>
<historyNodes historyNodeId="0" logicalName="test_run" physicalName="test_run" kind="test" testStatus="true" simtime="1000" timeunit="1" runCwd="/work" cpuTime="100" seed="12345" cmd="vsim" args="-coverage" date="2025-12-06T16:43:45" userName="TestUser" toolCategory="simulator" ucisVersion="1.0" vendorId="test" vendorTool="PyUCIS" vendorToolVersion="1.0"/>

<instanceCoverages name="top" key="0">
<id file="1" line="1" inlineCount="1"/>
<covergroupCoverage>

<!-- Covergroup 1: Transaction Monitor with partial coverage -->
<cgInstance name="transaction_cg" key="0">
<options/>
<cgId cgName="transaction_cg" moduleName="transaction_monitor">
<cginstSourceId file="1" line="10" inlineCount="1"/>
<cgSourceId file="1" line="10" inlineCount="1"/>
</cgId>

<!-- Coverpoint: Address with some uncovered bins -->
<coverpoint name="cp_addr" key="0">
<options/>
<coverpointBin name="addr_low" type="bins" key="0">
<range from="-1" to="-1">
<contents coverageCount="45"/>
</range>
</coverpointBin>
<coverpointBin name="addr_mid" type="bins" key="1">
<range from="-1" to="-1">
<contents coverageCount="0"/>
</range>
</coverpointBin>
<coverpointBin name="addr_high" type="bins" key="2">
<range from="-1" to="-1">
<contents coverageCount="12"/>
</range>
</coverpointBin>
</coverpoint>

<!-- Coverpoint: Command with all bins covered -->
<coverpoint name="cp_cmd" key="1">
<options/>
<coverpointBin name="READ" type="bins" key="0">
<range from="-1" to="-1">
<contents coverageCount="25"/>
</range>
</coverpointBin>
<coverpointBin name="WRITE" type="bins" key="1">
<range from="-1" to="-1">
<contents coverageCount="30"/>
</range>
</coverpointBin>
</coverpoint>

<!-- Coverpoint: Priority with mostly uncovered bins -->
<coverpoint name="cp_priority" key="2">
<options/>
<coverpointBin name="LOW" type="bins" key="0">
<range from="-1" to="-1">
<contents coverageCount="0"/>
</range>
</coverpointBin>
<coverpointBin name="MEDIUM" type="bins" key="1">
<range from="-1" to="-1">
<contents coverageCount="5"/>
</range>
</coverpointBin>
<coverpointBin name="HIGH" type="bins" key="2">
<range from="-1" to="-1">
<contents coverageCount="0"/>
</range>
</coverpointBin>
<coverpointBin name="CRITICAL" type="bins" key="3">
<range from="-1" to="-1">
<contents coverageCount="0"/>
</range>
</coverpointBin>
</coverpoint>

</cgInstance>

<!-- Covergroup 2: Protocol Checker with uncovered bins -->
<cgInstance name="protocol_cg" key="1">
<options/>
<cgId cgName="protocol_cg" moduleName="protocol_checker">
<cginstSourceId file="1" line="50" inlineCount="1"/>
<cgSourceId file="1" line="50" inlineCount="1"/>
</cgId>

<coverpoint name="cp_state" key="0">
<options/>
<coverpointBin name="IDLE" type="bins" key="0">
<range from="-1" to="-1">
<contents coverageCount="100"/>
</range>
</coverpointBin>
<coverpointBin name="ACTIVE" type="bins" key="1">
<range from="-1" to="-1">
<contents coverageCount="50"/>
</range>
</coverpointBin>
<coverpointBin name="ERROR" type="bins" key="2">
<range from="-1" to="-1">
<contents coverageCount="0"/>
</range>
</coverpointBin>
<coverpointBin name="RESET" type="bins" key="3">
<range from="-1" to="-1">
<contents coverageCount="0"/>
</range>
</coverpointBin>
</coverpoint>

<coverpoint name="cp_handshake" key="1">
<options/>
<coverpointBin name="REQ_ACK" type="bins" key="0">
<range from="-1" to="-1">
<contents coverageCount="30"/>
</range>
</coverpointBin>
<coverpointBin name="REQ_NACK" type="bins" key="1">
<range from="-1" to="-1">
<contents coverageCount="0"/>
</range>
</coverpointBin>
<coverpointBin name="TIMEOUT" type="bins" key="2">
<range from="-1" to="-1">
<contents coverageCount="0"/>
</range>
</coverpointBin>
</coverpoint>

</cgInstance>

<!-- Covergroup 3: Data Path with mixed coverage -->
<cgInstance name="datapath_cg" key="2">
<options/>
<cgId cgName="datapath_cg" moduleName="datapath">
<cginstSourceId file="1" line="100" inlineCount="1"/>
<cgSourceId file="1" line="100" inlineCount="1"/>
</cgId>

<coverpoint name="cp_data_size" key="0">
<options/>
<coverpointBin name="BYTE" type="bins" key="0">
<range from="-1" to="-1">
<contents coverageCount="50"/>
</range>
</coverpointBin>
<coverpointBin name="WORD" type="bins" key="1">
<range from="-1" to="-1">
<contents coverageCount="40"/>
</range>
</coverpointBin>
<coverpointBin name="DWORD" type="bins" key="2">
<range from="-1" to="-1">
<contents coverageCount="0"/>
</range>
</coverpointBin>
<coverpointBin name="QWORD" type="bins" key="3">
<range from="-1" to="-1">
<contents coverageCount="0"/>
</range>
</coverpointBin>
</coverpoint>

</cgInstance>

</covergroupCoverage>
</instanceCoverages>
</UCIS>
12 changes: 12 additions & 0 deletions test_db1.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
coverage:
covergroups:
- name: cvg1
instances:
- name: inst1
coverpoints:
- name: cp1
bins:
- name: b0
count: 1
- name: b1
count: 0
12 changes: 12 additions & 0 deletions test_db2.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
coverage:
covergroups:
- name: cvg1
instances:
- name: inst1
coverpoints:
- name: cp1
bins:
- name: b0
count: 0
- name: b1
count: 1
6 changes: 6 additions & 0 deletions test_merged.waive.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version='1.0' encoding='UTF-8'?>
<WaiveData version="1.0" coverageFile="test_merged.xml">
<Waive path="TYPE:cvg1/INST:inst1/CVP:cp1" waived="true" timestamp="2025-11-25T22:26:04.510258">
<Message>this item can waive</Message>
</Waive>
</WaiveData>
29 changes: 29 additions & 0 deletions test_merged.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<UCIS xmlns:ucis="http://www.w3.org/2001/XMLSchema-instance" writtenBy="HaPham" writtenTime="2025-11-25T00:00:00" ucisVersion="1.0">
<sourceFiles fileName="__null__file__" id="1"/>
<historyNodes historyNodeId="0" logicalName="dummy" physicalName="dummy" kind="dummy" testStatus="true" simtime="0" timeunit="0" runCwd="" cpuTime="0" seed="0" cmd="" args="" date="2025-11-25T21:42:24" userName="dummy" toolCategory="unknown" ucisVersion="1.0" vendorId="unknown" vendorTool="PyUCIS" vendorToolVersion="unknown"/>
<instanceCoverages name="cg_inst" key="0">
<id file="1" line="1" inlineCount="1"/>
<covergroupCoverage>
<cgInstance name="inst1" key="0">
<options/>
<cgId cgName="cvg1" moduleName="cvg1">
<cginstSourceId file="1" line="1" inlineCount="1"/>
<cgSourceId file="1" line="1" inlineCount="1"/>
</cgId>
<coverpoint name="cp1" key="0">
<options/>
<coverpointBin name="b0" type="bins" key="0">
<range from="-1" to="-1">
<contents coverageCount="0"/>
</range>
</coverpointBin>
<coverpointBin name="b1" type="bins" key="0">
<range from="-1" to="-1">
<contents coverageCount="1"/>
</range>
</coverpointBin>
</coverpoint>
</cgInstance>
</covergroupCoverage>
</instanceCoverages>
</UCIS>
22 changes: 22 additions & 0 deletions ve/unit/test_file_list/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Test directory for file list feature

This directory contains tests for the `--file-list` feature of the merge command.

## Tests

- `test_file_list_feature.py` - Comprehensive tests including:
- Basic file list functionality
- Comments and blank lines handling
- Combined file list + direct arguments
- Large scale test with 1000 databases
- Error handling

## Running Tests

```bash
# Run all file list tests
python -m unittest ve.unit.test_file_list.test_file_list_feature -v

# Run specific test
python -m unittest ve.unit.test_file_list.test_file_list_feature.TestFileList.test_file_list_large_scale -v
```
1 change: 1 addition & 0 deletions ve/unit/test_file_list/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Empty __init__.py to make this a Python package
Loading