Compare commits

..

No commits in common. "master" and "armv7l-cache" have entirely different histories.

35 changed files with 191 additions and 5503 deletions

1
.gitignore vendored
View File

@ -1,2 +1 @@
__pycache__
result result

View File

@ -1,7 +1,7 @@
# 0 "system-top.dts" # 0 "my_dts/system-top.dts"
# 0 "<built-in>" # 0 "<built-in>"
# 0 "<command-line>" # 0 "<command-line>"
# 1 "system-top.dts" # 1 "my_dts/system-top.dts"
@ -10,8 +10,8 @@
/dts-v1/; /dts-v1/;
# 1 "zynq-7000.dtsi" 1 # 1 "my_dts/zynq-7000.dtsi" 1
# 15 "zynq-7000.dtsi" # 15 "my_dts/zynq-7000.dtsi"
/ { / {
#address-cells = <1>; #address-cells = <1>;
#size-cells = <1>; #size-cells = <1>;
@ -564,8 +564,8 @@
}; };
}; };
}; };
# 10 "system-top.dts" 2 # 10 "my_dts/system-top.dts" 2
# 1 "pcw.dtsi" 1 # 1 "my_dts/pcw.dtsi" 1
@ -641,48 +641,7 @@
fclk-enable = <0x0>; fclk-enable = <0x0>;
ps-clk-frequency = <33333333>; ps-clk-frequency = <33333333>;
}; };
# 11 "system-top.dts" 2 # 11 "my_dts/system-top.dts" 2
# 1 "system-user.dtsi" 1
&spi0 {
is-decoded-cs = <1>;
num-cs = <4>;
spidev@1 {
compatible = "rohm,dh2228fv";
spi-max-frequency = <50000000>;
reg = <1>;
};
spidev@2 {
compatible = "rohm,dh2228fv";
spi-max-frequency = <50000000>;
reg = <2>;
};
spidev@3 {
compatible = "rohm,dh2228fv";
spi-max-frequency = <50000000>;
reg = <3>;
};
spidev@4 {
compatible = "rohm,dh2228fv";
spi-max-frequency = <50000000>;
reg = <4>;
};
};
&spi1 {
spidev@0 {
compatible = "rohm,dh2228fv";
spi-max-frequency = <50000000>;
reg = <0>;
};
};
# 12 "system-top.dts" 2
/ { / {
model = "Sinara Fast Servo board"; model = "Sinara Fast Servo board";
chosen { chosen {

View File

@ -1,38 +0,0 @@
# 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)
-
-
-

View File

@ -1,603 +0,0 @@
# 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 <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

View File

@ -1,5 +0,0 @@
## Source Repository
Files in this directory were copied from [elhep/Fast-Servo-Firmware](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).

View File

@ -1,3 +0,0 @@
import os
verilog_dir = os.path.join(os.path.abspath(os.path.dirname(__file__)), "verilog")

View File

@ -1,219 +0,0 @@
# 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
from misoc.interconnect.stream import AsyncFIFO
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()
self.clock_domains.cd_dco2d_45_degree = 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()
clk_dco2d_45_degree = Signal()
mmcm_ps_psdone = Signal()
self.locked = Signal()
self.mmcm_rst = Signal()
self.ddr_clk_phase_shift_en = Signal()
self.ddr_clk_phase_incdec = Signal()
platform.add_period_constraint(dco_clk_p, 1e9 / dco_freq)
self.specials += [
Instance(
"MMCME2_ADV",
p_BANDWIDTH="OPTIMIZED",
p_DIVCLK_DIVIDE=1,
p_CLKFBOUT_PHASE=0.0,
p_CLKFBOUT_MULT_F=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") | self.mmcm_rst,
i_CLKFBIN=clk_feedback_buf,
o_CLKFBOUT=clk_feedback,
p_CLKOUT0_USE_FINE_PS="TRUE",
p_CLKOUT0_DIVIDE_F=8,
p_CLKOUT0_PHASE=45.0,
p_CLKOUT0_DUTY_CYCLE=0.5,
o_CLKOUT0=clk_dco2d_45_degree, # 100 MHz <- dco_clk / 2 = 200 MHz / 2
o_LOCKED=self.locked,
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
p_CLKOUT3_DIVIDE=4,
p_CLKOUT3_PHASE=0.0,
p_CLKOUT3_DUTY_CYCLE=0.5,
o_CLKOUT3=clk_dco, # 200 MHz <- dco_clk
i_PSCLK=ClockSignal(),
i_PSEN=self.ddr_clk_phase_shift_en,
i_PSINCDEC=self.ddr_clk_phase_incdec,
o_PSDONE=mmcm_ps_psdone,
)
]
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_dco2d_45_degree, o_O=self.cd_dco2d_45_degree.clk)
self.specials += Instance("BUFG", i_I=clk_dco2x, o_O=self.cd_dco2x.clk)
# Ignore dco2d to mmcm dco_clk path created by SoC's rst.
platform.add_false_path_constraints(self.cd_dco2d.clk, dco_clk_buf)
self.specials += Instance("FD", p_INIT=1, i_D=~self.locked, i_C=self.cd_dco2d.clk, o_Q=self.cd_dco2d.rst)
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(5)
self.data_ch0 = CSRStatus(16)
self.data_ch1 = CSRStatus(16)
self.tap_delay = CSRStorage(5)
self.bitslip_csr = CSRStorage(1)
self.afe_ctrl = CSRStorage(7)
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.data_out_cdc = [Signal(16, reset_less=True), Signal(16, reset_less=True)]
self.s_frame = Signal(4)
self.s_frame_cdc = Signal(4)
self.submodules.cdc_fifo = ClockDomainsRenamer({"write": "dco2d", "read": "sys"})(AsyncFIFO([("data", 36)], 4))
self.comb += [
self.cdc_fifo.sink.data.eq(Cat(self.data_out_cdc[0], self.data_out_cdc[1], self.s_frame_cdc)),
self.cdc_fifo.sink.stb.eq(~ResetSignal("dco2d")),
Cat(self.data_out[0], self.data_out[1], self.s_frame).eq(self.cdc_fifo.source.data),
self.cdc_fifo.source.ack.eq(~ResetSignal("sys")),
]
###
# 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[0:4]
),
]
self.submodules.crg = CRG(platform, dco_clk, dco_freq)
self.comb += self.afe_ctrl.storage[4].eq(self.crg.mmcm_rst)
self.comb += self.afe_ctrl.storage[5].eq(self.crg.ddr_clk_phase_shift_en)
self.comb += self.afe_ctrl.storage[6].eq(self.crg.ddr_clk_phase_incdec)
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[0:4].eq(self.s_frame[0:4]),
self.frame_csr.status[4].eq(self.crg.locked),
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("dco2d"),
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_cdc[1], # LANES swapped on hardware
o_ADC1_out=self.data_out_cdc[0],
o_FR_out=self.s_frame_cdc,
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]),
]

View File

@ -1,99 +0,0 @@
# 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
from misoc.interconnect.stream import AsyncFIFO
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)]
self.data_in_csr = [Signal(14, reset_less=True), Signal(14, reset_less=True)]
self.data_in_cdc = [Signal(14, reset_less=True), Signal(14, reset_less=True)]
self.data_in_csr_cdc = [Signal(14, reset_less=True), Signal(14, reset_less=True)]
platform.add_period_constraint(dac_pads.dclkio, 10.0)
self.submodules.cdc_fifo = ClockDomainsRenamer({"write": "sys", "read": "dco2d"})(AsyncFIFO([("data", 56)], 4))
self.comb += [
self.data_in_csr[0].eq(self.output_value_ch0.storage),
self.data_in_csr[1].eq(self.output_value_ch1.storage),
self.cdc_fifo.sink.data.eq(Cat(self.data_in[0], self.data_in[1], self.data_in_csr[0], self.data_in_csr[1])),
self.cdc_fifo.sink.stb.eq(~ResetSignal("sys")),
Cat(self.data_in_cdc[0], self.data_in_cdc[1], self.data_in_csr_cdc[0], self.data_in_csr_cdc[1]).eq(self.cdc_fifo.source.data),
self.cdc_fifo.source.ack.eq(~ResetSignal("dco2d")),
]
self.comb += [
Cat(manual_override, ch0_pd, ch1_pd).eq(self.dac_ctrl.storage),
dac_pads.rst.eq(ResetSignal("dco2d")),
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.data_in_csr_cdc[0], self.data_in_cdc[0])
),
output_data_ch1.eq(
Mux(manual_override, self.data_in_csr_cdc[1], self.data_in_cdc[1])
),
]
self.specials += [
Instance("ODDR",
i_C=ClockSignal("dco2d"),
i_CE=~ResetSignal("dco2d"),
i_D1=output_data_ch0[lane], # DDR CLK Rising Edge
i_D2=output_data_ch1[lane], # DDR CLK Falling Edge
o_Q=dac_pads.data[lane],
p_DDR_CLK_EDGE="SAME_EDGE")
for lane in range(14)]
self.specials += Instance("ODDR",
i_C=ClockSignal("dco2d_45_degree"),
i_CE=~ResetSignal("dco2d"),
i_D1=0,
i_D2=1,
o_Q=dac_pads.dclkio,
p_DDR_CLK_EDGE="SAME_EDGE")
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]),
]

View File

@ -1,385 +0,0 @@
# 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),
]

View File

@ -1,193 +0,0 @@
# 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)

View File

@ -1,141 +0,0 @@
# 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,
)

View File

@ -1,336 +0,0 @@
# 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

View File

@ -1,291 +0,0 @@
# 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")
platform.add_false_path_constraints(self.crg.cd_sys.clk, self.adc.crg.cd_dco2d.clk)
# 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)

View File

@ -1,162 +0,0 @@
///////////////////////////////////////////////////////////////////////////////
// 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

View File

@ -1,265 +0,0 @@
/**
* $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

View File

@ -1,128 +0,0 @@
/**
* $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

View File

@ -1,111 +0,0 @@
`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

View File

@ -1,141 +0,0 @@
# Fix for bus error issues when compiling cpython extensions in pyrp3 v1.2.0+
# Patch sourced from: https://github.com/linien-org/pyrp3/tree/e6688acf8bd79d2dbe1d192d09c1a1baf1f6c67b (setup.py & monitor/Makefile)
# Reference: https://github.com/elhep/Fast-Servo-Firmware/blob/master/OS/scripts/linien_install_requirements.sh#L28
diff --git a/monitor/Makefile b/monitor/Makefile
new file mode 100644
index 0000000..044d88e
--- /dev/null
+++ b/monitor/Makefile
@@ -0,0 +1,31 @@
+# Makefile for libmonitor
+
+OBJS = monitor.o
+SRCS = $(subst .o,.c, $(OBJS))
+OSOBJS = monitor.os
+TARGETLIB=libmonitor.so
+CFLAGS=-g -std=gnu99 -Wall -Werror
+LIBS=-lm -lpthread
+
+# Use CROSS_COMPILE=arm-linux-gnueabi-
+CC=$(CROSS_COMPILE)gcc
+INSTALL_DIR ?= .
+
+
+all: $(TARGETLIB)
+lib: $(TARGETLIB)
+
+%.os: %.c
+ $(CC) -c -fPIC $(CFLAGS) $< -o $@
+
+$(TARGETLIB): $(OSOBJS)
+ $(CC) -o $@ -shared $^ $(CFLAGS) $(LIBS)
+
+clean:
+ rm -f $(TARGETLIB) *.o *.os
+
+# Install target - creates 'lib/' sub-directory in $(INSTALL_DIR) and copies all
+# executables to that location.
+install:
+ mkdir -p $(INSTALL_DIR)/lib
+ cp $(TARGETLIB) $(INSTALL_DIR)/lib
\ No newline at end of file
diff --git a/pyrp3/raw_memory.py b/pyrp3/raw_memory.py
index ce1b28e..233b82a 100644
--- a/pyrp3/raw_memory.py
+++ b/pyrp3/raw_memory.py
@@ -1,12 +1,9 @@
from ctypes import POINTER, c_uint32, cast, cdll, create_string_buffer, sizeof
-from importlib.machinery import EXTENSION_SUFFIXES
from pathlib import Path
import numpy as np
-libmonitor_file = str(
- Path(__file__).parent / ".." / "monitor{}".format(EXTENSION_SUFFIXES[0])
-)
+libmonitor_file = 'libmonitor.so'
libmonitor = cdll.LoadLibrary(libmonitor_file)
libmonitor.read_value.restype = c_uint32
diff --git a/setup.py b/setup.py
index 98bdaee..b0a8af4 100644
--- a/setup.py
+++ b/setup.py
@@ -1,5 +1,10 @@
import re
-from distutils.core import Extension, setup
+import os
+
+from distutils.core import setup
+from distutils.command.build import build
+from distutils.command.install import install
+
from pathlib import Path
# from https://stackoverflow.com/a/7071358/2750945
@@ -11,9 +16,50 @@ if mo:
verstr = mo.group(1)
else:
raise RuntimeError("Unable to find version string in %s." % (VERSIONFILE,))
+
+# Patch from https://github.com/linien-org/pyrp3/blob/e6688acf8bd79d2dbe1d192d09c1a1baf1f6c67b/setup.py#L16-L55
+build_dir = "monitor/"
+
+def compile_libmonitor():
+ cwd = os.getcwd() # get current directory
+ try:
+ os.chdir(build_dir)
+ os.system("make clean")
+ os.system("make all")
+ finally:
+ os.chdir(cwd)
+
+
+def install_libmonitor(prefix=""):
+ cwd = os.getcwd() # get current directory
+ try:
+ os.chdir(build_dir)
+ os.system("make install INSTALL_DIR={prefix}".format(prefix=prefix))
+ finally:
+ os.chdir(cwd)
+
+
+class lib_build(build):
+ def run(self):
+ compile_libmonitor()
+ build.run(self)
+
+
+class lib_install(install):
+ def run(self):
+ compile_libmonitor()
+ install_libmonitor(self.prefix)
+ # install.run(self)
+
+# Will use nix to install libmonitor
+cmdclass = {
+ "build": lib_build
+}
+
this_directory = Path(__file__).parent
long_description = (this_directory / "README.rst").read_text()
+
setup(
name="pyrp3",
version=verstr,
@@ -32,6 +78,7 @@ setup(
"cached_property>=1.5.2",
"numpy>=1.11.0",
],
+ cmdclass=cmdclass,
classifiers=[
"Intended Audience :: Developers",
"Intended Audience :: Education",
@@ -45,5 +92,4 @@ setup(
"Topic :: Software Development :: Libraries :: Python Modules",
],
keywords=["redpitaya", "FPGA", "zynq"],
- ext_modules=[Extension("monitor", ["monitor/monitor.c"])],
)

View File

@ -1,5 +0,0 @@
## Source Repository
Files in this directory were copied from [elhep/Fast-Servo-Firmware](https://github.com/elhep/Fast-Servo-Firmware/tree/master/fast_servo/pythonscripts).
## Commit ID
The files were copied from commit ID [7fae40c](https://github.com/elhep/Fast-Servo-Firmware/commit/7fae40c0f872a91218be378f8289b98b1e366729).

View File

@ -1,224 +0,0 @@
# 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 time
import spidev
from pyfastservo.common import (
ADC_AFE_CTRL_ADDR,
ADC_BITSLIP_ADDR,
ADC_CH0_HIGH_ADDR,
ADC_CH0_LOW_ADDR,
ADC_CH1_HIGH_ADDR,
ADC_CH1_LOW_ADDR,
ADC_DELAY_ADDR,
ADC_FRAME_ADDR,
AUX_ADC_ADDR,
MAP_MASK,
PAGESIZE,
write_to_memory,
read_from_memory
)
# /dev/spidev1.0 <=> spidev<BUS>.<DEVICE>
MAIN_ADC_BUS = 1
MAIN_ADC_DEVICE = 1
AUX_ADC_BUS = 1
AUX_ADC_PORT_A = 2
AUX_ADC_PORT_B = 3
def spi_write(spi, address, value):
spi.xfer2([address, value])
def spi_read(spi, address):
rx_buffer = spi.xfer2([0x80 | address, 0x00])
return rx_buffer[1]
def main_adc_config(spi, test_pattern):
high_word = (test_pattern & 0xFF00) >> 8
low_word = test_pattern & 0xFF
spi_write(spi, 0x00, 0x80) # reset
spi_write(spi, 0x01, 0x20) # REGISTER A1: set to Two's complement Data Format
spi_write(spi, 0x02, 0x15) # REGISTER A2: set to LVDS output, set 4 data lanes and turn on test mode
spi_write(spi, 0x03, high_word) # REGISTER A3: test pattern high word
spi_write(spi, 0x04, low_word) # REGISTER A4: test pattern low word
def main_adc_test_mode(spi, enable):
reg_contents = 0x15 if enable else 0x11 # set to LVDS output, set 4 data lanes and turn on or off test mode
spi_write(spi, 0x02, reg_contents)
def verify_adc_registers(spi, reg_to_check):
for register, expected_value in reg_to_check.items():
value = spi_read(spi, register)
print(f"Spi readback register 0x{register:02x}: 0x{value:02x}")
if value != expected_value:
print(f"Different value read than sent in reg 0x{register:02x}")
def read_frame():
return read_from_memory(ADC_FRAME_ADDR, 1)[0]
def perform_bitslip():
for i in range(4):
current_frame = read_frame()
if current_frame & 0x0F != 0x0C:
print(f"Performing bitslip (iteration: {i}). Current frame: 0x{current_frame:02x}")
write_to_memory(ADC_BITSLIP_ADDR, 1)
else:
print(f"No bitslip required; Current frame: 0x{current_frame:02x}")
return
def mmcm_rst():
curr_cfg = read_from_memory(ADC_AFE_CTRL_ADDR, 1)[0] & 0x0F
write_to_memory(ADC_AFE_CTRL_ADDR, 0x10 | curr_cfg) # Reset MMCM
write_to_memory(ADC_AFE_CTRL_ADDR, 0x00 | curr_cfg) # Release MMCM Reset
while not(read_frame() & 0x10):
print(f"Waiting for MMCM to lock")
time.sleep(0.001)
def inc_ddr_clk_phase():
curr_cfg = read_from_memory(ADC_AFE_CTRL_ADDR, 1)[0] & 0x1F
write_to_memory(ADC_AFE_CTRL_ADDR, 0x40 | curr_cfg) # Set MMCM Phase Shift to be INC
write_to_memory(ADC_AFE_CTRL_ADDR, 0x60 | curr_cfg) # Assert MMCM Phase Shift EN High
write_to_memory(ADC_AFE_CTRL_ADDR, curr_cfg) # Deassert MMCM Phase Shift EN High
def dec_ddr_clk_phase():
curr_cfg = read_from_memory(ADC_AFE_CTRL_ADDR, 1)[0] & 0x1F
write_to_memory(ADC_AFE_CTRL_ADDR, 0x00 | curr_cfg) # Set MMCM Phase Shift to be DEC
write_to_memory(ADC_AFE_CTRL_ADDR, 0x20 | curr_cfg) # Assert MMCM Phase Shift EN High
write_to_memory(ADC_AFE_CTRL_ADDR, curr_cfg) # Deassert MMCM Phase Shift EN High
def find_edge():
prev_frame = read_frame()
for tap_delay in range(32):
write_to_memory(ADC_DELAY_ADDR, tap_delay)
current_frame = read_frame()
print(f"Tap delay: {tap_delay}, Current frame: 0x{current_frame:02x}")
print(f"prev_frame: 0x{prev_frame:02x}")
if current_frame != prev_frame:
final_delay = ((tap_delay+1) // 2) + 2
print(f"Edge detected; setting iDelay to: {final_delay}")
write_to_memory(ADC_DELAY_ADDR, final_delay)
return
prev_frame = current_frame
# If no edge detected
final_delay = 11
print(f"No edge detected; setting iDelay to: {final_delay}")
write_to_memory(ADC_DELAY_ADDR, final_delay)
def read_adc_channel(high_addr, low_addr):
return (read_from_memory(high_addr, 1)[0] << 8) | read_from_memory(low_addr, 1)[0]
def print_adc_channels():
adc_ch0 = read_adc_channel(ADC_CH0_HIGH_ADDR, ADC_CH0_LOW_ADDR)
adc_ch1 = read_adc_channel(ADC_CH1_HIGH_ADDR, ADC_CH1_LOW_ADDR)
print(f"Final ADC_CH0: 0x{adc_ch0:04x}")
print(f"Final ADC_CH1: 0x{adc_ch1:04x}")
def enable_adc_afe(ch1_x10=False, ch2_x10=False):
ctrl_value = (ch2_x10 << 1) | ch1_x10
write_to_memory(ADC_AFE_CTRL_ADDR, ctrl_value)
afe_ctrl = read_from_memory(ADC_AFE_CTRL_ADDR, 1)[0]
print(f"ADC_AFE_CTRL: 0x{afe_ctrl:02X}")
return afe_ctrl
def search_edge():
for tap_delay in range(32):
print(f"iDelay to: {tap_delay}")
write_to_memory(ADC_DELAY_ADDR, tap_delay)
time.sleep(1)
current_frame = read_frame()
print(f"Tap delay: {tap_delay}, Current frame: 0x{current_frame:02x}")
print_adc_channels()
def print_adc_channel(ch):
if ch == 0:
adc_ch0 = read_adc_channel(ADC_CH0_HIGH_ADDR, ADC_CH0_LOW_ADDR)
print(f"Final ADC_CH0: 0x{adc_ch0:04x}")
if ch == 1:
adc_ch1 = read_adc_channel(ADC_CH1_HIGH_ADDR, ADC_CH1_LOW_ADDR)
print(f"Final ADC_CH1: 0x{adc_ch1:04x}")
def find_min_max_ch(ch):
test = []
for i in range(100):
if ch == 0:
test.append(read_adc_channel(ADC_CH0_HIGH_ADDR, ADC_CH0_LOW_ADDR))
else:
test.append(read_adc_channel(ADC_CH1_HIGH_ADDR, ADC_CH1_LOW_ADDR))
print("ch", ch, hex(test[-1]))
print("Min:", hex(min(test)))
print("Max:", hex(max(test)))
print("Diff:", hex(max(test)-min(test)))
def configure_ltc2195():
spi = spidev.SpiDev()
try:
spi.open(MAIN_ADC_BUS, MAIN_ADC_DEVICE)
spi.max_speed_hz = 50000
spi.mode = 0b00 # CPOL = 0 CPHA = 0
spi.cshigh = False
test_pattern = 0x811F
main_adc_config(spi, test_pattern)
verify_adc_registers(spi, {
0x01: 0x20,
0x02: 0x15,
0x03: (test_pattern & 0xFF00) >> 8,
0x04: test_pattern & 0xFF
})
# ADC software reset put its PLL to sleep momentarily. Thus, MMCM needs to be reset as well.
mmcm_rst()
# Performing Word Align
perform_bitslip()
find_edge()
# Printing it once is not enough to check whether the alignment is correct.
for i in range(100):
print_adc_channels()
main_adc_test_mode(spi, False)
verify_adc_registers(spi, {0x02: 0x11}) # Verify test mode is off
# FIXME: AFE Gain 1x is not functional on that batch of fast servo under development
enable_adc_afe(ch1_x10=1, ch2_x10=1)
#find_min_max_ch(0)
#find_min_max_ch(1)
#for i in range(10):
# print_adc_channel(0)
#for i in range(10):
# print_adc_channel(1)
finally:
spi.close()
if __name__ == "__main__":
configure_ltc2195()

View File

@ -1,120 +0,0 @@
# 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
import mmap
CSR_SIZE = 0x800
MAP_SIZE = 0x1000
MAP_MASK = 0xFFF
PAGESIZE = 0x1000
# LINIEN_OFFSET = 0x0
LINIEN_OFFSET = 0x300000
# ----------------------------------------------------------------
# FRONT PANEL LEDS REGISTER ADDRESSES
LED0_BASE_ADDR = 0x40005000 + LINIEN_OFFSET
LED1_BASE_ADDR = 0x40005800 + LINIEN_OFFSET
LED2_BASE_ADDR = 0x40006000 + LINIEN_OFFSET
LED3_BASE_ADDR = 0x40006800 + LINIEN_OFFSET
# ----------------------------------------------------------------
# DAC REGISTER ADDRESSES
ADC_BASE_ADDR = 0x40004800 + LINIEN_OFFSET
ADC_FRAME_OFFSET = 0x0
ADC_CH0_HIGH_OFFSET = 0x4
ADC_CH0_LOW_OFFSET = 0x8
ADC_CH1_HIGH_OFFSET = 0xC
ADC_CH1_LOW_OFFSET = 0x10
ADC_TAP_DELAY_OFFSET = 0x14
ADC_BITSLIP_OFFSET = 0x18
ADC_AFE_CTRL_OFFSET = 0x1C
ADC_FRAME_ADDR = ADC_BASE_ADDR + ADC_FRAME_OFFSET
ADC_CH0_HIGH_ADDR = ADC_BASE_ADDR + ADC_CH0_HIGH_OFFSET
ADC_CH0_LOW_ADDR = ADC_BASE_ADDR + ADC_CH0_LOW_OFFSET
ADC_CH1_HIGH_ADDR = ADC_BASE_ADDR + ADC_CH1_HIGH_OFFSET
ADC_CH1_LOW_ADDR = ADC_BASE_ADDR + ADC_CH1_LOW_OFFSET
ADC_DELAY_ADDR = ADC_BASE_ADDR + ADC_TAP_DELAY_OFFSET
ADC_BITSLIP_ADDR = ADC_BASE_ADDR + ADC_BITSLIP_OFFSET
ADC_AFE_CTRL_ADDR = ADC_BASE_ADDR + ADC_AFE_CTRL_OFFSET
AUX_ADC_ADDR = 0x40007800 + LINIEN_OFFSET
# ----------------------------------------------------------------
# DAC REGISTER ADDRESSES
DAC_BASE_ADDR = 0x40007000 + LINIEN_OFFSET
CTRL_OFFSET = 0x0
CH0_HIGH_WORD_OFFSET = 0x4
CH0_LOW_WORD_OFFSET = 0x8
CH1_HIGH_WORD_OFFSET = 0xC
CH1_LOW_WORD_OFFSET = 0x10
CTRL_ADDR = DAC_BASE_ADDR + CTRL_OFFSET
CH0_HIGH_WORD_ADDR = DAC_BASE_ADDR + CH0_HIGH_WORD_OFFSET
CH0_LOW_WORD_ADDR = DAC_BASE_ADDR + CH0_LOW_WORD_OFFSET
CH1_HIGH_WORD_ADDR = DAC_BASE_ADDR + CH1_HIGH_WORD_OFFSET
CH1_LOW_WORD_ADDR = DAC_BASE_ADDR + CH1_LOW_WORD_OFFSET
def read_from_memory(address, n_bytes):
assert n_bytes <= 4
addr = address
try:
f = os.open("/dev/mem", os.O_SYNC | os.O_RDWR)
with mmap.mmap(
f,
PAGESIZE,
mmap.MAP_SHARED,
mmap.PROT_READ | mmap.PROT_WRITE,
offset=addr & ~MAP_MASK,
) as mem:
start_addr = addr & MAP_MASK
stop_addr = start_addr + 4
contents = mem[start_addr:stop_addr]
read_value = list(contents)[:n_bytes]
finally:
os.close(f)
return read_value
def write_to_memory(address, value):
value_bytes = value.to_bytes(4, "little")
addr = address
try:
f = os.open("/dev/mem", os.O_SYNC | os.O_RDWR)
with mmap.mmap(
f,
PAGESIZE,
mmap.MAP_SHARED,
mmap.PROT_READ | mmap.PROT_WRITE,
offset=addr & ~MAP_MASK,
) as mem:
start_addr = addr & MAP_MASK
stop_addr = start_addr + 4
mem[start_addr:stop_addr] = value_bytes
contents = mem[start_addr:stop_addr]
finally:
os.close(f)

View File

@ -1,168 +0,0 @@
# 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 time
import spidev
from pyfastservo.common import (
CH0_HIGH_WORD_ADDR,
CH0_LOW_WORD_ADDR,
CH1_HIGH_WORD_ADDR,
CH1_LOW_WORD_ADDR,
CTRL_ADDR,
MAP_MASK,
PAGESIZE,
write_to_memory,
read_from_memory
)
# /dev/spidev2.0 <=> spidev<BUS>.<DEVICE>
MAIN_DAC_BUS = 2
MAIN_DAC_DEVICE = 0
DAC_VERSION = 0x0A
def spi_write(spi, address, value):
spi.xfer2([address, value])
def spi_read(spi, address):
rx_buffer = spi.xfer2([0x80 | address, 0x00])
return rx_buffer[1]
def soft_reset(spi):
spi_write(spi, 0x00, 0x10) # Software reset
spi_write(spi, 0x00, 0x00) # Release software reset
spi_read(spi, 0x00) # Read reset address (necessary for reset to take effect)
def check_version(spi):
version = spi_read(spi, 0x1F)
print(f"DAC version: 0x{version:02X}")
return version == DAC_VERSION
def configure_dac(spi):
power_down_reg = spi_read(spi, 0x01)
spi_write(spi, 0x01, power_down_reg & ~(1 << 0)) # Clear EXTREF bit for internal reference
spi_write(spi, 0x0D, 0x00) # Set RREF to 10 kΩ for 1.0V reference
spi_write(spi, 0x04, 0xA0) # Enable on-chip IRSET (1.6 kΩ for 20mA output)
spi_write(spi, 0x07, 0xA0) # Enable on-chip QRSET (1.6 kΩ for 20mA output)
spi_write(spi, 0x05, 0x00) # Disable internal IRCML
spi_write(spi, 0x08, 0x00) # Disable internal QRCML
spi_write(spi, 0x02, 0xB4) # Enable 2's complement, IFirst: True, IRising: True, DCI_EN: Enabled
spi_write(spi, 0x14, 0x00)
spi_write(spi, 0x14, 0x08) # Trigger the retimer to reacquire the clock relationship
spi_write(spi, 0x14, 0x00)
def dac_self_calibration(spi):
spi_write(spi, 0x12, 0x00) # Reset calibration status
spi_write(spi, 0x0E, 0x08) # Enable calibration clock, default divide ratio
spi_write(spi, 0x0E, 0x38) # CALSELI = 1, CALSELQ = 1, CALCLK = 1
spi_write(spi, 0x12, 0x10) # Set CALEN bit
while True:
status = spi_read(spi, 0x0F)
if status & 0xC0 == 0xC0: # Both CALSTATI and CALSTATQ are 1
break
time.sleep(0.01)
spi_write(spi, 0x12, 0x00) # Clear calibration bits
spi_write(spi, 0x0E, 0x30) # Keep CALSELI and CALSELQ set, clear CALCLK
print("DAC self-calibration completed")
def manual_override(enable=True):
reg_contents = read_from_memory(CTRL_ADDR, 1)[0]
to_write = reg_contents | 0b1 if enable else reg_contents & 0b110
write_to_memory(CTRL_ADDR, to_write)
print(f"Set DAC Output Manual Override: {enable}")
def power_down_afe(channel, power_down=True):
assert channel in (0, 1)
bitmask = 1 << (channel + 1) & 0b111
reg_contents = read_from_memory(CTRL_ADDR, 1)[0]
value = (1 if power_down else 0) << (channel + 1)
reg_contents &= ~bitmask
to_write = reg_contents | value
write_to_memory(CTRL_ADDR, to_write)
reg_contents = read_from_memory(CTRL_ADDR, 1)[0]
print(f"Power Down DAC AFE Ch{channel}: {power_down}")
def set_dac_output(value):
value = min(value, 0x3FFF)
low_word = value & 0xFF
high_word = (value >> 8) & 0x3F
# Note: DAC HIGH word and LOW word output are not updated
# at the same time. On scope, you will see more than one step
# of value changed.
write_to_memory(CH0_HIGH_WORD_ADDR, high_word)
write_to_memory(CH0_LOW_WORD_ADDR, low_word)
write_to_memory(CH1_HIGH_WORD_ADDR, high_word)
write_to_memory(CH1_LOW_WORD_ADDR, low_word)
print(f"DAC output set to: 0x{value:04X}")
def check_clk_relationship(spi):
clkmode_reg = spi_read(spi, 0x14)
print(f"CLKMODE reg: 0x{clkmode_reg:02X}")
if clkmode_reg & 0b00010000:
print("Clock relationship is not found")
return False
else:
print("Clock relationship is found")
return True
def configure_ad9117():
spi = spidev.SpiDev()
spi.open(MAIN_DAC_BUS, MAIN_DAC_DEVICE)
spi.max_speed_hz = 5000
spi.mode = 0b00 # CPOL = 0 CPHA = 0
spi.cshigh = False
try:
soft_reset(spi)
if not check_version(spi):
print("Unrecognized DAC version")
return False
power_down_afe(0, True)
power_down_afe(1, True)
configure_dac(spi)
check_clk_relationship(spi)
dac_self_calibration(spi)
# Enable DAC outputs
spi_write(spi, 0x01, spi_read(spi, 0x01) & ~((1 << 4) | (1 << 3)))
power_down_afe(0, False)
power_down_afe(1, False)
manual_override(False)
print("AD9117 configuration completed successfully")
return True
except Exception as e:
print(f"Error configuring AD9117: {e}")
return False
finally:
spi.close()
if __name__ == "__main__":
configure_ad9117()

View File

@ -1,66 +0,0 @@
# 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 mmap
import os
import time
from pyfastservo.common import (
LED0_BASE_ADDR,
LED1_BASE_ADDR,
LED2_BASE_ADDR,
LED3_BASE_ADDR,
MAP_MASK,
PAGESIZE,
)
ON = 1
OFF = 0
def main():
addrs = [LED0_BASE_ADDR, LED1_BASE_ADDR, LED2_BASE_ADDR, LED3_BASE_ADDR]
f = os.open("/dev/mem", os.O_SYNC | os.O_RDWR)
for addr in addrs:
with mmap.mmap(
f,
PAGESIZE,
mmap.MAP_SHARED,
mmap.PROT_READ | mmap.PROT_WRITE,
offset=addr & ~MAP_MASK,
) as mem:
for i in range(6):
start_addr = addr & MAP_MASK
stop_addr = start_addr + 4
print(
f"addr: 0x{addr:x}\tstart_addr: 0x{start_addr}\tstop_addr: 0x{stop_addr}"
)
mem[start_addr:stop_addr] = ON.to_bytes(4, "little")
contents = mem[start_addr:stop_addr]
time.sleep(0.5)
mem[start_addr:stop_addr] = OFF.to_bytes(4, "little")
contents = mem[start_addr:stop_addr]
time.sleep(0.5)
os.close(f)
if __name__ == "__main__":
main()

View File

@ -1,28 +0,0 @@
# 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 pyfastservo import adc, si5340, dac
def main():
si5340.configure_si5340()
adc.configure_ltc2195()
dac.configure_ad9117()
if __name__ == "__main__":
main()

View File

@ -1,280 +0,0 @@
# 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/>.
# Additional Reference:
# https://github.com/torvalds/linux/blob/master/drivers/clk/clk-si5341.c
import time
from smbus2 import SMBus
BUS_NO = 0
IC_ADDR = 0x74
DEVICE_READY = 0x00FE
PLL_M_DEN = 0x023B
STATUS = 0x000C
STATUS_STICKY = 0x0011
STATUS_LOSREF = 0x04
STATUS_LOL = 0x08
def write_register(bus, address, value):
page = address >> 8
register = address & 0xFF
bus.write_byte_data(IC_ADDR, 0x01, page)
try:
bus.write_byte_data(IC_ADDR, register, value)
except Exception as e:
raise Exception(f"Write failed 0x{value:02X} at 0x{address:04X}: {e}")
def write_preamble(bus):
preamble = [
(0x0B24, 0xC0),
(0x0B25, 0x00),
(0x0502, 0x01),
(0x0505, 0x03),
(0x0957, 0x17),
(0x0B4E, 0x1A),
]
for address, value in preamble:
write_register(bus, address, value)
def write_postamble(bus):
postamble = [
(0x001C, 0x01), # Soft reset
(0x0B24, 0xC3),
(0x0B25, 0x02),
]
for address, value in postamble:
write_register(bus, address, value)
def wait_device_ready(bus):
for _ in range(15):
if bus.read_byte_data(IC_ADDR, DEVICE_READY) == 0x0F:
return True
time.sleep(0.02)
return False
def wait_for_lock(bus):
for _ in range(10):
status = bus.read_byte_data(IC_ADDR, STATUS)
if not (status & (STATUS_LOSREF | STATUS_LOL)):
return True
time.sleep(0.01)
return False
def check_pll_status(bus):
pll_status = bus.read_byte_data(IC_ADDR, 0x0C)
pll_locked = not (pll_status & STATUS_LOL)
print(f"PLL {'locked' if pll_locked else 'unlocked'}")
return pll_locked
def check_los_status(bus):
los_status = bus.read_byte_data(IC_ADDR, 0x0D)
xaxb_los = (los_status & 0x10) != 0
print(f"XA/XB LOS {'asserted' if xaxb_los else 'deasserted'}")
return not xaxb_los
def configure_si5340():
with SMBus(BUS_NO) as bus:
if not wait_device_ready(bus):
print("Device not ready. Aborting.")
return
# Programming sequence from ClockBuilder Pro, default settings
# to initialize system using XTAL input
main_config = [
(0x0006, 0x00), # TOOL_VERSION
(0x0007, 0x00), # Not in datasheet
(0x0008, 0x00), # Not in datasheet
(0x000B, 0x74), # I2C_ADDR
(0x0017, 0xD0), # INT mask (disable interrupts)
(0x0018, 0xFF), # INT mask
(0x0021, 0x0F), # Select XTAL as input
(0x0022, 0x00), # Not in datasheet
(0x002B, 0x02), # SPI config
(0x002C, 0x20), # LOS enable for XTAL
(0x002D, 0x00), # LOS timing
(0x002E, 0x00), # LOS trigger (thresholds)
(0x002F, 0x00),
(0x0030, 0x00),
(0x0031, 0x00),
(0x0032, 0x00),
(0x0033, 0x00),
(0x0034, 0x00),
(0x0035, 0x00), # LOS trigger (thresholds) end
(0x0036, 0x00), # LOS clear (thresholds)
(0x0037, 0x00),
(0x0038, 0x00),
(0x0039, 0x00),
(0x003A, 0x00),
(0x003B, 0x00),
(0x003C, 0x00),
(0x003D, 0x00), # LOS clear (thresholds) end
(0x0041, 0x00), # LOS0_DIV_SEL
(0x0042, 0x00), # LOS1_DIV_SEL
(0x0043, 0x00), # LOS2_DIV_SEL
(0x0044, 0x00), # LOS3_DIV_SEL
(0x009E, 0x00), # LOL_SET_THR
(0x0102, 0x01), # Enable outputs
(0x013F, 0x00), # OUTX_ALWAYS_ON
(0x0140, 0x00), # OUTX_ALWAYS_ON
(0x0141, 0x40), # OUT_DIS_LOL_MSK, OUT_DIS_MSK_LOS_PFD
(0x0202, 0x00), # XAXB_FREQ_OFFSET (=0)
# PLL Configuration
(0x0235, 0x00), # M_NUM
(0x0236, 0x00),
(0x0237, 0x00),
(0x0238, 0x80),
(0x0239, 0x89),
(0x023A, 0x00),
(0x023B, 0x00), # M_DEN
(0x023C, 0x00),
(0x023D, 0x00),
(0x023E, 0x80),
# Synthesizer configuration
(0x0302, 0x00), # N0_NUM
(0x0303, 0x00),
(0x0304, 0x00),
(0x0305, 0x00),
(0x0306, 0x21),
(0x0307, 0x00),
(0x0308, 0x00), # N0_DEN
(0x0309, 0x00),
(0x030A, 0x00),
(0x030B, 0x80),
(0x030C, 0x01), # N0_UPDATE
# N1 Configuration (1:1 ratio)
(0x030D, 0x00), # N1_NUM
(0x030E, 0x00),
(0x030F, 0x00),
(0x0310, 0x00),
(0x0311, 0x00),
(0x0312, 0x01),
(0x0313, 0x00), # N1_DEN
(0x0314, 0x00),
(0x0315, 0x00),
(0x0316, 0x01),
(0x0317, 0x01), # N1_UPDATE
# N2 Configuration (1:1 ratio)
(0x0318, 0x00), # N2_NUM
(0x0319, 0x00),
(0x031A, 0x00),
(0x031B, 0x00),
(0x031C, 0x00),
(0x031D, 0x01),
(0x031E, 0x00), # N2_DEN
(0x031F, 0x00),
(0x0320, 0x00),
(0x0321, 0x01),
(0x0322, 0x01), # N2_UPDATE
# N3 Configuration (1:1 ratio)
(0x0323, 0x00), # N3_NUM
(0x0324, 0x00),
(0x0325, 0x00),
(0x0326, 0x00),
(0x0327, 0x00),
(0x0328, 0x01),
(0x0329, 0x00), # N3_DEN
(0x032A, 0x00),
(0x032B, 0x00),
(0x032C, 0x01),
(0x032D, 0x01), # N3_UPDATE
# Output configuration
(0x0112, 0x06), # OUT0 config
(0x0113, 0x09), # OUT0 format
(0x0114, 0x3B), # OUT0 CM/AMPL
(0x0115, 0x28), # OUT0 MUX_SEL
(0x0117, 0x06), # OUT1 config
(0x0118, 0x09), # OUT1 format
(0x0119, 0x3B), # OUT1 CM/AMPL
(0x011A, 0x28), # OUT1 MUX_SEL
(0x0126, 0x06), # OUT2 config
(0x0127, 0x09), # OUT2 format
(0x0128, 0x3B), # OUT2 CM/AMPL
(0x0129, 0x28), # OUT2 MUX_SEL
(0x012B, 0x06), # OUT3 config
(0x012C, 0xCC), # OUT3 format
(0x012D, 0x00), # OUT3 CM/AMPL
(0x012E, 0x58), # OUT3 MUX_SEL
# Miscellaneous configuration
(0x090E, 0x02), # XAXB_EXTCLK_EN=0 XAXB_PDNB=1 (use XTAL)
(0x091C, 0x04), # ZDM_EN=4 (Normal mode)
(0x0943, 0x00), # IO_VDD_SEL
(0x0949, 0x00), # IN_EN (disable input clocks)
(0x094A, 0x00), # INx_TO_PFD_EN (disabled)
(0x094E, 0x49), # REFCLK_HYS_SEL (set by CBPro)
(0x094F, 0x02), # Not in datasheet
(0x095E, 0x00), # M_INTEGER (set by CBPro)
(0x0A02, 0x00), # N_ADD_0P5 (set by CBPro)
(0x0A03, 0x01), # N_CLK_TO_OUTX_EN
(0x0A04, 0x01), # N_PIBYP
(0x0A05, 0x01), # N_PDNB
(0x0A14, 0x00), # N0_HIGH_FREQ (set by CBPro)
(0x0A1A, 0x00), # N1_HIGH_FREQ (set by CBPro)
(0x0A20, 0x00), # N2_HIGH_FREQ (set by CBPro)
(0x0A26, 0x00), # N3_HIGH_FREQ (set by CBPro)
(0x0B44, 0x0F), # PDIV_ENB (set by CBPro)
(0x0B4A, 0x0E), # N_CLK_DIS
(0x0B57, 0x0E), # VCO_RESET_CALCODE (set by CBPro)
(0x0B58, 0x01), # VCO_RESET_CALCODE (set by CBPro)
]
write_preamble(bus)
time.sleep(0.3)
print("Writing main configuration...")
for address, value in main_config:
write_register(bus, address, value)
print("Main configuration written")
write_postamble(bus)
if not wait_for_lock(bus):
print("Error waiting for input clock or PLL lock")
else:
print("Input clock present and PLL locked")
bus.write_byte_data(IC_ADDR, STATUS_STICKY, 0)
# Final status check
pll_locked = check_pll_status(bus)
xaxb_signal_present = check_los_status(bus)
if not pll_locked:
print("Error: PLL is not locked")
elif not xaxb_signal_present:
print("Error: XA/XB signal is lost")
else:
print("Si5340 configuration completed successfully")
if __name__ == "__main__":
configure_si5340()

View File

@ -18,16 +18,16 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1723938990, "lastModified": 1703961334,
"narHash": "sha256-9tUadhnZQbWIiYVXH8ncfGXGvkNq3Hag4RCBEMUk7MI=", "narHash": "sha256-M1mV/Cq+pgjk0rt6VxoyyD+O8cOUiai8t9Q6Yyq4noY=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "c42fcfbdfeae23e68fc520f9182dde9f38ad1890", "rev": "b0d36bd0a420ecee3bc916c91886caca87c894e9",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "NixOS", "owner": "NixOS",
"ref": "nixos-24.05", "ref": "nixos-unstable",
"repo": "nixpkgs", "repo": "nixpkgs",
"type": "github" "type": "github"
} }
@ -56,43 +56,7 @@
"root": { "root": {
"inputs": { "inputs": {
"nixpkgs": "nixpkgs", "nixpkgs": "nixpkgs",
"not-os": "not-os", "not-os": "not-os"
"src-migen": "src-migen",
"src-misoc": "src-misoc"
}
},
"src-migen": {
"flake": false,
"locked": {
"lastModified": 1721561053,
"narHash": "sha256-z3LRhNmKZrjr6rFD0yxtccSa/SWvFIYmb+G/D5d2Jd8=",
"owner": "m-labs",
"repo": "migen",
"rev": "9279e8623f8433bc4f23ac51e5e2331bfe544417",
"type": "github"
},
"original": {
"owner": "m-labs",
"repo": "migen",
"type": "github"
}
},
"src-misoc": {
"flake": false,
"locked": {
"lastModified": 1715647536,
"narHash": "sha256-q+USDcaKHABwW56Jzq8u94iGPWlyLXMyVt0j/Gyg+IE=",
"ref": "refs/heads/master",
"rev": "fea9de558c730bc394a5936094ae95bb9d6fa726",
"revCount": 2455,
"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"
} }
} }
}, },

380
flake.nix
View File

@ -1,216 +1,148 @@
{ {
description = "Firmware for Sinara Fast-Servo based on Not-OS and Linien"; description = "Firmware for Sinara Fast-Servo based on Not-OS and Linien";
inputs.nixpkgs.url = github:NixOS/nixpkgs/nixos-24.05; inputs.nixpkgs.url = github:NixOS/nixpkgs/nixos-unstable;
inputs.not-os.url = github:cleverca22/not-os; inputs.not-os.url = github:cleverca22/not-os;
inputs.not-os.inputs.nixpkgs.follows = "nixpkgs"; inputs.not-os.inputs.nixpkgs.follows = "nixpkgs";
inputs.src-migen = { url = github:m-labs/migen; flake = false; }; outputs = { self, nixpkgs, not-os }:
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 let
pkgs = import nixpkgs { system = "x86_64-linux"; overlays = [ crosspkgs-overlay ]; }; pkgs = import nixpkgs { system = "x86_64-linux"; };
pkgs-armv7l = pkgs.pkgsCross.zynq-armv7l-linux; not-os-cfg = not-os-configured.config.system;
fsbl-support = ./fast-servo/fsbl-support; fsbl-support = ./fast-servo/fsbl-support;
patched-not-os = pkgs.applyPatches { patched-not-os = pkgs.applyPatches {
name = "not-os-patched"; name = "not-os-patched";
src = not-os; src = not-os;
patches = [ patches = [
./not-os-patches/network.patch ./network.patch
./not-os-patches/pr-28.patch ./pr-28.patch
./not-os-patches/pr-29.patch ./pr-29.patch
./not-os-patches/pr-30.patch ./pr-30.patch
./not-os-patches/pr-31.patch
./not-os-patches/pr-33.patch
]; ];
}; };
crossSystem = { not-os-configured = (import patched-not-os {
system = "armv7l-linux"; inherit nixpkgs;
linux-kernel = { extraModules = [
name = "zynq"; "${patched-not-os}/zynq_image.nix"
baseConfig = "multi_v7_defconfig"; ];
target = "uImage";
installTarget = "uImage";
autoModules = false;
DTB = true;
makeFlags = [ "LOADADDR=0x8000" ];
};
};
crosspkgs-overlay = (self: super: {
pkgsCross = super.pkgsCross // {
zynq-baremetal = import super.path {
system = "x86_64-linux"; system = "x86_64-linux";
crossSystem = { crossSystem.system = "armv7l-linux";
config = "arm-none-eabihf";
libc = "newlib";
gcc.cpu = "cortex-a9";
gcc.fpu = "vfpv3";
};
};
zynq-armv7l-linux = import super.path {
system = "x86_64-linux";
inherit crossSystem;
};
};
}); });
migen = pkgs.python3Packages.buildPythonPackage rec { gnu-platform = "arm-none-eabi";
name = "migen";
src = src-migen; binutils-pkg = { zlib, extraConfigureFlags ? [] }: pkgs.stdenv.mkDerivation rec {
format = "pyproject"; basename = "binutils";
nativeBuildInputs = [ pkgs.python3Packages.setuptools ]; version = "2.30";
propagatedBuildInputs = [ pkgs.python3Packages.colorama ]; name = "${basename}-${gnu-platform}-${version}";
src = pkgs.fetchurl {
url = "https://ftp.gnu.org/gnu/binutils/binutils-${version}.tar.bz2";
sha256 = "028cklfqaab24glva1ks2aqa1zxa6w6xmc8q34zs1sb7h22dxspg";
};
configureFlags = [
"--enable-deterministic-archives"
"--target=${gnu-platform}"
"--with-cpu=cortex-a9"
"--with-fpu=vfpv3"
"--with-float=hard"
"--with-mode=thumb"
] ++ extraConfigureFlags;
outputs = [ "out" "info" "man" ];
depsBuildBuild = [ pkgs.buildPackages.stdenv.cc ];
buildInputs = [ zlib ];
enableParallelBuilding = true;
meta = {
description = "Tools for manipulating binaries (linker, assembler, etc.)";
longDescription = ''
The GNU Binutils are a collection of binary tools. The main
ones are `ld' (the GNU linker) and `as' (the GNU assembler).
They also include the BFD (Binary File Descriptor) library,
`gprof', `nm', `strip', etc.
'';
homepage = http://www.gnu.org/software/binutils/;
license = pkgs.lib.licenses.gpl3Plus;
/* Give binutils a lower priority than gcc-wrapper to prevent a
collision due to the ld/as wrappers/symlinks in the latter. */
priority = "10";
};
}; };
misoc = pkgs.python3Packages.buildPythonPackage { gcc-pkg = { gmp, mpfr, libmpc, platform-binutils, extraConfigureFlags ? [] }: pkgs.stdenv.mkDerivation rec {
name = "misoc"; basename = "gcc";
src = src-misoc; version = "9.1.0";
propagatedBuildInputs = with pkgs.python3Packages; [ jinja2 numpy migen pyserial asyncserial ]; name = "${basename}-${gnu-platform}-${version}";
src = pkgs.fetchurl {
url = "https://ftp.gnu.org/gnu/gcc/gcc-${version}/gcc-${version}.tar.xz";
sha256 = "1817nc2bqdc251k0lpc51cimna7v68xjrnvqzvc50q3ax4s6i9kr";
};
preConfigure = ''
mkdir build
cd build
'';
configureScript = "../configure";
configureFlags = [
"--target=${gnu-platform}"
"--with-arch=armv7-a"
"--with-tune=cortex-a9"
"--with-fpu=vfpv3"
"--with-float=hard"
"--disable-libssp"
"--enable-languages=c"
"--with-as=${platform-binutils}/bin/${gnu-platform}-as"
"--with-ld=${platform-binutils}/bin/${gnu-platform}-ld" ] ++ extraConfigureFlags;
outputs = [ "out" "info" "man" ];
hardeningDisable = [ "format" "pie" ];
propagatedBuildInputs = [ gmp mpfr libmpc platform-binutils ];
enableParallelBuilding = true;
dontFixup = true;
}; };
vivado = pkgs.buildFHSEnv { newlib-pkg = { platform-binutils, platform-gcc }: pkgs.stdenv.mkDerivation rec {
name = "vivado"; pname = "newlib";
targetPkgs = pkgs: with pkgs; let version = "3.1.0";
# Apply patch from https://github.com/nix-community/nix-environments/pull/54 src = pkgs.fetchurl {
# to fix ncurses libtinfo.so's soname issue url = "ftp://sourceware.org/pub/newlib/newlib-${version}.tar.gz";
ncurses' = ncurses5.overrideAttrs (old: { sha256 = "0ahh3n079zjp7d9wynggwrnrs27440aac04340chf1p9476a2kzv";
configureFlags = old.configureFlags ++ [ "--with-termlib" ]; };
postFixup = ""; nativeBuildInputs = [ platform-binutils platform-gcc ];
}); configureFlags = [
in [ "--target=${gnu-platform}"
libxcrypt-legacy
(ncurses'.override { unicodeSupport = false; }) "--with-cpu=cortex-a9"
zlib "--with-fpu=vfpv3"
libuuid "--with-float=hard"
xorg.libSM "--with-mode=thumb"
xorg.libICE "--enable-interwork"
xorg.libXrender "--disable-multilib"
xorg.libX11
xorg.libXext "--disable-newlib-supplied-syscalls"
xorg.libXtst "--with-gnu-ld"
xorg.libXi "--with-gnu-as"
freetype "--disable-newlib-io-float"
fontconfig "--disable-werror"
]; ];
profile = "set -e; source /opt/Xilinx/Vivado/2022.2/settings64.sh"; dontFixup = true;
runScript = "vivado";
}; };
pyrp3 = pkgs-armv7l.python3Packages.buildPythonPackage rec { gnutoolchain = rec {
pname = "pyrp3"; binutils-bootstrap = pkgs.callPackage binutils-pkg { };
version = "1.2.0"; gcc-bootstrap = pkgs.callPackage gcc-pkg {
pyproject = true; platform-binutils = binutils-bootstrap;
src = pkgs.fetchFromGitHub { extraConfigureFlags = [ "--disable-libgcc" ];
owner = "linien-org";
repo = "pyrp3";
rev = "v${version}";
hash = "sha256-43TTlpJ5SMAjQM71bNVvrWQyciRXM3zpuA/Dw41AEgU=";
}; };
patches = ./fast-servo/linien-pyrp3-monitor.patch; newlib = pkgs.callPackage newlib-pkg {
nativeBuildInputs = with pkgs-armv7l.python3Packages; [ platform-binutils = binutils-bootstrap;
setuptools wheel setuptools-scm platform-gcc = gcc-bootstrap;
] ++ (with pkgs-armv7l; [ gcc gnumake ]);
propagatedBuildInputs = with pkgs-armv7l.python3Packages; [
myhdl
rpyc4
cached-property
numpy
];
postInstall = ''
cp monitor/libmonitor.so $out/lib
'';
postFixup = ''
substituteInPlace $out/${pkgs.python3.sitePackages}/pyrp3/raw_memory.py \
--replace "libmonitor.so" "$out/lib/libmonitor.so"
'';
}; };
binutils = pkgs.callPackage binutils-pkg {
linien-server = pkgs-armv7l.python3Packages.buildPythonPackage rec { extraConfigureFlags = [ "--with-lib-path=${newlib}/arm-none-eabi/lib" ];
pname = "linien-server";
pyproject = true;
inherit (pkgs.python3Packages.linien-common) src version;
sourceRoot = "source/linien-server";
postPatch = ''
cp ${fast-servo-gateware}/csrmap.py linien_server/csrmap.py
substituteInPlace linien_server/acquisition.py \
--replace " start_nginx()" "" \
--replace " stop_nginx()" "" \
--replace " flash_fpga()" ""
'';
nativeBuildInputs = [ pkgs-armv7l.python3Packages.setuptools ];
propagatedBuildInputs = with pkgs-armv7l.python3Packages; [
appdirs
certifi
click
cma
pylpsd
pyrp3
requests
linien-common
];
}; };
gcc = pkgs.callPackage gcc-pkg {
fast-servo-gateware = pkgs.stdenv.mkDerivation rec { platform-binutils = binutils;
name = "fast-servo-gateware"; extraConfigureFlags = [ "--enable-newlib" "--with-headers=${newlib}/arm-none-eabi/include" ];
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.overrideAttrs(oa: {
# config.py tries to access $HOME, but we do not need it for building gateware
postPatch = ''
echo > linien_common/config.py
echo > linien_common/__init__.py
'';
doCheck = false;
}))
]))
vivado
];
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
cp linien-server/linien_server/csrmap.py $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
'';
}; };
pyfastservo = pkgs-armv7l.python3Packages.buildPythonPackage rec {
name = "pyfastservo";
src = ./fast-servo;
preBuild = ''
cat > setup.py << EOF
from setuptools import setup
setup(
name="pyfastservo",
packages=["pyfastservo"],
install_requires=["spidev", "smbus2"],
entry_points = {"console_scripts": ["fp_leds=pyfastservo.fp_leds:main"]},
)
EOF
'';
propagatedBuildInputs = with pkgs-armv7l.python3Packages; [
spidev
smbus2
];
}; };
mkbootimage = pkgs.stdenv.mkDerivation { mkbootimage = pkgs.stdenv.mkDerivation {
@ -236,38 +168,16 @@
hardeningDisable = [ "fortify" ]; hardeningDisable = [ "fortify" ];
}; };
board-package-set = { board }: let # Pinned qemu version due to networking errors in recent version 8.2.0
not-os-configured = (import patched-not-os { qemu = pkgs.qemu.overrideAttrs (oldAttrs: rec {
inherit nixpkgs; version = "8.1.3";
extraModules = [ src = pkgs.fetchurl {
"${patched-not-os}/zynq_image.nix" url = "https://download.qemu.org/qemu-${version}.tar.xz";
] ++ pkgs.lib.optionals (board == "fast-servo") [ hash = "sha256-Q8wXaAQQVYb3T5A5jzTp+FeH3/QA07ZA2B93efviZbs=";
({ config, pkgs, lib, ... }: { };
environment.systemPackages = [
linien-server
(pkgs.python3.withPackages(ps: [ pyfastservo ]))
];
boot.postBootCommands = lib.mkAfter ''
# Program the FPGA
set +x
echo "Loading bitstream into SRAM..."
echo 0 > /sys/class/fpga_manager/fpga0/flags
mkdir -p /lib/firmware
cp ${fast-servo-gateware}/gateware.bin /lib/firmware/
echo gateware.bin > /sys/class/fpga_manager/fpga0/firmware
# Run device init scripts
echo "Initializing clock generator, ADC, and DAC..."
python3 -m pyfastservo.initialize
'';
})];
system = "x86_64-linux";
inherit crossSystem;
}); });
not-os-build = not-os-configured.config.system.build; board-package-set = { board }: let
fsbl = pkgs.stdenv.mkDerivation { fsbl = pkgs.stdenv.mkDerivation {
name = "${board}-fsbl"; name = "${board}-fsbl";
src = pkgs.fetchFromGitHub { src = pkgs.fetchFromGitHub {
@ -277,8 +187,9 @@
sha256 = "sha256-UDz9KK/Hw3qM1BAeKif30rE8Bi6C2uvuZlvyvtJCMfw="; sha256 = "sha256-UDz9KK/Hw3qM1BAeKif30rE8Bi6C2uvuZlvyvtJCMfw=";
}; };
nativeBuildInputs = [ nativeBuildInputs = [
pkgs.pkgsCross.zynq-baremetal.buildPackages.binutils pkgs.gnumake
pkgs.pkgsCross.zynq-baremetal.buildPackages.gcc gnutoolchain.binutils
gnutoolchain.gcc
]; ];
postUnpack = '' postUnpack = ''
mkdir -p $sourceRoot/lib/sw_apps/zynq_fsbl/misc/fast-servo mkdir -p $sourceRoot/lib/sw_apps/zynq_fsbl/misc/fast-servo
@ -288,11 +199,7 @@
patches = [] ++ pkgs.lib.optional (board == "fast-servo") ./fast-servo/fsbl.patch; patches = [] ++ pkgs.lib.optional (board == "fast-servo") ./fast-servo/fsbl.patch;
postPatch = '' postPatch = ''
patchShebangs lib/sw_apps/zynq_fsbl/misc/copy_bsp.sh patchShebangs lib/sw_apps/zynq_fsbl/misc/copy_bsp.sh
echo 'SEARCH_DIR("${gnutoolchain.newlib}/arm-none-eabi/lib");' >> lib/sw_apps/zynq_fsbl/src/lscript.ld
for x in lib/sw_apps/zynq_fsbl/src/Makefile lib/sw_apps/zynq_fsbl/misc/copy_bsp.sh lib/bsp/standalone/src/arm/cortexa9/gcc/Makefile; do
substituteInPlace $x \
--replace "arm-none-eabi-" "arm-none-eabihf-"
done
''; '';
buildPhase = '' buildPhase = ''
cd lib/sw_apps/zynq_fsbl/src cd lib/sw_apps/zynq_fsbl/src
@ -306,8 +213,9 @@
dontFixup = true; dontFixup = true;
}; };
u-boot = (pkgs-armv7l.buildUBoot { u-boot = let
name = "${board}-u-boot"; fast-servo-dts = fast-servo/fast-servo.dts;
in (pkgs.pkgsCross.armv7l-hf-multiplatform.buildUBoot {
defconfig = "xilinx_zynq_virt_defconfig"; defconfig = "xilinx_zynq_virt_defconfig";
patches = [] ++ pkgs.lib.optional (board == "fast-servo") ./fast-servo/u-boot.patch; patches = [] ++ pkgs.lib.optional (board == "fast-servo") ./fast-servo/u-boot.patch;
preConfigure = '' preConfigure = ''
@ -317,7 +225,7 @@
CONFIG_SYS_PROMPT="${board}-boot> " CONFIG_SYS_PROMPT="${board}-boot> "
CONFIG_AUTOBOOT=y CONFIG_AUTOBOOT=y
CONFIG_BOOTCOMMAND="${builtins.replaceStrings [ "\n" ] [ "; " ] '' CONFIG_BOOTCOMMAND="${builtins.replaceStrings [ "\n" ] [ "; " ] ''
setenv bootargs 'root=/dev/mmcblk0p2 console=ttyPS0,115200n8 systemConfig=${builtins.unsafeDiscardStringContext not-os-build.toplevel}' setenv bootargs 'root=/dev/mmcblk0p2 console=ttyPS0,115200n8 systemConfig=${builtins.unsafeDiscardStringContext not-os-cfg.build.toplevel}'
fatload mmc 0 0x6400000 uImage fatload mmc 0 0x6400000 uImage
fatload mmc 0 0x8000000 ${board}.dtb fatload mmc 0 0x8000000 ${board}.dtb
fatload mmc 0 0xA400000 uRamdisk.image.gz fatload mmc 0 0xA400000 uRamdisk.image.gz
@ -330,7 +238,7 @@
filesToInstall = [ "u-boot.elf" ]; filesToInstall = [ "u-boot.elf" ];
}).overrideAttrs (oldAttrs: { }).overrideAttrs (oldAttrs: {
postUnpack = '' postUnpack = ''
cp ${fast-servo/fast-servo.dts} $sourceRoot/arch/arm/dts/zynq-fast-servo.dts cp ${fast-servo-dts} $sourceRoot/arch/arm/dts/zynq-fast-servo.dts
''; '';
postInstall = '' postInstall = ''
mkdir -p $out/dts mkdir -p $out/dts
@ -361,7 +269,7 @@
echo file binary-dist $out/boot.bin >> $out/nix-support/hydra-build-products echo file binary-dist $out/boot.bin >> $out/nix-support/hydra-build-products
''; '';
dtb = pkgs.runCommand "${board}-dtb" dtb = pkgs.runCommand "dtb"
{ {
buildInputs = [ pkgs.gcc pkgs.dtc ]; buildInputs = [ pkgs.gcc pkgs.dtc ];
} }
@ -381,14 +289,14 @@
sd-image = let sd-image = let
rootfsImage = pkgs.callPackage (pkgs.path + "/nixos/lib/make-ext4-fs.nix") { rootfsImage = pkgs.callPackage (pkgs.path + "/nixos/lib/make-ext4-fs.nix") {
storePaths = [ not-os-build.toplevel ]; storePaths = [ not-os-cfg.build.toplevel ];
volumeLabel = "ROOT"; volumeLabel = "ROOT";
}; };
# Current firmware (kernel, bootimage, etc..) takes ~18MB # Current firmware (kernel, bootimage, etc..) takes ~18MB
firmwareSize = 30; firmwareSize = 30;
firmwarePartitionOffset = 8; firmwarePartitionOffset = 8;
in pkgs.stdenv.mkDerivation { in pkgs.stdenv.mkDerivation {
name = "${board}-sd-image"; name = "sd-image";
nativeBuildInputs = with pkgs; [ dosfstools mtools libfaketime util-linux parted ]; nativeBuildInputs = with pkgs; [ dosfstools mtools libfaketime util-linux parted ];
buildCommand = '' buildCommand = ''
mkdir -p $out/nix-support $out/sd-image mkdir -p $out/nix-support $out/sd-image
@ -422,8 +330,8 @@
mkdir firmware mkdir firmware
cp ${bootimage}/boot.bin firmware/ cp ${bootimage}/boot.bin firmware/
cp ${dtb}/${board}.dtb firmware/ cp ${dtb}/${board}.dtb firmware/
cp ${not-os-build.kernel}/uImage firmware/ cp ${not-os-cfg.build.kernel}/uImage firmware/
cp ${not-os-build.uRamdisk}/initrd firmware/uRamdisk.image.gz cp ${not-os-cfg.build.uRamdisk}/initrd firmware/uRamdisk.image.gz
(cd firmware; mcopy -psvm -i ../firmware_part.img ./* ::) (cd firmware; mcopy -psvm -i ../firmware_part.img ./* ::)
dd conv=notrunc if=firmware_part.img of=$img seek=$START count=$SECTORS dd conv=notrunc if=firmware_part.img of=$img seek=$START count=$SECTORS
@ -433,12 +341,10 @@
not-os-qemu = let not-os-qemu = let
qemuScript = '' qemuScript = ''
#!/bin/bash #!/bin/bash
export PATH=${pkgs.qemu}/bin:$PATH export PATH=${qemu}/bin:$PATH
IMGDIR=$(mktemp -d /tmp/not-os-qemu-XXXXXX) IMGDIR=$(mktemp -d /tmp/not-os-qemu-XXXXXX)
BASE=$(realpath $(dirname $0)) BASE=$(realpath $(dirname $0))
qemu-img create -F raw -f qcow2 -b $BASE/sd-image.img $IMGDIR/sd-overlay.qcow2 512M
qemu-img convert -O qcow2 -f raw -o preallocation=metadata $BASE/sd-image.img $IMGDIR/sd-sparse.qcow2
qemu-img create -F qcow2 -f qcow2 -b $IMGDIR/sd-sparse.qcow2 $IMGDIR/sd-overlay.qcow2 2G
# Some command arguments are based from samples in Xilinx QEMU User Documentation # Some command arguments are based from samples in Xilinx QEMU User Documentation
# See: https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/821854273/Running+Bare+Metal+Applications+on+QEMU # See: https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/821854273/Running+Bare+Metal+Applications+on+QEMU
@ -453,7 +359,7 @@
rm -rf $IMGDIR rm -rf $IMGDIR
''; '';
in pkgs.runCommand "${board}-qemu" { in pkgs.runCommand "not-os-qemu" {
inherit qemuScript; inherit qemuScript;
passAsFile = [ "qemuScript" ]; passAsFile = [ "qemuScript" ];
preferLocalBuild = true; preferLocalBuild = true;
@ -478,13 +384,11 @@
in rec { in rec {
packages.x86_64-linux = { packages.x86_64-linux = {
inherit mkbootimage; inherit mkbootimage;
inherit migen misoc vivado;
}; };
packages.armv7l-linux = { packages.armv7l-linux =
inherit fast-servo-gateware linien-server;
} //
(board-package-set { board = "zc706"; }) // (board-package-set { board = "zc706"; }) //
(board-package-set { board = "fast-servo"; }); (board-package-set { board = "fast-servo"; });
hydraJobs = packages.x86_64-linux // packages.armv7l-linux; hydraJobs = packages.x86_64-linux // packages.armv7l-linux;
}; };

View File

@ -1,5 +1,5 @@
diff --git a/configuration.nix b/configuration.nix diff --git a/configuration.nix b/configuration.nix
index 010c487..2d08009 100644 index 010c487..e1e85ba 100644
--- a/configuration.nix --- a/configuration.nix
+++ b/configuration.nix +++ b/configuration.nix
@@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
@ -8,7 +8,7 @@ index 010c487..2d08009 100644
{ {
imports = [ ./qemu.nix ]; imports = [ ./qemu.nix ];
@@ -7,10 +7,16 @@ @@ -7,10 +7,15 @@
environment.etc = { environment.etc = {
"ssh/authorized_keys.d/root" = { "ssh/authorized_keys.d/root" = {
text = '' text = ''
@ -18,7 +18,6 @@ index 010c487..2d08009 100644
+ ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBNdIiLvP2hmDUFyyE0oLOIXrjrMdWWpBV9/gPR5m4AiARx4JkufIDZzmptdYQ5FhJORJ4lluPqp7dAmahoSwg4lv9Di0iNQpHMJvNGZLHYKM1H1FWCCFIEDJ8bD4SVfrDg== root + ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBNdIiLvP2hmDUFyyE0oLOIXrjrMdWWpBV9/gPR5m4AiARx4JkufIDZzmptdYQ5FhJORJ4lluPqp7dAmahoSwg4lv9Di0iNQpHMJvNGZLHYKM1H1FWCCFIEDJ8bD4SVfrDg== root
+ ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBF/YybP+fQ0J+bNqM5Vgx5vDmVqVWsgUdF1moUxghv7d73GZAFaM6IFBdrXTAa33AwnWwDPMrTgP1V6SXBkb3ciJo/lD1urJGbydbSI5Ksq9d59wvOeANvyWYrQw6+eqTQ== sb + ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBF/YybP+fQ0J+bNqM5Vgx5vDmVqVWsgUdF1moUxghv7d73GZAFaM6IFBdrXTAa33AwnWwDPMrTgP1V6SXBkb3ciJo/lD1urJGbydbSI5Ksq9d59wvOeANvyWYrQw6+eqTQ== sb
+ ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBFkmOCQ3BQh3qUjLtfdqyeBsx8rkk/QYlzB0TMrnfn6waLN6yKfPC3WVFv4zN5kNKb/OayvqDa+zfkKe85e/oIPQQKflF7GrCHdssz33DCnW90cz532E6iqG1pjeZjID2A== flo + ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBFkmOCQ3BQh3qUjLtfdqyeBsx8rkk/QYlzB0TMrnfn6waLN6yKfPC3WVFv4zN5kNKb/OayvqDa+zfkKe85e/oIPQQKflF7GrCHdssz33DCnW90cz532E6iqG1pjeZjID2A== flo
+ ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICAranL376soiSJ0kxdYNrwElcaZPW1heLFjs8Y7n0jT linuswck
''; '';
mode = "0444"; mode = "0444";
}; };

View File

@ -1,28 +0,0 @@
diff --git a/runit.nix b/runit.nix
index d7b0bf3..64f99f2 100644
--- a/runit.nix
+++ b/runit.nix
@@ -57,6 +57,23 @@ in
'';
"runit/3".source = pkgs.writeScript "3" ''
#!${pkgs.runtimeShell}
+ echo Waiting for services to stop...
+ sv force-stop /etc/service/*
+ sv exit /etc/service/*
+
+ echo Sending TERM signal to processes...
+ pkill --inverse -s0,1 -TERM
+ sleep 1
+ echo Sending KILL signal to processes...
+ pkill --inverse -s0,1 -KILL
+
+ echo Unmounting filesystems, disabling swap...
+ swapoff -a
+ umount -r -a -t nosysfs,noproc,nodevtmpfs,notmpfs
+ echo Remounting rootfs read-only...
+ mount -o remount,ro /
+
+ sync
echo and down we go
'';
"service/sshd/run".source = pkgs.writeScript "sshd_run" ''

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
diff --git a/base.nix b/base.nix diff --git a/base.nix b/base.nix
index 7eaee32..9aa338e 100644 index 7eaee32..3a2a0a9 100644
--- a/base.nix --- a/base.nix
+++ b/base.nix +++ b/base.nix
@@ -27,6 +27,11 @@ with lib; @@ -27,6 +27,11 @@ with lib;
@ -14,12 +14,9 @@ index 7eaee32..9aa338e 100644
not-os.simpleStaticIp = mkOption { not-os.simpleStaticIp = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
@@ -84,17 +89,25 @@ with lib; @@ -86,15 +91,25 @@ with lib;
};
environment.etc = {
"nix/nix.conf".source = pkgs.runCommand "nix.conf" {} '' "nix/nix.conf".source = pkgs.runCommand "nix.conf" {} ''
- extraPaths=$(for i in $(cat ${pkgs.writeReferencesToFile pkgs.runtimeShell}); do if test -d $i; then echo $i; fi; done) extraPaths=$(for i in $(cat ${pkgs.writeReferencesToFile pkgs.runtimeShell}); do if test -d $i; then echo $i; fi; done)
+ extraPaths=$(for i in $(cat ${pkgs.writeClosure [ pkgs.bash ]}); do if test -d $i; then echo $i; fi; done)
cat > $out << EOF cat > $out << EOF
- build-use-sandbox = true - build-use-sandbox = true
+ auto-optimise-store = true + auto-optimise-store = true
@ -31,6 +28,8 @@ index 7eaee32..9aa338e 100644
+ extra-sandbox-paths = /bin/sh=${pkgs.runtimeShell} $(echo $extraPaths) + extra-sandbox-paths = /bin/sh=${pkgs.runtimeShell} $(echo $extraPaths)
+ max-jobs = auto + max-jobs = auto
+ sandbox = true + sandbox = true
+ substituters = https://cache.armv7l.xyz
+ trusted-public-keys = cache.armv7l.xyz-1:kBY/eGnBAYiqYfg0fy0inWhshUo+pGFM3Pj7kIkmlBk=
+ trusted-users = root + trusted-users = root
EOF EOF
''; '';
@ -152,10 +151,10 @@ index c61f9d6..fbdf0fd 100644
}; };
} }
diff --git a/zynq_image.nix b/zynq_image.nix diff --git a/zynq_image.nix b/zynq_image.nix
index 3fa23ab..069fe89 100644 index 3fa23ab..727e3ef 100644
--- a/zynq_image.nix --- a/zynq_image.nix
+++ b/zynq_image.nix +++ b/zynq_image.nix
@@ -1,66 +1,89 @@ @@ -1,66 +1,96 @@
-{ config, pkgs, ... }: -{ config, pkgs, ... }:
+{ lib, config, pkgs, ... }: +{ lib, config, pkgs, ... }:
@ -164,7 +163,22 @@ index 3fa23ab..069fe89 100644
- # dont use overlays for the qemu, it causes a lot of wasted time on recompiles - # dont use overlays for the qemu, it causes a lot of wasted time on recompiles
- x86pkgs = import pkgs.path { system = "x86_64-linux"; }; - x86pkgs = import pkgs.path { system = "x86_64-linux"; };
- customKernel = pkgs.linux.override { - customKernel = pkgs.linux.override {
+ customKernel = (pkgs.linux_6_6.override { + crosspkgs = import pkgs.path {
+ system = "x86_64-linux";
+ crossSystem = {
+ system = "armv7l-linux";
+ linux-kernel = {
+ name = "zynq";
+ baseConfig = "multi_v7_defconfig";
+ target = "uImage";
+ installTarget = "uImage";
+ autoModules = false;
+ DTB = true;
+ makeFlags = [ "LOADADDR=0x8000" ];
+ };
+ };
+ };
+ customKernel = (crosspkgs.linux.override {
extraConfig = '' extraConfig = ''
OVERLAY_FS y OVERLAY_FS y
+ MEDIA_SUPPORT n + MEDIA_SUPPORT n
@ -173,23 +187,16 @@ index 3fa23ab..069fe89 100644
+ SOUND n + SOUND n
+ SQUASHFS n + SQUASHFS n
+ BACKLIGHT_CLASS_DEVICE n + BACKLIGHT_CLASS_DEVICE n
+ FPGA y
+ FPGA_BRIDGE y
+ FPGA_REGION y
+ OF_FPGA_REGION y
+ FPGA_MGR_ZYNQ_FPGA y
+ OF_OVERLAY y
''; '';
- }; - };
- customKernelPackages = pkgs.linuxPackagesFor customKernel;
+ }).overrideAttrs (oa: { + }).overrideAttrs (oa: {
+ postInstall = '' + postInstall = ''
+ if [ -e arch/arm/boot/uImage ]; then
+ cp arch/arm/boot/uImage $out + cp arch/arm/boot/uImage $out
+ fi
+ ${oa.postInstall} + ${oa.postInstall}
+ ''; + '';
+ }); + });
customKernelPackages = pkgs.linuxPackagesFor customKernel; + customKernelPackages = crosspkgs.linuxPackagesFor customKernel;
in { in {
imports = [ ./arm32-cross-fixes.nix ]; imports = [ ./arm32-cross-fixes.nix ];
boot.kernelPackages = customKernelPackages; boot.kernelPackages = customKernelPackages;
@ -240,17 +247,17 @@ index 3fa23ab..069fe89 100644
- chmod +x qemu-script - chmod +x qemu-script
- patchShebangs qemu-script - patchShebangs qemu-script
- ls -ltrh - ls -ltrh
- ''; '';
- system.build.rpi_image_tar = pkgs.runCommand "dist.tar" {} '' - system.build.rpi_image_tar = pkgs.runCommand "dist.tar" {} ''
- mkdir -p $out/nix-support - mkdir -p $out/nix-support
- tar -cvf $out/dist.tar ${config.system.build.rpi_image} - tar -cvf $out/dist.tar ${config.system.build.rpi_image}
- echo "file binary-dist $out/dist.tar" >> $out/nix-support/hydra-build-products - echo "file binary-dist $out/dist.tar" >> $out/nix-support/hydra-build-products
''; - '';
- environment.systemPackages = [ pkgs.strace ]; - environment.systemPackages = [ pkgs.strace ];
- environment.etc."service/getty/run".source = pkgs.writeShellScript "getty" '' - environment.etc."service/getty/run".source = pkgs.writeShellScript "getty" ''
- agetty ttyPS0 115200 - agetty ttyPS0 115200
+ environment = { + environment = {
+ systemPackages = with pkgs; [ inetutils wget gnugrep nano vim ]; + systemPackages = with pkgs; [ inetutils wget nano ];
+ etc = { + etc = {
+ "service/getty/run".source = pkgs.writeShellScript "getty" '' + "service/getty/run".source = pkgs.writeShellScript "getty" ''
+ hostname ${config.networking.hostName} + hostname ${config.networking.hostName}