Skip to content

Commit

Permalink
coredevice/analyzer: basic VCD writing
Browse files Browse the repository at this point in the history
sbourdeauducq committed Dec 20, 2015
1 parent e4615e7 commit cdcb57e
Showing 2 changed files with 116 additions and 6 deletions.
104 changes: 103 additions & 1 deletion artiq/coredevice/analyzer.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
from enum import Enum
from operator import itemgetter
from collections import namedtuple
from itertools import count
from enum import Enum
import struct
import importlib
import logging

from artiq.coredevice import ttl


logger = logging.getLogger(__name__)

@@ -75,3 +80,100 @@ def decode_dump(data):
position += 32
return messages


def vcd_codes():
codechars = [chr(i) for i in range(33, 127)]
for n in count():
q, r = divmod(n, len(codechars))
code = codechars[r]
while q > 0:
q, r = divmod(q, len(codechars))
code = codechars[r] + code
yield code


class VCDChannel:
def __init__(self, out, code):
self.out = out
self.code = code

def set_value(self, value):
if len(value) > 1:
self.out.write("b" + value + " " + self.code + "\n")
else:
self.out.write(value + self.code + "\n")


class VCDManager:
def __init__(self, filename):
self.out = open(filename, "w")
self.codes = vcd_codes()
self.current_time = None

def get_channel(self, name, width):
code = next(self.codes)
self.out.write("$var wire {width} {code} {name} $end\n"
.format(name=name, code=code, width=width))
return VCDChannel(self.out, code)

def set_time(self, time):
if time != self.current_time:
self.out.write("#{}\n".format(time))
self.current_time = time

def close(self):
self.out.close()


class TTLHandler:
def __init__(self, vcd_manager, name):
self.channel_value = vcd_manager.get_channel(name, 1)
self.last_value = "X"
self.oe = True

def process_message(self, message):
if isinstance(message, OutputMessage):
if message.address == 0:
self.last_value = str(message.data)
if self.oe:
self.channel_value.set_value(self.last_value)
elif messages.address == 1:
self.oe = bool(message.data)
if self.oe:
self.channel_value.set_value(self.last_value)
else:
self.channel_value.set_value("X")


def create_channel_handlers(vcd_manager, devices):
channel_handlers = dict()
for name, desc in sorted(devices.items(), key=itemgetter(0)):
if isinstance(desc, dict) and desc["type"] == "local":
module = importlib.import_module(desc["module"])
device_class = getattr(module, desc["class"])
if device_class in {ttl.TTLOut, ttl.TTLInOut}:
channel = desc["arguments"]["channel"]
channel_handlers[channel] = TTLHandler(vcd_manager, name)
return channel_handlers


def get_message_time(message):
return getattr(message, "timestamp", message.rtio_counter)


def messages_to_vcd(filename, devices, messages):
messages = [m for m in messages if get_message_time(m)] # TODO: remove this hack
messages = sorted(messages, key=get_message_time)
vcd_manager = VCDManager(filename)
try:
channel_handlers = create_channel_handlers(vcd_manager, devices)
vcd_manager.set_time(0)
if messages:
start_time = get_message_time(messages[0])
for message in messages:
if message.channel in channel_handlers:
vcd_manager.set_time(
get_message_time(message) - start_time)
channel_handlers[message.channel].process_message(message)
finally:
vcd_manager.close()
18 changes: 13 additions & 5 deletions artiq/frontend/artiq_coretool.py
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@

from artiq.master.databases import DeviceDB
from artiq.master.worker_db import DeviceManager
from artiq.coredevice.analyzer import decode_dump
from artiq.coredevice.analyzer import decode_dump, messages_to_vcd


def get_argparser():
@@ -46,7 +46,12 @@ def get_argparser():

subparsers.add_parser("cfg-erase", help="erase core device config")

subparsers.add_parser("analyzer-dump")
p_analyzer = subparsers.add_parser("analyzer-dump",
help="dump analyzer contents")
p_analyzer.add_argument("-m", default=False, action="store_true",
help="print raw messages")
p_analyzer.add_argument("-f", type=str, default="",
help="format and write contents to VCD file")

return parser

@@ -79,9 +84,12 @@ def main():
elif args.action == "cfg-erase":
comm.flash_storage_erase()
elif args.action == "analyzer-dump":
dump = comm.get_analyzer_dump()
for msg in decode_dump(dump):
print(msg)
messages = decode_dump(comm.get_analyzer_dump())
if args.m:
for message in messages:
print(message)
if args.f:
messages_to_vcd(args.f, device_mgr.get_device_db(), messages)
finally:
device_mgr.close_devices()

0 comments on commit cdcb57e

Please sign in to comment.