From: Jean THOMAS Date: Thu, 25 Jun 2020 19:00:20 +0000 (+0200) Subject: Add simulation code X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=0c6d000f65ed15929ffb475667605c43b3baab54;p=gram.git Add simulation code --- diff --git a/gram/simulation/README.md b/gram/simulation/README.md new file mode 100644 index 0000000..fa300c7 --- /dev/null +++ b/gram/simulation/README.md @@ -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 index 0000000..226f409 --- /dev/null +++ b/gram/simulation/runsimcrg.sh @@ -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 index 0000000..400d479 --- /dev/null +++ b/gram/simulation/simcrg.py @@ -0,0 +1,159 @@ +# This file is Copyright (c) 2020 LambdaConcept + +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 index 0000000..5e37736 --- /dev/null +++ b/gram/simulation/simcrgtb.v @@ -0,0 +1,48 @@ +// This file is Copyright (c) 2020 LambdaConcept + +`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