From 506bbcc0db3c8efa960bd6a15990efca2e424caa Mon Sep 17 00:00:00 2001 From: Florian Agbuya Date: Fri, 23 Feb 2024 18:42:11 +0800 Subject: [PATCH] add fast-servo linien gateware --- fast-servo/linien-fast-servo-gateware.patch | 38 ++ fast-servo/linien-fast-servo-server.patch | 603 ++++++++++++++++++++ flake.lock | 44 +- flake.nix | 84 ++- 4 files changed, 761 insertions(+), 8 deletions(-) create mode 100644 fast-servo/linien-fast-servo-gateware.patch create mode 100644 fast-servo/linien-fast-servo-server.patch diff --git a/fast-servo/linien-fast-servo-gateware.patch b/fast-servo/linien-fast-servo-gateware.patch new file mode 100644 index 0000000..cb294fe --- /dev/null +++ b/fast-servo/linien-fast-servo-gateware.patch @@ -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) +- +- +- diff --git a/fast-servo/linien-fast-servo-server.patch b/fast-servo/linien-fast-servo-server.patch new file mode 100644 index 0000000..018f974 --- /dev/null +++ b/fast-servo/linien-fast-servo-server.patch @@ -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 + + 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 + # Copyright 2018-2022 Benjamin Wiegand ++# Copyright 2023 Jakub Matyas + # + # 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 + # Copyright 2021-2023 Bastian Leykauf + # Copyright 2022 Christian Freier ++# Copyright 2023 Jakub Matyas + # + # 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 ++# 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 . ++ ++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 ++# Copyright 2018-2022 Benjamin Wiegand ++# Copyright 2021-2023 Bastian Leykauf ++# Copyright 2022 Christian Freier ++# Copyright 2023 Jakub Matyas ++# ++# 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 . ++ ++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 diff --git a/flake.lock b/flake.lock index a9962ab..87b10ad 100644 --- a/flake.lock +++ b/flake.lock @@ -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" } } }, diff --git a/flake.nix b/flake.nix index 8880993..ccaa592 100644 --- a/flake.nix +++ b/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; @@ -23,6 +26,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 = [ @@ -146,6 +191,34 @@ }; }; + fast-servo-gateware = pkgs.stdenv.mkDerivation rec { + name = "fast-servo-gateware"; + inherit (pkgs.python3Packages.linien-common) src; + prePatch = '' + mkdir -p fast_servo/gateware + cp -r ${./fast-servo/linien-gateware}/. fast_servo/gateware + ''; + patches = [ + fast-servo/linien-fast-servo-gateware.patch + fast-servo/linien-fast-servo-server.patch + ]; + nativeBuildInputs = [ + (pkgs.python3.withPackages(ps: [ migen misoc ps.linien-common ])) + vivado + ]; + buildPhase = '' + export HOME=$(mktemp -d) + 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"; @@ -385,10 +458,13 @@ in rec { packages.x86_64-linux = { inherit mkbootimage; + 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; };