Add fast-servo linien gateware #37

Merged
sb10q merged 4 commits from fsagbuya/nix-servo:gateware into master 2024-03-01 16:39:57 +08:00
4 changed files with 761 additions and 8 deletions
Showing only changes of commit 86bffe7280 - Show all commits

View File

@ -0,0 +1,38 @@
# diff from elhep/Fast-Servo-Firmmware commit ID 7fae40c:
# https://github.com/elhep/Fast-Servo-Firmware/commit/7fae40c0f872a91218be378f8289b98b1e366729
Outdated
Review

What can I say about that?

What can I say about that?
Outdated
Review

Why do we need the .bin?

Why do we need the .bin?

It seems that is the format supported by the fpga manager when loading gateware inside Linux.

It seems that is the [format supported by the fpga manager](https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/18841645/Solution+Zynq+PL+Programming+With+FPGA+Manager#SolutionZynqPLProgrammingWithFPGAManager-MissingFeatures,KnownIssuesandLimitations) when loading gateware inside Linux.
Outdated
Review

Okay then.

Okay then.
# 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)
-
-
-

View 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
Outdated
Review

?

?
Outdated
Review

I don't see a fast-servo-linien.patch in b73eea0788 so this looks like your mistake.

I don't see a fast-servo-linien.patch in https://github.com/elhep/linien/tree/b73eea07889dda8b55f0cf4c2afde96cf4c3efd1 so this looks like your mistake.

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

44
flake.lock generated
View File

@ -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"
}
}
},

View File

@ -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,34 @@
};
};
fast-servo-gateware = pkgs.stdenv.mkDerivation rec {
fsagbuya marked this conversation as resolved Outdated
Outdated
Review

fast-servo-gateware = ...

fast-servo-gateware = ...
name = "fast-servo-gateware";
inherit (pkgs.python3Packages.linien-common) src;
prePatch = ''
fsagbuya marked this conversation as resolved Outdated
Outdated
Review

Shouldn't this be done in prePatch, not postUnpack?

Shouldn't this be done in prePatch, not postUnpack?

prePatch handles modification on patches attribute. It is selected here since it is only copying the files and not dealing with patches essentially.

prePatch handles modification on `patches` attribute. It is selected here since it is only copying the files and not dealing with patches essentially.
Outdated
Review

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."

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."

Apologies, I maybe pointing to patchPhase 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
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 ```
Outdated
Review

Should be fairly easy to debug with ls etc.

Should be fairly easy to debug with ls etc.

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
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 ```
Outdated
Review

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.

Converted to prePatch. It does not need the variable sourceRoot now. 👍

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
Outdated
Review

/. should be removed I think?

``/.`` should be removed I think?

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
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
Outdated
Review

To which patch does this commit refer to?

To which patch does this commit refer to?
Outdated
Review

How does it relate to the provenance information in the patches?

How does it relate to the provenance information in the patches?

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.

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 ]))
vivado
];
fsagbuya marked this conversation as resolved Outdated
Outdated
Review

What needs that?

What needs that?

It is a fix to prevent this error:

PermissionError: [Errno 13] Permission denied: '/homeless-shelter'
It is a fix to prevent this error: ``` PermissionError: [Errno 13] Permission denied: '/homeless-shelter' ```
Outdated
Review

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.
buildPhase = ''
export HOME=$(mktemp -d)
fsagbuya marked this conversation as resolved Outdated
Outdated
Review

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.

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

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
Outdated
Review

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?

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.

Update: removed the linien-common dependency (which imports config.py) from the gateware build

Update: removed the `linien-common` dependency (which imports `config.py`) from the gateware build
Outdated
Review

What exactly did you change?

What exactly did you change?

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.

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.
Outdated
Review

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?

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?

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?
Outdated
Review

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;
}))
]))
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; })) ])) ```

Updated: Also need to modify the file __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.

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.
Outdated
Review

Aaah, the joys of physicist code. Removing the contents of that poorly designed __init__.py sounds fine to me as well.

Aaah, the joys of physicist code. Removing the contents of that poorly designed ``__init__.py`` sounds fine to me as well.
python -m gateware.fpga_image_helper -p fastservo
'';
installPhase = ''
mkdir -p $out $out/nix-support
fsagbuya marked this conversation as resolved Outdated
Outdated
Review

Indentation/style. My comment was just a hint, not a textual example.

Indentation/style. My comment was just a hint, not a textual example.
cp gateware/build/top.bit $out
cp linien-server/linien_server/gateware.bin $out
fsagbuya marked this conversation as resolved Outdated
Outdated
Review

The directory name inconsistency in these two lines is very suspicious.

The directory name inconsistency in these two lines is very suspicious.

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.
Outdated
Review

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.
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
fsagbuya marked this conversation as resolved Outdated
Outdated
Review

Why is it top.bit and gateware.bin? Why not top.bin?

Why is it top.bit and gateware.bin? Why not top.bin?
Outdated
Review

(Assuming we need .bin at all)

(Assuming we need .bin at all)

Will rename it as top.bin.

Will rename it as top.bin.
Outdated
Review
https://git.m-labs.hk/M-Labs/nix-servo/pulls/37#issuecomment-9150

Okay. Will retain it as is.

Okay. Will retain it as is.
'';
};
mkbootimage = pkgs.stdenv.mkDerivation {
pname = "mkbootimage";
version = "2.3dev";
@ -384,10 +457,13 @@
in rec {
packages.x86_64-linux = {
inherit mkbootimage;
fsagbuya marked this conversation as resolved Outdated
Outdated
Review

See all my previous comments about this kind of situation.

See all my previous comments about this kind of situation.
inherit migen misoc vivado;
};
packages.armv7l-linux =
(board-package-set { board = "zc706"; }) //
(board-package-set { board = "fast-servo"; });
packages.armv7l-linux = {
inherit fast-servo-gateware;
} //
(board-package-set { board = "zc706"; }) //
(board-package-set { board = "fast-servo"; });
hydraJobs = packages.x86_64-linux // packages.armv7l-linux;
};