Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: whitequark/glasgow
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: f33381734fbf
Choose a base ref
...
head repository: whitequark/glasgow
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 38eac301eb38
Choose a head ref
  • 3 commits
  • 6 files changed
  • 1 contributor

Commits on Dec 1, 2018

  1. Copy the full SHA
    de0d5cf View commit details
  2. Copy the full SHA
    eefae85 View commit details
  3. Copy the full SHA
    38eac30 View commit details
5 changes: 5 additions & 0 deletions software/glasgow/cli.py
Original file line number Diff line number Diff line change
@@ -16,6 +16,7 @@
from .device import GlasgowDeviceError
from .device.config import GlasgowConfig
from .target.hardware import GlasgowHardwareTarget
from .gateware import GatewareBuildError
from .gateware.analyzer import TraceDecoder
from .device.hardware import VID_QIHW, PID_GLASGOW, GlasgowHardwareDevice
from .access.direct import *
@@ -643,6 +644,10 @@ def startTest(test):
logger.error(e)
return 1

except GatewareBuildError as e:
applet.logger.error(e)
return 1

return 0


6 changes: 5 additions & 1 deletion software/glasgow/gateware/__init__.py
Original file line number Diff line number Diff line change
@@ -2,7 +2,11 @@
from migen import *


__all__ = ["simulation_test"]
__all__ = ["GatewareBuildError", "simulation_test"]


class GatewareBuildError(Exception):
pass


def simulation_test(case=None, **kwargs):
Empty file.
110 changes: 110 additions & 0 deletions software/glasgow/gateware/platform/lattice.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
from migen import *

from .. import GatewareBuildError
from ..pll import PLL


class LatticeiCE40PLL:
@staticmethod
def lower(dr):
return LatticeiCE40PLLImpl(dr, simple_feedback=True)


class LatticeiCE40PLLImpl(Module):
def __init__(self, pll, simple_feedback):
if not 10e6 <= pll.f_in <= 133e6:
pll.logger.error("PLL: f_in (%.3f MHz) must be between 10 and 133 MHz",
pll.f_in / 1e6)
raise GatewareBuildError("PLL f_in out of range")

if not 16e6 <= pll.f_out <= 275e6:
pll.logger.error("PLL: f_out (%.3f MHz) must be between 16 and 275 MHz",
pll.f_out / 1e6)
raise GatewareBuildError("PLL f_out out of range")

# The documentation in the iCE40 PLL Usage Guide incorrectly lists the
# maximum value of DIVF as 63, when it is only limited to 63 when using
# feedback modes other that SIMPLE.
if simple_feedback:
divf_max = 128
else:
divf_max = 64

variants = []
for divr in range(0, 16):
f_pfd = pll.f_in / (divr + 1)
if not 10e6 <= f_pfd <= 133e6:
continue

for divf in range(0, divf_max):
if simple_feedback:
f_vco = f_pfd * (divf + 1)
if not 533e6 <= f_vco <= 1066e6:
continue

for divq in range(1, 7):
f_out = f_vco * (2 ** -divq)
variants.append((divr, divf, divq, f_pfd, f_out))

else:
for divq in range(1, 7):
f_vco = f_pfd * (divf + 1) * (2 ** divq)
if not 533e6 <= f_vco <= 1066e6:
continue

f_out = f_vco * (2 ** -divq)
variants.append((divr, divf, divq, f_pfd, f_out))

if not variants:
pll.logger.error("PLL: f_in (%.3f MHz) to f_out (%.3f) constraints not satisfiable",
pll.f_in / 1e6, pll.f_out / 1e6)
raise GatewareBuildError("PLL f_in/f_out out of range")

def f_out_diff(variant):
*_, f_out = variant
return abs(f_out - pll.f_out)
divr, divf, divq, f_pfd, f_out = min(variants, key=f_out_diff)

if f_pfd < 17:
filter_range = 1
elif f_pfd < 26:
filter_range = 2
elif f_pfd < 44:
filter_range = 3
elif f_pfd < 66:
filter_range = 4
elif f_pfd < 101:
filter_range = 5
else:
filter_range = 6

if simple_feedback:
feedback_path = "SIMPLE"
else:
feedback_path = "NON_SIMPLE"

ppm = abs(pll.f_out - f_out) / pll.f_out * 1e6

pll.logger.debug("PLL: f_in=%.3f f_out(req)=%.3f f_out(act)=%.3f [MHz] ppm=%d",
pll.f_in / 1e6, pll.f_out / 1e6, f_out / 1e6, ppm)
pll.logger.trace("iCE40 PLL: feedback_path=%s divr=%d divf=%d divq=%d filter_range=%d",
feedback_path, divr, divf, divq, filter_range)

self.specials += \
Instance("SB_PLL40_CORE",
p_FEEDBACK_PATH=feedback_path,
p_PLLOUT_SELECT="GENCLK",
p_DIVR=divr,
p_DIVF=divf,
p_DIVQ=divq,
p_FILTER_RANGE=filter_range,
i_REFERENCECLK=ClockSignal(pll.idomain),
o_PLLOUTCORE=ClockSignal(pll.odomain),
i_RESETB=~ResetSignal(pll.idomain),
i_BYPASS=0,
)


special_overrides = {
PLL: LatticeiCE40PLL
}
24 changes: 24 additions & 0 deletions software/glasgow/gateware/pll.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import logging
from migen.fhdl.specials import Special


__all__ = ["PLL"]


class PLL(Special):
def __init__(self, f_in, f_out, odomain, idomain="sys", logger=None):
super().__init__()
self.logger = logger or logging.getLogger(__name__)
self.f_in = float(f_in)
self.f_out = float(f_out)
self.odomain = odomain
self.idomain = idomain

def rename_clock_domain(self, old, new):
if self.idomain == old:
self.idomain = new
if self.odomain == old:
self.odomain = new

def list_clock_domains(self):
return {self.idomain, self.odomain}
11 changes: 8 additions & 3 deletions software/glasgow/target/hardware.py
Original file line number Diff line number Diff line change
@@ -3,19 +3,24 @@
import sys
import tempfile
import shutil
import logging
from migen import *

from ..gateware.pads import Pads
from ..gateware.i2c import I2CSlave
from ..gateware.registers import I2CRegisters
from ..gateware.fx2 import FX2Arbiter
from ..gateware.platform.lattice import special_overrides
from ..platform import GlasgowPlatform
from .analyzer import GlasgowAnalyzer


__all__ = ["GlasgowHardwareTarget"]


logger = logging.getLogger(__name__)


class _CRG(Module):
def __init__(self, platform):
self.clock_domains.cd_por = ClockDomain(reset_less=True)
@@ -93,10 +98,10 @@ def get_fragment(self):
return super().get_fragment()

def build(self, **kwargs):
self.platform.build(self, **kwargs)
self.platform.build(self, special_overrides=special_overrides, **kwargs)

def get_verilog(self, **kwargs):
return self.platform.get_verilog(self)
return self.platform.get_verilog(self, special_overrides=special_overrides)

def get_bitstream_id(self, **kwargs):
verilog = str(self.get_verilog(**kwargs))
@@ -113,7 +118,7 @@ def get_bitstream(self, build_dir=None, debug=False, **kwargs):
shutil.rmtree(build_dir)
except:
if debug:
print("Keeping build tree as " + build_dir, file=sys.stderr)
logger.info("keeping build tree as %s", build_dir)
raise
finally:
if not debug: