Add simulation code
authorJean THOMAS <git0@pub.jeanthomas.me>
Thu, 25 Jun 2020 19:00:20 +0000 (21:00 +0200)
committerJean THOMAS <git0@pub.jeanthomas.me>
Thu, 25 Jun 2020 19:00:20 +0000 (21:00 +0200)
gram/simulation/README.md [new file with mode: 0644]
gram/simulation/runsimcrg.sh [new file with mode: 0755]
gram/simulation/simcrg.py [new file with mode: 0644]
gram/simulation/simcrgtb.v [new file with mode: 0644]

diff --git a/gram/simulation/README.md b/gram/simulation/README.md
new file mode 100644 (file)
index 0000000..fa300c7
--- /dev/null
@@ -0,0 +1,18 @@
+# Low level simulation
+
+This folder contains code used for low level simulation of various aspects of gram.
+
+## Requirements
+
+ * Icarius Verilog (preferably a recent version)
+ * ECP5 instances models from a Lattice Diamond installation (just install Lattice Diamond)
+
+## Available simulations
+
+### simcrg
+
+```
+./runsimcrg.sh
+```
+
+Produces `simcrg.vcd`.
diff --git a/gram/simulation/runsimcrg.sh b/gram/simulation/runsimcrg.sh
new file mode 100755 (executable)
index 0000000..226f409
--- /dev/null
@@ -0,0 +1,8 @@
+#!/bin/bash
+set -e
+
+LIB_DIR=/usr/local/diamond/3.11_x64/ispfpga/verilog/data/ecp5u
+
+python simcrg.py generate simcrg.v
+iverilog -o simcrg simcrgtb.v simcrg.v ${LIB_DIR}/ECLKSYNCB.v ${LIB_DIR}/CLKDIVF.v ${LIB_DIR}/EHXPLLL.v ${LIB_DIR}/PUR.v ${LIB_DIR}/GSR.v
+vvp simcrg -vcd
diff --git a/gram/simulation/simcrg.py b/gram/simulation/simcrg.py
new file mode 100644 (file)
index 0000000..400d479
--- /dev/null
@@ -0,0 +1,159 @@
+# This file is Copyright (c) 2020 LambdaConcept <contact@lambdaconcept.com>
+
+from nmigen import *
+from nmigen.cli import main
+from nmigen.lib.cdc import ResetSynchronizer
+
+class PLL(Elaboratable):
+    def __init__(self, clkin, clksel=Signal(shape=2, reset=2), clkout1=Signal(), clkout2=Signal(), clkout3=Signal(), clkout4=Signal(), lock=Signal(), CLKI_DIV=1, CLKFB_DIV=1, CLK1_DIV=3, CLK2_DIV=4, CLK3_DIV=5, CLK4_DIV=6):
+        self.clkin = clkin
+        self.clkout1 = clkout1
+        self.clkout2 = clkout2
+        self.clkout3 = clkout3
+        self.clkout4 = clkout4
+        self.clksel = clksel
+        self.lock = lock
+        self.CLKI_DIV = CLKI_DIV
+        self.CLKFB_DIV = CLKFB_DIV
+        self.CLKOP_DIV = CLK1_DIV
+        self.CLKOS_DIV = CLK2_DIV
+        self.CLKOS2_DIV = CLK3_DIV
+        self.CLKOS3_DIV = CLK4_DIV
+        self.ports = [
+            self.clkin,
+            self.clkout1,
+            self.clkout2,
+            self.clkout3,
+            self.clkout4,
+            self.clksel,
+            self.lock,
+        ]
+
+    def elaborate(self, platform):
+        clkfb = Signal()
+        pll = Instance("EHXPLLL",
+                       p_PLLRST_ENA='DISABLED',
+                       p_INTFB_WAKE='DISABLED',
+                       p_STDBY_ENABLE='DISABLED',
+                       p_CLKOP_FPHASE=0,
+                       p_CLKOP_CPHASE=1,
+                       p_OUTDIVIDER_MUXA='DIVA',
+                       p_CLKOP_ENABLE='ENABLED',
+                       p_CLKOP_DIV=self.CLKOP_DIV,
+                       p_CLKOS_DIV=self.CLKOS_DIV,
+                       p_CLKOS2_DIV=self.CLKOS2_DIV,
+                       p_CLKOS3_DIV=self.CLKOS3_DIV,
+                       p_CLKFB_DIV=self.CLKFB_DIV,
+                       p_CLKI_DIV=self.CLKI_DIV,
+                       p_FEEDBK_PATH='CLKOP',
+                       #p_FREQUENCY_PIN_CLKOP='200',
+                       i_CLKI=self.clkin,
+                       #i_CLKFB=clkfb,
+                       i_RST=0,
+                       i_STDBY=0,
+                       i_PHASESEL0=0,
+                       i_PHASESEL1=0,
+                       i_PHASEDIR=0,
+                       i_PHASESTEP=0,
+                       i_PLLWAKESYNC=0,
+                       i_ENCLKOP=0,
+                       i_ENCLKOS=0,
+                       i_ENCLKOS2=0,
+                       i_ENCLKOS3=0,
+                       o_CLKOP=self.clkout1,
+                       o_CLKOS=self.clkout2,
+                       o_CLKOS2=self.clkout3,
+                       o_CLKOS3=self.clkout4,
+                       o_LOCK=self.lock,
+                       )
+        m = Module()
+        m.submodules += pll
+        with m.If(self.clksel == 0):
+            m.d.comb += clkfb.eq(self.clkout1)
+        with m.Elif(self.clksel == 1):
+            m.d.comb += clkfb.eq(self.clkout2)
+        with m.Elif(self.clksel == 2):
+            m.d.comb += clkfb.eq(self.clkout3)
+        with m.Else():
+            m.d.comb += clkfb.eq(self.clkout4)
+        return m
+
+
+class ECPIX5CRG(Elaboratable):
+    def __init__(self):
+        self.clkin = Signal()
+
+    def elaborate(self, platform):
+        m = Module()
+
+        # Get 100Mhz from oscillator
+        cd_rawclk = ClockDomain("rawclk", local=True, reset_less=True)
+        m.d.comb += cd_rawclk.clk.eq(self.clkin)
+        m.domains += cd_rawclk
+
+        # Power-on delay (655us)
+        podcnt = Signal(16, reset=2**16-1)
+        pod_done = Signal()
+        with m.If(podcnt != 0):
+            m.d.rawclk += podcnt.eq(podcnt-1)
+        m.d.comb += pod_done.eq(podcnt == 0)
+
+        # Generating sync2x (200Mhz) and init (25Mhz) from clk100
+        cd_sync2x = ClockDomain("sync2x", local=False)
+        cd_sync2x_unbuf = ClockDomain("sync2x_unbuf", local=True, reset_less=True)
+        cd_init = ClockDomain("init", local=False)
+        cd_sync = ClockDomain("sync", local=False, reset_less=True)
+        cd_dramsync = ClockDomain("dramsync", local=False)
+        m.submodules.pll = pll = PLL(ClockSignal("rawclk"), CLKI_DIV=1, CLKFB_DIV=2, CLK1_DIV=2, CLK2_DIV=16, CLK3_DIV=4,
+            clkout1=ClockSignal("sync2x_unbuf"), clkout2=ClockSignal("init"))
+        m.submodules += Instance("ECLKSYNCB",
+                i_ECLKI = ClockSignal("sync2x_unbuf"),
+                i_STOP  = 0,
+                o_ECLKO = ClockSignal("sync2x"))
+        m.domains += cd_sync2x_unbuf
+        m.domains += cd_sync2x
+        m.domains += cd_init
+        m.domains += cd_sync
+        m.domains += cd_dramsync
+        m.d.comb += ResetSignal("init").eq(~pll.lock|~pod_done)
+        m.d.comb += ResetSignal("dramsync").eq(~pll.lock|~pod_done)
+
+        # Generating sync (100Mhz) from sync2x
+        
+        m.submodules += Instance("CLKDIVF",
+            p_DIV="2.0",
+            i_ALIGNWD=0,
+            i_CLKI=ClockSignal("sync2x"),
+            i_RST=0,
+            o_CDIVX=ClockSignal("sync"))
+        m.d.comb += ClockSignal("dramsync").eq(ClockSignal("sync"))
+
+        return m
+
+class SimCRGTop(Elaboratable):
+    def __init__(self):
+        self.clkin = Signal()
+
+        self.sync2x = Signal()
+        self.sync = Signal()
+        self.dramsync = Signal()
+        self.init = Signal()
+
+    def elaborate(self, platform):
+        m = Module()
+
+        m.submodules.crg = crg = ECPIX5CRG()
+        m.d.comb += [
+            crg.clkin.eq(self.clkin),
+            self.sync2x.eq(ClockSignal("sync2x")),
+            self.sync.eq(ClockSignal("sync")),
+            self.dramsync.eq(ClockSignal("dramsync")),
+            self.init.eq(ClockSignal("init")),
+        ]
+
+        return m
+
+
+if __name__ == "__main__":
+    top = SimCRGTop()
+    main(top, name="simcrgtop", ports=[top.clkin, top.sync, top.sync2x, top.dramsync, top.init])
diff --git a/gram/simulation/simcrgtb.v b/gram/simulation/simcrgtb.v
new file mode 100644 (file)
index 0000000..5e37736
--- /dev/null
@@ -0,0 +1,48 @@
+// This file is Copyright (c) 2020 LambdaConcept <contact@lambdaconcept.com>
+
+`timescale 1 ns / 10 fs
+
+module top;
+  // GSR & PUR init requires for Lattice models
+  GSR GSR_INST (
+    .GSR(1'b0)
+  );
+  PUR PUR_INST (
+    .PUR (1'b0)
+  );
+
+  reg clkin;
+  wire sync;
+  wire sync2x;
+  wire dramsync;
+  wire init;
+
+  // Generate 100 Mhz clock
+  always 
+  begin
+    clkin = 1'b1; 
+    #5;
+    clkin = 1'b0;
+    #5;
+  end
+  
+  simcrgtop simcrgtop (
+    .clkin(clkin),
+    .sync(sync),
+    .sync2x(sync2x),
+    .dramsync(dramsync),
+    .init(init)
+  );
+
+  initial
+  begin
+    $dumpfile("simcrg.vcd");
+    $dumpvars(0, clkin);
+    $dumpvars(0, sync);
+    $dumpvars(0, sync2x);
+    $dumpvars(0, dramsync);
+    $dumpvars(0, init);
+
+    #10000 $finish;
+  end
+endmodule