gen/sim/vcd: allow continous update of vcd file and dynamic signals
authorFlorent Kermarrec <florent@enjoy-digital.fr>
Sat, 28 May 2016 08:25:48 +0000 (10:25 +0200)
committerFlorent Kermarrec <florent@enjoy-digital.fr>
Sat, 28 May 2016 08:25:48 +0000 (10:25 +0200)
With continous update, VCD header needs to be writen at the beginning of the simulation.
When a new signal is created, we rewrite the header and the content.

litex/gen/sim/vcd.py

index bef43e28eaa729659758af0413e622d42c4edc9c..db369a6dc7266dcc63046578b1e8fc9d7c352e27 100644 (file)
@@ -21,13 +21,16 @@ def vcd_codes():
 class VCDWriter:
     def __init__(self, filename):
         self.filename = filename
-        self.out_file = open(self.filename, "w")
+        self.out_file = None
+        self.buffer_file = tempfile.TemporaryFile(
+            dir=os.path.dirname(filename), mode="w+")
+        self.initialized = False
         self.codegen = vcd_codes()
         self.codes = OrderedDict()
         self.signal_values = dict()
         self.t = 0
 
-    def _write_value(self, f, signal, value):
+    def _write_value(self, signal, value):
         l = len(signal)
         if value < 0:
             value += 2**l
@@ -35,10 +38,22 @@ class VCDWriter:
             fmtstr = "b{:0" + str(l) + "b} {}\n"
         else:
             fmtstr = "{}{}\n"
-        code = self.codes[signal]
-        f.write(fmtstr.format(value, code))
+        try:
+            code = self.codes[signal]
+        except KeyError:
+            code = next(self.codegen)
+            self.codes[signal] = code
+            self.init(self.codes.keys())
+
+        return fmtstr.format(value, code)
+
+    def _write(self, s):
+        self.out_file.write(s)
+        self.buffer_file.write(s)
 
     def init(self, signals):
+        self.out_file = open(self.filename, "w")
+
         # generate codes
         for signal in signals:
             try:
@@ -48,30 +63,40 @@ class VCDWriter:
                 self.codes[signal] = code
 
         # write vcd header
-        out = self.out_file
+        header = ""
         ns = build_namespace(self.codes.keys())
         for signal, code in self.codes.items():
             name = ns.get_name(signal)
-            out.write("$var wire {len} {code} {name} $end\n"
-                      .format(name=name, code=code, len=len(signal)))
-        out.write("$dumpvars\n")
+            header += "$var wire {len} {code} {name} $end\n".format(name=name, code=code, len=len(signal))
+        header += "$dumpvars\n"
         for signal in self.codes.keys():
-            self._write_value(out, signal, signal.reset.value)
-        out.write("$end\n")
-        out.write("#0\n")
+            header += self._write_value(signal, signal.reset.value)
+        header += "$end\n"
+        self.out_file.write(header)
+
+        if self.initialized:
+            self.buffer_file.seek(0)
+            shutil.copyfileobj(self.buffer_file, self.out_file)
+            self.buffer_file.seek(0, 2)
+        else:
+            # init time
+            self._write("#0\n")
+
+        self.initialized = True
 
     def set(self, signal, value):
         if (signal not in self.signal_values
                 or self.signal_values[signal] != value):
-            self._write_value(self.out_file, signal, value)
+            self._write(self._write_value(signal, value))
             self.signal_values[signal] = value
 
     def delay(self, delay):
         self.t += delay
-        self.out_file.write("#{}\n".format(self.t))
+        self._write("#{}\n".format(self.t))
 
     def close(self):
         self.out_file.close()
+        self.buffer_file.close()
 
 
 class DummyVCDWriter: