@@ -34,6 +34,13 @@ class ExceptionType(Enum):
34
34
i_overflow = 0b100001
35
35
36
36
37
+ class WaveformType (Enum ):
38
+ ANALOG = 0
39
+ BIT = 1
40
+ VECTOR = 2
41
+ LOG = 3
42
+
43
+
37
44
def get_analyzer_dump (host , port = 1382 ):
38
45
sock = socket .create_connection ((host , port ))
39
46
try :
@@ -150,6 +157,12 @@ def set_value_double(self, x):
150
157
integer_cast = struct .unpack (">Q" , struct .pack (">d" , x ))[0 ]
151
158
self .set_value ("{:064b}" .format (integer_cast ))
152
159
160
+ def set_log (self , log_message ):
161
+ value = ""
162
+ for c in log_message :
163
+ value += "{:08b}" .format (ord (c ))
164
+ self .set_value (value )
165
+
153
166
154
167
class VCDManager :
155
168
def __init__ (self , fileobj ):
@@ -160,15 +173,15 @@ def __init__(self, fileobj):
160
173
def set_timescale_ps (self , timescale ):
161
174
self .out .write ("$timescale {}ps $end\n " .format (round (timescale )))
162
175
163
- def get_channel (self , name , width ):
176
+ def get_channel (self , name , width , ty ):
164
177
code = next (self .codes )
165
178
self .out .write ("$var wire {width} {code} {name} $end\n "
166
179
.format (name = name , code = code , width = width ))
167
180
return VCDChannel (self .out , code )
168
181
169
182
@contextmanager
170
- def scope (self , name ):
171
- self .out .write ("$scope module {} $end\n " .format (name ))
183
+ def scope (self , scope , name ):
184
+ self .out .write ("$scope module {}/{} $end\n " .format (scope , name ))
172
185
yield
173
186
self .out .write ("$upscope $end\n " )
174
187
@@ -177,11 +190,66 @@ def set_time(self, time):
177
190
self .out .write ("#{}\n " .format (time ))
178
191
self .current_time = time
179
192
193
+ def set_end_time (self , time ):
194
+ pass
195
+
196
+
197
+ class WaveformManager :
198
+ def __init__ (self ):
199
+ self .current_time = 0
200
+ self .channels = list ()
201
+ self .current_scope = ""
202
+ self .trace = {"timescale" : 1 , "stopped_x" : None , "logs" : dict (), "data" : dict ()}
203
+
204
+ def set_timescale_ps (self , timescale ):
205
+ self .trace ["timescale" ] = int (timescale )
206
+
207
+ def get_channel (self , name , width , ty ):
208
+ if ty == WaveformType .LOG :
209
+ data = self .trace ["logs" ][self .current_scope + name ] = list ()
210
+ else :
211
+ data = self .trace ["data" ][self .current_scope + name ] = list ()
212
+ channel = WaveformChannel (data , self .current_time )
213
+ self .channels .append (channel )
214
+ return channel
215
+
216
+ @contextmanager
217
+ def scope (self , scope , name ):
218
+ old_scope = self .current_scope
219
+ self .current_scope = scope + "/"
220
+ yield
221
+ self .current_scope = old_scope
222
+
223
+ def set_time (self , time ):
224
+ for channel in self .channels :
225
+ channel .set_time (time )
226
+
227
+ def set_end_time (self , time ):
228
+ self .trace ["stopped_x" ] = time
229
+
230
+
231
+ class WaveformChannel :
232
+ def __init__ (self , data , current_time ):
233
+ self .data = data
234
+ self .current_time = current_time
235
+
236
+ def set_value (self , value ):
237
+ self .data .append ((self .current_time , value ))
238
+
239
+ def set_value_double (self , x ):
240
+ self .data .append ((self .current_time , x ))
241
+
242
+ def set_time (self , time ):
243
+ self .current_time = time
244
+
245
+ def set_log (self , log_message ):
246
+ self .data .append ((self .current_time , log_message ))
247
+
180
248
181
249
class TTLHandler :
182
- def __init__ (self , vcd_manager , name ):
250
+ def __init__ (self , manager , name ):
183
251
self .name = name
184
- self .channel_value = vcd_manager .get_channel ("ttl/" + name , 1 )
252
+ self .channel_value = manager .get_channel ("ttl/" + name , 1 , ty = WaveformType . BIT )
185
253
self .last_value = "X"
186
254
self .oe = True
187
255
@@ -206,11 +274,11 @@ def process_message(self, message):
206
274
207
275
208
276
class TTLClockGenHandler :
209
- def __init__ (self , vcd_manager , name , ref_period ):
277
+ def __init__ (self , manager , name , ref_period ):
210
278
self .name = name
211
279
self .ref_period = ref_period
212
- self .channel_frequency = vcd_manager .get_channel (
213
- "ttl_clkgen/" + name , 64 )
280
+ self .channel_frequency = manager .get_channel (
281
+ "ttl_clkgen/" + name , 64 , ty = WaveformType . ANALOG )
214
282
215
283
def process_message (self , message ):
216
284
if isinstance (message , OutputMessage ):
@@ -221,8 +289,8 @@ def process_message(self, message):
221
289
222
290
223
291
class DDSHandler :
224
- def __init__ (self , vcd_manager , onehot_sel , sysclk ):
225
- self .vcd_manager = vcd_manager
292
+ def __init__ (self , manager , onehot_sel , sysclk ):
293
+ self .manager = manager
226
294
self .onehot_sel = onehot_sel
227
295
self .sysclk = sysclk
228
296
@@ -231,11 +299,11 @@ def __init__(self, vcd_manager, onehot_sel, sysclk):
231
299
232
300
def add_dds_channel (self , name , dds_channel_nr ):
233
301
dds_channel = dict ()
234
- with self .vcd_manager .scope ("dds/{}" . format ( name ) ):
302
+ with self .manager .scope ("dds" , name ):
235
303
dds_channel ["vcd_frequency" ] = \
236
- self .vcd_manager .get_channel (name + "/frequency" , 64 )
304
+ self .manager .get_channel (name + "/frequency" , 64 , ty = WaveformType . ANALOG )
237
305
dds_channel ["vcd_phase" ] = \
238
- self .vcd_manager .get_channel (name + "/phase" , 64 )
306
+ self .manager .get_channel (name + "/phase" , 64 , ty = WaveformType . ANALOG )
239
307
dds_channel ["ftw" ] = [None , None ]
240
308
dds_channel ["pow" ] = None
241
309
self .dds_channels [dds_channel_nr ] = dds_channel
@@ -285,10 +353,10 @@ def process_message(self, message):
285
353
286
354
287
355
class WishboneHandler :
288
- def __init__ (self , vcd_manager , name , read_bit ):
356
+ def __init__ (self , manager , name , read_bit ):
289
357
self ._reads = []
290
358
self ._read_bit = read_bit
291
- self .stb = vcd_manager .get_channel ("{}/{}" . format ( name , " stb") , 1 )
359
+ self .stb = manager .get_channel (name + "/ stb" , 1 , ty = WaveformType . BIT )
292
360
293
361
def process_message (self , message ):
294
362
self .stb .set_value ("1" )
@@ -318,16 +386,17 @@ def process_read(self, address, data, read_slack):
318
386
319
387
320
388
class SPIMasterHandler (WishboneHandler ):
321
- def __init__ (self , vcd_manager , name ):
389
+ def __init__ (self , manager , name ):
322
390
self .channels = {}
323
- with vcd_manager .scope ("spi/{}" .format (name )):
324
- super ().__init__ (vcd_manager , name , read_bit = 0b100 )
391
+ self .scope = "spi"
392
+ with manager .scope ("spi" , name ):
393
+ super ().__init__ (manager , name , read_bit = 0b100 )
325
394
for reg_name , reg_width in [
326
395
("config" , 32 ), ("chip_select" , 16 ),
327
396
("write_length" , 8 ), ("read_length" , 8 ),
328
397
("write" , 32 ), ("read" , 32 )]:
329
- self .channels [reg_name ] = vcd_manager .get_channel (
330
- "{}/{}" .format (name , reg_name ), reg_width )
398
+ self .channels [reg_name ] = manager .get_channel (
399
+ "{}/{}" .format (name , reg_name ), reg_width , ty = WaveformType . VECTOR )
331
400
332
401
def process_write (self , address , data ):
333
402
if address == 0 :
@@ -352,20 +421,21 @@ def process_read(self, address, data, read_slack):
352
421
353
422
354
423
class SPIMaster2Handler (WishboneHandler ):
355
- def __init__ (self , vcd_manager , name ):
424
+ def __init__ (self , manager , name ):
356
425
self ._reads = []
357
426
self .channels = {}
358
- with vcd_manager .scope ("spi2/{}" .format (name )):
359
- self .stb = vcd_manager .get_channel ("{}/{}" .format (name , "stb" ), 1 )
427
+ self .scope = "spi2"
428
+ with manager .scope ("spi2" , name ):
429
+ self .stb = manager .get_channel (name + "/stb" , 1 , ty = WaveformType .BIT )
360
430
for reg_name , reg_width in [
361
431
("flags" , 8 ),
362
432
("length" , 5 ),
363
433
("div" , 8 ),
364
434
("chip_select" , 8 ),
365
435
("write" , 32 ),
366
436
("read" , 32 )]:
367
- self .channels [reg_name ] = vcd_manager .get_channel (
368
- "{}/{}" .format (name , reg_name ), reg_width )
437
+ self .channels [reg_name ] = manager .get_channel (
438
+ "{}/{}" .format (name , reg_name ), reg_width , ty = WaveformType . VECTOR )
369
439
370
440
def process_message (self , message ):
371
441
self .stb .set_value ("1" )
@@ -413,27 +483,25 @@ def _extract_log_chars(data):
413
483
414
484
415
485
class LogHandler :
416
- def __init__ (self , vcd_manager , vcd_log_channels ):
417
- self .vcd_channels = dict ()
418
- for name , maxlength in vcd_log_channels .items ():
419
- self .vcd_channels [name ] = vcd_manager .get_channel ("log/" + name ,
420
- maxlength * 8 )
486
+ def __init__ (self , manager , log_channels ):
487
+ self .channels = dict ()
488
+ for name , maxlength in log_channels .items ():
489
+ self .channels [name ] = manager .get_channel ("logs/" + name ,
490
+ maxlength * 8 ,
491
+ ty = WaveformType .LOG )
421
492
self .current_entry = ""
422
493
423
494
def process_message (self , message ):
424
495
if isinstance (message , OutputMessage ):
425
496
self .current_entry += _extract_log_chars (message .data )
426
497
if len (self .current_entry ) > 1 and self .current_entry [- 1 ] == "\x1D " :
427
498
channel_name , log_message = self .current_entry [:- 1 ].split ("\x1E " , maxsplit = 1 )
428
- vcd_value = ""
429
- for c in log_message :
430
- vcd_value += "{:08b}" .format (ord (c ))
431
- self .vcd_channels [channel_name ].set_value (vcd_value )
499
+ self .channels [channel_name ].set_log (log_message )
432
500
self .current_entry = ""
433
501
434
502
435
- def get_vcd_log_channels (log_channel , messages ):
436
- vcd_log_channels = dict ()
503
+ def get_log_channels (log_channel , messages ):
504
+ log_channels = dict ()
437
505
log_entry = ""
438
506
for message in messages :
439
507
if (isinstance (message , OutputMessage )
@@ -442,13 +510,13 @@ def get_vcd_log_channels(log_channel, messages):
442
510
if len (log_entry ) > 1 and log_entry [- 1 ] == "\x1D " :
443
511
channel_name , log_message = log_entry [:- 1 ].split ("\x1E " , maxsplit = 1 )
444
512
l = len (log_message )
445
- if channel_name in vcd_log_channels :
446
- if vcd_log_channels [channel_name ] < l :
447
- vcd_log_channels [channel_name ] = l
513
+ if channel_name in log_channels :
514
+ if log_channels [channel_name ] < l :
515
+ log_channels [channel_name ] = l
448
516
else :
449
- vcd_log_channels [channel_name ] = l
517
+ log_channels [channel_name ] = l
450
518
log_entry = ""
451
- return vcd_log_channels
519
+ return log_channels
452
520
453
521
454
522
def get_single_device_argument (devices , module , cls , argument ):
@@ -475,34 +543,34 @@ def get_dds_sysclk(devices):
475
543
("AD9914" ,), "sysclk" )
476
544
477
545
478
- def create_channel_handlers (vcd_manager , devices , ref_period ,
546
+ def create_channel_handlers (manager , devices , ref_period ,
479
547
dds_sysclk , dds_onehot_sel ):
480
548
channel_handlers = dict ()
481
549
for name , desc in sorted (devices .items (), key = itemgetter (0 )):
482
550
if isinstance (desc , dict ) and desc ["type" ] == "local" :
483
551
if (desc ["module" ] == "artiq.coredevice.ttl"
484
552
and desc ["class" ] in {"TTLOut" , "TTLInOut" }):
485
553
channel = desc ["arguments" ]["channel" ]
486
- channel_handlers [channel ] = TTLHandler (vcd_manager , name )
554
+ channel_handlers [channel ] = TTLHandler (manager , name )
487
555
if (desc ["module" ] == "artiq.coredevice.ttl"
488
556
and desc ["class" ] == "TTLClockGen" ):
489
557
channel = desc ["arguments" ]["channel" ]
490
- channel_handlers [channel ] = TTLClockGenHandler (vcd_manager , name , ref_period )
558
+ channel_handlers [channel ] = TTLClockGenHandler (manager , name , ref_period )
491
559
if (desc ["module" ] == "artiq.coredevice.ad9914"
492
560
and desc ["class" ] == "AD9914" ):
493
561
dds_bus_channel = desc ["arguments" ]["bus_channel" ]
494
562
dds_channel = desc ["arguments" ]["channel" ]
495
563
if dds_bus_channel in channel_handlers :
496
564
dds_handler = channel_handlers [dds_bus_channel ]
497
565
else :
498
- dds_handler = DDSHandler (vcd_manager , dds_onehot_sel , dds_sysclk )
566
+ dds_handler = DDSHandler (manager , dds_onehot_sel , dds_sysclk )
499
567
channel_handlers [dds_bus_channel ] = dds_handler
500
568
dds_handler .add_dds_channel (name , dds_channel )
501
569
if (desc ["module" ] == "artiq.coredevice.spi2" and
502
570
desc ["class" ] == "SPIMaster" ):
503
571
channel = desc ["arguments" ]["channel" ]
504
572
channel_handlers [channel ] = SPIMaster2Handler (
505
- vcd_manager , name )
573
+ manager , name )
506
574
return channel_handlers
507
575
508
576
@@ -512,11 +580,21 @@ def get_message_time(message):
512
580
513
581
def decoded_dump_to_vcd (fileobj , devices , dump , uniform_interval = False ):
514
582
vcd_manager = VCDManager (fileobj )
583
+ decoded_dump_to_target (vcd_manager , devices , dump , uniform_interval )
584
+
585
+
586
+ def decoded_dump_to_waveform_data (devices , dump , uniform_interval = False ):
587
+ manager = WaveformManager ()
588
+ decoded_dump_to_target (manager , devices , dump , uniform_interval )
589
+ return manager .trace
590
+
591
+
592
+ def decoded_dump_to_target (manager , devices , dump , uniform_interval ):
515
593
ref_period = get_ref_period (devices )
516
594
517
595
if ref_period is not None :
518
596
if not uniform_interval :
519
- vcd_manager .set_timescale_ps (ref_period * 1e12 )
597
+ manager .set_timescale_ps (ref_period * 1e12 )
520
598
else :
521
599
logger .warning ("unable to determine core device ref_period" )
522
600
ref_period = 1e-9 # guess
@@ -526,27 +604,29 @@ def decoded_dump_to_vcd(fileobj, devices, dump, uniform_interval=False):
526
604
dds_sysclk = 3e9 # guess
527
605
528
606
if isinstance (dump .messages [- 1 ], StoppedMessage ):
607
+ m = dump .messages [- 1 ]
608
+ end_time = get_message_time (m )
529
609
messages = dump .messages [:- 1 ]
530
610
else :
531
611
logger .warning ("StoppedMessage missing" )
532
612
messages = dump .messages
533
613
messages = sorted (messages , key = get_message_time )
534
614
535
615
channel_handlers = create_channel_handlers (
536
- vcd_manager , devices , ref_period ,
616
+ manager , devices , ref_period ,
537
617
dds_sysclk , dump .dds_onehot_sel )
538
- vcd_log_channels = get_vcd_log_channels (dump .log_channel , messages )
618
+ log_channels = get_log_channels (dump .log_channel , messages )
539
619
channel_handlers [dump .log_channel ] = LogHandler (
540
- vcd_manager , vcd_log_channels )
620
+ manager , log_channels )
541
621
if uniform_interval :
542
622
# RTIO event timestamp in machine units
543
- timestamp = vcd_manager .get_channel ("timestamp" , 64 )
623
+ timestamp = manager .get_channel ("timestamp" , 64 , ty = WaveformType . VECTOR )
544
624
# RTIO time interval between this and the next timed event
545
625
# in SI seconds
546
- interval = vcd_manager .get_channel ("interval" , 64 )
547
- slack = vcd_manager .get_channel ("rtio_slack" , 64 )
626
+ interval = manager .get_channel ("interval" , 64 , ty = WaveformType . ANALOG )
627
+ slack = manager .get_channel ("rtio_slack" , 64 , ty = WaveformType . ANALOG )
548
628
549
- vcd_manager .set_time (0 )
629
+ manager .set_time (0 )
550
630
start_time = 0
551
631
for m in messages :
552
632
start_time = get_message_time (m )
@@ -560,11 +640,11 @@ def decoded_dump_to_vcd(fileobj, devices, dump, uniform_interval=False):
560
640
if t >= 0 :
561
641
if uniform_interval :
562
642
interval .set_value_double ((t - t0 )* ref_period )
563
- vcd_manager .set_time (i )
643
+ manager .set_time (i )
564
644
timestamp .set_value ("{:064b}" .format (t ))
565
645
t0 = t
566
646
else :
567
- vcd_manager .set_time (t )
647
+ manager .set_time (t )
568
648
channel_handlers [message .channel ].process_message (message )
569
649
if isinstance (message , OutputMessage ):
570
650
slack .set_value_double (
0 commit comments