Add fast-servo linien gateware #37
1
.gitignore
vendored
@ -1 +1,2 @@
|
||||
__pycache__
|
||||
result
|
38
fast-servo/linien-fast-servo-gateware.patch
Normal file
@ -0,0 +1,38 @@
|
||||
# diff from elhep/Fast-Servo-Firmmware commit ID 7fae40c:
|
||||
# https://github.com/elhep/Fast-Servo-Firmware/commit/7fae40c0f872a91218be378f8289b98b1e366729
|
||||
|
||||
# Fix for migen add_source deprecation and removed xilinx bootgen command
|
||||
# .bin file is being generated by bit2bin.py from Linien repository
|
||||
# https://github.com/linien-org/linien/blob/master/gateware/bit2bin.py
|
||||
|
||||
diff --git a/fast_servo/gateware/fast_servo_platform.py b/fast_servo/gateware/fast_servo_platform.py
|
||||
index 13b4aa3..89a8103 100644
|
||||
--- a/fast_servo/gateware/fast_servo_platform.py
|
||||
+++ b/fast_servo/gateware/fast_servo_platform.py
|
||||
@@ -324,7 +324,12 @@ class Platform(XilinxPlatform):
|
||||
self.ps7_config = ps7_config
|
||||
|
||||
verilog_sources = os.listdir(verilog_dir)
|
||||
- self.add_sources(verilog_dir, *verilog_sources)
|
||||
+ self.add_source_dir(verilog_dir)
|
||||
+
|
||||
+ def build(self, *args, **kwargs):
|
||||
+ build_dir = kwargs.get('build_dir', 'build')
|
||||
+ self.copy_sources(build_dir)
|
||||
+ super().build(*args, **kwargs)
|
||||
|
||||
def do_finalize(self, fragment):
|
||||
try:
|
||||
diff --git a/fast_servo/gateware/fast_servo_soc.py b/fast_servo/gateware/fast_servo_soc.py
|
||||
index 02128f5..abfc583 100644
|
||||
--- a/fast_servo/gateware/fast_servo_soc.py
|
||||
+++ b/fast_servo/gateware/fast_servo_soc.py
|
||||
@@ -282,9 +282,3 @@ if __name__ == "__main__":
|
||||
os.chdir(os.path.join(root_path, build_dir))
|
||||
with open(f"{build_name}.bif", "w") as f:
|
||||
f.write(f"all:\n{{\n\t{build_name}.bit\n}}")
|
||||
-
|
||||
- cmd = f"bootgen -image {build_name}.bif -arch zynq -process_bitstream bin -w on".split(" ")
|
||||
- subprocess.run(cmd)
|
||||
-
|
||||
-
|
||||
-
|
603
fast-servo/linien-fast-servo-server.patch
Normal file
@ -0,0 +1,603 @@
|
||||
# diff between linen-org/linien commit ID 93f1f50:
|
||||
# https://github.com/linien-org/linien/commit/93f1f50ebd86fe3314cab5a549462d0fcbf6a658
|
||||
# and elhep/linien commit ID b73eea0:
|
||||
# https://github.com/elhep/linien/commit/b73eea07889dda8b55f0cf4c2afde96cf4c3efd1
|
||||
|
||||
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
|
||||
index b3f3683..98c6e51 100644
|
||||
--- a/.pre-commit-config.yaml
|
||||
+++ b/.pre-commit-config.yaml
|
||||
@@ -3,7 +3,7 @@ repos:
|
||||
rev: 23.11.0
|
||||
hooks:
|
||||
- id: black
|
||||
- exclude: ^(gateware/logic/|gateware/lowlevel/|gateware/linien_module.py|linien-server/linien_server/csrmap.py)
|
||||
+ exclude: ^(gateware/logic/|gateware/lowlevel/|gateware/linien_module.py|linien-server/linien_server/csrmap.py|gateware/targets)
|
||||
|
||||
- repo: https://github.com/pycqa/isort
|
||||
rev: 5.12.0
|
||||
diff --git a/gateware/build_fpga_image.sh b/gateware/build_fpga_image.sh
|
||||
index f822402..be7401c 100644
|
||||
--- a/gateware/build_fpga_image.sh
|
||||
+++ b/gateware/build_fpga_image.sh
|
||||
@@ -16,4 +16,9 @@ export PATH=$VIVADOPATH:$PATH
|
||||
fsagbuya marked this conversation as resolved
Outdated
sb10q
commented
? ?
sb10q
commented
I don't see a fast-servo-linien.patch in I don't see a fast-servo-linien.patch in https://github.com/elhep/linien/tree/b73eea07889dda8b55f0cf4c2afde96cf4c3efd1 so this looks like your mistake.
fsagbuya
commented
It seems I accidentally add that patch during test, apologies. Updated. It seems I accidentally add that patch during test, apologies. Updated.
|
||||
|
||||
rm linien-server/linien_server/gateware.bin -f
|
||||
# run with -m option to avoid errors related to relative imports without breaking pytest
|
||||
-python3 -m gateware.fpga_image_helper
|
||||
\ No newline at end of file
|
||||
+
|
||||
+if [ -z "$1" ]; then
|
||||
+ python3 -m gateware.fpga_image_helper
|
||||
+else
|
||||
+ python3 -m gateware.fpga_image_helper -p $1
|
||||
+fi
|
||||
\ No newline at end of file
|
||||
diff --git a/gateware/fpga_image_helper.py b/gateware/fpga_image_helper.py
|
||||
index 6c34429..a0b12d0 100644
|
||||
--- a/gateware/fpga_image_helper.py
|
||||
+++ b/gateware/fpga_image_helper.py
|
||||
@@ -1,5 +1,6 @@
|
||||
# Copyright 2014-2015 Robert Jördens <jordens@gmail.com>
|
||||
# Copyright 2018-2022 Benjamin Wiegand <benjamin.wiegand@physik.hu-berlin.de>
|
||||
+# Copyright 2023 Jakub Matyas <jakubk.m@gmail.com>
|
||||
#
|
||||
# This file is part of Linien and based on redpid.
|
||||
#
|
||||
@@ -23,14 +24,16 @@ from pathlib import Path
|
||||
REPO_ROOT_DIR = Path(__file__).resolve().parents[1]
|
||||
|
||||
from .bit2bin import bit2bin
|
||||
-from .hw_platform import Platform
|
||||
-from .linien_module import RootModule
|
||||
|
||||
|
||||
def py_csrconstants(map, fil):
|
||||
fil.write("csr_constants = {\n")
|
||||
- for k, v in root.linien.csrbanks.constants:
|
||||
- fil.write(" '{}_{}': {},\n".format(k, v.name, v.value.value))
|
||||
+ for k, v in root.csrbanks.constants:
|
||||
+ if k == "linien":
|
||||
+ # compaitbility layer
|
||||
+ fil.write(" '{}': {},\n".format(v.name, v.value.value))
|
||||
+ else:
|
||||
+ fil.write(" '{}_{}': {},\n".format(k, v.name, v.value.value))
|
||||
fil.write("}\n\n")
|
||||
|
||||
|
||||
@@ -52,26 +55,49 @@ def get_csrmap(banks):
|
||||
def py_csrmap(it, fil):
|
||||
fil.write("csr = {\n")
|
||||
for reg in it:
|
||||
- fil.write(" '{}_{}': ({}, 0x{:03x}, {}, {}),\n".format(*reg))
|
||||
+ main_name = reg[0]
|
||||
+ secondary_name = reg[1]
|
||||
+ # compaitbility layer
|
||||
+ if main_name == "linien" or secondary_name.startswith(main_name):
|
||||
+ fil.write(" '{}': ({}, 0x{:03x}, {}, {}),\n".format(*reg[1:]))
|
||||
+ else:
|
||||
+ fil.write(" '{}_{}': ({}, 0x{:03x}, {}, {}),\n".format(*reg))
|
||||
fil.write("}\n")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
- platform = Platform()
|
||||
- root = RootModule(platform)
|
||||
+ import argparse
|
||||
|
||||
+ parser = argparse.ArgumentParser()
|
||||
+ parser.add_argument("-p", "--platform", default=None)
|
||||
+ args = parser.parse_args()
|
||||
+ if args.platform is None or args.platform.lower() == "redpitaya":
|
||||
+ from gateware.hw_platform import Platform
|
||||
+ from gateware.targets.red_pitaya import PitayaSoC
|
||||
+
|
||||
+ platform = Platform()
|
||||
+ root = PitayaSoC(platform)
|
||||
+ elif args.platform.lower() == "fastservo":
|
||||
+ from fast_servo.gateware.fast_servo_platform import Platform
|
||||
+
|
||||
+ from gateware.targets.fast_servo import LinienFastServo
|
||||
+
|
||||
+ platform = Platform()
|
||||
+ root = LinienFastServo(platform)
|
||||
+ else:
|
||||
+ raise ValueError("Unknown platform")
|
||||
+
|
||||
+ platform.add_source_dir(REPO_ROOT_DIR / "gateware" / "verilog")
|
||||
+ build_dir = REPO_ROOT_DIR / "gateware" / "build"
|
||||
+ platform.build(root, build_name="top", build_dir=build_dir, run=True)
|
||||
with open(
|
||||
REPO_ROOT_DIR / "linien-server" / "linien_server" / "csrmap.py", "w"
|
||||
) as fil:
|
||||
- py_csrconstants(root.linien.csrbanks.constants, fil)
|
||||
- csr = get_csrmap(root.linien.csrbanks.banks)
|
||||
+ py_csrconstants(root.csrbanks.constants, fil)
|
||||
+ csr = get_csrmap([*root.csrbanks.banks, *root.linien.csrbanks.banks])
|
||||
py_csrmap(csr, fil)
|
||||
fil.write("states = {}\n".format(repr(root.linien.state_names)))
|
||||
fil.write("signals = {}\n".format(repr(root.linien.signal_names)))
|
||||
-
|
||||
- platform.add_source_dir(REPO_ROOT_DIR / "gateware" / "verilog")
|
||||
- build_dir = REPO_ROOT_DIR / "gateware" / "build"
|
||||
- platform.build(root, build_name="top", build_dir=build_dir)
|
||||
bit2bin(
|
||||
build_dir / "top.bit",
|
||||
REPO_ROOT_DIR / "linien-server" / "linien_server" / "gateware.bin",
|
||||
diff --git a/gateware/linien_module.py b/gateware/linien_module.py
|
||||
index 16ca186..6905ac0 100644
|
||||
--- a/gateware/linien_module.py
|
||||
+++ b/gateware/linien_module.py
|
||||
@@ -2,6 +2,7 @@
|
||||
# Copyright 2018-2022 Benjamin Wiegand <benjamin.wiegand@physik.hu-berlin.de>
|
||||
# Copyright 2021-2023 Bastian Leykauf <leykauf@physik.hu-berlin.de>
|
||||
# Copyright 2022 Christian Freier <christian.freier@nomadatomics.com>
|
||||
+# Copyright 2023 Jakub Matyas <jakubk.m@gmail.com>
|
||||
#
|
||||
# This file is part of Linien and based on redpid.
|
||||
#
|
||||
@@ -36,19 +37,13 @@ from misoc.interconnect.csr import AutoCSR, CSRStatus, CSRStorage
|
||||
from .logic.autolock import FPGAAutolock
|
||||
from .logic.chains import FastChain, SlowChain, cross_connect
|
||||
from .logic.decimation import Decimate
|
||||
-from .logic.delta_sigma import DeltaSigma
|
||||
from .logic.iir import Iir
|
||||
from .logic.limit import LimitCSR
|
||||
from .logic.modulate import Modulate
|
||||
from .logic.pid import PID
|
||||
from .logic.sweep import SweepCSR
|
||||
-from .lowlevel.analog import PitayaAnalog
|
||||
-from .lowlevel.crg import CRG
|
||||
-from .lowlevel.dna import DNA
|
||||
-from .lowlevel.gpio import Gpio
|
||||
-from .lowlevel.pitaya_ps import PitayaPS, Sys2CSR, SysCDC, SysInterconnect
|
||||
+from .lowlevel.pitaya_ps import Sys2CSR
|
||||
from .lowlevel.scopegen import ScopeGen
|
||||
-from .lowlevel.xadc import XADC
|
||||
|
||||
|
||||
class LinienLogic(Module, AutoCSR):
|
||||
@@ -156,45 +151,24 @@ class LinienLogic(Module, AutoCSR):
|
||||
|
||||
|
||||
class LinienModule(Module, AutoCSR):
|
||||
- def __init__(self, platform):
|
||||
+ def __init__(self, soc):
|
||||
width = 14
|
||||
signal_width = 25
|
||||
coeff_width = 25
|
||||
chain_factor_bits = 8
|
||||
|
||||
self.init_submodules(
|
||||
- width, signal_width, coeff_width, chain_factor_bits, platform
|
||||
+ width, signal_width, coeff_width, chain_factor_bits, soc
|
||||
)
|
||||
- self.connect_everything(width, signal_width, coeff_width, chain_factor_bits)
|
||||
+ self.connect_everything(width, signal_width, coeff_width, chain_factor_bits, soc)
|
||||
|
||||
def init_submodules(
|
||||
- self, width, signal_width, coeff_width, chain_factor_bits, platform
|
||||
+ self, width, signal_width, coeff_width, chain_factor_bits, soc
|
||||
):
|
||||
- sys_double = ClockDomainsRenamer("sys_double")
|
||||
|
||||
self.submodules.logic = LinienLogic(
|
||||
coeff_width=coeff_width, chain_factor_width=chain_factor_bits
|
||||
)
|
||||
- self.submodules.analog = PitayaAnalog(
|
||||
- platform.request("adc"), platform.request("dac")
|
||||
- )
|
||||
- self.submodules.xadc = XADC(platform.request("xadc"))
|
||||
-
|
||||
- for i in range(4):
|
||||
- pwm = platform.request("pwm", i)
|
||||
- ds = sys_double(DeltaSigma(width=15))
|
||||
- self.comb += pwm.eq(ds.out)
|
||||
- setattr(self.submodules, f"ds{i}", ds)
|
||||
-
|
||||
- exp = platform.request("exp")
|
||||
- self.submodules.gpio_n = Gpio(exp.n)
|
||||
- self.submodules.gpio_p = Gpio(exp.p)
|
||||
-
|
||||
- leds = Cat(*(platform.request("user_led", i) for i in range(8)))
|
||||
- self.comb += leds.eq(self.gpio_n.o)
|
||||
-
|
||||
- self.submodules.dna = DNA(version=2)
|
||||
-
|
||||
self.submodules.fast_a = FastChain(
|
||||
width,
|
||||
signal_width,
|
||||
@@ -210,18 +184,22 @@ class LinienModule(Module, AutoCSR):
|
||||
offset_signal=self.logic.chain_b_offset_signed,
|
||||
)
|
||||
|
||||
+ # FIXME: does it do anything?!
|
||||
_ = ClockDomainsRenamer("sys_slow")
|
||||
sys_double = ClockDomainsRenamer("sys_double")
|
||||
max_decimation = 16
|
||||
self.submodules.decimate = sys_double(Decimate(max_decimation))
|
||||
self.clock_domains.cd_decimated_clock = ClockDomain()
|
||||
decimated_clock = ClockDomainsRenamer("decimated_clock")
|
||||
+ # TODO: No support for slow Analog Out on Fast Servo
|
||||
self.submodules.slow_chain = decimated_clock(SlowChain())
|
||||
-
|
||||
self.submodules.scopegen = ScopeGen(signal_width)
|
||||
|
||||
+ soc.add_interconnect_slave(self.scopegen.scope_sys)
|
||||
+ soc.add_interconnect_slave(self.scopegen.asg_sys)
|
||||
+
|
||||
self.state_names, self.signal_names = cross_connect(
|
||||
- self.gpio_n,
|
||||
+ soc.gpio_n,
|
||||
[
|
||||
("fast_a", self.fast_a),
|
||||
("fast_b", self.fast_b),
|
||||
@@ -233,10 +211,6 @@ class LinienModule(Module, AutoCSR):
|
||||
)
|
||||
|
||||
csr_map = {
|
||||
- "dna": 28,
|
||||
- "xadc": 29,
|
||||
- "gpio_n": 30,
|
||||
- "gpio_p": 31,
|
||||
"fast_a": 0,
|
||||
"fast_b": 1,
|
||||
"slow_chain": 2,
|
||||
@@ -251,19 +225,13 @@ class LinienModule(Module, AutoCSR):
|
||||
name if mem is None else name + "_" + mem.name_override
|
||||
],
|
||||
)
|
||||
- self.submodules.sys2csr = Sys2CSR()
|
||||
- self.submodules.csrcon = csr_bus.Interconnect(
|
||||
- self.sys2csr.csr, self.csrbanks.get_buses()
|
||||
- )
|
||||
- self.submodules.syscdc = SysCDC()
|
||||
- self.comb += self.syscdc.target.connect(self.sys2csr.sys)
|
||||
|
||||
- def connect_everything(self, width, signal_width, coeff_width, chain_factor_bits):
|
||||
+ def connect_everything(self, width, signal_width, coeff_width, chain_factor_bits, soc):
|
||||
s = signal_width - width
|
||||
|
||||
self.comb += [
|
||||
- self.fast_a.adc.eq(self.analog.adc_a),
|
||||
- self.fast_b.adc.eq(self.analog.adc_b),
|
||||
+ self.fast_a.adc.eq(soc.analog.adc_a),
|
||||
+ self.fast_b.adc.eq(soc.analog.adc_b),
|
||||
]
|
||||
|
||||
# now, we combine the output of the two paths, with a variable factor each.
|
||||
@@ -297,7 +265,7 @@ class LinienModule(Module, AutoCSR):
|
||||
self.comb += [
|
||||
If(
|
||||
self.logic.pid_only_mode.storage,
|
||||
- self.logic.pid.input.eq(self.analog.adc_a << s),
|
||||
+ self.logic.pid.input.eq(soc.analog.adc_a << s),
|
||||
).Else(
|
||||
self.logic.pid.input.eq(mixed_limited),
|
||||
),
|
||||
@@ -347,40 +315,42 @@ class LinienModule(Module, AutoCSR):
|
||||
# ANALOG OUTPUTS ---------------------------------------------------------------
|
||||
# ANALOG OUT 0 gets a special treatment because it may contain signal of slow
|
||||
# pid or sweep
|
||||
- analog_out = Signal((width + 3, True))
|
||||
- self.comb += [
|
||||
- analog_out.eq(
|
||||
- Mux(
|
||||
- self.logic.sweep_channel.storage == OutputChannel.ANALOG_OUT0,
|
||||
- self.logic.sweep.y,
|
||||
- 0,
|
||||
- )
|
||||
- + Mux(
|
||||
- self.logic.sweep_channel.storage == OutputChannel.ANALOG_OUT0,
|
||||
- self.logic.out_offset_signed,
|
||||
- 0,
|
||||
- )
|
||||
- + Mux(
|
||||
- self.logic.slow_control_channel.storage
|
||||
+
|
||||
+ if soc.soc_name == "RedPitaya":
|
||||
+ analog_out = Signal((width + 3, True))
|
||||
+ self.comb += [
|
||||
+ analog_out.eq(
|
||||
+ Mux(
|
||||
+ self.logic.sweep_channel.storage == OutputChannel.ANALOG_OUT0,
|
||||
+ self.logic.sweep.y,
|
||||
+ 0,
|
||||
+ )
|
||||
+ + Mux(
|
||||
+ self.logic.sweep_channel.storage == OutputChannel.ANALOG_OUT0,
|
||||
+ self.logic.out_offset_signed,
|
||||
+ 0,
|
||||
+ )
|
||||
+ + Mux(
|
||||
+ self.logic.slow_control_channel.storage
|
||||
== OutputChannel.ANALOG_OUT0,
|
||||
self.slow_chain.output,
|
||||
- 0,
|
||||
- )
|
||||
- ),
|
||||
- ]
|
||||
- # NOTE: not sure why limit is used
|
||||
- self.comb += self.slow_chain.limit.x.eq(analog_out)
|
||||
- # ds0 apparently has 16 bit, but only allowing positive values --> "15 bit"?
|
||||
- slow_out_shifted = Signal(15)
|
||||
- self.sync += slow_out_shifted.eq((self.slow_chain.limit.y << 1) + (1 << 14))
|
||||
- self.comb += self.ds0.data.eq(slow_out_shifted)
|
||||
-
|
||||
- # connect other analog outputs
|
||||
- self.comb += [
|
||||
- self.ds1.data.eq(self.logic.analog_out_1.storage),
|
||||
- self.ds2.data.eq(self.logic.analog_out_2.storage),
|
||||
- self.ds3.data.eq(self.logic.analog_out_3.storage),
|
||||
- ]
|
||||
+ 0,
|
||||
+ )
|
||||
+ ),
|
||||
+ ]
|
||||
+ # NOTE: not sure why limit is used
|
||||
+ self.comb += self.slow_chain.limit.x.eq(analog_out)
|
||||
+ # ds0 apparently has 16 bit, but only allowing positive values --> "15 bit"?
|
||||
+ slow_out_shifted = Signal(15)
|
||||
+ self.sync += slow_out_shifted.eq((self.slow_chain.limit.y << 1) + (1 << 14))
|
||||
+ self.comb += soc.ds0.data.eq(slow_out_shifted)
|
||||
+
|
||||
+ # connect other analog outputs
|
||||
+ self.comb += [
|
||||
+ soc.ds1.data.eq(self.logic.analog_out_1.storage),
|
||||
+ soc.ds2.data.eq(self.logic.analog_out_2.storage),
|
||||
+ soc.ds3.data.eq(self.logic.analog_out_3.storage),
|
||||
+ ]
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
@@ -395,7 +365,7 @@ class LinienModule(Module, AutoCSR):
|
||||
|
||||
self.comb += [
|
||||
self.logic.autolock.robust.at_start.eq(self.logic.sweep.sweep.trigger),
|
||||
- self.scopegen.gpio_trigger.eq(self.gpio_p.i[0]),
|
||||
+ self.scopegen.gpio_trigger.eq(soc.gpio_p.i[0]),
|
||||
self.scopegen.sweep_trigger.eq(self.logic.sweep.sweep.trigger),
|
||||
self.scopegen.automatically_rearm.eq(
|
||||
self.logic.autolock.request_lock.storage
|
||||
@@ -404,8 +374,8 @@ class LinienModule(Module, AutoCSR):
|
||||
self.scopegen.automatically_trigger.eq(
|
||||
self.logic.autolock.lock_running.status
|
||||
),
|
||||
- self.analog.dac_a.eq(self.logic.limit_fast1.y),
|
||||
- self.analog.dac_b.eq(self.logic.limit_fast2.y),
|
||||
+ soc.analog.dac_a.eq(self.logic.limit_fast1.y),
|
||||
+ soc.analog.dac_b.eq(self.logic.limit_fast2.y),
|
||||
]
|
||||
|
||||
# Having this in a comb statement caused errors. See PR #251.
|
||||
@@ -428,23 +398,4 @@ class DummyHK(Module, AutoCSR):
|
||||
self.submodules.csrcon = csr_bus.Interconnect(
|
||||
self.sys2csr.csr, self.csrbanks.get_buses()
|
||||
)
|
||||
- self.sys = self.sys2csr.sys
|
||||
-
|
||||
-
|
||||
-class RootModule(Module):
|
||||
- def __init__(self, platform):
|
||||
- self.submodules.ps = PitayaPS(platform.request("cpu"))
|
||||
- self.submodules.crg = CRG(
|
||||
- platform.request("clk125"), self.ps.fclk[0], ~self.ps.frstn[0]
|
||||
- )
|
||||
- self.submodules.linien = LinienModule(platform)
|
||||
-
|
||||
- self.submodules.hk = ClockDomainsRenamer("sys_ps")(DummyHK())
|
||||
-
|
||||
- self.submodules.ic = SysInterconnect(
|
||||
- self.ps.axi.sys,
|
||||
- self.hk.sys,
|
||||
- self.linien.scopegen.scope_sys,
|
||||
- self.linien.scopegen.asg_sys,
|
||||
- self.linien.syscdc.source,
|
||||
- )
|
||||
+ self.sys = self.sys2csr.sys
|
||||
\ No newline at end of file
|
||||
diff --git a/gateware/targets/__init__.py b/gateware/targets/__init__.py
|
||||
new file mode 100644
|
||||
index 0000000..e69de29
|
||||
diff --git a/gateware/targets/fast_servo.py b/gateware/targets/fast_servo.py
|
||||
new file mode 100644
|
||||
index 0000000..da5bf3b
|
||||
--- /dev/null
|
||||
+++ b/gateware/targets/fast_servo.py
|
||||
@@ -0,0 +1,85 @@
|
||||
+# Copyright 2023 Jakub Matyas <jakubk.m@gmail.com>
|
||||
+# Warsaw University of Technology
|
||||
+#
|
||||
+# This file is part of Linien and provides support for Linien on
|
||||
+# Fast Servo platform.
|
||||
+#
|
||||
+# Linien is free software: you can redistribute it and/or modify
|
||||
+# it under the terms of the GNU General Public License as published by
|
||||
+# the Free Software Foundation, either version 3 of the License, or
|
||||
+# (at your option) any later version.
|
||||
+#
|
||||
+# Linien is distributed in the hope that it will be useful,
|
||||
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
+# GNU General Public License for more details.
|
||||
+#
|
||||
+# You should have received a copy of the GNU General Public License
|
||||
+# along with Linien. If not, see <http://www.gnu.org/licenses/>.
|
||||
+
|
||||
+from fast_servo.gateware.fast_servo_soc import BaseSoC
|
||||
+from migen import *
|
||||
+from misoc.interconnect import csr_bus
|
||||
+
|
||||
+from gateware.linien_module import DummyHK, LinienModule
|
||||
+from gateware.lowlevel.dna import DNA
|
||||
+from gateware.lowlevel.gpio import Gpio
|
||||
+from gateware.lowlevel.pitaya_ps import SysInterconnect
|
||||
+
|
||||
+
|
||||
+class FastServoAnalog(Module):
|
||||
+ def __init__(self, adc, dac):
|
||||
+ size = 14 # length of DAC
|
||||
+
|
||||
+ self.adc_a = Signal(size)
|
||||
+ self.adc_b = Signal(size)
|
||||
+ self.dac_a = Signal(size)
|
||||
+ self.dac_b = Signal(size)
|
||||
+
|
||||
+ self.comb += [
|
||||
+ self.adc_a.eq(adc.data_out[0][2:]),
|
||||
+ self.adc_b.eq(adc.data_out[1][2:]),
|
||||
+ ]
|
||||
+
|
||||
+ self.sync += [
|
||||
+ dac.data_in[0].eq(self.dac_a),
|
||||
+ dac.data_in[1].eq(self.dac_b),
|
||||
+ ]
|
||||
+
|
||||
+
|
||||
+class LinienFastServo(BaseSoC):
|
||||
+ def __init__(self, platform):
|
||||
+ super().__init__(platform)
|
||||
+
|
||||
+ self.submodules.dna = DNA(version=2)
|
||||
+
|
||||
+ self.submodules.analog = FastServoAnalog(self.adc, self.dac)
|
||||
+ gpios = platform.request("gpio")
|
||||
+ self.submodules.gpio_n = Gpio(gpios.n)
|
||||
+ # self.csr_devices.append("gpio_n")
|
||||
+ self.submodules.gpio_p = Gpio(gpios.p)
|
||||
+ # self.csr_devices.append("gpio_p")
|
||||
+ self.csr_map.update({
|
||||
+ "dna": 28,
|
||||
+ "gpio_n": 30,
|
||||
+ "gpio_p": 31,
|
||||
+ })
|
||||
+
|
||||
+ # ---------------------------------------------
|
||||
+ #
|
||||
+ # FIXME - passing self to LinienModule
|
||||
+ self.submodules.linien = LinienModule(self)
|
||||
+
|
||||
+ def soc_finalize(self):
|
||||
+ self.add_interconnect_slave(self.syscdc.source)
|
||||
+ self.submodules.csrbanks = csr_bus.CSRBankArray(self,
|
||||
+ self.get_csr_dev_address)
|
||||
+ self.submodules.csrcon = csr_bus.Interconnect(
|
||||
+ self.sys2csr.csr, [*self.csrbanks.get_buses(), *self.linien.csrbanks.get_buses()]
|
||||
+ )
|
||||
+ self.submodules.hk = DummyHK()
|
||||
+ self.submodules.interconnect = SysInterconnect(
|
||||
+ self.axi2sys.sys,
|
||||
+ self.hk.sys,
|
||||
+ *self.interconnect_slaves
|
||||
+ )
|
||||
\ No newline at end of file
|
||||
diff --git a/gateware/targets/red_pitaya.py b/gateware/targets/red_pitaya.py
|
||||
new file mode 100644
|
||||
index 0000000..c029e81
|
||||
--- /dev/null
|
||||
+++ b/gateware/targets/red_pitaya.py
|
||||
@@ -0,0 +1,103 @@
|
||||
+# Copyright 2014-2015 Robert Jördens <jordens@gmail.com>
|
||||
+# Copyright 2018-2022 Benjamin Wiegand <benjamin.wiegand@physik.hu-berlin.de>
|
||||
+# Copyright 2021-2023 Bastian Leykauf <leykauf@physik.hu-berlin.de>
|
||||
+# Copyright 2022 Christian Freier <christian.freier@nomadatomics.com>
|
||||
+# Copyright 2023 Jakub Matyas <jakubk.m@gmail.com>
|
||||
+#
|
||||
+# This file is part of Linien and based on redpid.
|
||||
+#
|
||||
+# Linien is free software: you can redistribute it and/or modify
|
||||
+# it under the terms of the GNU General Public License as published by
|
||||
+# the Free Software Foundation, either version 3 of the License, or
|
||||
+# (at your option) any later version.
|
||||
+#
|
||||
+# Linien is distributed in the hope that it will be useful,
|
||||
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
+# GNU General Public License for more details.
|
||||
+#
|
||||
+# You should have received a copy of the GNU General Public License
|
||||
+# along with Linien. If not, see <http://www.gnu.org/licenses/>.
|
||||
+
|
||||
+from migen import *
|
||||
+from misoc.interconnect import csr_bus
|
||||
+from misoc.interconnect.csr import AutoCSR
|
||||
+
|
||||
+from gateware.linien_module import DummyHK, LinienModule
|
||||
+from gateware.logic.delta_sigma import DeltaSigma
|
||||
+from gateware.lowlevel.analog import PitayaAnalog
|
||||
+from gateware.lowlevel.crg import CRG
|
||||
+from gateware.lowlevel.dna import DNA
|
||||
+from gateware.lowlevel.gpio import Gpio
|
||||
+from gateware.lowlevel.pitaya_ps import PitayaPS, Sys2CSR, SysCDC, SysInterconnect
|
||||
+from gateware.lowlevel.xadc import XADC
|
||||
+
|
||||
+
|
||||
+class PitayaSoC(Module, AutoCSR):
|
||||
+ def __init__(self, platform):
|
||||
+ self.csr_map = {
|
||||
+ "gpio_n": 30,
|
||||
+ "gpio_p": 31,
|
||||
+ "dna": 28,
|
||||
+ "xadc": 29,
|
||||
+ }
|
||||
+ self.soc_name = "RedPitaya"
|
||||
+ self.interconnect_slaves = []
|
||||
+
|
||||
+ self.submodules.ps = PitayaPS(platform.request("cpu"))
|
||||
+ self.submodules.crg = CRG(
|
||||
+ platform.request("clk125"), self.ps.fclk[0], ~self.ps.frstn[0]
|
||||
+ )
|
||||
+ self.submodules.sys2csr = Sys2CSR()
|
||||
+ self.submodules.syscdc = SysCDC()
|
||||
+ self.comb += self.syscdc.target.connect(self.sys2csr.sys)
|
||||
+
|
||||
+ self.submodules.xadc = XADC(platform.request("xadc"))
|
||||
+ self.submodules.analog = PitayaAnalog(platform.request("adc"), platform.request("dac"))
|
||||
+
|
||||
+ for i in range(4):
|
||||
+ pwm = platform.request("pwm", i)
|
||||
+ ds = ClockDomainsRenamer("sys_double")(DeltaSigma(width=15))
|
||||
+ self.comb += pwm.eq(ds.out)
|
||||
+ setattr(self.submodules, f"ds{i}", ds)
|
||||
+
|
||||
+ exp = platform.request("exp")
|
||||
+ self.submodules.gpio_n = Gpio(exp.n)
|
||||
+ self.submodules.gpio_p = Gpio(exp.p)
|
||||
+
|
||||
+ leds = Cat(*(platform.request("user_led", i) for i in range(8)))
|
||||
+ self.comb += leds.eq(self.gpio_n.o)
|
||||
+
|
||||
+ self.submodules.dna = DNA(version=2)
|
||||
+
|
||||
+ # ---------------------------------------------
|
||||
+ #
|
||||
+ # FIXME - passing self to LinienModule
|
||||
+ self.submodules.linien = LinienModule(self)
|
||||
+ self.add_interconnect_slave(self.syscdc.source)
|
||||
+ self.run_finalize()
|
||||
+
|
||||
+
|
||||
+ def add_interconnect_slave(self, slave):
|
||||
+ self.interconnect_slaves.append(slave)
|
||||
+
|
||||
+ def get_csr_dev_address(self, name, memory):
|
||||
+ if memory is not None:
|
||||
+ name = name + "_" + memory.name_override
|
||||
+ try:
|
||||
+ return self.csr_map[name]
|
||||
+ except KeyError:
|
||||
+ return None
|
||||
+
|
||||
+ def run_finalize(self):
|
||||
+ self.submodules.csrbanks = csr_bus.CSRBankArray(self,
|
||||
+ self.get_csr_dev_address)
|
||||
+ self.submodules.csrcon = csr_bus.Interconnect(
|
||||
+ self.sys2csr.csr, [*self.csrbanks.get_buses(), *self.linien.csrbanks.get_buses()]
|
||||
+ )
|
||||
+ self.submodules.hk = DummyHK()
|
||||
+ self.submodules.interconnect = SysInterconnect(
|
||||
+ self.ps.axi.sys,
|
||||
+ self.hk.sys,
|
||||
+ *self.interconnect_slaves
|
||||
+ )
|
||||
\ No newline at end of file
|
5
fast-servo/linien-gateware/README.md
Normal file
@ -0,0 +1,5 @@
|
||||
## Source Repository
|
||||
Files in this directory were copied from [elhep/Fast-Servo-Frimware](https://github.com/elhep/Fast-Servo-Firmware/tree/master/fast_servo/gateware).
|
||||
|
||||
## Commit ID
|
||||
The files were copied from commit ID [7fae40c](https://github.com/elhep/Fast-Servo-Firmware/commit/7fae40c0f872a91218be378f8289b98b1e366729).
|
3
fast-servo/linien-gateware/__init__.py
Normal file
@ -0,0 +1,3 @@
|
||||
import os
|
||||
|
||||
verilog_dir = os.path.join(os.path.abspath(os.path.dirname(__file__)), "verilog")
|
0
fast-servo/linien-gateware/cores/__init__.py
Normal file
179
fast-servo/linien-gateware/cores/adc.py
Normal file
@ -0,0 +1,179 @@
|
||||
# This file is part of Fast Servo Software Package.
|
||||
#
|
||||
# Copyright (C) 2023 Jakub Matyas
|
||||
# Warsaw University of Technology <jakubk.m@gmail.com>
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
from migen import *
|
||||
from migen.genlib.cdc import MultiReg
|
||||
from misoc.interconnect.csr import AutoCSR, CSRStatus, CSRStorage
|
||||
|
||||
|
||||
class _CRG(Module):
|
||||
def __init__(self, platform, dco_clk, dco_freq=200e6):
|
||||
self.clock_domains.cd_dco = ClockDomain()
|
||||
self.clock_domains.cd_dco2x = ClockDomain()
|
||||
self.clock_domains.cd_dco2d = ClockDomain()
|
||||
dco_clk_p, dco_clk_n = dco_clk
|
||||
|
||||
dco_clk_buf = Signal()
|
||||
self.specials += Instance(
|
||||
"IBUFGDS", i_I=dco_clk_p, i_IB=dco_clk_n, o_O=dco_clk_buf
|
||||
)
|
||||
|
||||
# # #
|
||||
clk_feedback = Signal()
|
||||
clk_feedback_buf = Signal()
|
||||
|
||||
clk_dco = Signal()
|
||||
clk_dco2x = Signal()
|
||||
clk_dco2d = Signal()
|
||||
self.locked = Signal()
|
||||
|
||||
platform.add_period_constraint(dco_clk_p, 1e9 / dco_freq)
|
||||
self.specials += [
|
||||
Instance(
|
||||
"PLLE2_BASE",
|
||||
p_BANDWIDTH="OPTIMIZED",
|
||||
p_DIVCLK_DIVIDE=1,
|
||||
p_CLKFBOUT_PHASE=0.0,
|
||||
p_CLKFBOUT_MULT=4, # VCO @ 800 MHz
|
||||
p_CLKIN1_PERIOD=(1e9 / dco_freq),
|
||||
p_REF_JITTER1=0.01,
|
||||
p_STARTUP_WAIT="FALSE",
|
||||
i_CLKIN1=dco_clk_buf,
|
||||
i_PWRDWN=0,
|
||||
i_RST=ResetSignal("sys"),
|
||||
i_CLKFBIN=clk_feedback_buf,
|
||||
o_CLKFBOUT=clk_feedback,
|
||||
p_CLKOUT0_DIVIDE=4,
|
||||
p_CLKOUT0_PHASE=0.0,
|
||||
p_CLKOUT0_DUTY_CYCLE=0.5,
|
||||
o_CLKOUT0=clk_dco, # 200 MHz <- dco_clk
|
||||
p_CLKOUT1_DIVIDE=2,
|
||||
p_CLKOUT1_PHASE=0.0,
|
||||
p_CLKOUT1_DUTY_CYCLE=0.5,
|
||||
o_CLKOUT1=clk_dco2x, # 400 MHZ <- 2 * dco_clk = 2*200 MHz
|
||||
p_CLKOUT2_DIVIDE=8,
|
||||
p_CLKOUT2_PHASE=0.0,
|
||||
p_CLKOUT2_DUTY_CYCLE=0.5,
|
||||
o_CLKOUT2=clk_dco2d, # 100 MHz <- dco_clk / 2 = 200 MHz / 2
|
||||
o_LOCKED=self.locked,
|
||||
)
|
||||
]
|
||||
|
||||
self.specials += Instance("BUFG", i_I=clk_feedback, o_O=clk_feedback_buf)
|
||||
self.specials += Instance("BUFG", i_I=clk_dco, o_O=self.cd_dco.clk)
|
||||
self.specials += Instance("BUFG", i_I=clk_dco2d, o_O=self.cd_dco2d.clk)
|
||||
self.specials += Instance("BUFG", i_I=clk_dco2x, o_O=self.cd_dco2x.clk)
|
||||
|
||||
|
||||
class ADC(Module, AutoCSR):
|
||||
def __init__(self, platform, dco_freq=200e6):
|
||||
adc_pads = platform.request("adc")
|
||||
afe_pads = platform.request("adc_afe")
|
||||
|
||||
self.frame_csr = CSRStatus(4)
|
||||
self.data_ch0 = CSRStatus(16)
|
||||
self.data_ch1 = CSRStatus(16)
|
||||
|
||||
self.tap_delay = CSRStorage(5)
|
||||
self.bitslip_csr = CSRStorage(1)
|
||||
|
||||
self.afe_ctrl = CSRStorage(4)
|
||||
|
||||
tap_delay_val = Signal(5)
|
||||
bitslip = Signal()
|
||||
bitslip_re_dco_2d = Signal()
|
||||
|
||||
ch1_gain_x10 = Signal()
|
||||
ch2_gain_x10 = Signal()
|
||||
ch1_shdn = Signal()
|
||||
ch2_shdn = Signal()
|
||||
|
||||
self.data_out = [Signal(16, reset_less=True), Signal(16, reset_less=True)]
|
||||
self.s_frame = Signal(4)
|
||||
|
||||
###
|
||||
|
||||
# DCO clock coming from LTC2195
|
||||
# dco_clk = Record([("p", 1), ("n", 1)])
|
||||
dco_clk =(adc_pads.dco_p, adc_pads.dco_n)
|
||||
self.comb += [
|
||||
# dco_clk.p.eq(adc_pads.dco_p),
|
||||
# dco_clk.n.eq(adc_pads.dco_n),
|
||||
tap_delay_val.eq(self.tap_delay.storage),
|
||||
Cat(ch1_gain_x10, ch2_gain_x10, ch1_shdn, ch2_shdn).eq(
|
||||
self.afe_ctrl.storage
|
||||
),
|
||||
]
|
||||
|
||||
self.submodules._crg = _CRG(platform, dco_clk, dco_freq)
|
||||
|
||||
self.specials += MultiReg(self.bitslip_csr.re, bitslip_re_dco_2d, "dco2d")
|
||||
self.sync.dco2d += [
|
||||
bitslip.eq(Mux(bitslip_re_dco_2d, self.bitslip_csr.storage, 0))
|
||||
]
|
||||
|
||||
self.comb += [
|
||||
self.frame_csr.status.eq(self.s_frame),
|
||||
self.data_ch0.status.eq(self.data_out[0]),
|
||||
self.data_ch1.status.eq(self.data_out[1]),
|
||||
]
|
||||
|
||||
self.comb += [
|
||||
afe_pads.ch1_gain.eq(ch1_gain_x10),
|
||||
afe_pads.ch2_gain.eq(ch2_gain_x10),
|
||||
afe_pads.nshdn_ch1.eq(~ch1_shdn),
|
||||
afe_pads.nshdn_ch2.eq(~ch2_shdn),
|
||||
]
|
||||
|
||||
dummy = Signal(8)
|
||||
dummy_idelay_rdy = Signal()
|
||||
|
||||
self.specials += Instance(
|
||||
"LTC2195",
|
||||
i_rst_in=ResetSignal("sys"),
|
||||
i_clk200=ClockSignal("idelay"),
|
||||
i_DCO=ClockSignal("dco"),
|
||||
i_DCO_2D=ClockSignal("dco2d"),
|
||||
i_FR_in_p=adc_pads.frame_p,
|
||||
i_FR_in_n=adc_pads.frame_n,
|
||||
i_D0_in_p=adc_pads.data0_p,
|
||||
i_D0_in_n=adc_pads.data0_n,
|
||||
i_D1_in_p=adc_pads.data1_p,
|
||||
i_D1_in_n=adc_pads.data1_n,
|
||||
i_bitslip=bitslip,
|
||||
i_delay_val=tap_delay_val,
|
||||
o_ADC0_out=self.data_out[1], # LANES swapped on hardware
|
||||
o_ADC1_out=self.data_out[0],
|
||||
o_FR_out=self.s_frame,
|
||||
o_o_data_from_pins=dummy,
|
||||
o_idelay_rdy=dummy_idelay_rdy,
|
||||
)
|
||||
|
||||
|
||||
class AUX_ADC_CTRL(Module, AutoCSR):
|
||||
def __init__(self, platform):
|
||||
adc_aux_pads = platform.request("aux_adc")
|
||||
|
||||
self.adc_aux_ctrl = CSRStorage(5)
|
||||
|
||||
self.comb += [
|
||||
adc_aux_pads.diff_n.eq(~self.adc_aux_ctrl.storage[0]),
|
||||
adc_aux_pads.a.eq(self.adc_aux_ctrl.storage[1:4]),
|
||||
adc_aux_pads.range.eq(self.adc_aux_ctrl.storage[4]),
|
||||
]
|
84
fast-servo/linien-gateware/cores/dac.py
Normal file
@ -0,0 +1,84 @@
|
||||
# This file is part of Fast Servo Software Package.
|
||||
#
|
||||
# Copyright (C) 2023 Jakub Matyas
|
||||
# Warsaw University of Technology <jakubk.m@gmail.com>
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
from migen import *
|
||||
from misoc.interconnect.csr import AutoCSR, CSRStorage
|
||||
from migen.genlib.io import DDROutput
|
||||
|
||||
|
||||
class DAC(Module, AutoCSR):
|
||||
def __init__(self, platform):
|
||||
dac_pads = platform.request("dac")
|
||||
dac_afe_pads = platform.request("dac_afe")
|
||||
self.dac_ctrl = CSRStorage(3)
|
||||
self.output_value_ch0 = CSRStorage(14)
|
||||
self.output_value_ch1 = CSRStorage(14)
|
||||
|
||||
manual_override = Signal()
|
||||
ch0_pd = Signal()
|
||||
ch1_pd = Signal()
|
||||
|
||||
output_data_ch0 = Signal(14)
|
||||
output_data_ch1 = Signal(14)
|
||||
|
||||
self.data_in = [Signal(14, reset_less=True), Signal(14, reset_less=True)]
|
||||
platform.add_period_constraint(dac_pads.dclkio, 10.0)
|
||||
|
||||
self.comb += [
|
||||
Cat(manual_override, ch0_pd, ch1_pd).eq(self.dac_ctrl.storage),
|
||||
dac_pads.rst.eq(ResetSignal("sys")),
|
||||
dac_afe_pads.ch1_pd_n.eq(~ch0_pd),
|
||||
dac_afe_pads.ch2_pd_n.eq(~ch1_pd),
|
||||
output_data_ch0.eq(
|
||||
Mux(manual_override, self.output_value_ch0.storage, self.data_in[0])
|
||||
),
|
||||
output_data_ch1.eq(
|
||||
Mux(manual_override, self.output_value_ch1.storage, self.data_in[1])
|
||||
),
|
||||
]
|
||||
|
||||
# data
|
||||
for lane in range(14):
|
||||
self.specials += DDROutput(
|
||||
i1 = output_data_ch0[lane],
|
||||
i2 = output_data_ch1[lane],
|
||||
o = dac_pads.data[lane],
|
||||
clk = ClockSignal("dco2d")
|
||||
)
|
||||
|
||||
# clock forwarding
|
||||
self.specials += DDROutput(
|
||||
i1 = 0b0,
|
||||
i2 = 0b1,
|
||||
o = dac_pads.dclkio,
|
||||
clk = ClockSignal("dco2d"),
|
||||
)
|
||||
|
||||
|
||||
class AUX_DAC_CTRL(Module, AutoCSR):
|
||||
def __init__(self, platform):
|
||||
dac_aux_pads = platform.request("aux_dac")
|
||||
|
||||
self.dac_aux_ctrl = CSRStorage(3)
|
||||
|
||||
self.comb += [
|
||||
dac_aux_pads.nclr.eq(~self.dac_aux_ctrl.storage[0]),
|
||||
dac_aux_pads.bin.eq(self.dac_aux_ctrl.storage[1]),
|
||||
dac_aux_pads.nldac.eq(~self.dac_aux_ctrl.storage[2]),
|
||||
]
|
385
fast-servo/linien-gateware/cores/pitaya_ps.py
Normal file
@ -0,0 +1,385 @@
|
||||
# Copyright 2014-2015 Robert Jördens <jordens@gmail.com>
|
||||
# Copyright 2018-2022 Benjamin Wiegand <benjamin.wiegand@physik.hu-berlin.de>
|
||||
# Copyright 2021-2022 Bastian Leykauf <leykauf@physik.hu-berlin.de>
|
||||
# Copyright 2023 Jakub Matyas
|
||||
# Warsaw University of Technology <jakubk.m@gmail.com>
|
||||
#
|
||||
# This file is part of Fast Servo Software Package and is based on Linien.
|
||||
#
|
||||
# Linien is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Linien is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Linien. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from functools import reduce
|
||||
from operator import or_
|
||||
|
||||
from migen import (
|
||||
DIR_M_TO_S,
|
||||
DIR_S_TO_M,
|
||||
Cat,
|
||||
ClockSignal,
|
||||
If,
|
||||
Instance,
|
||||
Module,
|
||||
Record,
|
||||
Replicate,
|
||||
ResetSignal,
|
||||
Signal,
|
||||
)
|
||||
from misoc.interconnect import csr_bus, wishbone
|
||||
|
||||
sys_layout = [
|
||||
("rstn", 1, DIR_M_TO_S),
|
||||
("clk", 1, DIR_M_TO_S),
|
||||
("addr", 32, DIR_M_TO_S),
|
||||
("wdata", 32, DIR_M_TO_S),
|
||||
("sel", 4, DIR_M_TO_S),
|
||||
("wen", 1, DIR_M_TO_S),
|
||||
("ren", 1, DIR_M_TO_S),
|
||||
("rdata", 32, DIR_S_TO_M),
|
||||
("err", 1, DIR_S_TO_M),
|
||||
("ack", 1, DIR_S_TO_M),
|
||||
]
|
||||
|
||||
|
||||
axi_layout = [
|
||||
("arvalid", 1),
|
||||
("awvalid", 1),
|
||||
("bready", 1),
|
||||
("rready", 1),
|
||||
("wlast", 1),
|
||||
("wvalid", 1),
|
||||
("arid", 12),
|
||||
("awid", 12),
|
||||
("wid", 12),
|
||||
("arburst", 2),
|
||||
("arlock", 2),
|
||||
("arsize", 3),
|
||||
("awburst", 2),
|
||||
("awlock", 2),
|
||||
("awsize", 3),
|
||||
("arprot", 3),
|
||||
("awprot", 3),
|
||||
("araddr", 32),
|
||||
("awaddr", 32),
|
||||
("wdata", 32),
|
||||
("arcache", 4),
|
||||
("arlen", 4),
|
||||
("arqos", 4),
|
||||
("awcache", 4),
|
||||
("awlen", 4),
|
||||
("awqos", 4),
|
||||
("wstrb", 4),
|
||||
("aclk", 1),
|
||||
("arready", 1),
|
||||
("awready", 1),
|
||||
("bvalid", 1),
|
||||
("rlast", 1),
|
||||
("rvalid", 1),
|
||||
("wready", 1),
|
||||
("bid", 12),
|
||||
("rid", 12),
|
||||
("bresp", 2),
|
||||
("rresp", 2),
|
||||
("rdata", 32),
|
||||
("arstn", 1),
|
||||
]
|
||||
|
||||
|
||||
class PitayaPS(Module):
|
||||
def __init__(self, cpu):
|
||||
self.fclk = Signal(4)
|
||||
self.frstn = Signal(4)
|
||||
|
||||
###
|
||||
|
||||
self.submodules.axi = Axi2Sys()
|
||||
axi = self.axi.axi
|
||||
self.comb += [
|
||||
axi.aclk.eq(self.fclk[0]),
|
||||
axi.arstn.eq(self.frstn[0]),
|
||||
]
|
||||
|
||||
self.specials += Instance(
|
||||
"system_processing_system7_0_0",
|
||||
io_MIO=cpu.mio,
|
||||
io_PS_CLK=cpu.ps_clk,
|
||||
io_PS_PORB=cpu.ps_porb,
|
||||
io_PS_SRSTB=cpu.ps_srstb,
|
||||
io_DDR_Addr=cpu.DDR_addr,
|
||||
io_DDR_BankAddr=cpu.DDR_ba,
|
||||
io_DDR_CAS_n=cpu.DDR_cas_n,
|
||||
io_DDR_Clk_n=cpu.DDR_ck_n,
|
||||
io_DDR_Clk=cpu.DDR_ck_p,
|
||||
io_DDR_CKE=cpu.DDR_cke,
|
||||
io_DDR_CS_n=cpu.DDR_cs_n,
|
||||
io_DDR_DM=cpu.DDR_dm,
|
||||
io_DDR_DQ=cpu.DDR_dq,
|
||||
io_DDR_DQS_n=cpu.DDR_dqs_n,
|
||||
io_DDR_DQS=cpu.DDR_dqs_p,
|
||||
io_DDR_ODT=cpu.DDR_odt,
|
||||
io_DDR_RAS_n=cpu.DDR_ras_n,
|
||||
io_DDR_DRSTB=cpu.DDR_reset_n,
|
||||
io_DDR_WEB=cpu.DDR_we_n,
|
||||
io_DDR_VRN=cpu.ddr_vrn,
|
||||
io_DDR_VRP=cpu.ddr_vrp,
|
||||
o_FCLK_CLK0=self.fclk[0],
|
||||
o_FCLK_CLK1=self.fclk[1],
|
||||
o_FCLK_CLK2=self.fclk[2],
|
||||
o_FCLK_CLK3=self.fclk[3],
|
||||
o_FCLK_RESET0_N=self.frstn[0],
|
||||
o_FCLK_RESET1_N=self.frstn[1],
|
||||
o_FCLK_RESET2_N=self.frstn[2],
|
||||
o_FCLK_RESET3_N=self.frstn[3],
|
||||
i_M_AXI_GP0_ACLK=axi.aclk,
|
||||
o_M_AXI_GP0_ARVALID=axi.arvalid,
|
||||
o_M_AXI_GP0_AWVALID=axi.awvalid,
|
||||
o_M_AXI_GP0_BREADY=axi.bready,
|
||||
o_M_AXI_GP0_RREADY=axi.rready,
|
||||
o_M_AXI_GP0_WLAST=axi.wlast,
|
||||
o_M_AXI_GP0_WVALID=axi.wvalid,
|
||||
o_M_AXI_GP0_ARID=axi.arid,
|
||||
o_M_AXI_GP0_AWID=axi.awid,
|
||||
o_M_AXI_GP0_WID=axi.wid,
|
||||
o_M_AXI_GP0_ARBURST=axi.arburst,
|
||||
o_M_AXI_GP0_ARLOCK=axi.arlock,
|
||||
o_M_AXI_GP0_ARSIZE=axi.arsize,
|
||||
o_M_AXI_GP0_AWBURST=axi.awburst,
|
||||
o_M_AXI_GP0_AWLOCK=axi.awlock,
|
||||
o_M_AXI_GP0_AWSIZE=axi.awsize,
|
||||
o_M_AXI_GP0_ARPROT=axi.arprot,
|
||||
o_M_AXI_GP0_AWPROT=axi.awprot,
|
||||
o_M_AXI_GP0_ARADDR=axi.araddr,
|
||||
o_M_AXI_GP0_AWADDR=axi.awaddr,
|
||||
o_M_AXI_GP0_WDATA=axi.wdata,
|
||||
o_M_AXI_GP0_ARCACHE=axi.arcache,
|
||||
o_M_AXI_GP0_ARLEN=axi.arlen,
|
||||
o_M_AXI_GP0_ARQOS=axi.arqos,
|
||||
o_M_AXI_GP0_AWCACHE=axi.awcache,
|
||||
o_M_AXI_GP0_AWLEN=axi.awlen,
|
||||
o_M_AXI_GP0_AWQOS=axi.awqos,
|
||||
o_M_AXI_GP0_WSTRB=axi.wstrb,
|
||||
i_M_AXI_GP0_ARREADY=axi.arready,
|
||||
i_M_AXI_GP0_AWREADY=axi.awready,
|
||||
i_M_AXI_GP0_BVALID=axi.bvalid,
|
||||
i_M_AXI_GP0_RLAST=axi.rlast,
|
||||
i_M_AXI_GP0_RVALID=axi.rvalid,
|
||||
i_M_AXI_GP0_WREADY=axi.wready,
|
||||
i_M_AXI_GP0_BID=axi.bid,
|
||||
i_M_AXI_GP0_RID=axi.rid,
|
||||
i_M_AXI_GP0_BRESP=axi.bresp,
|
||||
i_M_AXI_GP0_RRESP=axi.rresp,
|
||||
i_M_AXI_GP0_RDATA=axi.rdata,
|
||||
i_SPI0_SS_I=0,
|
||||
# i_SPI0_SS_I=spi.ss_i,
|
||||
# o_SPI0_SS_O=spi.ss_o,
|
||||
# o_SPI0_SS_T=spi.ss_t,
|
||||
# o_SPI0_SS1_O=spi.ss1_o,
|
||||
# o_SPI0_SS2_O=spi.ss2_o,
|
||||
i_SPI0_SCLK_I=0,
|
||||
# i_SPI0_SCLK_I=spi.sclk_i,
|
||||
# o_SPI0_SCLK_O=spi.sclk_o,
|
||||
# o_SPI0_SCLK_T=spi.sclk_t,
|
||||
i_SPI0_MOSI_I=0,
|
||||
# i_SPI0_MOSI_I=spi.mosi_i,
|
||||
# o_SPI0_MOSI_O=spi.mosi_o,
|
||||
# o_SPI0_MOSI_T=spi.mosi_t,
|
||||
i_SPI0_MISO_I=0,
|
||||
# i_SPI0_MISO_I=spi.miso_i,
|
||||
# o_SPI0_MISO_O=spi.miso_o,
|
||||
# o_SPI0_MISO_T=spi.miso_t,
|
||||
i_USB0_VBUS_PWRFAULT=0,
|
||||
)
|
||||
|
||||
|
||||
class Axi2Sys(Module):
|
||||
def __init__(self):
|
||||
self.sys = Record(sys_layout)
|
||||
self.axi = Record(axi_layout)
|
||||
|
||||
###
|
||||
|
||||
self.comb += [self.sys.clk.eq(self.axi.aclk), self.sys.rstn.eq(self.axi.arstn)]
|
||||
|
||||
self.specials += Instance(
|
||||
"axi_slave",
|
||||
p_AXI_DW=32,
|
||||
p_AXI_AW=32,
|
||||
p_AXI_IW=12,
|
||||
i_axi_clk_i=self.axi.aclk,
|
||||
i_axi_rstn_i=self.axi.arstn,
|
||||
i_axi_awid_i=self.axi.awid,
|
||||
i_axi_awaddr_i=self.axi.awaddr,
|
||||
i_axi_awlen_i=self.axi.awlen,
|
||||
i_axi_awsize_i=self.axi.awsize,
|
||||
i_axi_awburst_i=self.axi.awburst,
|
||||
i_axi_awlock_i=self.axi.awlock,
|
||||
i_axi_awcache_i=self.axi.awcache,
|
||||
i_axi_awprot_i=self.axi.awprot,
|
||||
i_axi_awvalid_i=self.axi.awvalid,
|
||||
o_axi_awready_o=self.axi.awready,
|
||||
i_axi_wid_i=self.axi.wid,
|
||||
i_axi_wdata_i=self.axi.wdata,
|
||||
i_axi_wstrb_i=self.axi.wstrb,
|
||||
i_axi_wlast_i=self.axi.wlast,
|
||||
i_axi_wvalid_i=self.axi.wvalid,
|
||||
o_axi_wready_o=self.axi.wready,
|
||||
o_axi_bid_o=self.axi.bid,
|
||||
o_axi_bresp_o=self.axi.bresp,
|
||||
o_axi_bvalid_o=self.axi.bvalid,
|
||||
i_axi_bready_i=self.axi.bready,
|
||||
i_axi_arid_i=self.axi.arid,
|
||||
i_axi_araddr_i=self.axi.araddr,
|
||||
i_axi_arlen_i=self.axi.arlen,
|
||||
i_axi_arsize_i=self.axi.arsize,
|
||||
i_axi_arburst_i=self.axi.arburst,
|
||||
i_axi_arlock_i=self.axi.arlock,
|
||||
i_axi_arcache_i=self.axi.arcache,
|
||||
i_axi_arprot_i=self.axi.arprot,
|
||||
i_axi_arvalid_i=self.axi.arvalid,
|
||||
o_axi_arready_o=self.axi.arready,
|
||||
o_axi_rid_o=self.axi.rid,
|
||||
o_axi_rdata_o=self.axi.rdata,
|
||||
o_axi_rresp_o=self.axi.rresp,
|
||||
o_axi_rlast_o=self.axi.rlast,
|
||||
o_axi_rvalid_o=self.axi.rvalid,
|
||||
i_axi_rready_i=self.axi.rready,
|
||||
o_sys_addr_o=self.sys.addr,
|
||||
o_sys_wdata_o=self.sys.wdata,
|
||||
o_sys_sel_o=self.sys.sel,
|
||||
o_sys_wen_o=self.sys.wen,
|
||||
o_sys_ren_o=self.sys.ren,
|
||||
i_sys_rdata_i=self.sys.rdata,
|
||||
i_sys_err_i=self.sys.err,
|
||||
i_sys_ack_i=self.sys.ack,
|
||||
)
|
||||
|
||||
|
||||
class SysInterconnect(Module):
|
||||
def __init__(self, master, *slaves):
|
||||
cs = Signal(max=len(slaves)) if len(slaves) != 1 else Signal()
|
||||
self.comb += cs.eq(master.addr[20:23])
|
||||
rets = []
|
||||
for i, s in enumerate(slaves):
|
||||
sel = Signal()
|
||||
self.comb += [
|
||||
sel.eq(cs == i),
|
||||
s.clk.eq(master.clk),
|
||||
s.rstn.eq(master.rstn),
|
||||
s.addr.eq(master.addr),
|
||||
s.wdata.eq(master.wdata),
|
||||
s.sel.eq(master.sel),
|
||||
s.wen.eq(sel & master.wen),
|
||||
s.ren.eq(sel & master.ren),
|
||||
]
|
||||
ret = Cat(s.err, s.ack, s.rdata)
|
||||
rets.append(Replicate(sel, len(ret)) & ret)
|
||||
self.comb += Cat(master.err, master.ack, master.rdata).eq(reduce(or_, rets))
|
||||
|
||||
|
||||
class Sys2Wishbone(Module):
|
||||
def __init__(self):
|
||||
self.wishbone = wb = wishbone.Interface()
|
||||
self.sys = sys = Record(sys_layout)
|
||||
|
||||
###
|
||||
|
||||
sys2 = Record(sys_layout)
|
||||
|
||||
self.specials += Instance(
|
||||
"bus_clk_bridge",
|
||||
i_sys_clk_i=sys.clk,
|
||||
i_sys_rstn_i=sys.rstn,
|
||||
i_sys_addr_i=sys.addr,
|
||||
i_sys_wdata_i=sys.wdata,
|
||||
i_sys_sel_i=sys.sel,
|
||||
i_sys_wen_i=sys.wen,
|
||||
i_sys_ren_i=sys.ren,
|
||||
o_sys_rdata_o=sys.rdata,
|
||||
o_sys_err_o=sys.err,
|
||||
o_sys_ack_o=sys.ack,
|
||||
i_clk_i=ClockSignal(),
|
||||
i_rstn_i=~ResetSignal(),
|
||||
o_addr_o=sys2.addr,
|
||||
o_wen_o=sys2.wen,
|
||||
o_ren_o=sys2.ren,
|
||||
o_wdata_o=sys2.wdata,
|
||||
i_rdata_i=sys2.rdata,
|
||||
i_err_i=sys2.err,
|
||||
i_ack_i=sys2.ack,
|
||||
)
|
||||
self.sync += [
|
||||
If(
|
||||
sys2.ren | sys2.wen,
|
||||
wb.cyc.eq(1),
|
||||
wb.adr.eq(sys2.addr[2:]),
|
||||
wb.we.eq(sys2.wen),
|
||||
wb.dat_w.eq(sys2.wdata),
|
||||
).Elif(wb.ack, wb.cyc.eq(0))
|
||||
]
|
||||
self.comb += [
|
||||
wb.stb.eq(wb.cyc),
|
||||
sys2.rdata.eq(wb.dat_r),
|
||||
sys2.ack.eq(wb.ack),
|
||||
sys2.err.eq(wb.err),
|
||||
]
|
||||
|
||||
|
||||
class SysCDC(Module):
|
||||
def __init__(self, cd_target="sys"):
|
||||
self.source = Record(sys_layout)
|
||||
self.target = Record(sys_layout)
|
||||
|
||||
self.specials += Instance(
|
||||
"bus_clk_bridge",
|
||||
i_sys_clk_i=self.source.clk,
|
||||
i_sys_rstn_i=self.source.rstn,
|
||||
i_sys_addr_i=self.source.addr,
|
||||
i_sys_wdata_i=self.source.wdata,
|
||||
i_sys_sel_i=self.source.sel,
|
||||
i_sys_wen_i=self.source.wen,
|
||||
i_sys_ren_i=self.source.ren,
|
||||
o_sys_rdata_o=self.source.rdata,
|
||||
o_sys_err_o=self.source.err,
|
||||
o_sys_ack_o=self.source.ack,
|
||||
i_clk_i=self.target.clk,
|
||||
i_rstn_i=self.target.rstn,
|
||||
o_addr_o=self.target.addr,
|
||||
o_wdata_o=self.target.wdata,
|
||||
o_wen_o=self.target.wen,
|
||||
o_ren_o=self.target.ren,
|
||||
i_rdata_i=self.target.rdata,
|
||||
i_err_i=self.target.err,
|
||||
i_ack_i=self.target.ack,
|
||||
)
|
||||
self.comb += [
|
||||
self.target.clk.eq(ClockSignal(cd_target)),
|
||||
self.target.rstn.eq(~ResetSignal(cd_target)),
|
||||
]
|
||||
|
||||
|
||||
class Sys2CSR(Module):
|
||||
def __init__(self):
|
||||
self.csr = csr_bus.Interface()
|
||||
self.sys = Record(sys_layout)
|
||||
|
||||
###
|
||||
|
||||
stb = Signal()
|
||||
self.sync += [
|
||||
stb.eq(self.sys.wen | self.sys.ren),
|
||||
self.csr.adr.eq(self.sys.addr[2:]),
|
||||
self.csr.we.eq(self.sys.wen),
|
||||
self.csr.dat_w.eq(self.sys.wdata),
|
||||
self.sys.ack.eq(stb),
|
||||
self.sys.rdata.eq(self.csr.dat_r),
|
||||
]
|
193
fast-servo/linien-gateware/cores/ps7.py
Normal file
@ -0,0 +1,193 @@
|
||||
# This file is part of Fast Servo Software Package.
|
||||
#
|
||||
# Copyright (C) 2023 Jakub Matyas
|
||||
# Warsaw University of Technology <jakubk.m@gmail.com>
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
from migen import *
|
||||
|
||||
|
||||
class PS7(Module):
|
||||
def __init__(self, platform, ps7_name=None):
|
||||
self.frstn = Signal()
|
||||
self.ps7_tcl = []
|
||||
self.platform = platform
|
||||
|
||||
self.ps7_name = "Zynq" if ps7_name is None else ps7_name
|
||||
|
||||
ps7_clk = platform.request("ps7_clk")
|
||||
ps7_porb = platform.request("ps7_porb")
|
||||
ps7_srstb = platform.request("ps7_srstb")
|
||||
ps7_mio = platform.request("ps7_mio")
|
||||
ps7_ddram = platform.request("ps7_ddram")
|
||||
|
||||
self.cpu_params = dict(
|
||||
# Clk / Rst.
|
||||
io_PS_CLK = ps7_clk,
|
||||
io_PS_PORB = ps7_porb,
|
||||
io_PS_SRSTB = ps7_srstb,
|
||||
|
||||
# MIO.
|
||||
io_MIO = ps7_mio,
|
||||
|
||||
# DDRAM.
|
||||
io_DDR_Addr = ps7_ddram.addr,
|
||||
io_DDR_BankAddr = ps7_ddram.ba,
|
||||
io_DDR_CAS_n = ps7_ddram.cas_n,
|
||||
io_DDR_Clk_n = ps7_ddram.ck_n,
|
||||
io_DDR_Clk = ps7_ddram.ck_p,
|
||||
io_DDR_CKE = ps7_ddram.cke,
|
||||
io_DDR_CS_n = ps7_ddram.cs_n,
|
||||
io_DDR_DM = ps7_ddram.dm,
|
||||
io_DDR_DQ = ps7_ddram.dq,
|
||||
io_DDR_DQS_n = ps7_ddram.dqs_n,
|
||||
io_DDR_DQS = ps7_ddram.dqs_p,
|
||||
io_DDR_ODT = ps7_ddram.odt,
|
||||
io_DDR_RAS_n = ps7_ddram.ras_n,
|
||||
io_DDR_DRSTB = ps7_ddram.reset_n,
|
||||
io_DDR_WEB = ps7_ddram.we_n,
|
||||
io_DDR_VRN = ps7_ddram.vrn,
|
||||
io_DDR_VRP = ps7_ddram.vrp,
|
||||
|
||||
# USB0.
|
||||
# i_USB0_VBUS_PWRFAULT = 0,
|
||||
|
||||
# Fabric Clk / Rst.
|
||||
# o_FCLK_CLK0 = ClockSignal("ps7"),
|
||||
o_FCLK_RESET0_N = self.frstn
|
||||
)
|
||||
|
||||
self.set_ps7(name=self.ps7_name,
|
||||
config={
|
||||
**self.platform.ps7_config
|
||||
})
|
||||
|
||||
def add_ps7_config(self, config):
|
||||
# Config must be provided as a config, value dict.
|
||||
assert isinstance(config, dict)
|
||||
# Add configs to PS7.
|
||||
self.ps7_tcl.append("set_property -dict [list \\")
|
||||
for config, value in config.items():
|
||||
self.ps7_tcl.append("CONFIG.{} {} \\".format(config, '{{' + str(value) + '}}'))
|
||||
self.ps7_tcl.append(f"] [get_ips {self.ps7_name}]")
|
||||
|
||||
def set_ps7(self, name=None, config=None, preset=None):
|
||||
self.ps7_name = name
|
||||
self.ps7_tcl.append(f"set ps7 [create_ip -vendor xilinx.com -name processing_system7 -module_name {self.ps7_name}]")
|
||||
self.add_ps7_config(config)
|
||||
|
||||
def add_axi_gp_master(self, interface):
|
||||
# assert type(interface) is Axi2Sys
|
||||
|
||||
axi_interface = interface
|
||||
|
||||
self.cpu_params.update({
|
||||
# AXI GP clk.
|
||||
f"i_M_AXI_GP0_ACLK" : axi_interface.aclk,
|
||||
|
||||
# AXI GP aw.
|
||||
f"o_M_AXI_GP0_AWVALID" : axi_interface.awvalid,
|
||||
f"i_M_AXI_GP0_AWREADY" : axi_interface.awready,
|
||||
f"o_M_AXI_GP0_AWADDR" : axi_interface.awaddr,
|
||||
f"o_M_AXI_GP0_AWBURST" : axi_interface.awburst,
|
||||
f"o_M_AXI_GP0_AWLEN" : axi_interface.awlen,
|
||||
f"o_M_AXI_GP0_AWSIZE" : axi_interface.awsize,
|
||||
f"o_M_AXI_GP0_AWID" : axi_interface.awid,
|
||||
f"o_M_AXI_GP0_AWLOCK" : axi_interface.awlock,
|
||||
f"o_M_AXI_GP0_AWPROT" : axi_interface.awprot,
|
||||
f"o_M_AXI_GP0_AWCACHE" : axi_interface.awcache,
|
||||
f"o_M_AXI_GP0_AWQOS" : axi_interface.awqos,
|
||||
|
||||
# AXI GP w.
|
||||
f"o_M_AXI_GP0_WVALID" : axi_interface.wvalid,
|
||||
f"o_M_AXI_GP0_WLAST" : axi_interface.wlast,
|
||||
f"i_M_AXI_GP0_WREADY" : axi_interface.wready,
|
||||
f"o_M_AXI_GP0_WID" : axi_interface.wid,
|
||||
f"o_M_AXI_GP0_WDATA" : axi_interface.wdata,
|
||||
f"o_M_AXI_GP0_WSTRB" : axi_interface.wstrb,
|
||||
|
||||
# AXI GP b.
|
||||
f"i_M_AXI_GP0_BVALID" : axi_interface.bvalid,
|
||||
f"o_M_AXI_GP0_BREADY" : axi_interface.bready,
|
||||
f"i_M_AXI_GP0_BID" : axi_interface.bid,
|
||||
f"i_M_AXI_GP0_BRESP" : axi_interface.bresp,
|
||||
|
||||
# AXI GP ar.
|
||||
f"o_M_AXI_GP0_ARVALID" : axi_interface.arvalid,
|
||||
f"i_M_AXI_GP0_ARREADY" : axi_interface.arready,
|
||||
f"o_M_AXI_GP0_ARADDR" : axi_interface.araddr,
|
||||
f"o_M_AXI_GP0_ARBURST" : axi_interface.arburst,
|
||||
f"o_M_AXI_GP0_ARLEN" : axi_interface.arlen,
|
||||
f"o_M_AXI_GP0_ARID" : axi_interface.arid,
|
||||
f"o_M_AXI_GP0_ARLOCK" : axi_interface.arlock,
|
||||
f"o_M_AXI_GP0_ARSIZE" : axi_interface.arsize,
|
||||
f"o_M_AXI_GP0_ARPROT" : axi_interface.arprot,
|
||||
f"o_M_AXI_GP0_ARCACHE" : axi_interface.arcache,
|
||||
f"o_M_AXI_GP0_ARQOS" : axi_interface.arqos,
|
||||
|
||||
# AXI GP r.
|
||||
f"i_M_AXI_GP0_RVALID" : axi_interface.rvalid,
|
||||
f"o_M_AXI_GP0_RREADY" : axi_interface.rready,
|
||||
f"i_M_AXI_GP0_RLAST" : axi_interface.rlast,
|
||||
f"i_M_AXI_GP0_RID" : axi_interface.rid,
|
||||
f"i_M_AXI_GP0_RRESP" : axi_interface.rresp,
|
||||
f"i_M_AXI_GP0_RDATA" : axi_interface.rdata,
|
||||
})
|
||||
|
||||
def add_i2c_emio(self, platform, i2c_name, i2c_number):
|
||||
ps7_i2c_pads = platform.request(i2c_name, i2c_number) #, loose=True)
|
||||
if ps7_i2c_pads is not None:
|
||||
o_i2c_scl = Signal()
|
||||
i_i2c_scl = Signal()
|
||||
t_i2c_scl = Signal()
|
||||
o_i2c_sda = Signal()
|
||||
i_i2c_sda = Signal()
|
||||
t_i2c_sda = Signal()
|
||||
|
||||
self.specials += Instance("IOBUF",
|
||||
i_T = t_i2c_sda,
|
||||
i_I = o_i2c_sda,
|
||||
io_IO = ps7_i2c_pads.sda,
|
||||
o_O = i_i2c_sda,
|
||||
)
|
||||
|
||||
self.specials += Instance("IOBUF",
|
||||
i_T = t_i2c_scl,
|
||||
i_I = o_i2c_scl,
|
||||
io_IO = ps7_i2c_pads.scl,
|
||||
o_O = i_i2c_scl,
|
||||
)
|
||||
|
||||
self.cpu_params.update({
|
||||
f"i_I2C{i2c_number}_SCL_I" : i_i2c_scl,
|
||||
f"o_I2C{i2c_number}_SCL_T" : t_i2c_scl,
|
||||
f"o_I2C{i2c_number}_SCL_O" : o_i2c_scl,
|
||||
|
||||
f"i_I2C{i2c_number}_SDA_I" : i_i2c_sda,
|
||||
f"o_I2C{i2c_number}_SDA_T" : t_i2c_sda,
|
||||
f"o_I2C{i2c_number}_SDA_O" : o_i2c_sda,
|
||||
})
|
||||
|
||||
def do_finalize(self):
|
||||
if len(self.ps7_tcl):
|
||||
self.ps7_tcl += [
|
||||
f"upgrade_ip [get_ips {self.ps7_name}]",
|
||||
f"generate_target all [get_ips {self.ps7_name}]",
|
||||
f"synth_ip [get_ips {self.ps7_name}]"
|
||||
]
|
||||
self.platform.toolchain.pre_synthesis_commands += self.ps7_tcl
|
||||
|
||||
self.specials += Instance(self.ps7_name, **self.cpu_params)
|
141
fast-servo/linien-gateware/cores/spi_phy.py
Normal file
@ -0,0 +1,141 @@
|
||||
# This file is part of Fast Servo Software Package.
|
||||
#
|
||||
# Copyright (C) 2023 Jakub Matyas
|
||||
# Warsaw University of Technology <jakubk.m@gmail.com>
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
from enum import Enum
|
||||
|
||||
from migen import *
|
||||
|
||||
|
||||
class SpiInterface(Enum):
|
||||
ADC = 0
|
||||
DAC = 1
|
||||
|
||||
|
||||
class SpiPhy(Module):
|
||||
def __init__(self, spi_type, ps7_spi_pads):
|
||||
assert isinstance(spi_type, SpiInterface)
|
||||
|
||||
self.ps_ss = Signal(3, reset_less=True)
|
||||
|
||||
self.ps_miso_o = Signal()
|
||||
self.ps_miso_t = Signal()
|
||||
self.ps_mosi_o = Signal()
|
||||
self.ps_mosi_t = Signal()
|
||||
self.ps_sclk_o = Signal()
|
||||
self.ps_sclk_t = Signal()
|
||||
self.ps_sclk_i = Signal()
|
||||
self.ps_mosi_i = Signal()
|
||||
self.ps_miso_i = Signal()
|
||||
self.ps_ss_i = Signal()
|
||||
self.ps_ss_t = Signal()
|
||||
|
||||
if spi_type.name == "ADC":
|
||||
|
||||
cs_translated = Signal(4, reset_less=True)
|
||||
|
||||
main_adc_miso = Signal(reset_less=True)
|
||||
aux_adc_miso_a = Signal(reset_less=True)
|
||||
aux_adc_miso_b = Signal(reset_less=True)
|
||||
aux_dac_miso = Signal(reset_less=True)
|
||||
|
||||
miso_signals = [main_adc_miso, aux_adc_miso_a, aux_adc_miso_b, aux_dac_miso]
|
||||
|
||||
# MAIN ADC
|
||||
self.specials += Instance("OBUFT", i_I=self.ps_sclk_o, i_T=self.ps_sclk_t, o_O=ps7_spi_pads.sclk)
|
||||
self.specials += Instance("OBUFT", i_I=self.ps_mosi_o, i_T=self.ps_mosi_t, o_O=ps7_spi_pads.mosi)
|
||||
self.specials += Instance("IBUF", i_I=ps7_spi_pads.miso, o_O=main_adc_miso)
|
||||
|
||||
# AUX ADC
|
||||
self.specials += Instance("OBUFT", i_I=self.ps_sclk_o, i_T=self.ps_sclk_t, o_O=ps7_spi_pads.aux_adc_sclk)
|
||||
self.specials += Instance("IBUF", i_I=ps7_spi_pads.aux_adc_miso_a, o_O=aux_adc_miso_a)
|
||||
self.specials += Instance("IBUF", i_I=ps7_spi_pads.aux_adc_miso_b, o_O=aux_adc_miso_b)
|
||||
|
||||
# AUX DAC
|
||||
self.specials += Instance("OBUFT", i_I=self.ps_sclk_o, i_T=self.ps_sclk_t, o_O=ps7_spi_pads.aux_dac_sclk)
|
||||
self.specials += Instance("OBUFT", i_I=self.ps_mosi_o, i_T=self.ps_mosi_t, o_O=ps7_spi_pads.aux_dac_mosi)
|
||||
self.specials += Instance("IBUF", i_I=ps7_spi_pads.aux_dac_miso, o_O=aux_dac_miso)
|
||||
|
||||
cases = {}
|
||||
# for i in range(4):
|
||||
# case_mask = ~(1 << i) & 0xF
|
||||
# print(f"Case mask: 0b{case_mask:04b}")
|
||||
# cases[i + 1] = [
|
||||
# cs_translated.eq(case_mask),
|
||||
# self.ps_miso_i.eq(miso_signals[i])
|
||||
# ]
|
||||
|
||||
cases[0b001] = [
|
||||
cs_translated.eq(0b1110),
|
||||
self.ps_miso_i.eq(main_adc_miso),
|
||||
]
|
||||
|
||||
cases[0b010] = [
|
||||
cs_translated.eq(0b1101),
|
||||
self.ps_miso_i.eq(aux_adc_miso_a),
|
||||
]
|
||||
|
||||
cases[0b011] = [
|
||||
cs_translated.eq(0b1011),
|
||||
self.ps_miso_i.eq(aux_adc_miso_b),
|
||||
]
|
||||
cases[0b100] = [
|
||||
cs_translated.eq(0b0111),
|
||||
self.ps_miso_i.eq(aux_dac_miso),
|
||||
]
|
||||
|
||||
cases["default"] = [
|
||||
cs_translated.eq(0b1111),
|
||||
self.ps_miso_i.eq(0b1),
|
||||
]
|
||||
|
||||
self.comb += [
|
||||
self.ps_ss_i.eq(1),
|
||||
Case(self.ps_ss, cases),
|
||||
|
||||
ps7_spi_pads.cs.eq(cs_translated[0]),
|
||||
|
||||
# only one CS line physically available to AUX ADC
|
||||
ps7_spi_pads.aux_adc_cs.eq(cs_translated[1] & cs_translated[2]),
|
||||
ps7_spi_pads.aux_dac_miso.eq(cs_translated[3]),
|
||||
|
||||
]
|
||||
else:
|
||||
self.specials += Instance(
|
||||
"spi2threewire",
|
||||
o_ps_sclk_i = self.ps_sclk_i,
|
||||
i_ps_sclk_o = self.ps_sclk_o,
|
||||
i_ps_sclk_t = self.ps_sclk_t,
|
||||
|
||||
o_ps_mosi_i = self.ps_mosi_i,
|
||||
i_ps_mosi_o = self.ps_mosi_o,
|
||||
i_ps_mosi_t = self.ps_mosi_t,
|
||||
|
||||
o_ps_miso_i = self.ps_miso_i,
|
||||
i_ps_miso_o = self.ps_miso_o,
|
||||
i_ps_miso_t = self.ps_miso_t,
|
||||
|
||||
o_ps_ss_i = self.ps_ss_i,
|
||||
i_ps_ss = self.ps_ss,
|
||||
i_ps_ss_t = self.ps_ss_t,
|
||||
|
||||
o_o_ss = ps7_spi_pads.cs,
|
||||
o_o_sclk = ps7_spi_pads.sclk,
|
||||
io_sdio = ps7_spi_pads.sdio,
|
||||
)
|
||||
|
336
fast-servo/linien-gateware/fast_servo_platform.py
Normal file
@ -0,0 +1,336 @@
|
||||
# This file is part of Fast Servo Software Package.
|
||||
#
|
||||
# Copyright (C) 2022-2023 Jakub Matyas
|
||||
# Warsaw University of Technology <jakubk.m@gmail.com>
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
from migen.build.generic_platform import *
|
||||
from migen.build.xilinx import XilinxPlatform
|
||||
|
||||
import os
|
||||
from fast_servo.gateware import verilog_dir
|
||||
|
||||
|
||||
# IOs ----------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
_io = [
|
||||
# Front panel LEDs
|
||||
("fp_led", 0, Pins("G7"), IOStandard("LVCMOS25")),
|
||||
("fp_led", 1, Pins("G8"), IOStandard("LVCMOS25")),
|
||||
("fp_led", 2, Pins("G2"), IOStandard("LVCMOS25")),
|
||||
("fp_led", 3, Pins("G3"), IOStandard("LVCMOS25")),
|
||||
|
||||
# LEDs
|
||||
("user_led", 0, Pins("AB16"), IOStandard("LVCMOS33")),
|
||||
("user_led", 1, Pins("AA14"), IOStandard("LVCMOS33")),
|
||||
("user_led", 2, Pins("AA15"), IOStandard("LVCMOS33")),
|
||||
|
||||
# ETH LEDs
|
||||
("eth_led", 0, Pins("V11"), IOStandard("LVCMOS33")),
|
||||
("eth_led", 1, Pins("U13"), IOStandard("LVCMOS33")),
|
||||
|
||||
("from_eth_phy", 0, Pins("J3"), IOStandard("LVCMOS18")),
|
||||
("from_eth_phy", 1, Pins("K8"), IOStandard("LVCMOS18")),
|
||||
|
||||
|
||||
# CLK 100 MHz from oscillator
|
||||
("clk100", 0, Pins("Y14"), IOStandard("LVCMOS33")),
|
||||
|
||||
# MGT clk from on-board Si5338A
|
||||
("mgt_clk1", 0,
|
||||
Subsignal("p", Pins("U5")),
|
||||
Subsignal("n", Pins("V5")),
|
||||
IOStandard("LVDS_25"),
|
||||
),
|
||||
|
||||
# FCLK125 from on-board Si5338A
|
||||
("fclk125", 0, Pins("K2"), IOStandard("LVCMOS18")),
|
||||
|
||||
# # ADC CLK
|
||||
# ("fpga_clk", 0,
|
||||
# Subsignal("p", Pins("C6")),
|
||||
# Subsignal("n", Pins("C5")),
|
||||
# IOStandard("LVDS_25"),
|
||||
# ),
|
||||
|
||||
# DAC CLK
|
||||
("fpga_clk", 1,
|
||||
Subsignal("p", Pins("J7")),
|
||||
Subsignal("n", Pins("J6")),
|
||||
IOStandard("LVDS_25"),
|
||||
),
|
||||
|
||||
# MAIN ADC LT2195
|
||||
("adc", 0,
|
||||
Subsignal("data0_p", Pins("F7 B7 E4 D1"), IOStandard("LVDS_25")),
|
||||
Subsignal("data0_n", Pins("E7 B6 E3 C1"), IOStandard("LVDS_25")),
|
||||
Subsignal("data1_p", Pins("A2 D5 F2 D7"), IOStandard("LVDS_25")),
|
||||
Subsignal("data1_n", Pins("A1 C4 F1 D6"), IOStandard("LVDS_25")),
|
||||
Subsignal("dco_p", Pins("B4"), IOStandard("LVDS_25")),
|
||||
Subsignal("dco_n", Pins("B3"), IOStandard("LVDS_25")),
|
||||
Subsignal("frame_p", Pins("B2"), IOStandard("LVDS_25")),
|
||||
Subsignal("frame_n", Pins("B1"), IOStandard("LVDS_25"))
|
||||
),
|
||||
|
||||
# ADC AFE
|
||||
("adc_afe", 0,
|
||||
Subsignal("ch1_gain", Pins("AA12"), IOStandard("LVCMOS33")),
|
||||
Subsignal("ch2_gain", Pins("AB11"), IOStandard("LVCMOS33")),
|
||||
Subsignal("nshdn_ch1", Pins("G4"), IOStandard("LVCMOS25")),
|
||||
Subsignal("nshdn_ch2", Pins("F4"), IOStandard("LVCMOS25")),
|
||||
),
|
||||
|
||||
# P5 R5 N1 N4 L2 P6 N3 R4 P1 L1 M3 M4 U2 T2
|
||||
# MAIN DAC AD9117
|
||||
("dac", 0,
|
||||
Subsignal("data",
|
||||
Pins("T2 U2 M4 M3 L1 P1 R4 N3 P6 L2 N4 N1 R5 P5"),
|
||||
IOStandard("LVCMOS18")),
|
||||
Subsignal("dclkio", Pins("U1"), IOStandard("LVCMOS18")),
|
||||
Subsignal("rst", Pins("T1"), IOStandard("LVCMOS18")),
|
||||
),
|
||||
|
||||
# DAC AFE
|
||||
("dac_afe", 0,
|
||||
Subsignal("ch1_pd_n", Pins("L5")),
|
||||
Subsignal("ch2_pd_n", Pins("L4")),
|
||||
IOStandard("LVCMOS18"),
|
||||
),
|
||||
|
||||
# AUXILIARY ADC
|
||||
("aux_adc", 0,
|
||||
Subsignal("diff_n", Pins("W18")),
|
||||
Subsignal("a", Pins("AB18 AB19 W17")),
|
||||
Subsignal("range", Pins("U19")),
|
||||
IOStandard("LVCMOS33")
|
||||
),
|
||||
|
||||
# AUXILIARY DAC
|
||||
("aux_dac", 0,
|
||||
Subsignal("nclr", Pins("V19")),
|
||||
Subsignal("bin", Pins("AA19")),
|
||||
Subsignal("nldac", Pins("AB21")),
|
||||
IOStandard("LVCMOS33")
|
||||
),
|
||||
|
||||
# ADC SPI
|
||||
("spi", 0,
|
||||
Subsignal("sclk", Pins("J1"), IOStandard("LVCMOS18")),
|
||||
Subsignal("mosi", Pins("J5"), IOStandard("LVCMOS18")),
|
||||
Subsignal("miso", Pins("K5"), IOStandard("LVCMOS18")),
|
||||
Subsignal("cs", Pins("J2"), IOStandard("LVCMOS18")),
|
||||
Subsignal("aux_adc_sclk", Pins("AB22"), IOStandard("LVCMOS33")),
|
||||
Subsignal("aux_adc_miso_a", Pins("Y18"), IOStandard("LVCMOS33")),
|
||||
Subsignal("aux_adc_miso_b", Pins("AA16"), IOStandard("LVCMOS33")),
|
||||
Subsignal("aux_adc_cs", Pins("Y19"), IOStandard("LVCMOS33")),
|
||||
Subsignal("aux_dac_sclk", Pins("V18"), IOStandard("LVCMOS33")),
|
||||
Subsignal("aux_dac_mosi", Pins("U17"), IOStandard("LVCMOS33")),
|
||||
Subsignal("aux_dac_miso", Pins("U18"), IOStandard("LVCMOS33")),
|
||||
Subsignal("aux_dac_cs", Pins("AA20"), IOStandard("LVCMOS33")),
|
||||
),
|
||||
|
||||
# DAC SPI
|
||||
("spi", 1,
|
||||
Subsignal("sclk", Pins("K3"), IOStandard("LVCMOS18")),
|
||||
Subsignal("sdio", Pins("R2"), IOStandard("LVCMOS18")),
|
||||
Subsignal("cs", Pins("R3"), IOStandard("LVCMOS18")),
|
||||
# Subsignal("sclk_aux", Pins("V18"), IOStandard("LVCMOS33")),
|
||||
# Subsignal("mosi_aux", Pins("U17"), IOStandard("LVCMOS33")),
|
||||
# Subsignal("miso_aux", Pins("U18"), IOStandard("LVCMOS33")),
|
||||
# Subsignal("cs_aux", Pins("AA20"), IOStandard("LVCMOS33")),
|
||||
),
|
||||
#Pins("Y15 AB14 AB13 V13 V14 V15 U12 W13 W12 R17 W15 AB17 Y12 Y13 V16 W16 AA17 Y17"),
|
||||
("gpio", 0,
|
||||
Subsignal("n", Pins("Y15 AB14 AB13 V13 V14 V15 U12 W13"), IOStandard("LVCMOS33")),
|
||||
Subsignal("p", Pins("W12 R17 W15 AB17 Y12 Y13 V16 W16"), IOStandard("LVCMOS33")),
|
||||
),
|
||||
|
||||
# PS7
|
||||
("ps7_clk", 0, Pins("_" * 1)),
|
||||
("ps7_porb", 0, Pins("_" * 1)),
|
||||
("ps7_srstb", 0, Pins("_" * 1)),
|
||||
("ps7_mio", 0, Pins("_" * 54)),
|
||||
("ps7_ddram", 0,
|
||||
Subsignal("addr", Pins("_" * 15)),
|
||||
Subsignal("ba", Pins("_" * 3)),
|
||||
Subsignal("cas_n", Pins("_" * 1)),
|
||||
Subsignal("ck_n", Pins("_" * 1)),
|
||||
Subsignal("ck_p", Pins("_" * 1)),
|
||||
Subsignal("cke", Pins("_" * 1)),
|
||||
Subsignal("cs_n", Pins("_" * 1)),
|
||||
Subsignal("dm", Pins("_" * 4)),
|
||||
Subsignal("dq", Pins("_" * 32)),
|
||||
Subsignal("dqs_n", Pins("_" * 4)),
|
||||
Subsignal("dqs_p", Pins("_" * 4)),
|
||||
Subsignal("odt", Pins("_" * 1)),
|
||||
Subsignal("ras_n", Pins("_" * 1)),
|
||||
Subsignal("reset_n", Pins("_" * 1)),
|
||||
Subsignal("we_n", Pins("_" * 1)),
|
||||
Subsignal("vrn", Pins("_" * 1)),
|
||||
Subsignal("vrp", Pins("_" * 1)),
|
||||
|
||||
),
|
||||
|
||||
# I2C0 to Si5340 on Fast Servo
|
||||
("ps7_i2c", 0,
|
||||
Subsignal("sda", Pins("M2")),
|
||||
Subsignal("scl", Pins("M1")),
|
||||
IOStandard("LVCMOS18")
|
||||
),
|
||||
|
||||
# Si540 nRST
|
||||
("nrst", 0, Pins("M7"), IOStandard("LVCMOS18")),
|
||||
|
||||
]
|
||||
|
||||
|
||||
|
||||
_connector_eem = [
|
||||
("eem", {
|
||||
"d0_cc_n": "C3",
|
||||
"d0_cc_p": "D3",
|
||||
"d1_n": "A4",
|
||||
"d1_p": "A5",
|
||||
"d2_n": "F6",
|
||||
"d2_p": "G6",
|
||||
"d3_n": "A6",
|
||||
"d3_p": "A7",
|
||||
"d4_n": "E5",
|
||||
"d4_p": "F5",
|
||||
"d5_n": "H3",
|
||||
"d5_p": "H4",
|
||||
"d6_n": "B8",
|
||||
"d6_p": "C8",
|
||||
"d7_n": "D8",
|
||||
"d7_p": "E8",
|
||||
}),
|
||||
]
|
||||
|
||||
_connector_gpio = [
|
||||
("gpio", {
|
||||
"qspi_io3": "Y15",
|
||||
"qspi_io2": "AB14",
|
||||
"qspi_io1": "AB13",
|
||||
"qspi_io0": "V13",
|
||||
"qspi_clk": "V14",
|
||||
"qspi_ncs": "V15",
|
||||
"hrtim_che1": "U12",
|
||||
"hrtim_che2": "W13",
|
||||
"hrtim_cha1": "W12",
|
||||
"hrtim_cha2": "R17",
|
||||
"lptim2_out": "W15",
|
||||
"uart4_tx": "AB17",
|
||||
"spi1_mosi": "Y12",
|
||||
"spi1_miso": "Y13",
|
||||
"spi1_nss": "V16",
|
||||
"spi1_sck": "W16",
|
||||
"i2c1_sda": "AA17",
|
||||
"i2c1_scl": "Y17",
|
||||
})
|
||||
]
|
||||
|
||||
# PS7 config ---------------------------------------------------------------------------------------
|
||||
|
||||
ps7_config_board_preset = {
|
||||
"PCW_PRESET_BANK0_VOLTAGE" : "LVCMOS 3.3V",
|
||||
"PCW_PRESET_BANK1_VOLTAGE" : "LVCMOS 1.8V",
|
||||
"PCW_CRYSTAL_PERIPHERAL_FREQMHZ" : "33.333333",
|
||||
"PCW_QSPI_PERIPHERAL_ENABLE" : "1",
|
||||
"PCW_QSPI_GRP_SINGLE_SS_ENABLE" : "1",
|
||||
"PCW_SINGLE_QSPI_DATA_MODE" : "x4",
|
||||
"PCW_QSPI_QSPI_IO" : "MIO 1 .. 6",
|
||||
"PCW_QSPI_GRP_FBCLK_ENABLE" : "1",
|
||||
|
||||
# SD Card
|
||||
"PCW_SD0_PERIPHERAL_ENABLE" : "1",
|
||||
"PCW_SD0_SD0_IO" : "MIO 40 .. 45",
|
||||
"PCW_MIO_40_PULLUP" : "disabled",
|
||||
"PCW_MIO_41_PULLUP" : "disabled",
|
||||
"PCW_MIO_42_PULLUP" : "disabled",
|
||||
"PCW_MIO_43_PULLUP" : "disabled",
|
||||
"PCW_MIO_44_PULLUP" : "disabled",
|
||||
"PCW_MIO_45_PULLUP" : "disabled",
|
||||
|
||||
# UART
|
||||
"PCW_UART0_PERIPHERAL_ENABLE" : "1",
|
||||
"PCW_UART0_UART0_IO" : "MIO 10 .. 11",
|
||||
|
||||
# ETHERNET
|
||||
"PCW_ACT_ENET0_PERIPHERAL_FREQMHZ" : "125",
|
||||
"PCW_ENET0_PERIPHERAL_CLKSRC" : "ARM PLL",
|
||||
"PCW_ENET0_PERIPHERAL_ENABLE" : "1",
|
||||
"PCW_ENET0_ENET0_IO" : "MIO 16 .. 27",
|
||||
"PCW_ENET0_GRP_MDIO_ENABLE" : "1",
|
||||
"PCW_ENET0_GRP_MDIO_IO" : "MIO 52 .. 53",
|
||||
"PCW_ENET_RESET_ENABLE" : "1",
|
||||
"PCW_ENET0_RESET_ENABLE" : "1",
|
||||
"PCW_ENET0_RESET_IO" : "MIO 50",
|
||||
|
||||
# USB
|
||||
"PCW_USB0_PERIPHERAL_ENABLE" : "1",
|
||||
"PCW_USB0_USB0_IO" : "MIO 28 .. 39",
|
||||
"PCW_USB_RESET_ENABLE" : "1",
|
||||
"PCW_USB0_RESET_ENABLE" : "1",
|
||||
"PCW_USB0_RESET_IO" : "MIO 51",
|
||||
|
||||
"PCW_WDT_PERIPHERAL_ENABLE" : "1",
|
||||
"PCW_TTC0_PERIPHERAL_ENABLE" : "1", # TTC0 required for Linux
|
||||
|
||||
# I2C
|
||||
"PCW_I2C_RESET_ENABLE" : "0",
|
||||
"PCW_I2C_RESET_POLARITY" : "Active Low",
|
||||
|
||||
# I2C0
|
||||
"PCW_I2C0_I2C0_IO" : "EMIO",
|
||||
"PCW_I2C0_PERIPHERAL_ENABLE" : "1",
|
||||
"PCW_I2C0_GRP_INT_ENABLE" : "1",
|
||||
"PCW_I2C0_GRP_INT_IO" : "EMIO",
|
||||
|
||||
# I2C1
|
||||
"PCW_I2C1_PERIPHERAL_ENABLE" : "1",
|
||||
"PCW_I2C1_I2C1_IO" : "MIO 48 .. 49",
|
||||
"PCW_I2C1_I2C1_IO" : "MIO 12 .. 13",
|
||||
"PCW_I2C1_PERIPHERAL_ENABLE" : "1",
|
||||
|
||||
"PCW_UIPARAM_DDR_MEMORY_TYPE" : "DDR 3 (Low Voltage)",
|
||||
"PCW_UIPARAM_DDR_PARTNO" : "MT41J256M16 RE-125",
|
||||
"PCW_GPIO_MIO_GPIO_ENABLE" : "1",
|
||||
|
||||
"PCW_FPGA0_PERIPHERAL_FREQMHZ" : "100",
|
||||
"PCW_EN_CLK0_PORT" : "0", # dont use FCLK0
|
||||
}
|
||||
|
||||
class Platform(XilinxPlatform):
|
||||
default_clk_name = "clk100"
|
||||
default_clk_period = 10.0
|
||||
|
||||
def __init__(self):
|
||||
XilinxPlatform.__init__(self, "xc7z015-clg485-1", _io, _connector_gpio + _connector_eem, toolchain="vivado")
|
||||
ps7_config = ps7_config_board_preset
|
||||
self.ps7_config = ps7_config
|
||||
|
||||
verilog_sources = os.listdir(verilog_dir)
|
||||
self.add_sources(verilog_dir, *verilog_sources)
|
||||
|
||||
def do_finalize(self, fragment):
|
||||
try:
|
||||
XilinxPlatform.do_finalize(self, fragment)
|
||||
self.add_period_constraint(self.lookup_request(self.default_clk_name, loose=True), self.default_clk_period)
|
||||
except ValueError:
|
||||
pass
|
||||
except ConstraintError:
|
||||
pass
|
290
fast-servo/linien-gateware/fast_servo_soc.py
Normal file
@ -0,0 +1,290 @@
|
||||
# This file is part of Fast Servo Software Package.
|
||||
#
|
||||
# Copyright (C) 2023 Jakub Matyas
|
||||
# Warsaw University of Technology <jakubk.m@gmail.com>
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import os
|
||||
|
||||
from migen import *
|
||||
from misoc.interconnect import csr_bus
|
||||
from misoc.interconnect.csr import AutoCSR, CSRStorage
|
||||
|
||||
from fast_servo.gateware.cores.adc import ADC, AUX_ADC_CTRL
|
||||
from fast_servo.gateware.cores.dac import AUX_DAC_CTRL, DAC
|
||||
from fast_servo.gateware.cores.pitaya_ps import Axi2Sys, Sys2CSR, SysCDC, SysInterconnect
|
||||
from fast_servo.gateware.cores.ps7 import PS7
|
||||
from fast_servo.gateware.cores.spi_phy import SpiInterface, SpiPhy
|
||||
|
||||
|
||||
class CRG(Module):
|
||||
def __init__(self, platform):
|
||||
self.ps_rst = Signal()
|
||||
self.locked = Signal()
|
||||
self.clock_domains.cd_sys = ClockDomain()
|
||||
self.clock_domains.cd_sys_double = ClockDomain()
|
||||
self.clock_domains.cd_idelay = ClockDomain()
|
||||
|
||||
# # #
|
||||
|
||||
# Clk.
|
||||
clk100 = platform.request("clk100")
|
||||
platform.add_period_constraint(clk100, 10.0)
|
||||
self.clkin = clk100
|
||||
clk100_buf = Signal()
|
||||
self.specials += Instance("IBUFG", i_I=clk100, o_O=clk100_buf)
|
||||
|
||||
clk_feedback = Signal()
|
||||
clk_feedback_buf = Signal()
|
||||
|
||||
clk_sys = Signal()
|
||||
clk_idelay = Signal()
|
||||
|
||||
self.specials += [
|
||||
Instance(
|
||||
"PLLE2_BASE",
|
||||
p_BANDWIDTH="OPTIMIZED",
|
||||
p_DIVCLK_DIVIDE=1,
|
||||
p_CLKFBOUT_PHASE=0.0,
|
||||
p_CLKFBOUT_MULT=10,
|
||||
p_CLKIN1_PERIOD=10.0,
|
||||
p_REF_JITTER1=0.01,
|
||||
p_STARTUP_WAIT="FALSE",
|
||||
i_CLKIN1=clk100_buf,
|
||||
i_PWRDWN=0,
|
||||
i_RST=self.ps_rst,
|
||||
i_CLKFBIN=clk_feedback_buf,
|
||||
o_CLKFBOUT=clk_feedback,
|
||||
p_CLKOUT0_DIVIDE=10,
|
||||
p_CLKOUT0_PHASE=0.0,
|
||||
p_CLKOUT0_DUTY_CYCLE=0.5,
|
||||
o_CLKOUT0=clk_sys, # 100 MHz <- sys_clk
|
||||
p_CLKOUT1_DIVIDE=5,
|
||||
p_CLKOUT1_PHASE=0.0,
|
||||
p_CLKOUT1_DUTY_CYCLE=0.5,
|
||||
o_CLKOUT1=clk_idelay, # 200 MHZ <- 2 * sys_clk = 2*100 MHz
|
||||
o_LOCKED=self.locked,
|
||||
)
|
||||
]
|
||||
|
||||
self.specials += Instance("BUFG", i_I=clk_feedback, o_O=clk_feedback_buf)
|
||||
self.specials += Instance("BUFG", i_I=clk_sys, o_O=self.cd_sys.clk)
|
||||
self.specials += Instance("BUFG", i_I=clk_idelay, o_O=self.cd_idelay.clk)
|
||||
self.specials += Instance("BUFG", i_I=clk_idelay, o_O=self.cd_sys_double.clk)
|
||||
|
||||
|
||||
# Ignore sys_clk to pll clkin path created by SoC's rst.
|
||||
platform.add_false_path_constraints(self.cd_sys.clk, self.clkin)
|
||||
|
||||
self.specials += Instance("FD", p_INIT=1, i_D=~self.locked, i_C=self.cd_sys.clk, o_Q=self.cd_sys.rst)
|
||||
|
||||
|
||||
class BaseSoC(PS7, AutoCSR):
|
||||
def __init__(self, platform, passthrouh=False):
|
||||
PS7.__init__(self, platform)
|
||||
|
||||
# TODO:
|
||||
# LINIEN SPECIFIC csr_map - in the future should be moved
|
||||
# to csr_devices list
|
||||
self.csr_map = {
|
||||
"adc": 9,
|
||||
"fp_led0": 10,
|
||||
"fp_led1": 11,
|
||||
"fp_led2": 12,
|
||||
"fp_led3": 13,
|
||||
"dac": 14,
|
||||
"adc_aux_ctrl": 15,
|
||||
"dac_aux_ctrl": 16,
|
||||
}
|
||||
self.soc_name = "FastServo"
|
||||
self.interconnect_slaves = []
|
||||
self.csr_devices = []
|
||||
|
||||
self.platform = platform
|
||||
|
||||
self.submodules.crg = CRG(platform)
|
||||
|
||||
# # # AXI to system bus bridge
|
||||
self.submodules.axi2sys = Axi2Sys()
|
||||
self.submodules.sys2csr = Sys2CSR()
|
||||
self.submodules.syscdc = SysCDC()
|
||||
self.add_axi_gp_master(self.axi2sys.axi)
|
||||
|
||||
self.comb += [
|
||||
self.axi2sys.axi.aclk.eq(ClockSignal("sys")),
|
||||
self.axi2sys.axi.arstn.eq(self.frstn),
|
||||
self.syscdc.target.connect(self.sys2csr.sys),
|
||||
]
|
||||
|
||||
# ETH LEDS
|
||||
self.comb += [
|
||||
platform.request("eth_led", 0).eq(platform.request("from_eth_phy", 0)),
|
||||
platform.request("eth_led", 1).eq(platform.request("from_eth_phy", 1)),
|
||||
]
|
||||
|
||||
# I2C0 to Si5340 on Fast Servo
|
||||
self.add_i2c_emio(platform, "ps7_i2c", 0)
|
||||
|
||||
# SPI0 - interface to main ADC and auxiliary ADC
|
||||
self.add_spi_interface(platform, SpiInterface.ADC)
|
||||
|
||||
# SPI1 - interface to main DAC and auxiliary DAC
|
||||
self.add_spi_interface(platform, SpiInterface.DAC)
|
||||
|
||||
# self.add_main_adc(platform)
|
||||
self.submodules.adc = ADC(platform)
|
||||
self.csr_devices.append("adc")
|
||||
|
||||
# self.add_main_dac(platform)
|
||||
self.submodules.dac = DAC(platform)
|
||||
self.csr_devices.append("dac")
|
||||
|
||||
# DEBUG
|
||||
if passthrouh:
|
||||
DAC_DATA_WIDTH = 14
|
||||
for ch in range(2):
|
||||
saturate = Signal()
|
||||
adc_signal = self.adc.data_out[ch]
|
||||
self.comb += [
|
||||
saturate.eq(adc_signal[-3:] != Replicate(adc_signal[-1], 3)),
|
||||
self.dac.data_in[ch].eq(Mux(saturate,
|
||||
Cat(Replicate(~adc_signal[-1], DAC_DATA_WIDTH-1), adc_signal[-1]),
|
||||
adc_signal[:-2]))
|
||||
]
|
||||
|
||||
si_5340_nrst = platform.request("nrst")
|
||||
self.comb += si_5340_nrst.eq(1)
|
||||
|
||||
for i in range(4):
|
||||
led_pin = platform.request("fp_led", i)
|
||||
setattr(self.submodules, f"fp_led{i}", LED(led_pin))
|
||||
self.csr_devices.append(f"fp_led{i}")
|
||||
|
||||
self.submodules.adc_aux_ctrl = AUX_ADC_CTRL(platform)
|
||||
self.csr_devices.append("adc_aux_ctrl")
|
||||
|
||||
self.submodules.dac_aux_ctrl = AUX_DAC_CTRL(platform)
|
||||
self.csr_devices.append("dac_aux_ctrl")
|
||||
|
||||
def add_spi_interface(self, platform, spi_type):
|
||||
assert isinstance(spi_type, SpiInterface)
|
||||
n = spi_type.value
|
||||
|
||||
ps7_spi_pads = platform.request("spi", spi_type.value)
|
||||
spi_phy = SpiPhy(spi_type, ps7_spi_pads)
|
||||
self.submodules += spi_phy
|
||||
|
||||
ps7_config_spi = {
|
||||
f"PCW_SPI{n}_GRP_SS0_ENABLE" : "1",
|
||||
f"PCW_SPI{n}_GRP_SS0_IO" : "EMIO",
|
||||
f"PCW_SPI{n}_GRP_SS1_ENABLE" : "1",
|
||||
f"PCW_SPI{n}_GRP_SS1_IO" : "EMIO",
|
||||
f"PCW_SPI{n}_GRP_SS2_ENABLE" : "1",
|
||||
f"PCW_SPI{n}_GRP_SS2_IO" : "EMIO",
|
||||
f"PCW_SPI{n}_PERIPHERAL_ENABLE" : "1",
|
||||
f"PCW_SPI{n}_SPI{n}_IO" : "EMIO",
|
||||
f"PCW_SPI_PERIPHERAL_CLKSRC" : "IO PLL",
|
||||
f"PCW_SPI_PERIPHERAL_DIVISOR0" : "10",
|
||||
f"PCW_SPI_PERIPHERAL_FREQMHZ" : "166.666666",
|
||||
}
|
||||
self.add_ps7_config(ps7_config_spi)
|
||||
|
||||
self.cpu_params.update({
|
||||
f"o_SPI{n}_MISO_O" : spi_phy.ps_miso_o,
|
||||
f"o_SPI{n}_MISO_T" : spi_phy.ps_miso_t,
|
||||
f"o_SPI{n}_MOSI_O" : spi_phy.ps_mosi_o,
|
||||
f"o_SPI{n}_MOSI_T" : spi_phy.ps_mosi_t,
|
||||
f"o_SPI{n}_SCLK_O" : spi_phy.ps_sclk_o,
|
||||
f"o_SPI{n}_SCLK_T" : spi_phy.ps_sclk_t,
|
||||
|
||||
f"i_SPI{n}_SCLK_I" : spi_phy.ps_sclk_i,
|
||||
f"i_SPI{n}_MOSI_I" : spi_phy.ps_mosi_i,
|
||||
f"i_SPI{n}_MISO_I" : spi_phy.ps_miso_i,
|
||||
f"i_SPI{n}_SS_I" : spi_phy.ps_ss_i,
|
||||
f"o_SPI{n}_SS_O" : spi_phy.ps_ss[0],
|
||||
f"o_SPI{n}_SS1_O" : spi_phy.ps_ss[1],
|
||||
f"o_SPI{n}_SS2_O" : spi_phy.ps_ss[2],
|
||||
f"o_SPI{n}_SS_T" : spi_phy.ps_ss_t,
|
||||
})
|
||||
|
||||
def add_interconnect_slave(self, slave):
|
||||
self.interconnect_slaves.append(slave)
|
||||
|
||||
def get_csr_dev_address(self, name, memory):
|
||||
# TODO: switch to MiSoC-like address retriving from
|
||||
# the list of CSR devices
|
||||
if memory is not None:
|
||||
name = name + "_" + memory.name_override
|
||||
try:
|
||||
return self.csr_map[name]
|
||||
except KeyError:
|
||||
return None
|
||||
|
||||
def soc_finalize(self):
|
||||
# Overload this method to customize SystemInterconnect
|
||||
# and csrbanks - especially useful in Linien
|
||||
self.add_interconnect_slave(self.syscdc.source)
|
||||
self.submodules.interconnect = SysInterconnect(
|
||||
self.axi2sys.sys,
|
||||
*self.interconnect_slaves
|
||||
)
|
||||
self.submodules.csrbanks = csr_bus.CSRBankArray(self,
|
||||
self.get_csr_dev_address)
|
||||
self.submodules.csrcon = csr_bus.Interconnect(
|
||||
self.sys2csr.csr, self.csrbanks.get_buses()
|
||||
)
|
||||
|
||||
def do_finalize(self):
|
||||
self.soc_finalize()
|
||||
PS7.do_finalize(self)
|
||||
|
||||
def build(self, *args, **kwargs):
|
||||
self.platform.build(self, *args, **kwargs)
|
||||
|
||||
class LED(Module, AutoCSR):
|
||||
def __init__(self, led):
|
||||
|
||||
self.led_out = CSRStorage(1)
|
||||
|
||||
self.comb += led.eq(self.led_out.storage)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import subprocess
|
||||
from fast_servo.gateware.fast_servo_platform import Platform
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--debug", action="store_true", default=False, help="Hardwire ADC data to DAC")
|
||||
args = parser.parse_args()
|
||||
|
||||
|
||||
root_path = os.getcwd()
|
||||
platform = Platform()
|
||||
fast_servo = BaseSoC(platform, passthrouh=args.debug)
|
||||
|
||||
build_dir = "builds/fast_servo_gw_debug" if args.debug else"builds/fast_servo_gw"
|
||||
build_name = "top"
|
||||
fast_servo.build(build_dir=build_dir, build_name=build_name, run=True)
|
||||
os.chdir(os.path.join(root_path, build_dir))
|
||||
with open(f"{build_name}.bif", "w") as f:
|
||||
f.write(f"all:\n{{\n\t{build_name}.bit\n}}")
|
||||
|
||||
cmd = f"bootgen -image {build_name}.bif -arch zynq -process_bitstream bin -w on".split(" ")
|
||||
subprocess.run(cmd)
|
||||
|
||||
|
||||
|
162
fast-servo/linien-gateware/verilog/LTC2195.v
Normal file
@ -0,0 +1,162 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// LTC2195.v
|
||||
//
|
||||
// 8/03/21
|
||||
// Jakub Matyas
|
||||
//
|
||||
// LTC2195 controller.
|
||||
//
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// `include "timescale.v"
|
||||
`timescale 1ns/1ps // this was in the SelectIO design
|
||||
|
||||
module LTC2195(
|
||||
input rst_in,
|
||||
input clk200,
|
||||
input DCO,
|
||||
input DCO_2D,
|
||||
input FR_in_p,
|
||||
input FR_in_n,
|
||||
input [3:0] D0_in_p,
|
||||
input [3:0] D0_in_n,
|
||||
input [3:0] D1_in_p,
|
||||
input [3:0] D1_in_n,
|
||||
input bitslip,
|
||||
input [4:0] delay_val,
|
||||
|
||||
output reg [15:0] ADC0_out,
|
||||
output reg [15:0] ADC1_out,
|
||||
output reg [3:0] FR_out,
|
||||
output wire [8:0] o_data_from_pins,
|
||||
output idelay_rdy
|
||||
);
|
||||
|
||||
// ///////////////////////////////////////////////////////////////////////////////
|
||||
// // LVDS inputs
|
||||
|
||||
localparam N_BITS = 4;
|
||||
localparam N_LANES = 9; // for each channel 4 lanes + 1 lane for FRAME
|
||||
wire [N_LANES-1:0] data_in_p, data_in_n, data_in_from_pins, data_in_from_pins_delay;
|
||||
assign data_in_p = {FR_in_p, D1_in_p, D0_in_p};
|
||||
assign data_in_n = {FR_in_n, D1_in_n, D0_in_n};
|
||||
assign o_data_from_pins = data_in_from_pins_delay;
|
||||
|
||||
|
||||
wire [N_LANES*4 -1:0] data_out;
|
||||
wire [35:0 ]data_out_mod;
|
||||
|
||||
|
||||
assign data_out_mod = {~data_out[35:24], data_out[23:20], ~data_out[19:16], data_out[15:0]};
|
||||
|
||||
|
||||
always @(posedge DCO_2D) begin
|
||||
ADC0_out <= {
|
||||
data_out_mod[0], data_out_mod[4], data_out_mod[1], data_out_mod[5],
|
||||
data_out_mod[2], data_out_mod[6], data_out_mod[3], data_out_mod[7],
|
||||
data_out_mod[8], data_out_mod[12], data_out_mod[9], data_out_mod[13],
|
||||
data_out_mod[10], data_out_mod[14], data_out_mod[11], data_out_mod[15]
|
||||
};
|
||||
|
||||
ADC1_out <= {
|
||||
data_out_mod[16 + 0], data_out_mod[16 + 4], data_out_mod[16 + 1], data_out_mod[16 + 5],
|
||||
data_out_mod[16 + 2], data_out_mod[16 + 6], data_out_mod[16 + 3], data_out_mod[16 + 7],
|
||||
data_out_mod[16 + 8], data_out_mod[16 + 12], data_out_mod[16 + 9], data_out_mod[16 + 13],
|
||||
data_out_mod[16 + 10], data_out_mod[16 + 14], data_out_mod[16 + 11], data_out_mod[16 + 15]
|
||||
};
|
||||
FR_out <= {data_out_mod[32], data_out_mod[33], data_out_mod[34], data_out_mod[35]}; // value that arrived first is LSB, therefore reversing order
|
||||
end
|
||||
|
||||
wire s_idelay_rdy;
|
||||
IDELAYCTRL IDELAYCTRL_inst (
|
||||
.RDY(s_idelay_rdy), // 1-bit output: Ready output
|
||||
.REFCLK(clk200), // 1-bit input: Reference clock input
|
||||
.RST(s_rst) // 1-bit input: Active high reset input
|
||||
);
|
||||
|
||||
assign idelay_rdy = s_idelay_rdy;
|
||||
|
||||
|
||||
reg s_rst;
|
||||
reg [5:0] rst_cnt;
|
||||
wire serdes_o;
|
||||
|
||||
always @(posedge DCO_2D) begin
|
||||
if (rst_in) begin
|
||||
s_rst <= 1'b1;
|
||||
rst_cnt <= 'b0;
|
||||
end else begin
|
||||
if (rst_cnt == 22)
|
||||
s_rst <= 'b0;
|
||||
else
|
||||
rst_cnt <= rst_cnt + 1;
|
||||
end
|
||||
end
|
||||
|
||||
genvar lane;
|
||||
generate for (lane=0; lane<N_LANES; lane=lane+1) begin
|
||||
IBUFDS #(
|
||||
.DIFF_TERM("TRUE")
|
||||
)
|
||||
ibufds_inst (
|
||||
.I(data_in_p[lane]),
|
||||
.IB(data_in_n[lane]),
|
||||
.O(data_in_from_pins[lane])
|
||||
);
|
||||
IDELAYE2 #(
|
||||
.CINVCTRL_SEL("FALSE"), // Enable dynamic clock inversion (FALSE, TRUE)
|
||||
.DELAY_SRC("IDATAIN"), // Delay input (IDATAIN, DATAIN)
|
||||
.HIGH_PERFORMANCE_MODE("TRUE"), // Reduced jitter ("TRUE"), Reduced power ("FALSE")
|
||||
.IDELAY_TYPE("VAR_LOAD"), // FIXED, VARIABLE, VAR_LOAD, VAR_LOAD_PIPE
|
||||
.IDELAY_VALUE(0), // Input delay tap setting (0-31)
|
||||
.PIPE_SEL("FALSE"), // Select pipelined mode, FALSE, TRUE
|
||||
.REFCLK_FREQUENCY(200.0), // IDELAYCTRL clock input frequency in MHz (190.0-210.0, 290.0-310.0).
|
||||
.SIGNAL_PATTERN("DATA") // DATA, CLOCK input signal
|
||||
)
|
||||
IDELAYE2_inst (
|
||||
.C(clk200),
|
||||
.CE('b0),
|
||||
.CNTVALUEIN(delay_val),
|
||||
.LD(1'b1),
|
||||
.DATAOUT(data_in_from_pins_delay[lane]), // 1-bit output: Delayed data output
|
||||
.IDATAIN(data_in_from_pins[lane]), // 1-bit input: Data input from the I/O
|
||||
.LDPIPEEN (1'b0),
|
||||
.REGRST (1'b0),
|
||||
.CINVCTRL (1'b0)
|
||||
);
|
||||
|
||||
ISERDESE2 #(
|
||||
.DATA_RATE("DDR"),
|
||||
.DATA_WIDTH(3'd4),
|
||||
.INTERFACE_TYPE("NETWORKING"),
|
||||
.IOBDELAY("BOTH"),
|
||||
.SERDES_MODE("MASTER"),
|
||||
.NUM_CE(2'd2)
|
||||
)
|
||||
iserdes_inst (
|
||||
.CE1(1'd1),
|
||||
.CE2(1'd1),
|
||||
.DYNCLKDIVSEL('b0),
|
||||
.DYNCLKSEL('b0),
|
||||
.CLK(DCO),
|
||||
.CLKB(!DCO),
|
||||
.CLKDIV(DCO_2D),
|
||||
// .D(data_in_from_pins[lane]),
|
||||
.DDLY(data_in_from_pins_delay[lane]),
|
||||
.RST(s_rst),
|
||||
.BITSLIP(bitslip),
|
||||
// DATA is MSB first and OUTA is LANE0, so in case of OUTA:
|
||||
// Q1 = D9
|
||||
// Q2 = D11
|
||||
// Q3 = D13
|
||||
// Q4 = D15
|
||||
.Q1(data_out[lane*N_BITS + 3]),
|
||||
.Q2(data_out[lane*N_BITS + 2]),
|
||||
.Q3(data_out[lane*N_BITS + 1]),
|
||||
.Q4(data_out[lane*N_BITS + 0])
|
||||
);
|
||||
end
|
||||
endgenerate
|
||||
|
||||
endmodule
|
265
fast-servo/linien-gateware/verilog/axi_slave.v
Normal file
@ -0,0 +1,265 @@
|
||||
/**
|
||||
* $Id: axi_slave.v 961 2014-01-21 11:40:39Z matej.oblak $
|
||||
*
|
||||
* @brief Red Pitaya symplified AXI slave.
|
||||
*
|
||||
* @Author Matej Oblak
|
||||
*
|
||||
* (c) Red Pitaya http://www.redpitaya.com
|
||||
*
|
||||
* This part of code is written in Verilog hardware description language (HDL).
|
||||
* Please visit http://en.wikipedia.org/wiki/Verilog
|
||||
* for more details on the language used herein.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* GENERAL DESCRIPTION:
|
||||
*
|
||||
* AXI slave used also for simple bus master.
|
||||
*
|
||||
*
|
||||
* /------\
|
||||
* WR ADDRESS ----> | WR |
|
||||
* WR DATA ----> | | -----------
|
||||
* WR RESPONSE <---- | CH | |
|
||||
* \------/ /--------\
|
||||
* | SIMPLE | ---> WR/RD ADDRRESS
|
||||
* AXI | | ---> WR DATA
|
||||
* | RP | <--- RD DATA
|
||||
* | BUS | <--- ACKNOWLEDGE
|
||||
* /------\ \--------/
|
||||
* RD ADDRESS ----> | RD | |
|
||||
* RD DATA <---- | CH | -----------
|
||||
* \------/
|
||||
*
|
||||
*
|
||||
* Because AXI bus is quite complex simplier bus was created.
|
||||
*
|
||||
* It combines write and read channel, where write has bigger priority. Command
|
||||
* is then send forward to red pitaya bus. When wite or read acknowledge is
|
||||
* received AXI response is created and new AXI is accepted.
|
||||
*
|
||||
* To prevent AXI lockups because no response is received, this slave creates its
|
||||
* own after 32 cycles (ack_cnt).
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
module axi_slave
|
||||
#(
|
||||
parameter AXI_DW = 64 , // data width (8,16,...,1024)
|
||||
parameter AXI_AW = 32 , // address width
|
||||
parameter AXI_IW = 8 , // ID width
|
||||
parameter AXI_SW = AXI_DW >> 3 // strobe width - 1 bit for every data byte
|
||||
)
|
||||
(
|
||||
// global signals
|
||||
input axi_clk_i , //!< AXI global clock
|
||||
input axi_rstn_i , //!< AXI global reset
|
||||
|
||||
// axi write address channel
|
||||
input [ AXI_IW-1: 0] axi_awid_i , //!< AXI write address ID
|
||||
input [ AXI_AW-1: 0] axi_awaddr_i , //!< AXI write address
|
||||
input [ 4-1: 0] axi_awlen_i , //!< AXI write burst length
|
||||
input [ 3-1: 0] axi_awsize_i , //!< AXI write burst size
|
||||
input [ 2-1: 0] axi_awburst_i , //!< AXI write burst type
|
||||
input [ 2-1: 0] axi_awlock_i , //!< AXI write lock type
|
||||
input [ 4-1: 0] axi_awcache_i , //!< AXI write cache type
|
||||
input [ 3-1: 0] axi_awprot_i , //!< AXI write protection type
|
||||
input axi_awvalid_i , //!< AXI write address valid
|
||||
output axi_awready_o , //!< AXI write ready
|
||||
|
||||
// axi write data channel
|
||||
input [ AXI_IW-1: 0] axi_wid_i , //!< AXI write data ID
|
||||
input [ AXI_DW-1: 0] axi_wdata_i , //!< AXI write data
|
||||
input [ AXI_SW-1: 0] axi_wstrb_i , //!< AXI write strobes
|
||||
input axi_wlast_i , //!< AXI write last
|
||||
input axi_wvalid_i , //!< AXI write valid
|
||||
output axi_wready_o , //!< AXI write ready
|
||||
|
||||
// axi write response channel
|
||||
output [ AXI_IW-1: 0] axi_bid_o , //!< AXI write response ID
|
||||
output reg [ 2-1: 0] axi_bresp_o , //!< AXI write response
|
||||
output reg axi_bvalid_o , //!< AXI write response valid
|
||||
input axi_bready_i , //!< AXI write response ready
|
||||
|
||||
// axi read address channel
|
||||
input [ AXI_IW-1: 0] axi_arid_i , //!< AXI read address ID
|
||||
input [ AXI_AW-1: 0] axi_araddr_i , //!< AXI read address
|
||||
input [ 4-1: 0] axi_arlen_i , //!< AXI read burst length
|
||||
input [ 3-1: 0] axi_arsize_i , //!< AXI read burst size
|
||||
input [ 2-1: 0] axi_arburst_i , //!< AXI read burst type
|
||||
input [ 2-1: 0] axi_arlock_i , //!< AXI read lock type
|
||||
input [ 4-1: 0] axi_arcache_i , //!< AXI read cache type
|
||||
input [ 3-1: 0] axi_arprot_i , //!< AXI read protection type
|
||||
input axi_arvalid_i , //!< AXI read address valid
|
||||
output axi_arready_o , //!< AXI read address ready
|
||||
|
||||
// axi read data channel
|
||||
output [ AXI_IW-1: 0] axi_rid_o , //!< AXI read response ID
|
||||
output reg [ AXI_DW-1: 0] axi_rdata_o , //!< AXI read data
|
||||
output reg [ 2-1: 0] axi_rresp_o , //!< AXI read response
|
||||
output reg axi_rlast_o , //!< AXI read last
|
||||
output reg axi_rvalid_o , //!< AXI read response valid
|
||||
input axi_rready_i , //!< AXI read response ready
|
||||
|
||||
// RP system read/write channel
|
||||
output [ AXI_AW-1: 0] sys_addr_o , //!< system bus read/write address.
|
||||
output [ AXI_DW-1: 0] sys_wdata_o , //!< system bus write data.
|
||||
output reg [ AXI_SW-1: 0] sys_sel_o , //!< system bus write byte select.
|
||||
output reg sys_wen_o , //!< system bus write enable.
|
||||
output reg sys_ren_o , //!< system bus read enable.
|
||||
input [ AXI_DW-1: 0] sys_rdata_i , //!< system bus read data.
|
||||
input sys_err_i , //!< system bus error indicator.
|
||||
input sys_ack_i //!< system bus acknowledge signal.
|
||||
);
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
//
|
||||
// AXI slave Module
|
||||
wire ack ;
|
||||
reg [ 6-1: 0] ack_cnt ;
|
||||
|
||||
reg rd_do ;
|
||||
reg [ AXI_IW-1: 0] rd_arid ;
|
||||
reg [ AXI_AW-1: 0] rd_araddr ;
|
||||
reg rd_error ;
|
||||
wire rd_errorw ;
|
||||
|
||||
reg wr_do ;
|
||||
reg [ AXI_IW-1: 0] wr_awid ;
|
||||
reg [ AXI_AW-1: 0] wr_awaddr ;
|
||||
reg [ AXI_IW-1: 0] wr_wid ;
|
||||
reg [ AXI_DW-1: 0] wr_wdata ;
|
||||
reg wr_error ;
|
||||
wire wr_errorw ;
|
||||
|
||||
assign wr_errorw = (axi_awlen_i != 4'h0) || (axi_awsize_i != 3'b010); // error if write burst and more/less than 4B transfer
|
||||
assign rd_errorw = (axi_arlen_i != 4'h0) || (axi_arsize_i != 3'b010); // error if read burst and more/less than 4B transfer
|
||||
|
||||
always @(posedge axi_clk_i) begin
|
||||
if (axi_rstn_i == 1'b0) begin
|
||||
rd_do <= 1'b0 ;
|
||||
rd_error <= 1'b0 ;
|
||||
end
|
||||
else begin
|
||||
if (axi_arvalid_i && !rd_do && !axi_awvalid_i && !wr_do) // accept just one read request - write has priority
|
||||
rd_do <= 1'b1 ;
|
||||
else if (axi_rready_i && rd_do && ack)
|
||||
rd_do <= 1'b0 ;
|
||||
|
||||
if (axi_arvalid_i && axi_arready_o) begin // latch ID and address
|
||||
rd_arid <= axi_arid_i ;
|
||||
rd_araddr <= axi_araddr_i ;
|
||||
rd_error <= rd_errorw ;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
always @(posedge axi_clk_i) begin
|
||||
if (axi_rstn_i == 1'b0) begin
|
||||
wr_do <= 1'b0 ;
|
||||
wr_error <= 1'b0 ;
|
||||
end
|
||||
else begin
|
||||
if (axi_awvalid_i && !wr_do && !rd_do) // accept just one write request - if idle
|
||||
wr_do <= 1'b1 ;
|
||||
else if (axi_bready_i && wr_do && ack)
|
||||
wr_do <= 1'b0 ;
|
||||
|
||||
if (axi_awvalid_i && axi_awready_o) begin // latch ID and address
|
||||
wr_awid <= axi_awid_i ;
|
||||
wr_awaddr <= axi_awaddr_i ;
|
||||
wr_error <= wr_errorw ;
|
||||
end
|
||||
|
||||
if (axi_wvalid_i && wr_do) begin // latch ID and write data
|
||||
wr_wid <= axi_wid_i ;
|
||||
wr_wdata <= axi_wdata_i ;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
assign axi_awready_o = !wr_do && !rd_do ;
|
||||
assign axi_wready_o = (wr_do && axi_wvalid_i) || (wr_errorw && axi_wvalid_i) ;
|
||||
assign axi_bid_o = wr_awid ;
|
||||
//assign axi_bresp_o = {wr_error,1'b0} ; // 2'b10 SLVERR
|
||||
//assign axi_bvalid_o = (sys_wen_o && axi_bready_i) || (wr_error && axi_bready_i) ;
|
||||
|
||||
assign axi_arready_o = !rd_do && !wr_do && !axi_awvalid_i ;
|
||||
assign axi_rid_o = rd_arid ;
|
||||
//assign axi_rdata_o = sys_rdata_i ;
|
||||
|
||||
always @(posedge axi_clk_i) begin
|
||||
if (axi_rstn_i == 1'b0) begin
|
||||
axi_bvalid_o <= 1'b0 ;
|
||||
axi_bresp_o <= 2'h0 ;
|
||||
axi_rlast_o <= 1'b0 ;
|
||||
axi_rvalid_o <= 1'b0 ;
|
||||
axi_rresp_o <= 2'h0 ;
|
||||
end
|
||||
else begin
|
||||
axi_bvalid_o <= wr_do && ack ;
|
||||
axi_bresp_o <= {(wr_error || ack_cnt[5]),1'b0} ; // 2'b10 SLVERR 2'b00 OK
|
||||
axi_rlast_o <= rd_do && ack ;
|
||||
axi_rvalid_o <= rd_do && ack ;
|
||||
axi_rresp_o <= {(rd_error || ack_cnt[5]),1'b0} ; // 2'b10 SLVERR 2'b00 OK
|
||||
axi_rdata_o <= sys_rdata_i ;
|
||||
end
|
||||
end
|
||||
|
||||
// acknowledge protection
|
||||
always @(posedge axi_clk_i) begin
|
||||
if (axi_rstn_i == 1'b0) begin
|
||||
ack_cnt <= 6'h0 ;
|
||||
end
|
||||
else begin
|
||||
if ((axi_arvalid_i && axi_arready_o) || (axi_awvalid_i && axi_awready_o)) // rd || wr request
|
||||
ack_cnt <= 6'h1 ;
|
||||
else if (ack)
|
||||
ack_cnt <= 6'h0 ;
|
||||
else if (|ack_cnt)
|
||||
ack_cnt <= ack_cnt + 6'h1 ;
|
||||
end
|
||||
end
|
||||
|
||||
assign ack = sys_ack_i || ack_cnt[5] || (rd_do && rd_errorw) || (wr_do && wr_errorw); // bus acknowledge or timeout or error
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//------------------------------------------
|
||||
// Simple slave interface
|
||||
|
||||
always @(posedge axi_clk_i) begin
|
||||
if (axi_rstn_i == 1'b0) begin
|
||||
sys_wen_o <= 1'b0 ;
|
||||
sys_ren_o <= 1'b0 ;
|
||||
sys_sel_o <= {AXI_SW{1'b0}} ;
|
||||
end
|
||||
else begin
|
||||
sys_wen_o <= wr_do && axi_wvalid_i && !wr_errorw ;
|
||||
sys_ren_o <= axi_arvalid_i && axi_arready_o && !rd_errorw ;
|
||||
sys_sel_o <= {AXI_SW{1'b1}} ;
|
||||
end
|
||||
end
|
||||
|
||||
assign sys_addr_o = rd_do ? rd_araddr : wr_awaddr ;
|
||||
assign sys_wdata_o = wr_wdata ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
endmodule
|
128
fast-servo/linien-gateware/verilog/bus_clk_bridge.v
Normal file
@ -0,0 +1,128 @@
|
||||
/**
|
||||
* $Id: bus_clk_bridge.v 961 2014-01-21 11:40:39Z matej.oblak $
|
||||
*
|
||||
* @brief Red Pitaya system bus clock crossing bridge.
|
||||
*
|
||||
* @Author Matej Oblak
|
||||
*
|
||||
* (c) Red Pitaya http://www.redpitaya.com
|
||||
*
|
||||
* This part of code is written in Verilog hardware description language (HDL).
|
||||
* Please visit http://en.wikipedia.org/wiki/Verilog
|
||||
* for more details on the language used herein.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* GENERAL DESCRIPTION:
|
||||
*
|
||||
* Clock domain bridge for system bus.
|
||||
*
|
||||
*
|
||||
* /------\
|
||||
* SYSTEM | | PROCESSING
|
||||
* BUS <-----> | SYNC | <-----> BUS
|
||||
* | |
|
||||
* \------/
|
||||
*
|
||||
*
|
||||
* System bus runs on one clock domain while processing runs on separate. To
|
||||
* simplify transition of writing and reading data this bridge was created.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
module bus_clk_bridge
|
||||
(
|
||||
// system bus
|
||||
input sys_clk_i , //!< bus clock
|
||||
input sys_rstn_i , //!< bus reset - active low
|
||||
input [ 32-1: 0] sys_addr_i , //!< bus address
|
||||
input [ 32-1: 0] sys_wdata_i , //!< bus write data
|
||||
input [ 4-1: 0] sys_sel_i , //!< bus write byte select
|
||||
input sys_wen_i , //!< bus write enable
|
||||
input sys_ren_i , //!< bus read enable
|
||||
output [ 32-1: 0] sys_rdata_o , //!< bus read data
|
||||
output sys_err_o , //!< bus error indicator
|
||||
output sys_ack_o , //!< bus acknowledge signal
|
||||
|
||||
|
||||
// Destination bus
|
||||
input clk_i , //!< clock
|
||||
input rstn_i , //!< reset - active low
|
||||
output reg [ 32-1: 0] addr_o , //!< address
|
||||
output reg [ 32-1: 0] wdata_o , //!< write data
|
||||
output wen_o , //!< write enable
|
||||
output ren_o , //!< read enable
|
||||
input [ 32-1: 0] rdata_i , //!< read data
|
||||
input err_i , //!< error indicator
|
||||
input ack_i //!< acknowledge signal
|
||||
);
|
||||
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
// Synchronize signals between clock domains
|
||||
|
||||
reg sys_rd ;
|
||||
reg sys_wr ;
|
||||
reg sys_do ;
|
||||
reg [ 2-1: 0] sys_sync ;
|
||||
reg sys_done ;
|
||||
reg dst_do ;
|
||||
reg [ 2-1: 0] dst_sync ;
|
||||
reg dst_done ;
|
||||
|
||||
always @(posedge sys_clk_i) begin
|
||||
if (sys_rstn_i == 1'b0) begin
|
||||
sys_rd <= 1'b0 ;
|
||||
sys_wr <= 1'b0 ;
|
||||
sys_do <= 1'b0 ;
|
||||
sys_sync <= 2'h0 ;
|
||||
sys_done <= 1'b0 ;
|
||||
end
|
||||
else begin
|
||||
|
||||
if ((sys_do == sys_done) && (sys_wen_i || sys_ren_i)) begin
|
||||
addr_o <= sys_addr_i ;
|
||||
wdata_o <= sys_wdata_i ;
|
||||
sys_rd <= sys_ren_i ;
|
||||
sys_wr <= sys_wen_i ;
|
||||
sys_do <= !sys_do ;
|
||||
end
|
||||
|
||||
sys_sync <= {sys_sync[0], dst_done};
|
||||
sys_done <= sys_sync[1];
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
always @(posedge clk_i) begin
|
||||
if (rstn_i == 1'b0) begin
|
||||
dst_do <= 1'b0 ;
|
||||
dst_sync <= 2'h0 ;
|
||||
dst_done <= 1'b0 ;
|
||||
end
|
||||
else begin
|
||||
dst_sync <= {dst_sync[0], sys_do};
|
||||
dst_do <= dst_sync[1];
|
||||
|
||||
if (ack_i && (dst_do != dst_done))
|
||||
dst_done <= dst_do;
|
||||
end
|
||||
end
|
||||
|
||||
assign ren_o = sys_rd && (dst_sync[1]^dst_do);
|
||||
assign wen_o = sys_wr && (dst_sync[1]^dst_do);
|
||||
|
||||
|
||||
assign sys_rdata_o = rdata_i ;
|
||||
assign sys_err_o = err_i ;
|
||||
assign sys_ack_o = sys_done ^ sys_sync[1] ;
|
||||
|
||||
|
||||
|
||||
endmodule
|
111
fast-servo/linien-gateware/verilog/spi2threewire.v
Normal file
@ -0,0 +1,111 @@
|
||||
`timescale 1ns / 1ps
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// Company: WUT
|
||||
// Engineer: Jakub Matyas
|
||||
//
|
||||
// Create Date: 03/02/2023 01:39:08 PM
|
||||
// Design Name:
|
||||
// Module Name: spi2threewire
|
||||
// Project Name:
|
||||
// Target Devices:
|
||||
// Tool Versions:
|
||||
// Description:
|
||||
//
|
||||
// Dependencies:
|
||||
//
|
||||
// Revision:
|
||||
// Revision 0.01 - File Created
|
||||
// Additional Comments:
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
module spi2threewire (
|
||||
output ps_sclk_i,
|
||||
input ps_sclk_o,
|
||||
input ps_sclk_t,
|
||||
|
||||
output ps_mosi_i,
|
||||
input ps_mosi_o,
|
||||
input ps_mosi_t,
|
||||
|
||||
output ps_miso_i,
|
||||
input ps_miso_o,
|
||||
input ps_miso_t,
|
||||
|
||||
output ps_ss_i,
|
||||
input [2:0] ps_ss,
|
||||
input ps_ss_t,
|
||||
|
||||
output o_ss,
|
||||
output o_sclk,
|
||||
inout sdio
|
||||
|
||||
);
|
||||
|
||||
assign ps_sclk_i = 1'b0;
|
||||
assign ps_mosi_i = 1'b0;
|
||||
assign ps_ss_i = 1'b1;
|
||||
|
||||
|
||||
reg [3:0] bit_count = 'd0;
|
||||
|
||||
// rd_wr_n - whether it will be READ transaction or WRITE
|
||||
// first bit of the command
|
||||
reg rd_wr_n = 'd0;
|
||||
reg sdio_buffer_direction = 'd0;
|
||||
|
||||
wire s_sclk;
|
||||
wire s_csn;
|
||||
wire s_sdio_buffer_direction;
|
||||
|
||||
assign s_sclk = ps_sclk_o;
|
||||
assign s_csn = ps_ss[0];
|
||||
assign o_ss = s_csn;
|
||||
|
||||
// 1 if there is a SPI tranmsission going on (CS_N is LOW)
|
||||
// AND transmission is of READ type
|
||||
// 0 otherwise
|
||||
assign s_sdio_buffer_direction = sdio_buffer_direction & ~s_csn;
|
||||
|
||||
always @(posedge s_sclk or posedge s_csn) begin
|
||||
if (s_csn == 1'b1) begin
|
||||
// after the transmission, fill bit counter with ZEROS
|
||||
// and zero transmission type (rd_wr_n)
|
||||
bit_count <= 4'd0;
|
||||
rd_wr_n <= 1'b0;
|
||||
end else begin
|
||||
// on every rising edge increment bit counter
|
||||
// sample first bit to get the knowledge of the transmission type
|
||||
bit_count <= (bit_count < 4'd15) ? bit_count + 1'b1 : bit_count;
|
||||
if (bit_count == 4'b0)
|
||||
rd_wr_n <= ps_mosi_o;
|
||||
end
|
||||
end
|
||||
|
||||
always @(negedge s_sclk or posedge s_csn) begin
|
||||
if (s_csn == 1'b1)
|
||||
sdio_buffer_direction <= 1'b0;
|
||||
else begin
|
||||
if (bit_count == 4'd8)
|
||||
// after the 8th bit, on falling edge,
|
||||
// set the SDIO buffer direction
|
||||
// accordingly to the transmission type
|
||||
sdio_buffer_direction <= rd_wr_n;
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
IOBUF IOBUF_inst (
|
||||
.O(ps_miso_i),
|
||||
.IO(sdio),
|
||||
.I(ps_mosi_o),
|
||||
.T(s_sdio_buffer_direction) // 3-state enable input, high=input (from ext), low=output
|
||||
);
|
||||
|
||||
OBUFT sclk_buf (
|
||||
.O(o_sclk),
|
||||
.I(ps_sclk_o),
|
||||
.T('b0)
|
||||
);
|
||||
|
||||
endmodule
|
44
flake.lock
generated
@ -18,11 +18,11 @@
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1703961334,
|
||||
"narHash": "sha256-M1mV/Cq+pgjk0rt6VxoyyD+O8cOUiai8t9Q6Yyq4noY=",
|
||||
"lastModified": 1706107048,
|
||||
"narHash": "sha256-SqcJ9KxQVY+eLojoqYuJhWa4+D9utUzEuFJzOcUS8iY=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "b0d36bd0a420ecee3bc916c91886caca87c894e9",
|
||||
"rev": "6fd7935607b68a96949b51ff08f12109e99ffd1f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@ -56,7 +56,43 @@
|
||||
"root": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs",
|
||||
"not-os": "not-os"
|
||||
"not-os": "not-os",
|
||||
"src-migen": "src-migen",
|
||||
"src-misoc": "src-misoc"
|
||||
}
|
||||
},
|
||||
"src-migen": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1702942348,
|
||||
"narHash": "sha256-gKIfHZxsv+jcgDFRW9mPqmwqbZXuRvXefkZcSFjOGHw=",
|
||||
"owner": "m-labs",
|
||||
"repo": "migen",
|
||||
"rev": "50934ad10a87ade47219b796535978b9bdf24023",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "m-labs",
|
||||
"repo": "migen",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"src-misoc": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1699352904,
|
||||
"narHash": "sha256-SglyTmXOPv8jJOjwAjJrj/WhAkItQfUbvKfUqrynwRg=",
|
||||
"ref": "refs/heads/master",
|
||||
"rev": "a53859f2167c31ab5225b6c09f30cf05527b94f4",
|
||||
"revCount": 2452,
|
||||
"submodules": true,
|
||||
"type": "git",
|
||||
"url": "https://github.com/m-labs/misoc.git"
|
||||
},
|
||||
"original": {
|
||||
"submodules": true,
|
||||
"type": "git",
|
||||
"url": "https://github.com/m-labs/misoc.git"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
89
flake.nix
@ -5,7 +5,10 @@
|
||||
inputs.not-os.url = github:cleverca22/not-os;
|
||||
inputs.not-os.inputs.nixpkgs.follows = "nixpkgs";
|
||||
|
||||
outputs = { self, nixpkgs, not-os }:
|
||||
inputs.src-migen = { url = github:m-labs/migen; flake = false; };
|
||||
inputs.src-misoc = { type = "git"; url = "https://github.com/m-labs/misoc.git"; submodules = true; flake = false; };
|
||||
|
||||
outputs = { self, nixpkgs, not-os, src-migen, src-misoc }:
|
||||
let
|
||||
pkgs = import nixpkgs { system = "x86_64-linux"; };
|
||||
not-os-cfg = not-os-configured.config.system;
|
||||
@ -22,6 +25,48 @@
|
||||
];
|
||||
};
|
||||
|
||||
migen = pkgs.python3Packages.buildPythonPackage rec {
|
||||
name = "migen";
|
||||
src = src-migen;
|
||||
format = "pyproject";
|
||||
nativeBuildInputs = [ pkgs.python3Packages.setuptools ];
|
||||
propagatedBuildInputs = [ pkgs.python3Packages.colorama ];
|
||||
};
|
||||
|
||||
misoc = pkgs.python3Packages.buildPythonPackage {
|
||||
name = "misoc";
|
||||
src = src-misoc;
|
||||
propagatedBuildInputs = with pkgs.python3Packages; [ jinja2 numpy migen pyserial asyncserial ];
|
||||
};
|
||||
|
||||
vivado = pkgs.buildFHSEnv {
|
||||
name = "vivado";
|
||||
targetPkgs = pkgs: with pkgs; let
|
||||
# Apply patch from https://github.com/nix-community/nix-environments/pull/54
|
||||
# to fix ncurses libtinfo.so's soname issue
|
||||
ncurses' = ncurses5.overrideAttrs (old: {
|
||||
configureFlags = old.configureFlags ++ [ "--with-termlib" ];
|
||||
postFixup = "";
|
||||
});
|
||||
in [
|
||||
libxcrypt-legacy
|
||||
(ncurses'.override { unicodeSupport = false; })
|
||||
zlib
|
||||
libuuid
|
||||
xorg.libSM
|
||||
xorg.libICE
|
||||
xorg.libXrender
|
||||
xorg.libX11
|
||||
xorg.libXext
|
||||
xorg.libXtst
|
||||
xorg.libXi
|
||||
freetype
|
||||
fontconfig
|
||||
];
|
||||
profile = "set -e; source /opt/Xilinx/Vivado/2022.2/settings64.sh";
|
||||
runScript = "vivado";
|
||||
};
|
||||
|
||||
not-os-configured = (import patched-not-os {
|
||||
inherit nixpkgs;
|
||||
extraModules = [
|
||||
@ -145,6 +190,43 @@
|
||||
};
|
||||
};
|
||||
|
||||
fast-servo-gateware = pkgs.stdenv.mkDerivation rec {
|
||||
fsagbuya marked this conversation as resolved
Outdated
sb10q
commented
fast-servo-gateware = ... fast-servo-gateware = ...
|
||||
name = "fast-servo-gateware";
|
||||
inherit (pkgs.python3Packages.linien-common) src;
|
||||
prePatch = ''
|
||||
fsagbuya marked this conversation as resolved
Outdated
sb10q
commented
Shouldn't this be done in prePatch, not postUnpack? Shouldn't this be done in prePatch, not postUnpack?
fsagbuya
commented
prePatch handles modification on prePatch handles modification on `patches` attribute. It is selected here since it is only copying the files and not dealing with patches essentially.
sb10q
commented
Where did you get that information from? Where did you get that information from?
https://ryantm.github.io/nixpkgs/stdenv/stdenv/#var-stdenv-prePatch (and IIRC other sources) just say "Hook executed at the start of the patch phase."
fsagbuya
commented
Apologies, I maybe pointing to patchPhase not the prePatch. However applying it on prePatch returns a hunk error.
Apologies, I maybe pointing to [patchPhase](https://ryantm.github.io/nixpkgs/stdenv/stdenv/#ssec-patch-phase) not the prePatch. However applying it on prePatch returns a hunk error.
```
> --------------------------
> |diff --git a/fast_servo/gateware/fast_servo_soc.py b/fast_servo/gateware/fast_servo_soc.py
> |index 02128f5..abfc583 100644
> |--- a/fast_servo/gateware/fast_servo_soc.py
> |+++ b/fast_servo/gateware/fast_servo_soc.py
> --------------------------
> File to patch:
> Skip this patch? [y]
> Skipping patch.
> 1 out of 1 hunk ignored
```
sb10q
commented
Should be fairly easy to debug with ls etc. Should be fairly easy to debug with ls etc.
fsagbuya
commented
Running ls after
Running ls after `mkdir -p $sourceRoot/fast_servo/gateware` and it does not found the directory:
```
fast-servo-gateware> source root is source
fast-servo-gateware> Running phase: patchPhase
fast-servo-gateware> CHANGELOG.md README.md linien-client linien-server source
fast-servo-gateware> CITATION.cff docs linien-common mypy.ini tests
fast-servo-gateware> LICENSE gateware linien-gui pyproject.toml version-info.json
```
sb10q
commented
As usual please figure out what exactly what is going on and sort it out. As usual please figure out what exactly what is going on and sort it out.
fsagbuya
commented
Converted to Converted to `prePatch`. It does not need the variable `sourceRoot` now. 👍
|
||||
mkdir -p fast_servo/gateware
|
||||
cp -r ${./fast-servo/linien-gateware}/. fast_servo/gateware
|
||||
fsagbuya marked this conversation as resolved
Outdated
sb10q
commented
``/.`` should be removed I think?
fsagbuya
commented
Removing it will cause it to create a copy of the ls result:
Removing it will cause it to create a copy of the `linien-gateware` directory itself and not the contents alone.
ls result:
```
b535q358y1izxkmd4zfijf51ws9fsrn7-linien-gateware
```
|
||||
'';
|
||||
patches = [
|
||||
fast-servo/linien-fast-servo-gateware.patch
|
||||
fast-servo/linien-fast-servo-server.patch
|
||||
];
|
||||
fsagbuya marked this conversation as resolved
Outdated
sb10q
commented
To which patch does this commit refer to? To which patch does this commit refer to?
sb10q
commented
How does it relate to the provenance information in the patches? How does it relate to the provenance information in the patches?
fsagbuya
commented
Will clean this up and update to the match the provenance info from patches. Will clean this up and update to the match the provenance info from patches.
fsagbuya
commented
Removed the comment instead, since it will be described from the provenance info. Removed the comment instead, since it will be described from the provenance info.
|
||||
nativeBuildInputs = [
|
||||
(pkgs.python3.withPackages(ps: [
|
||||
migen misoc
|
||||
(ps.linien-common.overrideAttrs(oa: {
|
||||
fsagbuya marked this conversation as resolved
Outdated
sb10q
commented
What needs that? What needs that?
fsagbuya
commented
It is a fix to prevent this error:
It is a fix to prevent this error:
```
PermissionError: [Errno 13] Permission denied: '/homeless-shelter'
```
sb10q
commented
I've been using Nix for 6 years and I had already guessed that much. I've been using Nix for 6 years and I had already guessed that much.
|
||||
# config.py tries to access $HOME, but we do not need it for building gateware
|
||||
postPatch = ''
|
||||
fsagbuya marked this conversation as resolved
Outdated
sb10q
commented
You have not answered the question about which part of the build system needs $HOME. You have not answered the question about which part of the build system needs $HOME.
fsagbuya
commented
According to the trace log:
It is found on this part of the build system: According to the trace log:
```
FileNotFoundError: [Errno 2] No such file or directory: '/homeless-shelter/.local/share/linien'
```
It is found on this part of the build system:
https://github.com/elhep/linien/blob/fast_servo_merging/linien-common/linien_common/config.py#L27
sb10q
commented
Do we actually need this stuff to build the gateware or can config.py be replaced with an empty/dummy file? Do we actually need this stuff to build the gateware or can config.py be replaced with an empty/dummy file?
fsagbuya
commented
I think it can be replaced with an empty/dummy file, will test and have it added to the patch. I think it can be replaced with an empty/dummy file, will test and have it added to the patch.
fsagbuya
commented
Update: removed the Update: removed the `linien-common` dependency (which imports `config.py`) from the gateware build
sb10q
commented
What exactly did you change? What exactly did you change?
fsagbuya
commented
Added a new commit for the changes. Converted the variables to its actual value in Added a new commit for the changes. Converted the variables to its actual value in `linien_common` and `config.py`, so that we can omit the dependency for this use case.
sb10q
commented
That's much worse than even the one line of code that sets $HOME. I had suggested to edit config.py (and not other files), what is wrong with this approach? That's much worse than even the one line of code that sets $HOME. I had suggested to edit config.py (and not other files), what is wrong with this approach?
fsagbuya
commented
The config.py file that requires modification is part of the linien-common dependency:
To implement the necessary changes, we need to apply an override/overlay for the linien-common package in the upstream. Would this approach be acceptable? The config.py file that requires modification is part of the linien-common dependency:
```
nativeBuildInputs = [
(pkgs.python3.withPackages(ps: [ migen misoc ps.linien-common ]))
```
To implement the necessary changes, we need to apply an override/overlay for the linien-common package in the upstream. Would this approach be acceptable?
sb10q
commented
You can submit a clean patch upstream so building gateware doesn't need config.py/$HOME. And in the meantime something like:
You can submit a clean patch upstream so building gateware doesn't need config.py/$HOME. And in the meantime something like:
```
(pkgs.python3.withPackages(ps: [ migen misoc (ps.linien-common.overrideAttrs(oa: {
# config.py tries to access $HOME, but we do not need it for building gateware
postPatch = "echo > config.py";
doCheck = false;
}))
]))
```
fsagbuya
commented
Updated: Also need to modify the file
For this temporary fix, it is also set to an empty file. Other approach is to create a patch that removes related lines to config.py import. Updated: Also need to modify the [file](https://github.com/linien-org/linien/blob/master/linien-common/linien_common/__init__.py#L6) `__init__.py `:
```
> File "/nix/store/04nl55kmfkaacbv7vdm18gzhyl586r4r-python3.11-linien-common-1.0.1/lib/python3.11/site-packages/linien_common/__init__.py", line 6, in <module>
> from .config import LOG_FILE_PATH
> ImportError: cannot import name 'LOG_FILE_PATH' from 'linien_common.config'
```
For this temporary fix, it is also set to an empty file. Other approach is to create a patch that removes related lines to config.py import.
sb10q
commented
Aaah, the joys of physicist code. Removing the contents of that poorly designed Aaah, the joys of physicist code. Removing the contents of that poorly designed ``__init__.py`` sounds fine to me as well.
|
||||
echo > linien_common/config.py
|
||||
echo > linien_common/__init__.py
|
||||
'';
|
||||
doCheck = false;
|
||||
fsagbuya marked this conversation as resolved
Outdated
sb10q
commented
Indentation/style. My comment was just a hint, not a textual example. Indentation/style. My comment was just a hint, not a textual example.
|
||||
}))
|
||||
]))
|
||||
fsagbuya marked this conversation as resolved
Outdated
sb10q
commented
The directory name inconsistency in these two lines is very suspicious. The directory name inconsistency in these two lines is very suspicious.
fsagbuya
commented
This is linien's default output directory for the bin file. I agree this is suspicious. Will add a patch to use the same directory for the top.bit. This is [linien's default output directory](https://github.com/elhep/linien/blob/fast_servo_merging/gateware/fpga_image_helper.py#L101-L103) for the bin file. I agree this is suspicious. Will add a patch to use the same directory for the top.bit.
sb10q
commented
If this is an upstream issue then fine. Just want to make sure it's understood and not introduced here. If this is an upstream issue then fine. Just want to make sure it's understood and not introduced here.
|
||||
vivado
|
||||
];
|
||||
fsagbuya marked this conversation as resolved
Outdated
sb10q
commented
Why is it top.bit and gateware.bin? Why not top.bin? Why is it top.bit and gateware.bin? Why not top.bin?
sb10q
commented
(Assuming we need .bin at all) (Assuming we need .bin at all)
fsagbuya
commented
Will rename it as top.bin. Will rename it as top.bin.
sb10q
commented
https://git.m-labs.hk/M-Labs/nix-servo/pulls/37#issuecomment-9150
fsagbuya
commented
Okay. Will retain it as is. Okay. Will retain it as is.
|
||||
buildPhase = ''
|
||||
python -m gateware.fpga_image_helper -p fastservo
|
||||
'';
|
||||
installPhase = ''
|
||||
mkdir -p $out $out/nix-support
|
||||
cp gateware/build/top.bit $out
|
||||
cp linien-server/linien_server/gateware.bin $out
|
||||
echo file binary-dist $out/top.bit >> $out/nix-support/hydra-build-products
|
||||
echo file binary-dist $out/gateware.bin >> $out/nix-support/hydra-build-products
|
||||
'';
|
||||
};
|
||||
|
||||
mkbootimage = pkgs.stdenv.mkDerivation {
|
||||
pname = "mkbootimage";
|
||||
version = "2.3dev";
|
||||
@ -384,8 +466,11 @@
|
||||
in rec {
|
||||
packages.x86_64-linux = {
|
||||
inherit mkbootimage;
|
||||
inherit migen misoc vivado;
|
||||
};
|
||||
packages.armv7l-linux =
|
||||
packages.armv7l-linux = {
|
||||
inherit fast-servo-gateware;
|
||||
} //
|
||||
(board-package-set { board = "zc706"; }) //
|
||||
(board-package-set { board = "fast-servo"; });
|
||||
|
||||
|
What can I say about that?
Why do we need the .bin?
It seems that is the format supported by the fpga manager when loading gateware inside Linux.
Okay then.