Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Import Libre-SOC/Raptor Computing System patches #55

Open
wants to merge 47 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
8401717
fix ECP5DDRPHY cs declaration
Feb 16, 2022
e1f067d
fix gram unit test imports
Feb 19, 2022
ce19ad0
add name to DFI Interface (helps gtkwave traces)
Feb 20, 2022
8f91ce4
add dfii submodules so they get explicit names
Feb 20, 2022
8a966e2
add a debug verilog dump of one of the FakePHY SocTest cases
Feb 21, 2022
059639b
add debug print statements to investigate FakePHY
Feb 21, 2022
8610c6e
remove continue/skip and add comment that all
Feb 22, 2022
44ff21c
add CSRs to FakePHY which allows at least testing of firmware as-is
Feb 24, 2022
e9a4f8b
replace the simulation Clock-Reset-Generator with one that is more ge…
Feb 24, 2022
391fdaa
add a BitSlip module
Feb 24, 2022
b5553cc
allow DDR3 reset (rst) signal to be controlled by DFI commands,
Feb 25, 2022
aa34bd0
set name of DFI interface to ecp5phy in ECP5DDRPHY
Feb 25, 2022
2d03876
restore naming convention "cs_r" on DFI Interface
Feb 25, 2022
3b6f611
get chipselect (cs_n) name right in ECP5DDRPHY
Feb 25, 2022
67f6ece
add missing reset-HI values to cas_n, cs_n, we_n and act_n
Feb 26, 2022
65fd652
use dict for lookup of DFI to pads names
Feb 26, 2022
01df3a4
remove unneeded import
Feb 28, 2022
d20b197
fix up simulation to be more like VERSA_ECP5
Mar 1, 2022
7dcba5b
code-cleanup and copyright notices
Mar 10, 2022
08f04d1
tidy up gramWishbone constructor, pass Wishbone features to bus
Mar 10, 2022
180026c
tidyup on gramWishbone class, add comments
Mar 10, 2022
41c51d7
annoyingly reverting reset_n naming back to reset
Mar 11, 2022
0107a36
add a 2nd clock, this one deliberately the
Mar 11, 2022
b1b115d
add 1024M_ddr3_parameters.vh for MT41K64M16
Mar 13, 2022
3e49966
add alternative variant of runsimsoc.sh
Mar 17, 2022
7f70b44
initialise bitslip with a specific value rather than an incrementor
Mar 17, 2022
6b41f65
Add initial support for external DRAM init on the Raptor Versa ECP5-8…
Apr 7, 2022
ca3e97f
Properly connect reset and cs signals
Apr 7, 2022
03e79da
Partially revert GIT hash 180026c72f0e1d3ef365b2214288d4a543a238dd
Apr 7, 2022
c95ea6e
Switch CRG back over to ECP5 version
Apr 7, 2022
f0d0337
Working at 50MHz system clock
Apr 7, 2022
725400f
Backport litedram 05ed5bf59d31029d3f91c5a348cdd539a150631b
Apr 7, 2022
ffdcef6
Re-apply part of 180026c72f0e1d3ef365b2214288d4a543a238dd
Apr 7, 2022
7cb3e51
Wire up missing CRG / DDR3 clock control / reset signals
Apr 9, 2022
11d7297
Avoid timing violation on ECP5 PHY PAUSE signal
Apr 9, 2022
689c871
Revert "Avoid timing violation on ECP5 PHY PAUSE signal"
Apr 9, 2022
6b7e293
Avoid timing violation on ECP5 PHY PAUSE signal
Apr 9, 2022
423fdc3
Put sysclk2x back under system reset control
Apr 10, 2022
8f6a40b
Don't reset the core / peripherals on DRAM controller reset request
Apr 10, 2022
dedba09
whilst IOpads and PLLs were driving from dramsync, they were *not*
Apr 14, 2022
1765baa
connect (new) reset signal on IOPads which comes from the nmigen Pin.
Apr 15, 2022
aa538b6
fix reset to be xdr=4x in ECP5DDRPHY
Apr 15, 2022
c2a19a5
remove pyvcd dependency, it is pulled in by nmigen anyway
Apr 15, 2022
dcb0693
Merge runsimsoc2.sh into runsimsoc.sh
cestrauss Jul 23, 2022
b33a894
Use DELAYG instead of DELAYF on Icarus simulation
cestrauss Jul 23, 2022
2818912
Do not invert DDR3 CS pin on Icarus testbench
cestrauss Jul 23, 2022
60ec195
Remove unused Minerva CPU import from headless examples
cestrauss Jul 23, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
Unless otherwise noted, Gram is Copyright 2020 / LambdaConcept
ECP5 DDR3 fixes and extensions Copyright 2022 Raptor Engineering, LLC

Initial development is based on MiSoC's LASMICON / Copyright 2007-2016 / M-Labs
LiteDRAM / Copyright 2012-2018 / EnjoyDigital
Expand Down
261 changes: 261 additions & 0 deletions examples/ecp5_crg.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,261 @@
# Copyright (c) 2020 LambdaConcept <[email protected]>
# Copyright (c) 2021 Luke Kenneth Casson Leighton <[email protected]>
# Copyright (c) 2018-2020 Florent Kermarrec <[email protected]>
# Copyright (c) 2019 Michael Betz <[email protected]>
#
# Based on code from LambaConcept, from the gram example which is BSD-2-License
# https://github.com/jeanthom/gram/tree/master/examples
#
# Modifications for the Libre-SOC Project funded by NLnet and NGI POINTER
# under EU Grants 871528 and 957073, under the LGPLv3+ License


from nmigen import (Elaboratable, Module, Signal, ClockDomain, Instance,
ClockSignal, ResetSignal, Const)

__all__ = ["ECP5CRG"]


class PLL(Elaboratable):
nclkouts_max = 3
clki_div_range = (1, 128+1)
clkfb_div_range = (1, 128+1)
clko_div_range = (1, 128+1)
clki_freq_range = ( 8e6, 400e6)
clko_freq_range = (3.125e6, 400e6)
vco_freq_range = ( 400e6, 800e6)

def __init__(self, clkin,
clksel=Signal(shape=2, reset=2),
reset=Signal(reset_less=True),
locked=Signal()):
self.clkin = clkin
self.clkin_freq = None
self.clksel = clksel
self.locked = locked
self.reset = reset
self.nclkouts = 0
self.clkouts = {}
self.config = {}
self.params = {}

def ports(self):
return [
self.clkin,
self.clksel,
self.lock,
] + list(self.clkouts.values())

def set_clkin_freq(self, freq):
(clki_freq_min, clki_freq_max) = self.clki_freq_range
assert freq >= clki_freq_min
assert freq <= clki_freq_max
self.clkin_freq = freq

def create_clkout(self, cd, freq, phase=0, margin=1e-2):
(clko_freq_min, clko_freq_max) = self.clko_freq_range
assert freq >= clko_freq_min
assert freq <= clko_freq_max
assert self.nclkouts < self.nclkouts_max
self.clkouts[self.nclkouts] = (cd, freq, phase, margin)
#create_clkout_log(self.logger, cd.name, freq, margin, self.nclkouts)
print("clock domain", cd.domain, freq, margin, self.nclkouts)
self.nclkouts += 1

def compute_config(self):
config = {}
for clki_div in range(*self.clki_div_range):
config["clki_div"] = clki_div
for clkfb_div in range(*self.clkfb_div_range):
all_valid = True
vco_freq = self.clkin_freq/clki_div*clkfb_div*1 # clkos3_div=1
(vco_freq_min, vco_freq_max) = self.vco_freq_range
if vco_freq >= vco_freq_min and vco_freq <= vco_freq_max:
for n, (clk, f, p, m) in sorted(self.clkouts.items()):
valid = False
for d in range(*self.clko_div_range):
clk_freq = vco_freq/d
if abs(clk_freq - f) <= f*m:
config["clko{}_freq".format(n)] = clk_freq
config["clko{}_div".format(n)] = d
config["clko{}_phase".format(n)] = p
valid = True
break
if not valid:
all_valid = False
else:
all_valid = False
if all_valid:
config["vco"] = vco_freq
config["clkfb_div"] = clkfb_div
#compute_config_log(self.logger, config)
print ("PLL config", config)
return config
raise ValueError("No PLL config found")

def elaborate(self, platform):
config = self.compute_config()
clkfb = Signal()
self.params.update(
# attributes
a_FREQUENCY_PIN_CLKI = str(self.clkin_freq/1e6),
a_ICP_CURRENT = "6",
a_LPF_RESISTOR = "16",
a_MFG_ENABLE_FILTEROPAMP = "1",
a_MFG_GMCREF_SEL = "2",
# parameters
p_FEEDBK_PATH = "INT_OS3", # CLKOS3 rsvd for feedback with div=1.
p_CLKOS3_ENABLE = "ENABLED",
p_CLKOS3_DIV = 1,
p_CLKFB_DIV = config["clkfb_div"],
p_CLKI_DIV = config["clki_div"],
# reset, input clock, lock-achieved output
i_RST = self.reset,
i_CLKI = self.clkin,
o_LOCK = self.locked,
)
# for each clock-out, set additional parameters
for n, (clk, f, p, m) in sorted(self.clkouts.items()):
n_to_l = {0: "P", 1: "S", 2: "S2"}
div = config["clko{}_div".format(n)]
cphase = int(p*(div + 1)/360 + div)
self.params["p_CLKO{}_ENABLE".format(n_to_l[n])] = "ENABLED"
self.params["p_CLKO{}_DIV".format(n_to_l[n])] = div
self.params["p_CLKO{}_FPHASE".format(n_to_l[n])] = 0
self.params["p_CLKO{}_CPHASE".format(n_to_l[n])] = cphase
self.params["o_CLKO{}".format(n_to_l[n])] = clk

m = Module()
print ("params", self.params)
pll = Instance("EHXPLLL", **self.params)
m.submodules.pll = pll
return m

pll = Instance("EHXPLLL",
p_OUTDIVIDER_MUXA='DIVA',
p_OUTDIVIDER_MUXB='DIVB',
p_CLKOP_ENABLE='ENABLED',
p_CLKOS_ENABLE='ENABLED',
p_CLKOS2_ENABLE='DISABLED',
p_CLKOS3_ENABLE='DISABLED',
p_CLKOP_DIV=self.CLKOP_DIV,
p_CLKOS_DIV=self.CLKOS_DIV,
p_CLKFB_DIV=self.CLKFB_DIV,
p_CLKI_DIV=self.CLKI_DIV,
p_FEEDBK_PATH='INT_OP',
p_CLKOP_TRIM_POL="FALLING",
p_CLKOP_TRIM_DELAY=0,
p_CLKOS_TRIM_POL="FALLING",
p_CLKOS_TRIM_DELAY=0,
i_CLKI=self.clkin,
i_RST=0,
i_STDBY=0,
i_PHASESEL0=0,
i_PHASESEL1=0,
i_PHASEDIR=0,
i_PHASESTEP=0,
i_PHASELOADREG=0,
i_PLLWAKESYNC=0,
i_ENCLKOP=1,
i_ENCLKOS=1,
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,
)


class ECP5CRG(Elaboratable):
def __init__(self, sys_clk_freq=100e6, pod_bits=16):
self.sys_clk_freq = sys_clk_freq
self.pod_bits = pod_bits

# DDR clock control signals
self.ddr_clk_stop = Signal()
self.ddr_clk_reset = Signal()

def elaborate(self, platform):
m = Module()

# Get 100Mhz from oscillator
extclk = platform.request(platform.default_clk)
cd_rawclk = ClockDomain("rawclk", local=True, reset_less=True)
m.d.comb += cd_rawclk.clk.eq(extclk)
m.domains += cd_rawclk

# Reset
if platform.default_rst is not None:
reset = platform.request(platform.default_rst).i
else:
reset = Const(0) # whoops

gsr0 = Signal()
gsr1 = Signal()

m.submodules += [
Instance("FD1S3AX", p_GSR="DISABLED",
i_CK=ClockSignal("rawclk"),
i_D=~reset,
o_Q=gsr0),
Instance("FD1S3AX", p_GSR="DISABLED",
i_CK=ClockSignal("rawclk"),
i_D=gsr0,
o_Q=gsr1),
Instance("SGSR", i_CLK=ClockSignal("rawclk"),
i_GSR=gsr1),
]

# Power-on delay
podcnt = Signal(self.pod_bits, reset=-1)
pod_done = Signal()
with m.If(podcnt != 0):
m.d.rawclk += podcnt.eq(podcnt-1)
m.d.rawclk += pod_done.eq(podcnt == 0)

# PLL
m.submodules.pll = pll = PLL(ClockSignal("rawclk"), reset=~pod_done|~reset)

# Generating sync2x (200Mhz) and init (25Mhz) from extclk
cd_sync2x = ClockDomain("sync2x", local=False)
cd_sync2x_unbuf = ClockDomain("sync2x_unbuf",
local=False, reset_less=True)
cd_init = ClockDomain("init", local=False)
cd_sync = ClockDomain("sync", local=False)
cd_dramsync = ClockDomain("dramsync", local=False)

# create PLL clocks
pll.set_clkin_freq(platform.default_clk_frequency)
pll.create_clkout(ClockSignal("sync2x_unbuf"), 2*self.sys_clk_freq)
pll.create_clkout(ClockSignal("init"), 25e6)
m.submodules += Instance("ECLKSYNCB",
i_ECLKI = ClockSignal("sync2x_unbuf"),
i_STOP = self.ddr_clk_stop,
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
reset_ok = Signal(reset_less=True)
m.d.comb += reset_ok.eq(~pll.locked|~pod_done)
m.d.comb += ResetSignal("init").eq(reset_ok)
m.d.comb += ResetSignal("sync").eq(reset_ok)
m.d.comb += ResetSignal("dramsync").eq(reset_ok|self.ddr_clk_reset)

# # Generating sync (100Mhz) from sync2x

m.submodules += Instance("CLKDIVF",
p_DIV="2.0",
i_ALIGNWD=0,
i_CLKI=ClockSignal("sync2x"),
i_RST=ResetSignal("dramsync"),
o_CDIVX=ClockSignal("sync"))

# temporarily set dram sync clock exactly equal to main sync
m.d.comb += ClockSignal("dramsync").eq(ClockSignal("sync"))

return m

1 change: 0 additions & 1 deletion examples/headless-ecpix5.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
from nmigen.lib.cdc import ResetSynchronizer
from nmigen_soc import wishbone, memory

from lambdasoc.cpu.minerva import MinervaCPU
from lambdasoc.periph.intc import GenericInterruptController
from lambdasoc.periph.serial import AsyncSerialPeripheral
from lambdasoc.periph.sram import SRAMPeripheral
Expand Down
94 changes: 94 additions & 0 deletions examples/headless-versa-85.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# This file is Copyright (c) 2020 LambdaConcept <[email protected]>
# This file is Copyright (c) 2022 Raptor Engineering, LLC <[email protected]>

from nmigen import *
from nmigen.lib.cdc import ResetSynchronizer
from nmigen_soc import wishbone, memory

from lambdasoc.periph.intc import GenericInterruptController
from lambdasoc.periph.serial import AsyncSerialPeripheral
from lambdasoc.periph.sram import SRAMPeripheral
from lambdasoc.periph.timer import TimerPeripheral
from lambdasoc.periph import Peripheral
from lambdasoc.soc.base import SoC

from gram.core import gramCore
from gram.phy.ecp5ddrphy import ECP5DDRPHY
from gram.modules import MT41K64M16
from gram.frontend.wishbone import gramWishbone

from nmigen_boards.versa_ecp5 import VersaECP5Platform85
from ecp5_crg import ECP5CRG
#from crg import ECPIX5CRG
from uartbridge import UARTBridge
from crg import *

class DDR3SoC(SoC, Elaboratable):
def __init__(self, *,
ddrphy_addr, dramcore_addr,
ddr_addr):
self._decoder = wishbone.Decoder(addr_width=30, data_width=32, granularity=8,
features={"cti", "bte"})

#desired_sys_clk_freq = 100e6
#desired_sys_clk_freq = 90e6
#desired_sys_clk_freq = 75e6
#desired_sys_clk_freq = 70e6
#desired_sys_clk_freq = 65e6
#desired_sys_clk_freq = 60e6
#desired_sys_clk_freq = 55e6
desired_sys_clk_freq = 50e6

#self.crg = ECPIX5CRG()
self.crg = ECP5CRG(sys_clk_freq=desired_sys_clk_freq)

self.ub = UARTBridge(divisor=int(desired_sys_clk_freq/115200), pins=platform.request("uart", 0))

ddr_pins = platform.request("ddr3", 0, dir={"dq":"-", "dqs":"-"},
xdr={"clk":4, "a":4, "ba":4, "clk_en":4, "odt":4, "ras":4, "cas":4, "we":4, "cs":4, "rst":1})
self.ddrphy = DomainRenamer("dramsync")(ECP5DDRPHY(ddr_pins))
self._decoder.add(self.ddrphy.bus, addr=ddrphy_addr)

ddrmodule = MT41K64M16(self.crg.sys_clk_freq, "1:2")

self.dramcore = DomainRenamer("dramsync")(gramCore(
phy=self.ddrphy,
geom_settings=ddrmodule.geom_settings,
timing_settings=ddrmodule.timing_settings,
clk_freq=self.crg.sys_clk_freq))
self._decoder.add(self.dramcore.bus, addr=dramcore_addr)

self.drambone = DomainRenamer("dramsync")(gramWishbone(self.dramcore))
self._decoder.add(self.drambone.bus, addr=ddr_addr)

self.memory_map = self._decoder.bus.memory_map

self.clk_freq = self.crg.sys_clk_freq

def elaborate(self, platform):
m = Module()

m.submodules.sysclk = self.crg

m.submodules.ub = self.ub

m.submodules.decoder = self._decoder
m.submodules.ddrphy = self.ddrphy
m.submodules.dramcore = self.dramcore
m.submodules.drambone = self.drambone

m.d.comb += [
self.ub.bus.connect(self._decoder.bus),
]

return m


if __name__ == "__main__":
platform = VersaECP5Platform85()

soc = DDR3SoC(ddrphy_addr=0x00008000, dramcore_addr=0x00009000,
ddr_addr=0x10000000)

soc.build(do_build=True)
platform.build(soc, do_program=True)
Loading