-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.py
More file actions
154 lines (127 loc) · 6.63 KB
/
main.py
File metadata and controls
154 lines (127 loc) · 6.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
import csv
import sys
import os
from datetime import datetime
def csv_to_vcd(csv_file, vcd_file, signal_names, timestep=1e-6, skip_header=False,
time_unit='us', signal_width=None, signal_type='wire', custom_ids=None):
"""
Convert CSV data to VCD format with enhanced stability and features
Args:
csv_file: Input CSV file path
vcd_file: Output VCD file path
signal_names: List of signal names
timestep: Time between samples in seconds
skip_header: Whether to skip the first row of CSV
time_unit: Time unit for VCD file ('s', 'ms', 'us', 'ns', 'ps', 'fs')
signal_width: List of bit widths for each signal (defaults to 1 if None)
signal_type: Type of signal ('wire', 'reg', etc.)
custom_ids: Custom identifiers for signals (uses automatic if None)
"""
num_signals = len(signal_names)
values = []
# Set default signal widths if not provided
if signal_width is None:
signal_width = [1] * num_signals
elif len(signal_width) != num_signals:
raise ValueError(f"Signal width list length ({len(signal_width)}) doesn't match signal names ({num_signals})")
# Validate input files
if not os.path.exists(csv_file):
raise FileNotFoundError(f"CSV file not found: {csv_file}")
try:
# Read CSV data
with open(csv_file, 'r', newline='') as f:
reader = csv.reader(f)
# Skip header if requested
if skip_header:
next(reader, None)
for row_num, row in enumerate(reader, start=1):
if not row: # Skip empty rows
continue
if len(row) != num_signals:
raise ValueError(f"Row {row_num} has {len(row)} values, expected {num_signals}")
# Validate values before adding
validated_row = []
for i, val in enumerate(row):
val = val.strip()
# For 1-bit signals, ensure values are 0, 1, x, z, X, Z
if signal_width[i] == 1 and val not in ['0', '1', 'x', 'z', 'X', 'Z']:
print(f"Warning: Row {row_num}, Signal {signal_names[i]}: Invalid value '{val}' converted to 'x'")
val = 'x'
validated_row.append(val)
values.append(validated_row)
if not values:
raise ValueError("No data found in CSV file")
# Validate time unit
valid_units = ['s', 'ms', 'us', 'ns', 'ps', 'fs']
if time_unit not in valid_units:
raise ValueError(f"Invalid time unit: {time_unit}. Must be one of {', '.join(valid_units)}")
# Create IDs for signals
ids = []
if custom_ids and len(custom_ids) == num_signals:
ids = custom_ids
else:
# Generate IDs using printable ASCII characters (33-126)
for i in range(num_signals):
if i < 94: # Number of printable ASCII chars (127-33)
signal_id = chr(33 + i)
else:
# For more than 94 signals, use multi-character IDs
signal_id = f"s{i}"
ids.append(signal_id)
# Start writing VCD
with open(vcd_file, 'w') as f:
f.write(f"$date\n {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n$end\n")
f.write("$version\n Enhanced csv_to_vcd v2.0\n$end\n")
f.write(f"$timescale 1 {time_unit} $end\n")
f.write("$scope module logic $end\n")
# Write signal declarations
for i, name in enumerate(signal_names):
f.write(f"$var {signal_type} {signal_width[i]} {ids[i]} {name} $end\n")
f.write("$upscope $end\n$enddefinitions $end\n")
# Initial values
f.write("$dumpvars\n")
for i, sig_id in enumerate(ids):
if signal_width[i] == 1:
f.write(f"{values[0][i]}{sig_id}\n")
else:
f.write(f"b{values[0][i]} {sig_id}\n")
f.write("$end\n")
# Calculate time multiplier based on time_unit
time_multipliers = {'s': 1, 'ms': 1e3, 'us': 1e6, 'ns': 1e9, 'ps': 1e12, 'fs': 1e15}
time_mult = time_multipliers[time_unit]
# Write time steps and changes
prev_values = values[0]
for t, row in enumerate(values):
timestamp = int(t * timestep * time_mult)
f.write(f"#{timestamp}\n")
# Only write values that changed for efficiency
for i, val in enumerate(row):
if val != prev_values[i]:
if signal_width[i] == 1:
f.write(f"{val}{ids[i]}\n")
else:
f.write(f"b{val} {ids[i]}\n")
prev_values = row
print(f"Successfully converted {csv_file} to {vcd_file} with {num_signals} signals and {len(values)} timesteps")
except Exception as e:
print(f"Error converting CSV to VCD: {str(e)}", file=sys.stderr)
raise
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser(description="Convert a CSV file to VCD format")
parser.add_argument("csv_file", help="Input CSV file")
parser.add_argument("vcd_file", help="Output VCD file")
parser.add_argument("--timestep", type=float, default=1e-6, help="Time between samples in seconds (default: 1e-6)")
parser.add_argument("--signal-names", nargs='+', required=True, help="List of signal names")
parser.add_argument("--skip-header", action="store_true", help="Skip first row of CSV file (header)")
parser.add_argument("--time-unit", default="us", choices=["s", "ms", "us", "ns", "ps", "fs"],
help="Time unit for VCD file (default: us)")
parser.add_argument("--signal-width", type=int, nargs='+', help="List of bit widths for each signal (default: 1)")
parser.add_argument("--signal-type", default="wire", choices=["wire", "reg", "integer", "parameter"],
help="Type of signals (default: wire)")
args = parser.parse_args()
try:
csv_to_vcd(args.csv_file, args.vcd_file, args.signal_names, args.timestep,
args.skip_header, args.time_unit, args.signal_width, args.signal_type)
except Exception as e:
sys.exit(1) # Exit with error code