1
0
Fork 0

Compare commits

...

82 Commits

Author SHA1 Message Date
linuswck 77643909ef pyfastservo: add note for dac output override 2024-11-15 15:42:25 +08:00
linuswck a5dc232be4 gateware: add cdc fifo for dac output value override csr 2024-11-15 15:42:25 +08:00
linuswck 87059eef2b gateware: async fifo with depth of 2 is broken
- Changing depth to 4 has resolved cdc issue
2024-11-15 15:42:25 +08:00
linuswck 8a40bb4f21 gateware: Add cdc fifo for adc and dac
- dco2d and sys clk use two different clock sources
2024-11-13 15:43:35 +08:00
linuswck bbe09de52c pyfastservo adc: Add helper fn for phase shifting the dac ddr clock 2024-11-08 16:37:29 +08:00
linuswck 9f2e609b6e pyfastservo dac: Change debug MSG 2024-11-08 16:37:16 +08:00
linuswck 6705b182d5 pyfastservo dac: power_down -> power_down_afe 2024-11-08 16:35:52 +08:00
linuswck 51c8b755d2 pyfastservo dac: hard_reset -> soft_reset 2024-11-08 16:35:52 +08:00
linuswck 5d55ab4c9c pyfastservo dac: reacquire clk relationship at init 2024-11-08 16:35:52 +08:00
linuswck 560b28508c pyfastservo dac: turn off manual override by default 2024-11-08 16:35:52 +08:00
linuswck b1a9fa0ad4 pyfastservo adc: Set default afe gain to 10x 2024-11-08 16:35:52 +08:00
linuswck 5343b3d45a pyfastservo adc: print 100 times to check test pattern 2024-11-08 16:35:52 +08:00
linuswck 4940ee52cc pyfastservo adc: Add mmcm rst after ADC is rst 2024-11-08 16:35:52 +08:00
linuswck 382e8467d9 pyfastservo adc: Fix find edge bug
- Fix: if frame changed at 31 tap delay, edge would not get detected
2024-11-08 16:35:52 +08:00
linuswck 6cef418756 gateware: Add CSR Ctrl to PL's MMCM
- Generate 45 Degree Phase Shifted DDR Clock
- PLLE2_Base -> MMCM_ADV for ddr clock dynamic phase shift
- Add mmcm_rst, ddr_clk_ps, mmcm_locked status to CSR
- Generate dco2d rst signal from mmcm and connect to the related logic
2024-11-08 16:33:17 +08:00
Florian Agbuya e708696b5d add grep and vim 2024-10-31 19:06:59 +08:00
Florian Agbuya 3cf9a721cf add linuswck ssh key 2024-10-31 14:54:14 +08:00
Florian Agbuya 8b20379427 remove nixos armv7l unofficial binary cache 2024-08-22 14:14:51 +08:00
Florian Agbuya 15a66c01fa dac: fix initialization order 2024-08-20 16:35:49 +08:00
Sebastien Bourdeauducq 2d75b4112e flake: update dependencies 2024-08-19 22:03:51 +08:00
Florian Agbuya ed816517cf si5340: implement paged register writes
Signed-off-by: Florian Agbuya <fa@m-labs.ph>
2024-07-31 16:44:39 +08:00
Florian Agbuya f5729d3bdb pyfastservo: update initialize script 2024-07-10 16:11:17 +08:00
Florian Agbuya e3b1525125 pyfastservo: fix adc init script and cleanup 2024-07-10 16:11:17 +08:00
Florian Agbuya b92d401f2b pyfastservo: fix dac init script and cleanup 2024-07-10 16:11:17 +08:00
Florian Agbuya eed43e3fe3 pyfastservo: transfer common functions to common 2024-07-10 16:11:17 +08:00
Florian Agbuya b2dedd77ad rebased from linux 6.6 LTS 2024-07-02 14:42:39 +08:00
Florian Agbuya 693e301ccf fix pkgs.writeReferencesToFile deprecation and pin linux version 2024-07-02 14:26:07 +08:00
Florian Agbuya 6fca060256 flake: update to nixpkgs 24.05 2024-07-02 14:23:54 +08:00
Florian Agbuya 85af23e547 use recommended init sequence for si5340
Signed-off-by: Florian Agbuya <fa@m-labs.ph>
2024-06-25 10:19:58 +08:00
Florian Agbuya c9d34348bc fix adc and dac initialization 2024-06-10 10:02:29 +08:00
Florian Agbuya db88e5db59 use libmonitor compiled by gnumake 2024-05-22 15:32:23 +08:00
Florian Agbuya 7d5fbdd281 use fast-servo csrmap 2024-05-21 16:07:48 +08:00
Florian Agbuya fc71fe0ab3 fix incorrect terminology 2024-04-25 10:36:28 +08:00
Florian Agbuya 1ee382564e add pyfastservo package and initialize at boot 2024-04-24 18:03:17 +08:00
Florian Agbuya 7c6320f66d configure loading of bitstream at boot time 2024-04-24 18:03:17 +08:00
Florian Agbuya 3d98549fd1 rename board specific packages 2024-04-23 14:19:19 +08:00
Florian Agbuya 0ff299aa55 increase qemu image size 2024-04-04 13:43:19 +08:00
Florian Agbuya c2d38540c0 integrate linien-server to not-os 2024-04-04 13:06:01 +08:00
Florian Agbuya d9a2d60b50 configure arm linux toolchain 2024-03-26 17:53:25 +08:00
Florian Agbuya 26dd210eb6 rebase from 251f65f 2024-03-26 17:51:46 +08:00
Florian Agbuya 251f65f217 cross-compilation transferred to crossSystem 2024-03-26 17:50:40 +08:00
Florian Agbuya 0d3f87c5bc use nix gnu toolchain format for baremetal apps 2024-03-25 15:14:15 +08:00
Florian Agbuya 208d56adb2 fix linien-server red pitaya dependencies 2024-03-20 13:40:09 +08:00
Florian Agbuya 628582a981 add spidev on device tree 2024-03-15 11:46:51 +08:00
Florian Agbuya bc09e60a15 add fpga programming support 2024-03-14 13:03:09 +08:00
Florian Agbuya 88b3197c0c add provenance information 2024-03-08 14:35:59 +08:00
Florian Agbuya 0cda432bf9 add fast-servo python init scripts 2024-03-08 14:35:59 +08:00
Florian Agbuya 1244c84f67 fix typo 2024-03-06 17:53:13 +08:00
Florian Agbuya 3618a1f17d add linien-server package 2024-03-06 11:48:08 +08:00
Florian Agbuya 22992e2e82 update nixpkgs and use upstream qemu 2024-03-05 09:50:55 +08:00
Florian Agbuya d6ac3944fb linux: add fpga support 2024-03-04 17:40:33 +08:00
Florian Agbuya c61597ea4f fix qemu build errors 2024-03-01 18:09:53 +08:00
Florian Agbuya efe58d8106 move not-os patches to dedicated folder 2024-03-01 17:14:09 +08:00
Florian Agbuya 007ca18cab fix homeless-shelter error 2024-03-01 16:39:56 +08:00
Florian Agbuya 506bbcc0db add fast-servo linien gateware 2024-03-01 16:39:56 +08:00
Florian Agbuya e12b672cdc add __pycache__ 2024-03-01 16:39:56 +08:00
Florian Agbuya cd9590503c add fast-servo gateware support files 2024-03-01 16:39:56 +08:00
Florian Agbuya e4dcc0e84a configure shutdown instructions in runit stage 3 2024-02-22 09:58:29 +08:00
Florian Agbuya 1f3591a693 add nix substituters and update nix.conf 2024-02-20 14:02:51 +08:00
Florian Agbuya afa00efee3 clean up device tree package 2024-02-20 09:51:57 +08:00
Florian Agbuya 25ef8fa486 refactor build script for better board management 2024-02-20 09:51:57 +08:00
Florian Agbuya 073f1c9bbd device tree source from u-boot and cleanup 2024-02-20 09:51:44 +08:00
Florian Agbuya 388e7e7082 configure qemu with u-boot and cleanup 2024-02-20 09:51:00 +08:00
Florian Agbuya 22129bc04e fix fast-servo u-boot 2024-02-20 09:51:00 +08:00
Florian Agbuya 62b8b691fe configure device-tree support 2024-02-20 09:50:41 +08:00
Florian Agbuya 69a252e488 add fast-servo bootimage, sd-image and cleanup 2024-02-20 09:48:40 +08:00
Florian Agbuya ae31216084 add fast-servo fsbl support 2024-02-20 09:48:40 +08:00
Florian Agbuya e6f4512554 add device-tree builder 2024-02-20 09:48:40 +08:00
Florian Agbuya eb10e3ad4e configure fast-servo u-boot 2024-02-20 09:48:40 +08:00
Florian Agbuya d17356e750 add fast-servo device tree files 2024-02-20 09:48:40 +08:00
Florian Agbuya 72e91bfdb2 set NIX_PATH 2024-02-19 15:55:59 +08:00
Florian Agbuya a86db3cd33 add nano as default text editor 2024-02-15 17:29:11 +08:00
Florian Agbuya 0de5ddeb1e transfer definition of nameserver to avoid patch hunk error 2024-02-15 17:26:56 +08:00
Florian Agbuya 38638fa5fe fix modprobe and nix-path-registration error 2024-02-14 16:58:40 +08:00
Florian Agbuya b252e0a913 add ssl certificates 2024-01-22 11:30:40 +08:00
Florian Agbuya e94262db53 remove kernel module bloat 2024-01-17 17:56:38 +08:00
Florian Agbuya 2639192a92 replace nameserver 2024-01-17 10:33:29 +08:00
Florian Agbuya f6055cf908 fix login errors 2024-01-17 10:16:17 +08:00
Florian Agbuya 8f664049d6 zynq: remove strace and add wget 2024-01-16 14:33:22 +08:00
Florian Agbuya c74391e94e zynq: add first boot commands 2024-01-16 12:21:37 +08:00
Florian Agbuya bd4885c597 enable host key generation on first boot 2024-01-15 17:51:52 +08:00
Florian Agbuya dad71891b6 zynq: configure networking 2024-01-13 21:59:22 +08:00
41 changed files with 32345 additions and 510 deletions

1
.gitignore vendored
View File

@ -1 +1,2 @@
__pycache__
result

706
fast-servo/fast-servo.dts Normal file
View File

@ -0,0 +1,706 @@
# 0 "system-top.dts"
# 0 "<built-in>"
# 0 "<command-line>"
# 1 "system-top.dts"
/dts-v1/;
# 1 "zynq-7000.dtsi" 1
# 15 "zynq-7000.dtsi"
/ {
#address-cells = <1>;
#size-cells = <1>;
compatible = "xlnx,zynq-7000";
cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu0: cpu@0 {
compatible = "arm,cortex-a9";
device_type = "cpu";
reg = <0>;
clocks = <&clkc 3>;
clock-latency = <1000>;
cpu0-supply = <&regulator_vccpint>;
operating-points = <
666667 1000000
333334 1000000
>;
};
cpu1: cpu@1 {
compatible = "arm,cortex-a9";
device_type = "cpu";
reg = <1>;
clocks = <&clkc 3>;
};
};
fpga_full: fpga-full {
compatible = "fpga-region";
fpga-mgr = <&devcfg>;
#address-cells = <1>;
#size-cells = <1>;
ranges;
};
pmu@f8891000 {
compatible = "arm,cortex-a9-pmu";
interrupts = <0 5 4>, <0 6 4>;
interrupt-parent = <&intc>;
reg = < 0xf8891000 0x1000 0xf8893000 0x1000 >;
};
regulator_vccpint: fixedregulator {
compatible = "regulator-fixed";
regulator-name = "VCCPINT";
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <1000000>;
regulator-boot-on;
regulator-always-on;
};
replicator {
compatible = "arm,coresight-static-replicator";
clocks = <&clkc 27>, <&clkc 46>, <&clkc 47>;
clock-names = "apb_pclk", "dbg_trc", "dbg_apb";
out-ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
replicator_out_port0: endpoint {
remote-endpoint = <&tpiu_in_port>;
};
};
port@1 {
reg = <1>;
replicator_out_port1: endpoint {
remote-endpoint = <&etb_in_port>;
};
};
};
in-ports {
port {
replicator_in_port0: endpoint {
remote-endpoint = <&funnel_out_port>;
};
};
};
};
amba: axi {
u-boot,dm-pre-reloc;
compatible = "simple-bus";
#address-cells = <1>;
#size-cells = <1>;
interrupt-parent = <&intc>;
ranges;
adc: adc@f8007100 {
compatible = "xlnx,zynq-xadc-1.00.a";
reg = <0xf8007100 0x20>;
interrupts = <0 7 4>;
interrupt-parent = <&intc>;
clocks = <&clkc 12>;
};
can0: can@e0008000 {
compatible = "xlnx,zynq-can-1.0";
status = "disabled";
clocks = <&clkc 19>, <&clkc 36>;
clock-names = "can_clk", "pclk";
reg = <0xe0008000 0x1000>;
interrupts = <0 28 4>;
interrupt-parent = <&intc>;
tx-fifo-depth = <0x40>;
rx-fifo-depth = <0x40>;
};
can1: can@e0009000 {
compatible = "xlnx,zynq-can-1.0";
status = "disabled";
clocks = <&clkc 20>, <&clkc 37>;
clock-names = "can_clk", "pclk";
reg = <0xe0009000 0x1000>;
interrupts = <0 51 4>;
interrupt-parent = <&intc>;
tx-fifo-depth = <0x40>;
rx-fifo-depth = <0x40>;
};
gpio0: gpio@e000a000 {
compatible = "xlnx,zynq-gpio-1.0";
#gpio-cells = <2>;
clocks = <&clkc 42>;
gpio-controller;
interrupt-controller;
#interrupt-cells = <2>;
interrupt-parent = <&intc>;
interrupts = <0 20 4>;
reg = <0xe000a000 0x1000>;
};
i2c0: i2c@e0004000 {
compatible = "cdns,i2c-r1p10";
status = "disabled";
clocks = <&clkc 38>;
interrupt-parent = <&intc>;
interrupts = <0 25 4>;
reg = <0xe0004000 0x1000>;
#address-cells = <1>;
#size-cells = <0>;
};
i2c1: i2c@e0005000 {
compatible = "cdns,i2c-r1p10";
status = "disabled";
clocks = <&clkc 39>;
interrupt-parent = <&intc>;
interrupts = <0 48 4>;
reg = <0xe0005000 0x1000>;
#address-cells = <1>;
#size-cells = <0>;
};
intc: interrupt-controller@f8f01000 {
compatible = "arm,cortex-a9-gic";
#interrupt-cells = <3>;
interrupt-controller;
reg = <0xF8F01000 0x1000>,
<0xF8F00100 0x100>;
};
L2: cache-controller@f8f02000 {
compatible = "arm,pl310-cache";
reg = <0xF8F02000 0x1000>;
interrupts = <0 2 4>;
arm,data-latency = <3 2 2>;
arm,tag-latency = <2 2 2>;
cache-unified;
cache-level = <2>;
};
mc: memory-controller@f8006000 {
compatible = "xlnx,zynq-ddrc-a05";
reg = <0xf8006000 0x1000>;
};
ocm: sram@fffc0000 {
compatible = "mmio-sram";
reg = <0xfffc0000 0x10000>;
};
uart0: serial@e0000000 {
compatible = "xlnx,xuartps", "cdns,uart-r1p8";
status = "disabled";
clocks = <&clkc 23>, <&clkc 40>;
clock-names = "uart_clk", "pclk";
reg = <0xE0000000 0x1000>;
interrupts = <0 27 4>;
};
uart1: serial@e0001000 {
compatible = "xlnx,xuartps", "cdns,uart-r1p8";
status = "disabled";
clocks = <&clkc 24>, <&clkc 41>;
clock-names = "uart_clk", "pclk";
reg = <0xE0001000 0x1000>;
interrupts = <0 50 4>;
};
spi0: spi@e0006000 {
compatible = "xlnx,zynq-spi-r1p6";
reg = <0xe0006000 0x1000>;
status = "disabled";
interrupt-parent = <&intc>;
interrupts = <0 26 4>;
clocks = <&clkc 25>, <&clkc 34>;
clock-names = "ref_clk", "pclk";
#address-cells = <1>;
#size-cells = <0>;
};
spi1: spi@e0007000 {
compatible = "xlnx,zynq-spi-r1p6";
reg = <0xe0007000 0x1000>;
status = "disabled";
interrupt-parent = <&intc>;
interrupts = <0 49 4>;
clocks = <&clkc 26>, <&clkc 35>;
clock-names = "ref_clk", "pclk";
#address-cells = <1>;
#size-cells = <0>;
};
qspi: spi@e000d000 {
clock-names = "ref_clk", "pclk";
clocks = <&clkc 10>, <&clkc 43>;
compatible = "xlnx,zynq-qspi-1.0";
status = "disabled";
interrupt-parent = <&intc>;
interrupts = <0 19 4>;
reg = <0xe000d000 0x1000>;
#address-cells = <1>;
#size-cells = <0>;
};
gem0: ethernet@e000b000 {
compatible = "xlnx,zynq-gem", "cdns,zynq-gem", "cdns,gem";
reg = <0xe000b000 0x1000>;
status = "disabled";
interrupts = <0 22 4>;
clocks = <&clkc 30>, <&clkc 30>, <&clkc 13>;
clock-names = "pclk", "hclk", "tx_clk";
#address-cells = <1>;
#size-cells = <0>;
};
gem1: ethernet@e000c000 {
compatible = "xlnx,zynq-gem", "cdns,zynq-gem", "cdns,gem";
reg = <0xe000c000 0x1000>;
status = "disabled";
interrupts = <0 45 4>;
clocks = <&clkc 31>, <&clkc 31>, <&clkc 14>;
clock-names = "pclk", "hclk", "tx_clk";
#address-cells = <1>;
#size-cells = <0>;
};
smcc: memory-controller@e000e000 {
compatible = "arm,pl353-smc-r2p1", "arm,primecell";
reg = <0xe000e000 0x0001000>;
status = "disabled";
clock-names = "memclk", "apb_pclk";
clocks = <&clkc 11>, <&clkc 44>;
ranges = <0x0 0x0 0xe1000000 0x1000000
0x1 0x0 0xe2000000 0x2000000
0x2 0x0 0xe4000000 0x2000000>;
#address-cells = <2>;
#size-cells = <1>;
interrupt-parent = <&intc>;
interrupts = <0 18 4>;
nfc0: nand-controller@0,0 {
compatible = "arm,pl353-nand-r2p1";
reg = <0 0 0x1000000>;
status = "disabled";
#address-cells = <0x1>;
#size-cells = <0x0>;
};
nor0: flash@1,0 {
status = "disabled";
compatible = "cfi-flash";
reg = <1 0 0x2000000>;
#address-cells = <1>;
#size-cells = <1>;
};
};
sdhci0: mmc@e0100000 {
compatible = "arasan,sdhci-8.9a";
status = "disabled";
clock-names = "clk_xin", "clk_ahb";
clocks = <&clkc 21>, <&clkc 32>;
interrupt-parent = <&intc>;
interrupts = <0 24 4>;
reg = <0xe0100000 0x1000>;
};
sdhci1: mmc@e0101000 {
compatible = "arasan,sdhci-8.9a";
status = "disabled";
clock-names = "clk_xin", "clk_ahb";
clocks = <&clkc 22>, <&clkc 33>;
interrupt-parent = <&intc>;
interrupts = <0 47 4>;
reg = <0xe0101000 0x1000>;
};
slcr: slcr@f8000000 {
u-boot,dm-pre-reloc;
#address-cells = <1>;
#size-cells = <1>;
compatible = "xlnx,zynq-slcr", "syscon", "simple-mfd";
reg = <0xF8000000 0x1000>;
ranges;
clkc: clkc@100 {
u-boot,dm-pre-reloc;
#clock-cells = <1>;
compatible = "xlnx,ps7-clkc";
fclk-enable = <0xf>;
clock-output-names = "armpll", "ddrpll", "iopll", "cpu_6or4x",
"cpu_3or2x", "cpu_2x", "cpu_1x", "ddr2x", "ddr3x",
"dci", "lqspi", "smc", "pcap", "gem0", "gem1",
"fclk0", "fclk1", "fclk2", "fclk3", "can0", "can1",
"sdio0", "sdio1", "uart0", "uart1", "spi0", "spi1",
"dma", "usb0_aper", "usb1_aper", "gem0_aper",
"gem1_aper", "sdio0_aper", "sdio1_aper",
"spi0_aper", "spi1_aper", "can0_aper", "can1_aper",
"i2c0_aper", "i2c1_aper", "uart0_aper", "uart1_aper",
"gpio_aper", "lqspi_aper", "smc_aper", "swdt",
"dbg_trc", "dbg_apb";
reg = <0x100 0x100>;
};
rstc: rstc@200 {
compatible = "xlnx,zynq-reset";
reg = <0x200 0x48>;
#reset-cells = <1>;
syscon = <&slcr>;
};
pinctrl0: pinctrl@700 {
compatible = "xlnx,pinctrl-zynq";
reg = <0x700 0x200>;
syscon = <&slcr>;
};
};
dmac_s: dmac@f8003000 {
compatible = "arm,pl330", "arm,primecell";
reg = <0xf8003000 0x1000>;
interrupt-parent = <&intc>;
interrupt-names = "abort", "dma0", "dma1", "dma2", "dma3",
"dma4", "dma5", "dma6", "dma7";
interrupts = <0 13 4>,
<0 14 4>, <0 15 4>,
<0 16 4>, <0 17 4>,
<0 40 4>, <0 41 4>,
<0 42 4>, <0 43 4>;
#dma-cells = <1>;
#dma-channels = <8>;
#dma-requests = <4>;
clocks = <&clkc 27>;
clock-names = "apb_pclk";
};
devcfg: devcfg@f8007000 {
compatible = "xlnx,zynq-devcfg-1.0";
interrupt-parent = <&intc>;
interrupts = <0 8 4>;
reg = <0xf8007000 0x100>;
clocks = <&clkc 12>, <&clkc 15>, <&clkc 16>, <&clkc 17>, <&clkc 18>;
clock-names = "ref_clk", "fclk0", "fclk1", "fclk2", "fclk3";
syscon = <&slcr>;
};
efuse: efuse@f800d000 {
compatible = "xlnx,zynq-efuse";
reg = <0xf800d000 0x20>;
};
global_timer: timer@f8f00200 {
compatible = "arm,cortex-a9-global-timer";
reg = <0xf8f00200 0x20>;
interrupts = <1 11 0x301>;
interrupt-parent = <&intc>;
clocks = <&clkc 4>;
};
ttc0: timer@f8001000 {
interrupt-parent = <&intc>;
interrupts = <0 10 4>, <0 11 4>, <0 12 4>;
compatible = "cdns,ttc";
clocks = <&clkc 6>;
reg = <0xF8001000 0x1000>;
};
ttc1: timer@f8002000 {
interrupt-parent = <&intc>;
interrupts = <0 37 4>, <0 38 4>, <0 39 4>;
compatible = "cdns,ttc";
clocks = <&clkc 6>;
reg = <0xF8002000 0x1000>;
};
scutimer: timer@f8f00600 {
interrupt-parent = <&intc>;
interrupts = <1 13 0x301>;
compatible = "arm,cortex-a9-twd-timer";
reg = <0xf8f00600 0x20>;
clocks = <&clkc 4>;
};
usb0: usb@e0002000 {
compatible = "xlnx,zynq-usb-2.20a", "chipidea,usb2";
status = "disabled";
clocks = <&clkc 28>;
interrupt-parent = <&intc>;
interrupts = <0 21 4>;
reg = <0xe0002000 0x1000>;
phy_type = "ulpi";
};
usb1: usb@e0003000 {
compatible = "xlnx,zynq-usb-2.20a", "chipidea,usb2";
status = "disabled";
clocks = <&clkc 29>;
interrupt-parent = <&intc>;
interrupts = <0 44 4>;
reg = <0xe0003000 0x1000>;
phy_type = "ulpi";
};
watchdog0: watchdog@f8005000 {
clocks = <&clkc 45>;
compatible = "cdns,wdt-r1p2";
interrupt-parent = <&intc>;
interrupts = <0 9 1>;
reg = <0xf8005000 0x1000>;
timeout-sec = <10>;
};
etb@f8801000 {
compatible = "arm,coresight-etb10", "arm,primecell";
reg = <0xf8801000 0x1000>;
clocks = <&clkc 27>, <&clkc 46>, <&clkc 47>;
clock-names = "apb_pclk", "dbg_trc", "dbg_apb";
in-ports {
port {
etb_in_port: endpoint {
remote-endpoint = <&replicator_out_port1>;
};
};
};
};
tpiu@f8803000 {
compatible = "arm,coresight-tpiu", "arm,primecell";
reg = <0xf8803000 0x1000>;
clocks = <&clkc 27>, <&clkc 46>, <&clkc 47>;
clock-names = "apb_pclk", "dbg_trc", "dbg_apb";
in-ports {
port {
tpiu_in_port: endpoint {
remote-endpoint = <&replicator_out_port0>;
};
};
};
};
funnel@f8804000 {
compatible = "arm,coresight-static-funnel", "arm,primecell";
reg = <0xf8804000 0x1000>;
clocks = <&clkc 27>, <&clkc 46>, <&clkc 47>;
clock-names = "apb_pclk", "dbg_trc", "dbg_apb";
out-ports {
port {
funnel_out_port: endpoint {
remote-endpoint =
<&replicator_in_port0>;
};
};
};
in-ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
funnel0_in_port0: endpoint {
remote-endpoint = <&ptm0_out_port>;
};
};
port@1 {
reg = <1>;
funnel0_in_port1: endpoint {
remote-endpoint = <&ptm1_out_port>;
};
};
port@2 {
reg = <2>;
funnel0_in_port2: endpoint {
};
};
};
};
ptm@f889c000 {
compatible = "arm,coresight-etm3x", "arm,primecell";
reg = <0xf889c000 0x1000>;
clocks = <&clkc 27>, <&clkc 46>, <&clkc 47>;
clock-names = "apb_pclk", "dbg_trc", "dbg_apb";
cpu = <&cpu0>;
out-ports {
port {
ptm0_out_port: endpoint {
remote-endpoint = <&funnel0_in_port0>;
};
};
};
};
ptm@f889d000 {
compatible = "arm,coresight-etm3x", "arm,primecell";
reg = <0xf889d000 0x1000>;
clocks = <&clkc 27>, <&clkc 46>, <&clkc 47>;
clock-names = "apb_pclk", "dbg_trc", "dbg_apb";
cpu = <&cpu1>;
out-ports {
port {
ptm1_out_port: endpoint {
remote-endpoint = <&funnel0_in_port1>;
};
};
};
};
};
};
# 10 "system-top.dts" 2
# 1 "pcw.dtsi" 1
/ {
cpus {
cpu@0 {
operating-points = <500000 1000000 250000 1000000>;
};
};
};
&gem0 {
enet-reset = <&gpio0 50 0>;
phy-mode = "rgmii-id";
status = "okay";
xlnx,ptp-enet-clock = <0x4f790d8>;
};
&gpio0 {
emio-gpio-width = <64>;
gpio-mask-high = <0x0>;
gpio-mask-low = <0x5600>;
};
&i2c0 {
clock-frequency = <400000>;
status = "okay";
};
&i2c1 {
clock-frequency = <400000>;
status = "okay";
};
&intc {
num_cpus = <2>;
num_interrupts = <96>;
};
&qspi {
is-dual = <0>;
num-cs = <1>;
spi-rx-bus-width = <4>;
spi-tx-bus-width = <4>;
status = "okay";
};
&sdhci0 {
status = "okay";
xlnx,has-cd = <0x0>;
xlnx,has-power = <0x0>;
xlnx,has-wp = <0x0>;
};
&spi0 {
is-decoded-cs = <0>;
num-cs = <3>;
status = "okay";
};
&spi1 {
is-decoded-cs = <0>;
num-cs = <3>;
status = "okay";
};
&uart0 {
cts-override ;
device_type = "serial";
port-number = <0>;
status = "okay";
};
&usb0 {
phy_type = "ulpi";
status = "okay";
usb-reset = <&gpio0 51 0>;
};
&clkc {
fclk-enable = <0x0>;
ps-clk-frequency = <33333333>;
};
# 11 "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";
chosen {
bootargs = "earlycon";
stdout-path = "serial0:115200n8";
};
aliases {
ethernet0 = &gem0;
i2c0 = &i2c0;
i2c1 = &i2c1;
serial0 = &uart0;
mmc0 = &sdhci0;
spi0 = &qspi;
spi1 = &spi0;
spi2 = &spi1;
};
memory {
device_type = "memory";
reg = <0x0 0x40000000>;
};
};

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

241
fast-servo/fsbl.patch Normal file
View File

@ -0,0 +1,241 @@
diff --git a/lib/sw_apps/zynq_fsbl/misc/fast-servo/ps7_init.h b/lib/sw_apps/zynq_fsbl/misc/fast-servo/ps7_init.h
index 9572636306..2f3816271e 100644
--- a/lib/sw_apps/zynq_fsbl/misc/fast-servo/ps7_init.h
+++ b/lib/sw_apps/zynq_fsbl/misc/fast-servo/ps7_init.h
@@ -67,20 +67,20 @@ extern unsigned long * ps7_peripherals_init_data;
/* Freq of all peripherals */
-#define APU_FREQ 666666687
+#define APU_FREQ 500000000
#define DDR_FREQ 533333374
#define DCI_FREQ 10158730
#define QSPI_FREQ 200000000
#define SMC_FREQ 10000000
-#define ENET0_FREQ 25000000
+#define ENET0_FREQ 125000000
#define ENET1_FREQ 10000000
#define USB0_FREQ 60000000
#define USB1_FREQ 60000000
-#define SDIO_FREQ 50000000
-#define UART_FREQ 50000000
-#define SPI_FREQ 10000000
-#define I2C_FREQ 111111115
-#define WDT_FREQ 111111115
+#define SDIO_FREQ 100000000
+#define UART_FREQ 100000000
+#define SPI_FREQ 166666672
+#define I2C_FREQ 83333336
+#define WDT_FREQ 83333336
#define TTC_FREQ 50000000
#define CAN_FREQ 10000000
#define PCAP_FREQ 200000000
diff --git a/lib/sw_apps/zynq_fsbl/misc/fast-servo/ps7_init_gpl.h b/lib/sw_apps/zynq_fsbl/misc/fast-servo/ps7_init_gpl.h
index 8962bed427..df2f16adec 100644
--- a/lib/sw_apps/zynq_fsbl/misc/fast-servo/ps7_init_gpl.h
+++ b/lib/sw_apps/zynq_fsbl/misc/fast-servo/ps7_init_gpl.h
@@ -81,20 +81,20 @@ extern unsigned long * ps7_peripherals_init_data;
/* Freq of all peripherals */
-#define APU_FREQ 666666687
+#define APU_FREQ 500000000
#define DDR_FREQ 533333374
#define DCI_FREQ 10158730
#define QSPI_FREQ 200000000
#define SMC_FREQ 10000000
-#define ENET0_FREQ 25000000
+#define ENET0_FREQ 125000000
#define ENET1_FREQ 10000000
#define USB0_FREQ 60000000
#define USB1_FREQ 60000000
-#define SDIO_FREQ 50000000
-#define UART_FREQ 50000000
-#define SPI_FREQ 10000000
-#define I2C_FREQ 111111115
-#define WDT_FREQ 111111115
+#define SDIO_FREQ 100000000
+#define UART_FREQ 100000000
+#define SPI_FREQ 166666672
+#define I2C_FREQ 83333336
+#define WDT_FREQ 83333336
#define TTC_FREQ 50000000
#define CAN_FREQ 10000000
#define PCAP_FREQ 200000000
diff --git a/lib/sw_apps/zynq_fsbl/misc/fast-servo/xparameters.h b/lib/sw_apps/zynq_fsbl/misc/fast-servo/xparameters.h
index 997a982ca1..5461fbb477 100644
--- a/lib/sw_apps/zynq_fsbl/misc/fast-servo/xparameters.h
+++ b/lib/sw_apps/zynq_fsbl/misc/fast-servo/xparameters.h
@@ -9,21 +9,26 @@
#define XPAR_CPU_ID 0U
/* Definitions for peripheral PS7_CORTEXA9_0 */
-#define XPAR_PS7_CORTEXA9_0_CPU_CLK_FREQ_HZ 666666687
+#define XPAR_PS7_CORTEXA9_0_CPU_CLK_FREQ_HZ 500000000
/******************************************************************/
/* Canonical definitions for peripheral PS7_CORTEXA9_0 */
-#define XPAR_CPU_CORTEXA9_0_CPU_CLK_FREQ_HZ 666666687
+#define XPAR_CPU_CORTEXA9_0_CPU_CLK_FREQ_HZ 500000000
/******************************************************************/
+
+/* Definitions for interface M_AXI_GP0 */
+#define XPAR_M_AXI_GP0_BASEADDR 0x40000000
+#define XPAR_M_AXI_GP0_HIGHADDR 0x40001FFF
+
#include "xparameters_ps.h"
-#define STDIN_BASEADDRESS 0xE0001000
-#define STDOUT_BASEADDRESS 0xE0001000
+#define STDIN_BASEADDRESS 0xE0000000
+#define STDOUT_BASEADDRESS 0xE0000000
/******************************************************************/
@@ -120,7 +125,7 @@
#define XPAR_PS7_ETHERNET_0_DEVICE_ID 0
#define XPAR_PS7_ETHERNET_0_BASEADDR 0xE000B000
#define XPAR_PS7_ETHERNET_0_HIGHADDR 0xE000BFFF
-#define XPAR_PS7_ETHERNET_0_ENET_CLK_FREQ_HZ 25000000
+#define XPAR_PS7_ETHERNET_0_ENET_CLK_FREQ_HZ 125000000
#define XPAR_PS7_ETHERNET_0_ENET_SLCR_1000MBPS_DIV0 8
#define XPAR_PS7_ETHERNET_0_ENET_SLCR_1000MBPS_DIV1 1
#define XPAR_PS7_ETHERNET_0_ENET_SLCR_100MBPS_DIV0 8
@@ -138,7 +143,7 @@
#define XPAR_XEMACPS_0_DEVICE_ID XPAR_PS7_ETHERNET_0_DEVICE_ID
#define XPAR_XEMACPS_0_BASEADDR 0xE000B000
#define XPAR_XEMACPS_0_HIGHADDR 0xE000BFFF
-#define XPAR_XEMACPS_0_ENET_CLK_FREQ_HZ 25000000
+#define XPAR_XEMACPS_0_ENET_CLK_FREQ_HZ 125000000
#define XPAR_XEMACPS_0_ENET_SLCR_1000Mbps_DIV0 8
#define XPAR_XEMACPS_0_ENET_SLCR_1000Mbps_DIV1 1
#define XPAR_XEMACPS_0_ENET_SLCR_100Mbps_DIV0 8
@@ -265,13 +270,13 @@
/******************************************************************/
/* Definitions for driver IICPS */
-#define XPAR_XIICPS_NUM_INSTANCES 1
+#define XPAR_XIICPS_NUM_INSTANCES 2
/* Definitions for peripheral PS7_I2C_0 */
#define XPAR_PS7_I2C_0_DEVICE_ID 0
#define XPAR_PS7_I2C_0_BASEADDR 0xE0004000
#define XPAR_PS7_I2C_0_HIGHADDR 0xE0004FFF
-#define XPAR_PS7_I2C_0_I2C_CLK_FREQ_HZ 111111115
+#define XPAR_PS7_I2C_0_I2C_CLK_FREQ_HZ 83333336
/******************************************************************/
@@ -280,7 +285,7 @@
#define XPAR_XIICPS_0_DEVICE_ID XPAR_PS7_I2C_0_DEVICE_ID
#define XPAR_XIICPS_0_BASEADDR 0xE0004000
#define XPAR_XIICPS_0_HIGHADDR 0xE0004FFF
-#define XPAR_XIICPS_0_I2C_CLK_FREQ_HZ 111111115
+#define XPAR_XIICPS_0_I2C_CLK_FREQ_HZ 83333336
/******************************************************************/
@@ -376,9 +381,9 @@
#define XPAR_PS7_SD_0_DEVICE_ID 0
#define XPAR_PS7_SD_0_BASEADDR 0xE0100000
#define XPAR_PS7_SD_0_HIGHADDR 0xE0100FFF
-#define XPAR_PS7_SD_0_SDIO_CLK_FREQ_HZ 50000000
-#define XPAR_PS7_SD_0_HAS_CD 1
-#define XPAR_PS7_SD_0_HAS_WP 1
+#define XPAR_PS7_SD_0_SDIO_CLK_FREQ_HZ 100000000
+#define XPAR_PS7_SD_0_HAS_CD 0
+#define XPAR_PS7_SD_0_HAS_WP 0
#define XPAR_PS7_SD_0_BUS_WIDTH 0
#define XPAR_PS7_SD_0_MIO_BANK 0
#define XPAR_PS7_SD_0_HAS_EMIO 0
@@ -398,9 +403,9 @@
#define XPAR_XSDPS_0_DEVICE_ID XPAR_PS7_SD_0_DEVICE_ID
#define XPAR_XSDPS_0_BASEADDR 0xE0100000
#define XPAR_XSDPS_0_HIGHADDR 0xE0100FFF
-#define XPAR_XSDPS_0_SDIO_CLK_FREQ_HZ 50000000
-#define XPAR_XSDPS_0_HAS_CD 1
-#define XPAR_XSDPS_0_HAS_WP 1
+#define XPAR_XSDPS_0_SDIO_CLK_FREQ_HZ 100000000
+#define XPAR_XSDPS_0_HAS_CD 0
+#define XPAR_XSDPS_0_HAS_WP 0
#define XPAR_XSDPS_0_BUS_WIDTH 0
#define XPAR_XSDPS_0_MIO_BANK 0
#define XPAR_XSDPS_0_HAS_EMIO 0
@@ -422,15 +427,15 @@
/* Definitions for peripheral PS7_TTC_0 */
#define XPAR_PS7_TTC_0_DEVICE_ID 0U
#define XPAR_PS7_TTC_0_BASEADDR 0XF8001000U
-#define XPAR_PS7_TTC_0_TTC_CLK_FREQ_HZ 111111115U
+#define XPAR_PS7_TTC_0_TTC_CLK_FREQ_HZ 83333336U
#define XPAR_PS7_TTC_0_TTC_CLK_CLKSRC 0U
#define XPAR_PS7_TTC_1_DEVICE_ID 1U
#define XPAR_PS7_TTC_1_BASEADDR 0XF8001004U
-#define XPAR_PS7_TTC_1_TTC_CLK_FREQ_HZ 111111115U
+#define XPAR_PS7_TTC_1_TTC_CLK_FREQ_HZ 83333336U
#define XPAR_PS7_TTC_1_TTC_CLK_CLKSRC 0U
#define XPAR_PS7_TTC_2_DEVICE_ID 2U
#define XPAR_PS7_TTC_2_BASEADDR 0XF8001008U
-#define XPAR_PS7_TTC_2_TTC_CLK_FREQ_HZ 111111115U
+#define XPAR_PS7_TTC_2_TTC_CLK_FREQ_HZ 83333336U
#define XPAR_PS7_TTC_2_TTC_CLK_CLKSRC 0U
@@ -439,17 +444,17 @@
/* Canonical definitions for peripheral PS7_TTC_0 */
#define XPAR_XTTCPS_0_DEVICE_ID XPAR_PS7_TTC_0_DEVICE_ID
#define XPAR_XTTCPS_0_BASEADDR 0xF8001000U
-#define XPAR_XTTCPS_0_TTC_CLK_FREQ_HZ 111111115U
+#define XPAR_XTTCPS_0_TTC_CLK_FREQ_HZ 83333336U
#define XPAR_XTTCPS_0_TTC_CLK_CLKSRC 0U
#define XPAR_XTTCPS_1_DEVICE_ID XPAR_PS7_TTC_1_DEVICE_ID
#define XPAR_XTTCPS_1_BASEADDR 0xF8001004U
-#define XPAR_XTTCPS_1_TTC_CLK_FREQ_HZ 111111115U
+#define XPAR_XTTCPS_1_TTC_CLK_FREQ_HZ 83333336U
#define XPAR_XTTCPS_1_TTC_CLK_CLKSRC 0U
#define XPAR_XTTCPS_2_DEVICE_ID XPAR_PS7_TTC_2_DEVICE_ID
#define XPAR_XTTCPS_2_BASEADDR 0xF8001008U
-#define XPAR_XTTCPS_2_TTC_CLK_FREQ_HZ 111111115U
+#define XPAR_XTTCPS_2_TTC_CLK_FREQ_HZ 83333336U
#define XPAR_XTTCPS_2_TTC_CLK_CLKSRC 0U
@@ -458,21 +463,21 @@
/* Definitions for driver UARTPS */
#define XPAR_XUARTPS_NUM_INSTANCES 1
-/* Definitions for peripheral PS7_UART_1 */
-#define XPAR_PS7_UART_1_DEVICE_ID 0
-#define XPAR_PS7_UART_1_BASEADDR 0xE0001000
-#define XPAR_PS7_UART_1_HIGHADDR 0xE0001FFF
-#define XPAR_PS7_UART_1_UART_CLK_FREQ_HZ 50000000
-#define XPAR_PS7_UART_1_HAS_MODEM 0
+/* Definitions for peripheral PS7_UART_0 */
+#define XPAR_PS7_UART_0_DEVICE_ID 0
+#define XPAR_PS7_UART_0_BASEADDR 0xE0000000
+#define XPAR_PS7_UART_0_HIGHADDR 0xE0000FFF
+#define XPAR_PS7_UART_0_UART_CLK_FREQ_HZ 100000000
+#define XPAR_PS7_UART_0_HAS_MODEM 0
/******************************************************************/
-/* Canonical definitions for peripheral PS7_UART_1 */
-#define XPAR_XUARTPS_0_DEVICE_ID XPAR_PS7_UART_1_DEVICE_ID
-#define XPAR_XUARTPS_0_BASEADDR 0xE0001000
-#define XPAR_XUARTPS_0_HIGHADDR 0xE0001FFF
-#define XPAR_XUARTPS_0_UART_CLK_FREQ_HZ 50000000
+/* Canonical definitions for peripheral PS7_UART_0 */
+#define XPAR_XUARTPS_0_DEVICE_ID XPAR_PS7_UART_0_DEVICE_ID
+#define XPAR_XUARTPS_0_BASEADDR 0xE0000000
+#define XPAR_XUARTPS_0_HIGHADDR 0xE0000FFF
+#define XPAR_XUARTPS_0_UART_CLK_FREQ_HZ 100000000
#define XPAR_XUARTPS_0_HAS_MODEM 0

View File

@ -0,0 +1,38 @@
# diff from elhep/Fast-Servo-Firmmware commit ID 7fae40c:
# https://github.com/elhep/Fast-Servo-Firmware/commit/7fae40c0f872a91218be378f8289b98b1e366729
# Fix for migen add_source deprecation and removed xilinx bootgen command
# .bin file is being generated by bit2bin.py from Linien repository
# https://github.com/linien-org/linien/blob/master/gateware/bit2bin.py
diff --git a/fast_servo/gateware/fast_servo_platform.py b/fast_servo/gateware/fast_servo_platform.py
index 13b4aa3..89a8103 100644
--- a/fast_servo/gateware/fast_servo_platform.py
+++ b/fast_servo/gateware/fast_servo_platform.py
@@ -324,7 +324,12 @@ class Platform(XilinxPlatform):
self.ps7_config = ps7_config
verilog_sources = os.listdir(verilog_dir)
- self.add_sources(verilog_dir, *verilog_sources)
+ self.add_source_dir(verilog_dir)
+
+ def build(self, *args, **kwargs):
+ build_dir = kwargs.get('build_dir', 'build')
+ self.copy_sources(build_dir)
+ super().build(*args, **kwargs)
def do_finalize(self, fragment):
try:
diff --git a/fast_servo/gateware/fast_servo_soc.py b/fast_servo/gateware/fast_servo_soc.py
index 02128f5..abfc583 100644
--- a/fast_servo/gateware/fast_servo_soc.py
+++ b/fast_servo/gateware/fast_servo_soc.py
@@ -282,9 +282,3 @@ if __name__ == "__main__":
os.chdir(os.path.join(root_path, build_dir))
with open(f"{build_name}.bif", "w") as f:
f.write(f"all:\n{{\n\t{build_name}.bit\n}}")
-
- cmd = f"bootgen -image {build_name}.bif -arch zynq -process_bitstream bin -w on".split(" ")
- subprocess.run(cmd)
-
-
-

View File

@ -0,0 +1,603 @@
# diff between linen-org/linien commit ID 93f1f50:
# https://github.com/linien-org/linien/commit/93f1f50ebd86fe3314cab5a549462d0fcbf6a658
# and elhep/linien commit ID b73eea0:
# https://github.com/elhep/linien/commit/b73eea07889dda8b55f0cf4c2afde96cf4c3efd1
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index b3f3683..98c6e51 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -3,7 +3,7 @@ repos:
rev: 23.11.0
hooks:
- id: black
- exclude: ^(gateware/logic/|gateware/lowlevel/|gateware/linien_module.py|linien-server/linien_server/csrmap.py)
+ exclude: ^(gateware/logic/|gateware/lowlevel/|gateware/linien_module.py|linien-server/linien_server/csrmap.py|gateware/targets)
- repo: https://github.com/pycqa/isort
rev: 5.12.0
diff --git a/gateware/build_fpga_image.sh b/gateware/build_fpga_image.sh
index f822402..be7401c 100644
--- a/gateware/build_fpga_image.sh
+++ b/gateware/build_fpga_image.sh
@@ -16,4 +16,9 @@ export PATH=$VIVADOPATH:$PATH
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

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

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

View File

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

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

@ -0,0 +1,385 @@
# Copyright 2014-2015 Robert Jördens <jordens@gmail.com>
# Copyright 2018-2022 Benjamin Wiegand <benjamin.wiegand@physik.hu-berlin.de>
# Copyright 2021-2022 Bastian Leykauf <leykauf@physik.hu-berlin.de>
# Copyright 2023 Jakub Matyas
# Warsaw University of Technology <jakubk.m@gmail.com>
#
# This file is part of Fast Servo Software Package and is based on Linien.
#
# Linien is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Linien is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Linien. If not, see <http://www.gnu.org/licenses/>.
from functools import reduce
from operator import or_
from migen import (
DIR_M_TO_S,
DIR_S_TO_M,
Cat,
ClockSignal,
If,
Instance,
Module,
Record,
Replicate,
ResetSignal,
Signal,
)
from misoc.interconnect import csr_bus, wishbone
sys_layout = [
("rstn", 1, DIR_M_TO_S),
("clk", 1, DIR_M_TO_S),
("addr", 32, DIR_M_TO_S),
("wdata", 32, DIR_M_TO_S),
("sel", 4, DIR_M_TO_S),
("wen", 1, DIR_M_TO_S),
("ren", 1, DIR_M_TO_S),
("rdata", 32, DIR_S_TO_M),
("err", 1, DIR_S_TO_M),
("ack", 1, DIR_S_TO_M),
]
axi_layout = [
("arvalid", 1),
("awvalid", 1),
("bready", 1),
("rready", 1),
("wlast", 1),
("wvalid", 1),
("arid", 12),
("awid", 12),
("wid", 12),
("arburst", 2),
("arlock", 2),
("arsize", 3),
("awburst", 2),
("awlock", 2),
("awsize", 3),
("arprot", 3),
("awprot", 3),
("araddr", 32),
("awaddr", 32),
("wdata", 32),
("arcache", 4),
("arlen", 4),
("arqos", 4),
("awcache", 4),
("awlen", 4),
("awqos", 4),
("wstrb", 4),
("aclk", 1),
("arready", 1),
("awready", 1),
("bvalid", 1),
("rlast", 1),
("rvalid", 1),
("wready", 1),
("bid", 12),
("rid", 12),
("bresp", 2),
("rresp", 2),
("rdata", 32),
("arstn", 1),
]
class PitayaPS(Module):
def __init__(self, cpu):
self.fclk = Signal(4)
self.frstn = Signal(4)
###
self.submodules.axi = Axi2Sys()
axi = self.axi.axi
self.comb += [
axi.aclk.eq(self.fclk[0]),
axi.arstn.eq(self.frstn[0]),
]
self.specials += Instance(
"system_processing_system7_0_0",
io_MIO=cpu.mio,
io_PS_CLK=cpu.ps_clk,
io_PS_PORB=cpu.ps_porb,
io_PS_SRSTB=cpu.ps_srstb,
io_DDR_Addr=cpu.DDR_addr,
io_DDR_BankAddr=cpu.DDR_ba,
io_DDR_CAS_n=cpu.DDR_cas_n,
io_DDR_Clk_n=cpu.DDR_ck_n,
io_DDR_Clk=cpu.DDR_ck_p,
io_DDR_CKE=cpu.DDR_cke,
io_DDR_CS_n=cpu.DDR_cs_n,
io_DDR_DM=cpu.DDR_dm,
io_DDR_DQ=cpu.DDR_dq,
io_DDR_DQS_n=cpu.DDR_dqs_n,
io_DDR_DQS=cpu.DDR_dqs_p,
io_DDR_ODT=cpu.DDR_odt,
io_DDR_RAS_n=cpu.DDR_ras_n,
io_DDR_DRSTB=cpu.DDR_reset_n,
io_DDR_WEB=cpu.DDR_we_n,
io_DDR_VRN=cpu.ddr_vrn,
io_DDR_VRP=cpu.ddr_vrp,
o_FCLK_CLK0=self.fclk[0],
o_FCLK_CLK1=self.fclk[1],
o_FCLK_CLK2=self.fclk[2],
o_FCLK_CLK3=self.fclk[3],
o_FCLK_RESET0_N=self.frstn[0],
o_FCLK_RESET1_N=self.frstn[1],
o_FCLK_RESET2_N=self.frstn[2],
o_FCLK_RESET3_N=self.frstn[3],
i_M_AXI_GP0_ACLK=axi.aclk,
o_M_AXI_GP0_ARVALID=axi.arvalid,
o_M_AXI_GP0_AWVALID=axi.awvalid,
o_M_AXI_GP0_BREADY=axi.bready,
o_M_AXI_GP0_RREADY=axi.rready,
o_M_AXI_GP0_WLAST=axi.wlast,
o_M_AXI_GP0_WVALID=axi.wvalid,
o_M_AXI_GP0_ARID=axi.arid,
o_M_AXI_GP0_AWID=axi.awid,
o_M_AXI_GP0_WID=axi.wid,
o_M_AXI_GP0_ARBURST=axi.arburst,
o_M_AXI_GP0_ARLOCK=axi.arlock,
o_M_AXI_GP0_ARSIZE=axi.arsize,
o_M_AXI_GP0_AWBURST=axi.awburst,
o_M_AXI_GP0_AWLOCK=axi.awlock,
o_M_AXI_GP0_AWSIZE=axi.awsize,
o_M_AXI_GP0_ARPROT=axi.arprot,
o_M_AXI_GP0_AWPROT=axi.awprot,
o_M_AXI_GP0_ARADDR=axi.araddr,
o_M_AXI_GP0_AWADDR=axi.awaddr,
o_M_AXI_GP0_WDATA=axi.wdata,
o_M_AXI_GP0_ARCACHE=axi.arcache,
o_M_AXI_GP0_ARLEN=axi.arlen,
o_M_AXI_GP0_ARQOS=axi.arqos,
o_M_AXI_GP0_AWCACHE=axi.awcache,
o_M_AXI_GP0_AWLEN=axi.awlen,
o_M_AXI_GP0_AWQOS=axi.awqos,
o_M_AXI_GP0_WSTRB=axi.wstrb,
i_M_AXI_GP0_ARREADY=axi.arready,
i_M_AXI_GP0_AWREADY=axi.awready,
i_M_AXI_GP0_BVALID=axi.bvalid,
i_M_AXI_GP0_RLAST=axi.rlast,
i_M_AXI_GP0_RVALID=axi.rvalid,
i_M_AXI_GP0_WREADY=axi.wready,
i_M_AXI_GP0_BID=axi.bid,
i_M_AXI_GP0_RID=axi.rid,
i_M_AXI_GP0_BRESP=axi.bresp,
i_M_AXI_GP0_RRESP=axi.rresp,
i_M_AXI_GP0_RDATA=axi.rdata,
i_SPI0_SS_I=0,
# i_SPI0_SS_I=spi.ss_i,
# o_SPI0_SS_O=spi.ss_o,
# o_SPI0_SS_T=spi.ss_t,
# o_SPI0_SS1_O=spi.ss1_o,
# o_SPI0_SS2_O=spi.ss2_o,
i_SPI0_SCLK_I=0,
# i_SPI0_SCLK_I=spi.sclk_i,
# o_SPI0_SCLK_O=spi.sclk_o,
# o_SPI0_SCLK_T=spi.sclk_t,
i_SPI0_MOSI_I=0,
# i_SPI0_MOSI_I=spi.mosi_i,
# o_SPI0_MOSI_O=spi.mosi_o,
# o_SPI0_MOSI_T=spi.mosi_t,
i_SPI0_MISO_I=0,
# i_SPI0_MISO_I=spi.miso_i,
# o_SPI0_MISO_O=spi.miso_o,
# o_SPI0_MISO_T=spi.miso_t,
i_USB0_VBUS_PWRFAULT=0,
)
class Axi2Sys(Module):
def __init__(self):
self.sys = Record(sys_layout)
self.axi = Record(axi_layout)
###
self.comb += [self.sys.clk.eq(self.axi.aclk), self.sys.rstn.eq(self.axi.arstn)]
self.specials += Instance(
"axi_slave",
p_AXI_DW=32,
p_AXI_AW=32,
p_AXI_IW=12,
i_axi_clk_i=self.axi.aclk,
i_axi_rstn_i=self.axi.arstn,
i_axi_awid_i=self.axi.awid,
i_axi_awaddr_i=self.axi.awaddr,
i_axi_awlen_i=self.axi.awlen,
i_axi_awsize_i=self.axi.awsize,
i_axi_awburst_i=self.axi.awburst,
i_axi_awlock_i=self.axi.awlock,
i_axi_awcache_i=self.axi.awcache,
i_axi_awprot_i=self.axi.awprot,
i_axi_awvalid_i=self.axi.awvalid,
o_axi_awready_o=self.axi.awready,
i_axi_wid_i=self.axi.wid,
i_axi_wdata_i=self.axi.wdata,
i_axi_wstrb_i=self.axi.wstrb,
i_axi_wlast_i=self.axi.wlast,
i_axi_wvalid_i=self.axi.wvalid,
o_axi_wready_o=self.axi.wready,
o_axi_bid_o=self.axi.bid,
o_axi_bresp_o=self.axi.bresp,
o_axi_bvalid_o=self.axi.bvalid,
i_axi_bready_i=self.axi.bready,
i_axi_arid_i=self.axi.arid,
i_axi_araddr_i=self.axi.araddr,
i_axi_arlen_i=self.axi.arlen,
i_axi_arsize_i=self.axi.arsize,
i_axi_arburst_i=self.axi.arburst,
i_axi_arlock_i=self.axi.arlock,
i_axi_arcache_i=self.axi.arcache,
i_axi_arprot_i=self.axi.arprot,
i_axi_arvalid_i=self.axi.arvalid,
o_axi_arready_o=self.axi.arready,
o_axi_rid_o=self.axi.rid,
o_axi_rdata_o=self.axi.rdata,
o_axi_rresp_o=self.axi.rresp,
o_axi_rlast_o=self.axi.rlast,
o_axi_rvalid_o=self.axi.rvalid,
i_axi_rready_i=self.axi.rready,
o_sys_addr_o=self.sys.addr,
o_sys_wdata_o=self.sys.wdata,
o_sys_sel_o=self.sys.sel,
o_sys_wen_o=self.sys.wen,
o_sys_ren_o=self.sys.ren,
i_sys_rdata_i=self.sys.rdata,
i_sys_err_i=self.sys.err,
i_sys_ack_i=self.sys.ack,
)
class SysInterconnect(Module):
def __init__(self, master, *slaves):
cs = Signal(max=len(slaves)) if len(slaves) != 1 else Signal()
self.comb += cs.eq(master.addr[20:23])
rets = []
for i, s in enumerate(slaves):
sel = Signal()
self.comb += [
sel.eq(cs == i),
s.clk.eq(master.clk),
s.rstn.eq(master.rstn),
s.addr.eq(master.addr),
s.wdata.eq(master.wdata),
s.sel.eq(master.sel),
s.wen.eq(sel & master.wen),
s.ren.eq(sel & master.ren),
]
ret = Cat(s.err, s.ack, s.rdata)
rets.append(Replicate(sel, len(ret)) & ret)
self.comb += Cat(master.err, master.ack, master.rdata).eq(reduce(or_, rets))
class Sys2Wishbone(Module):
def __init__(self):
self.wishbone = wb = wishbone.Interface()
self.sys = sys = Record(sys_layout)
###
sys2 = Record(sys_layout)
self.specials += Instance(
"bus_clk_bridge",
i_sys_clk_i=sys.clk,
i_sys_rstn_i=sys.rstn,
i_sys_addr_i=sys.addr,
i_sys_wdata_i=sys.wdata,
i_sys_sel_i=sys.sel,
i_sys_wen_i=sys.wen,
i_sys_ren_i=sys.ren,
o_sys_rdata_o=sys.rdata,
o_sys_err_o=sys.err,
o_sys_ack_o=sys.ack,
i_clk_i=ClockSignal(),
i_rstn_i=~ResetSignal(),
o_addr_o=sys2.addr,
o_wen_o=sys2.wen,
o_ren_o=sys2.ren,
o_wdata_o=sys2.wdata,
i_rdata_i=sys2.rdata,
i_err_i=sys2.err,
i_ack_i=sys2.ack,
)
self.sync += [
If(
sys2.ren | sys2.wen,
wb.cyc.eq(1),
wb.adr.eq(sys2.addr[2:]),
wb.we.eq(sys2.wen),
wb.dat_w.eq(sys2.wdata),
).Elif(wb.ack, wb.cyc.eq(0))
]
self.comb += [
wb.stb.eq(wb.cyc),
sys2.rdata.eq(wb.dat_r),
sys2.ack.eq(wb.ack),
sys2.err.eq(wb.err),
]
class SysCDC(Module):
def __init__(self, cd_target="sys"):
self.source = Record(sys_layout)
self.target = Record(sys_layout)
self.specials += Instance(
"bus_clk_bridge",
i_sys_clk_i=self.source.clk,
i_sys_rstn_i=self.source.rstn,
i_sys_addr_i=self.source.addr,
i_sys_wdata_i=self.source.wdata,
i_sys_sel_i=self.source.sel,
i_sys_wen_i=self.source.wen,
i_sys_ren_i=self.source.ren,
o_sys_rdata_o=self.source.rdata,
o_sys_err_o=self.source.err,
o_sys_ack_o=self.source.ack,
i_clk_i=self.target.clk,
i_rstn_i=self.target.rstn,
o_addr_o=self.target.addr,
o_wdata_o=self.target.wdata,
o_wen_o=self.target.wen,
o_ren_o=self.target.ren,
i_rdata_i=self.target.rdata,
i_err_i=self.target.err,
i_ack_i=self.target.ack,
)
self.comb += [
self.target.clk.eq(ClockSignal(cd_target)),
self.target.rstn.eq(~ResetSignal(cd_target)),
]
class Sys2CSR(Module):
def __init__(self):
self.csr = csr_bus.Interface()
self.sys = Record(sys_layout)
###
stb = Signal()
self.sync += [
stb.eq(self.sys.wen | self.sys.ren),
self.csr.adr.eq(self.sys.addr[2:]),
self.csr.we.eq(self.sys.wen),
self.csr.dat_w.eq(self.sys.wdata),
self.sys.ack.eq(stb),
self.sys.rdata.eq(self.csr.dat_r),
]

View File

@ -0,0 +1,193 @@
# This file is part of Fast Servo Software Package.
#
# Copyright (C) 2023 Jakub Matyas
# Warsaw University of Technology <jakubk.m@gmail.com>
# SPDX-License-Identifier: GPL-3.0-or-later
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
from migen import *
class PS7(Module):
def __init__(self, platform, ps7_name=None):
self.frstn = Signal()
self.ps7_tcl = []
self.platform = platform
self.ps7_name = "Zynq" if ps7_name is None else ps7_name
ps7_clk = platform.request("ps7_clk")
ps7_porb = platform.request("ps7_porb")
ps7_srstb = platform.request("ps7_srstb")
ps7_mio = platform.request("ps7_mio")
ps7_ddram = platform.request("ps7_ddram")
self.cpu_params = dict(
# Clk / Rst.
io_PS_CLK = ps7_clk,
io_PS_PORB = ps7_porb,
io_PS_SRSTB = ps7_srstb,
# MIO.
io_MIO = ps7_mio,
# DDRAM.
io_DDR_Addr = ps7_ddram.addr,
io_DDR_BankAddr = ps7_ddram.ba,
io_DDR_CAS_n = ps7_ddram.cas_n,
io_DDR_Clk_n = ps7_ddram.ck_n,
io_DDR_Clk = ps7_ddram.ck_p,
io_DDR_CKE = ps7_ddram.cke,
io_DDR_CS_n = ps7_ddram.cs_n,
io_DDR_DM = ps7_ddram.dm,
io_DDR_DQ = ps7_ddram.dq,
io_DDR_DQS_n = ps7_ddram.dqs_n,
io_DDR_DQS = ps7_ddram.dqs_p,
io_DDR_ODT = ps7_ddram.odt,
io_DDR_RAS_n = ps7_ddram.ras_n,
io_DDR_DRSTB = ps7_ddram.reset_n,
io_DDR_WEB = ps7_ddram.we_n,
io_DDR_VRN = ps7_ddram.vrn,
io_DDR_VRP = ps7_ddram.vrp,
# USB0.
# i_USB0_VBUS_PWRFAULT = 0,
# Fabric Clk / Rst.
# o_FCLK_CLK0 = ClockSignal("ps7"),
o_FCLK_RESET0_N = self.frstn
)
self.set_ps7(name=self.ps7_name,
config={
**self.platform.ps7_config
})
def add_ps7_config(self, config):
# Config must be provided as a config, value dict.
assert isinstance(config, dict)
# Add configs to PS7.
self.ps7_tcl.append("set_property -dict [list \\")
for config, value in config.items():
self.ps7_tcl.append("CONFIG.{} {} \\".format(config, '{{' + str(value) + '}}'))
self.ps7_tcl.append(f"] [get_ips {self.ps7_name}]")
def set_ps7(self, name=None, config=None, preset=None):
self.ps7_name = name
self.ps7_tcl.append(f"set ps7 [create_ip -vendor xilinx.com -name processing_system7 -module_name {self.ps7_name}]")
self.add_ps7_config(config)
def add_axi_gp_master(self, interface):
# assert type(interface) is Axi2Sys
axi_interface = interface
self.cpu_params.update({
# AXI GP clk.
f"i_M_AXI_GP0_ACLK" : axi_interface.aclk,
# AXI GP aw.
f"o_M_AXI_GP0_AWVALID" : axi_interface.awvalid,
f"i_M_AXI_GP0_AWREADY" : axi_interface.awready,
f"o_M_AXI_GP0_AWADDR" : axi_interface.awaddr,
f"o_M_AXI_GP0_AWBURST" : axi_interface.awburst,
f"o_M_AXI_GP0_AWLEN" : axi_interface.awlen,
f"o_M_AXI_GP0_AWSIZE" : axi_interface.awsize,
f"o_M_AXI_GP0_AWID" : axi_interface.awid,
f"o_M_AXI_GP0_AWLOCK" : axi_interface.awlock,
f"o_M_AXI_GP0_AWPROT" : axi_interface.awprot,
f"o_M_AXI_GP0_AWCACHE" : axi_interface.awcache,
f"o_M_AXI_GP0_AWQOS" : axi_interface.awqos,
# AXI GP w.
f"o_M_AXI_GP0_WVALID" : axi_interface.wvalid,
f"o_M_AXI_GP0_WLAST" : axi_interface.wlast,
f"i_M_AXI_GP0_WREADY" : axi_interface.wready,
f"o_M_AXI_GP0_WID" : axi_interface.wid,
f"o_M_AXI_GP0_WDATA" : axi_interface.wdata,
f"o_M_AXI_GP0_WSTRB" : axi_interface.wstrb,
# AXI GP b.
f"i_M_AXI_GP0_BVALID" : axi_interface.bvalid,
f"o_M_AXI_GP0_BREADY" : axi_interface.bready,
f"i_M_AXI_GP0_BID" : axi_interface.bid,
f"i_M_AXI_GP0_BRESP" : axi_interface.bresp,
# AXI GP ar.
f"o_M_AXI_GP0_ARVALID" : axi_interface.arvalid,
f"i_M_AXI_GP0_ARREADY" : axi_interface.arready,
f"o_M_AXI_GP0_ARADDR" : axi_interface.araddr,
f"o_M_AXI_GP0_ARBURST" : axi_interface.arburst,
f"o_M_AXI_GP0_ARLEN" : axi_interface.arlen,
f"o_M_AXI_GP0_ARID" : axi_interface.arid,
f"o_M_AXI_GP0_ARLOCK" : axi_interface.arlock,
f"o_M_AXI_GP0_ARSIZE" : axi_interface.arsize,
f"o_M_AXI_GP0_ARPROT" : axi_interface.arprot,
f"o_M_AXI_GP0_ARCACHE" : axi_interface.arcache,
f"o_M_AXI_GP0_ARQOS" : axi_interface.arqos,
# AXI GP r.
f"i_M_AXI_GP0_RVALID" : axi_interface.rvalid,
f"o_M_AXI_GP0_RREADY" : axi_interface.rready,
f"i_M_AXI_GP0_RLAST" : axi_interface.rlast,
f"i_M_AXI_GP0_RID" : axi_interface.rid,
f"i_M_AXI_GP0_RRESP" : axi_interface.rresp,
f"i_M_AXI_GP0_RDATA" : axi_interface.rdata,
})
def add_i2c_emio(self, platform, i2c_name, i2c_number):
ps7_i2c_pads = platform.request(i2c_name, i2c_number) #, loose=True)
if ps7_i2c_pads is not None:
o_i2c_scl = Signal()
i_i2c_scl = Signal()
t_i2c_scl = Signal()
o_i2c_sda = Signal()
i_i2c_sda = Signal()
t_i2c_sda = Signal()
self.specials += Instance("IOBUF",
i_T = t_i2c_sda,
i_I = o_i2c_sda,
io_IO = ps7_i2c_pads.sda,
o_O = i_i2c_sda,
)
self.specials += Instance("IOBUF",
i_T = t_i2c_scl,
i_I = o_i2c_scl,
io_IO = ps7_i2c_pads.scl,
o_O = i_i2c_scl,
)
self.cpu_params.update({
f"i_I2C{i2c_number}_SCL_I" : i_i2c_scl,
f"o_I2C{i2c_number}_SCL_T" : t_i2c_scl,
f"o_I2C{i2c_number}_SCL_O" : o_i2c_scl,
f"i_I2C{i2c_number}_SDA_I" : i_i2c_sda,
f"o_I2C{i2c_number}_SDA_T" : t_i2c_sda,
f"o_I2C{i2c_number}_SDA_O" : o_i2c_sda,
})
def do_finalize(self):
if len(self.ps7_tcl):
self.ps7_tcl += [
f"upgrade_ip [get_ips {self.ps7_name}]",
f"generate_target all [get_ips {self.ps7_name}]",
f"synth_ip [get_ips {self.ps7_name}]"
]
self.platform.toolchain.pre_synthesis_commands += self.ps7_tcl
self.specials += Instance(self.ps7_name, **self.cpu_params)

View File

@ -0,0 +1,141 @@
# This file is part of Fast Servo Software Package.
#
# Copyright (C) 2023 Jakub Matyas
# Warsaw University of Technology <jakubk.m@gmail.com>
# SPDX-License-Identifier: GPL-3.0-or-later
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
from enum import Enum
from migen import *
class SpiInterface(Enum):
ADC = 0
DAC = 1
class SpiPhy(Module):
def __init__(self, spi_type, ps7_spi_pads):
assert isinstance(spi_type, SpiInterface)
self.ps_ss = Signal(3, reset_less=True)
self.ps_miso_o = Signal()
self.ps_miso_t = Signal()
self.ps_mosi_o = Signal()
self.ps_mosi_t = Signal()
self.ps_sclk_o = Signal()
self.ps_sclk_t = Signal()
self.ps_sclk_i = Signal()
self.ps_mosi_i = Signal()
self.ps_miso_i = Signal()
self.ps_ss_i = Signal()
self.ps_ss_t = Signal()
if spi_type.name == "ADC":
cs_translated = Signal(4, reset_less=True)
main_adc_miso = Signal(reset_less=True)
aux_adc_miso_a = Signal(reset_less=True)
aux_adc_miso_b = Signal(reset_less=True)
aux_dac_miso = Signal(reset_less=True)
miso_signals = [main_adc_miso, aux_adc_miso_a, aux_adc_miso_b, aux_dac_miso]
# MAIN ADC
self.specials += Instance("OBUFT", i_I=self.ps_sclk_o, i_T=self.ps_sclk_t, o_O=ps7_spi_pads.sclk)
self.specials += Instance("OBUFT", i_I=self.ps_mosi_o, i_T=self.ps_mosi_t, o_O=ps7_spi_pads.mosi)
self.specials += Instance("IBUF", i_I=ps7_spi_pads.miso, o_O=main_adc_miso)
# AUX ADC
self.specials += Instance("OBUFT", i_I=self.ps_sclk_o, i_T=self.ps_sclk_t, o_O=ps7_spi_pads.aux_adc_sclk)
self.specials += Instance("IBUF", i_I=ps7_spi_pads.aux_adc_miso_a, o_O=aux_adc_miso_a)
self.specials += Instance("IBUF", i_I=ps7_spi_pads.aux_adc_miso_b, o_O=aux_adc_miso_b)
# AUX DAC
self.specials += Instance("OBUFT", i_I=self.ps_sclk_o, i_T=self.ps_sclk_t, o_O=ps7_spi_pads.aux_dac_sclk)
self.specials += Instance("OBUFT", i_I=self.ps_mosi_o, i_T=self.ps_mosi_t, o_O=ps7_spi_pads.aux_dac_mosi)
self.specials += Instance("IBUF", i_I=ps7_spi_pads.aux_dac_miso, o_O=aux_dac_miso)
cases = {}
# for i in range(4):
# case_mask = ~(1 << i) & 0xF
# print(f"Case mask: 0b{case_mask:04b}")
# cases[i + 1] = [
# cs_translated.eq(case_mask),
# self.ps_miso_i.eq(miso_signals[i])
# ]
cases[0b001] = [
cs_translated.eq(0b1110),
self.ps_miso_i.eq(main_adc_miso),
]
cases[0b010] = [
cs_translated.eq(0b1101),
self.ps_miso_i.eq(aux_adc_miso_a),
]
cases[0b011] = [
cs_translated.eq(0b1011),
self.ps_miso_i.eq(aux_adc_miso_b),
]
cases[0b100] = [
cs_translated.eq(0b0111),
self.ps_miso_i.eq(aux_dac_miso),
]
cases["default"] = [
cs_translated.eq(0b1111),
self.ps_miso_i.eq(0b1),
]
self.comb += [
self.ps_ss_i.eq(1),
Case(self.ps_ss, cases),
ps7_spi_pads.cs.eq(cs_translated[0]),
# only one CS line physically available to AUX ADC
ps7_spi_pads.aux_adc_cs.eq(cs_translated[1] & cs_translated[2]),
ps7_spi_pads.aux_dac_miso.eq(cs_translated[3]),
]
else:
self.specials += Instance(
"spi2threewire",
o_ps_sclk_i = self.ps_sclk_i,
i_ps_sclk_o = self.ps_sclk_o,
i_ps_sclk_t = self.ps_sclk_t,
o_ps_mosi_i = self.ps_mosi_i,
i_ps_mosi_o = self.ps_mosi_o,
i_ps_mosi_t = self.ps_mosi_t,
o_ps_miso_i = self.ps_miso_i,
i_ps_miso_o = self.ps_miso_o,
i_ps_miso_t = self.ps_miso_t,
o_ps_ss_i = self.ps_ss_i,
i_ps_ss = self.ps_ss,
i_ps_ss_t = self.ps_ss_t,
o_o_ss = ps7_spi_pads.cs,
o_o_sclk = ps7_spi_pads.sclk,
io_sdio = ps7_spi_pads.sdio,
)

View File

@ -0,0 +1,336 @@
# This file is part of Fast Servo Software Package.
#
# Copyright (C) 2022-2023 Jakub Matyas
# Warsaw University of Technology <jakubk.m@gmail.com>
# SPDX-License-Identifier: GPL-3.0-or-later
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
from migen.build.generic_platform import *
from migen.build.xilinx import XilinxPlatform
import os
from fast_servo.gateware import verilog_dir
# IOs ----------------------------------------------------------------------------------------------
_io = [
# Front panel LEDs
("fp_led", 0, Pins("G7"), IOStandard("LVCMOS25")),
("fp_led", 1, Pins("G8"), IOStandard("LVCMOS25")),
("fp_led", 2, Pins("G2"), IOStandard("LVCMOS25")),
("fp_led", 3, Pins("G3"), IOStandard("LVCMOS25")),
# LEDs
("user_led", 0, Pins("AB16"), IOStandard("LVCMOS33")),
("user_led", 1, Pins("AA14"), IOStandard("LVCMOS33")),
("user_led", 2, Pins("AA15"), IOStandard("LVCMOS33")),
# ETH LEDs
("eth_led", 0, Pins("V11"), IOStandard("LVCMOS33")),
("eth_led", 1, Pins("U13"), IOStandard("LVCMOS33")),
("from_eth_phy", 0, Pins("J3"), IOStandard("LVCMOS18")),
("from_eth_phy", 1, Pins("K8"), IOStandard("LVCMOS18")),
# CLK 100 MHz from oscillator
("clk100", 0, Pins("Y14"), IOStandard("LVCMOS33")),
# MGT clk from on-board Si5338A
("mgt_clk1", 0,
Subsignal("p", Pins("U5")),
Subsignal("n", Pins("V5")),
IOStandard("LVDS_25"),
),
# FCLK125 from on-board Si5338A
("fclk125", 0, Pins("K2"), IOStandard("LVCMOS18")),
# # ADC CLK
# ("fpga_clk", 0,
# Subsignal("p", Pins("C6")),
# Subsignal("n", Pins("C5")),
# IOStandard("LVDS_25"),
# ),
# DAC CLK
("fpga_clk", 1,
Subsignal("p", Pins("J7")),
Subsignal("n", Pins("J6")),
IOStandard("LVDS_25"),
),
# MAIN ADC LT2195
("adc", 0,
Subsignal("data0_p", Pins("F7 B7 E4 D1"), IOStandard("LVDS_25")),
Subsignal("data0_n", Pins("E7 B6 E3 C1"), IOStandard("LVDS_25")),
Subsignal("data1_p", Pins("A2 D5 F2 D7"), IOStandard("LVDS_25")),
Subsignal("data1_n", Pins("A1 C4 F1 D6"), IOStandard("LVDS_25")),
Subsignal("dco_p", Pins("B4"), IOStandard("LVDS_25")),
Subsignal("dco_n", Pins("B3"), IOStandard("LVDS_25")),
Subsignal("frame_p", Pins("B2"), IOStandard("LVDS_25")),
Subsignal("frame_n", Pins("B1"), IOStandard("LVDS_25"))
),
# ADC AFE
("adc_afe", 0,
Subsignal("ch1_gain", Pins("AA12"), IOStandard("LVCMOS33")),
Subsignal("ch2_gain", Pins("AB11"), IOStandard("LVCMOS33")),
Subsignal("nshdn_ch1", Pins("G4"), IOStandard("LVCMOS25")),
Subsignal("nshdn_ch2", Pins("F4"), IOStandard("LVCMOS25")),
),
# P5 R5 N1 N4 L2 P6 N3 R4 P1 L1 M3 M4 U2 T2
# MAIN DAC AD9117
("dac", 0,
Subsignal("data",
Pins("T2 U2 M4 M3 L1 P1 R4 N3 P6 L2 N4 N1 R5 P5"),
IOStandard("LVCMOS18")),
Subsignal("dclkio", Pins("U1"), IOStandard("LVCMOS18")),
Subsignal("rst", Pins("T1"), IOStandard("LVCMOS18")),
),
# DAC AFE
("dac_afe", 0,
Subsignal("ch1_pd_n", Pins("L5")),
Subsignal("ch2_pd_n", Pins("L4")),
IOStandard("LVCMOS18"),
),
# AUXILIARY ADC
("aux_adc", 0,
Subsignal("diff_n", Pins("W18")),
Subsignal("a", Pins("AB18 AB19 W17")),
Subsignal("range", Pins("U19")),
IOStandard("LVCMOS33")
),
# AUXILIARY DAC
("aux_dac", 0,
Subsignal("nclr", Pins("V19")),
Subsignal("bin", Pins("AA19")),
Subsignal("nldac", Pins("AB21")),
IOStandard("LVCMOS33")
),
# ADC SPI
("spi", 0,
Subsignal("sclk", Pins("J1"), IOStandard("LVCMOS18")),
Subsignal("mosi", Pins("J5"), IOStandard("LVCMOS18")),
Subsignal("miso", Pins("K5"), IOStandard("LVCMOS18")),
Subsignal("cs", Pins("J2"), IOStandard("LVCMOS18")),
Subsignal("aux_adc_sclk", Pins("AB22"), IOStandard("LVCMOS33")),
Subsignal("aux_adc_miso_a", Pins("Y18"), IOStandard("LVCMOS33")),
Subsignal("aux_adc_miso_b", Pins("AA16"), IOStandard("LVCMOS33")),
Subsignal("aux_adc_cs", Pins("Y19"), IOStandard("LVCMOS33")),
Subsignal("aux_dac_sclk", Pins("V18"), IOStandard("LVCMOS33")),
Subsignal("aux_dac_mosi", Pins("U17"), IOStandard("LVCMOS33")),
Subsignal("aux_dac_miso", Pins("U18"), IOStandard("LVCMOS33")),
Subsignal("aux_dac_cs", Pins("AA20"), IOStandard("LVCMOS33")),
),
# DAC SPI
("spi", 1,
Subsignal("sclk", Pins("K3"), IOStandard("LVCMOS18")),
Subsignal("sdio", Pins("R2"), IOStandard("LVCMOS18")),
Subsignal("cs", Pins("R3"), IOStandard("LVCMOS18")),
# Subsignal("sclk_aux", Pins("V18"), IOStandard("LVCMOS33")),
# Subsignal("mosi_aux", Pins("U17"), IOStandard("LVCMOS33")),
# Subsignal("miso_aux", Pins("U18"), IOStandard("LVCMOS33")),
# Subsignal("cs_aux", Pins("AA20"), IOStandard("LVCMOS33")),
),
#Pins("Y15 AB14 AB13 V13 V14 V15 U12 W13 W12 R17 W15 AB17 Y12 Y13 V16 W16 AA17 Y17"),
("gpio", 0,
Subsignal("n", Pins("Y15 AB14 AB13 V13 V14 V15 U12 W13"), IOStandard("LVCMOS33")),
Subsignal("p", Pins("W12 R17 W15 AB17 Y12 Y13 V16 W16"), IOStandard("LVCMOS33")),
),
# PS7
("ps7_clk", 0, Pins("_" * 1)),
("ps7_porb", 0, Pins("_" * 1)),
("ps7_srstb", 0, Pins("_" * 1)),
("ps7_mio", 0, Pins("_" * 54)),
("ps7_ddram", 0,
Subsignal("addr", Pins("_" * 15)),
Subsignal("ba", Pins("_" * 3)),
Subsignal("cas_n", Pins("_" * 1)),
Subsignal("ck_n", Pins("_" * 1)),
Subsignal("ck_p", Pins("_" * 1)),
Subsignal("cke", Pins("_" * 1)),
Subsignal("cs_n", Pins("_" * 1)),
Subsignal("dm", Pins("_" * 4)),
Subsignal("dq", Pins("_" * 32)),
Subsignal("dqs_n", Pins("_" * 4)),
Subsignal("dqs_p", Pins("_" * 4)),
Subsignal("odt", Pins("_" * 1)),
Subsignal("ras_n", Pins("_" * 1)),
Subsignal("reset_n", Pins("_" * 1)),
Subsignal("we_n", Pins("_" * 1)),
Subsignal("vrn", Pins("_" * 1)),
Subsignal("vrp", Pins("_" * 1)),
),
# I2C0 to Si5340 on Fast Servo
("ps7_i2c", 0,
Subsignal("sda", Pins("M2")),
Subsignal("scl", Pins("M1")),
IOStandard("LVCMOS18")
),
# Si540 nRST
("nrst", 0, Pins("M7"), IOStandard("LVCMOS18")),
]
_connector_eem = [
("eem", {
"d0_cc_n": "C3",
"d0_cc_p": "D3",
"d1_n": "A4",
"d1_p": "A5",
"d2_n": "F6",
"d2_p": "G6",
"d3_n": "A6",
"d3_p": "A7",
"d4_n": "E5",
"d4_p": "F5",
"d5_n": "H3",
"d5_p": "H4",
"d6_n": "B8",
"d6_p": "C8",
"d7_n": "D8",
"d7_p": "E8",
}),
]
_connector_gpio = [
("gpio", {
"qspi_io3": "Y15",
"qspi_io2": "AB14",
"qspi_io1": "AB13",
"qspi_io0": "V13",
"qspi_clk": "V14",
"qspi_ncs": "V15",
"hrtim_che1": "U12",
"hrtim_che2": "W13",
"hrtim_cha1": "W12",
"hrtim_cha2": "R17",
"lptim2_out": "W15",
"uart4_tx": "AB17",
"spi1_mosi": "Y12",
"spi1_miso": "Y13",
"spi1_nss": "V16",
"spi1_sck": "W16",
"i2c1_sda": "AA17",
"i2c1_scl": "Y17",
})
]
# PS7 config ---------------------------------------------------------------------------------------
ps7_config_board_preset = {
"PCW_PRESET_BANK0_VOLTAGE" : "LVCMOS 3.3V",
"PCW_PRESET_BANK1_VOLTAGE" : "LVCMOS 1.8V",
"PCW_CRYSTAL_PERIPHERAL_FREQMHZ" : "33.333333",
"PCW_QSPI_PERIPHERAL_ENABLE" : "1",
"PCW_QSPI_GRP_SINGLE_SS_ENABLE" : "1",
"PCW_SINGLE_QSPI_DATA_MODE" : "x4",
"PCW_QSPI_QSPI_IO" : "MIO 1 .. 6",
"PCW_QSPI_GRP_FBCLK_ENABLE" : "1",
# SD Card
"PCW_SD0_PERIPHERAL_ENABLE" : "1",
"PCW_SD0_SD0_IO" : "MIO 40 .. 45",
"PCW_MIO_40_PULLUP" : "disabled",
"PCW_MIO_41_PULLUP" : "disabled",
"PCW_MIO_42_PULLUP" : "disabled",
"PCW_MIO_43_PULLUP" : "disabled",
"PCW_MIO_44_PULLUP" : "disabled",
"PCW_MIO_45_PULLUP" : "disabled",
# UART
"PCW_UART0_PERIPHERAL_ENABLE" : "1",
"PCW_UART0_UART0_IO" : "MIO 10 .. 11",
# ETHERNET
"PCW_ACT_ENET0_PERIPHERAL_FREQMHZ" : "125",
"PCW_ENET0_PERIPHERAL_CLKSRC" : "ARM PLL",
"PCW_ENET0_PERIPHERAL_ENABLE" : "1",
"PCW_ENET0_ENET0_IO" : "MIO 16 .. 27",
"PCW_ENET0_GRP_MDIO_ENABLE" : "1",
"PCW_ENET0_GRP_MDIO_IO" : "MIO 52 .. 53",
"PCW_ENET_RESET_ENABLE" : "1",
"PCW_ENET0_RESET_ENABLE" : "1",
"PCW_ENET0_RESET_IO" : "MIO 50",
# USB
"PCW_USB0_PERIPHERAL_ENABLE" : "1",
"PCW_USB0_USB0_IO" : "MIO 28 .. 39",
"PCW_USB_RESET_ENABLE" : "1",
"PCW_USB0_RESET_ENABLE" : "1",
"PCW_USB0_RESET_IO" : "MIO 51",
"PCW_WDT_PERIPHERAL_ENABLE" : "1",
"PCW_TTC0_PERIPHERAL_ENABLE" : "1", # TTC0 required for Linux
# I2C
"PCW_I2C_RESET_ENABLE" : "0",
"PCW_I2C_RESET_POLARITY" : "Active Low",
# I2C0
"PCW_I2C0_I2C0_IO" : "EMIO",
"PCW_I2C0_PERIPHERAL_ENABLE" : "1",
"PCW_I2C0_GRP_INT_ENABLE" : "1",
"PCW_I2C0_GRP_INT_IO" : "EMIO",
# I2C1
"PCW_I2C1_PERIPHERAL_ENABLE" : "1",
"PCW_I2C1_I2C1_IO" : "MIO 48 .. 49",
"PCW_I2C1_I2C1_IO" : "MIO 12 .. 13",
"PCW_I2C1_PERIPHERAL_ENABLE" : "1",
"PCW_UIPARAM_DDR_MEMORY_TYPE" : "DDR 3 (Low Voltage)",
"PCW_UIPARAM_DDR_PARTNO" : "MT41J256M16 RE-125",
"PCW_GPIO_MIO_GPIO_ENABLE" : "1",
"PCW_FPGA0_PERIPHERAL_FREQMHZ" : "100",
"PCW_EN_CLK0_PORT" : "0", # dont use FCLK0
}
class Platform(XilinxPlatform):
default_clk_name = "clk100"
default_clk_period = 10.0
def __init__(self):
XilinxPlatform.__init__(self, "xc7z015-clg485-1", _io, _connector_gpio + _connector_eem, toolchain="vivado")
ps7_config = ps7_config_board_preset
self.ps7_config = ps7_config
verilog_sources = os.listdir(verilog_dir)
self.add_sources(verilog_dir, *verilog_sources)
def do_finalize(self, fragment):
try:
XilinxPlatform.do_finalize(self, fragment)
self.add_period_constraint(self.lookup_request(self.default_clk_name, loose=True), self.default_clk_period)
except ValueError:
pass
except ConstraintError:
pass

View File

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

@ -0,0 +1,162 @@
///////////////////////////////////////////////////////////////////////////////
// LTC2195.v
//
// 8/03/21
// Jakub Matyas
//
// LTC2195 controller.
//
//
///////////////////////////////////////////////////////////////////////////////
// `include "timescale.v"
`timescale 1ns/1ps // this was in the SelectIO design
module LTC2195(
input rst_in,
input clk200,
input DCO,
input DCO_2D,
input FR_in_p,
input FR_in_n,
input [3:0] D0_in_p,
input [3:0] D0_in_n,
input [3:0] D1_in_p,
input [3:0] D1_in_n,
input bitslip,
input [4:0] delay_val,
output reg [15:0] ADC0_out,
output reg [15:0] ADC1_out,
output reg [3:0] FR_out,
output wire [8:0] o_data_from_pins,
output idelay_rdy
);
// ///////////////////////////////////////////////////////////////////////////////
// // LVDS inputs
localparam N_BITS = 4;
localparam N_LANES = 9; // for each channel 4 lanes + 1 lane for FRAME
wire [N_LANES-1:0] data_in_p, data_in_n, data_in_from_pins, data_in_from_pins_delay;
assign data_in_p = {FR_in_p, D1_in_p, D0_in_p};
assign data_in_n = {FR_in_n, D1_in_n, D0_in_n};
assign o_data_from_pins = data_in_from_pins_delay;
wire [N_LANES*4 -1:0] data_out;
wire [35:0 ]data_out_mod;
assign data_out_mod = {~data_out[35:24], data_out[23:20], ~data_out[19:16], data_out[15:0]};
always @(posedge DCO_2D) begin
ADC0_out <= {
data_out_mod[0], data_out_mod[4], data_out_mod[1], data_out_mod[5],
data_out_mod[2], data_out_mod[6], data_out_mod[3], data_out_mod[7],
data_out_mod[8], data_out_mod[12], data_out_mod[9], data_out_mod[13],
data_out_mod[10], data_out_mod[14], data_out_mod[11], data_out_mod[15]
};
ADC1_out <= {
data_out_mod[16 + 0], data_out_mod[16 + 4], data_out_mod[16 + 1], data_out_mod[16 + 5],
data_out_mod[16 + 2], data_out_mod[16 + 6], data_out_mod[16 + 3], data_out_mod[16 + 7],
data_out_mod[16 + 8], data_out_mod[16 + 12], data_out_mod[16 + 9], data_out_mod[16 + 13],
data_out_mod[16 + 10], data_out_mod[16 + 14], data_out_mod[16 + 11], data_out_mod[16 + 15]
};
FR_out <= {data_out_mod[32], data_out_mod[33], data_out_mod[34], data_out_mod[35]}; // value that arrived first is LSB, therefore reversing order
end
wire s_idelay_rdy;
IDELAYCTRL IDELAYCTRL_inst (
.RDY(s_idelay_rdy), // 1-bit output: Ready output
.REFCLK(clk200), // 1-bit input: Reference clock input
.RST(s_rst) // 1-bit input: Active high reset input
);
assign idelay_rdy = s_idelay_rdy;
reg s_rst;
reg [5:0] rst_cnt;
wire serdes_o;
always @(posedge DCO_2D) begin
if (rst_in) begin
s_rst <= 1'b1;
rst_cnt <= 'b0;
end else begin
if (rst_cnt == 22)
s_rst <= 'b0;
else
rst_cnt <= rst_cnt + 1;
end
end
genvar lane;
generate for (lane=0; lane<N_LANES; lane=lane+1) begin
IBUFDS #(
.DIFF_TERM("TRUE")
)
ibufds_inst (
.I(data_in_p[lane]),
.IB(data_in_n[lane]),
.O(data_in_from_pins[lane])
);
IDELAYE2 #(
.CINVCTRL_SEL("FALSE"), // Enable dynamic clock inversion (FALSE, TRUE)
.DELAY_SRC("IDATAIN"), // Delay input (IDATAIN, DATAIN)
.HIGH_PERFORMANCE_MODE("TRUE"), // Reduced jitter ("TRUE"), Reduced power ("FALSE")
.IDELAY_TYPE("VAR_LOAD"), // FIXED, VARIABLE, VAR_LOAD, VAR_LOAD_PIPE
.IDELAY_VALUE(0), // Input delay tap setting (0-31)
.PIPE_SEL("FALSE"), // Select pipelined mode, FALSE, TRUE
.REFCLK_FREQUENCY(200.0), // IDELAYCTRL clock input frequency in MHz (190.0-210.0, 290.0-310.0).
.SIGNAL_PATTERN("DATA") // DATA, CLOCK input signal
)
IDELAYE2_inst (
.C(clk200),
.CE('b0),
.CNTVALUEIN(delay_val),
.LD(1'b1),
.DATAOUT(data_in_from_pins_delay[lane]), // 1-bit output: Delayed data output
.IDATAIN(data_in_from_pins[lane]), // 1-bit input: Data input from the I/O
.LDPIPEEN (1'b0),
.REGRST (1'b0),
.CINVCTRL (1'b0)
);
ISERDESE2 #(
.DATA_RATE("DDR"),
.DATA_WIDTH(3'd4),
.INTERFACE_TYPE("NETWORKING"),
.IOBDELAY("BOTH"),
.SERDES_MODE("MASTER"),
.NUM_CE(2'd2)
)
iserdes_inst (
.CE1(1'd1),
.CE2(1'd1),
.DYNCLKDIVSEL('b0),
.DYNCLKSEL('b0),
.CLK(DCO),
.CLKB(!DCO),
.CLKDIV(DCO_2D),
// .D(data_in_from_pins[lane]),
.DDLY(data_in_from_pins_delay[lane]),
.RST(s_rst),
.BITSLIP(bitslip),
// DATA is MSB first and OUTA is LANE0, so in case of OUTA:
// Q1 = D9
// Q2 = D11
// Q3 = D13
// Q4 = D15
.Q1(data_out[lane*N_BITS + 3]),
.Q2(data_out[lane*N_BITS + 2]),
.Q3(data_out[lane*N_BITS + 1]),
.Q4(data_out[lane*N_BITS + 0])
);
end
endgenerate
endmodule

View File

@ -0,0 +1,265 @@
/**
* $Id: axi_slave.v 961 2014-01-21 11:40:39Z matej.oblak $
*
* @brief Red Pitaya symplified AXI slave.
*
* @Author Matej Oblak
*
* (c) Red Pitaya http://www.redpitaya.com
*
* This part of code is written in Verilog hardware description language (HDL).
* Please visit http://en.wikipedia.org/wiki/Verilog
* for more details on the language used herein.
*/
/**
* GENERAL DESCRIPTION:
*
* AXI slave used also for simple bus master.
*
*
* /------\
* WR ADDRESS ----> | WR |
* WR DATA ----> | | -----------
* WR RESPONSE <---- | CH | |
* \------/ /--------\
* | SIMPLE | ---> WR/RD ADDRRESS
* AXI | | ---> WR DATA
* | RP | <--- RD DATA
* | BUS | <--- ACKNOWLEDGE
* /------\ \--------/
* RD ADDRESS ----> | RD | |
* RD DATA <---- | CH | -----------
* \------/
*
*
* Because AXI bus is quite complex simplier bus was created.
*
* It combines write and read channel, where write has bigger priority. Command
* is then send forward to red pitaya bus. When wite or read acknowledge is
* received AXI response is created and new AXI is accepted.
*
* To prevent AXI lockups because no response is received, this slave creates its
* own after 32 cycles (ack_cnt).
*
*/
module axi_slave
#(
parameter AXI_DW = 64 , // data width (8,16,...,1024)
parameter AXI_AW = 32 , // address width
parameter AXI_IW = 8 , // ID width
parameter AXI_SW = AXI_DW >> 3 // strobe width - 1 bit for every data byte
)
(
// global signals
input axi_clk_i , //!< AXI global clock
input axi_rstn_i , //!< AXI global reset
// axi write address channel
input [ AXI_IW-1: 0] axi_awid_i , //!< AXI write address ID
input [ AXI_AW-1: 0] axi_awaddr_i , //!< AXI write address
input [ 4-1: 0] axi_awlen_i , //!< AXI write burst length
input [ 3-1: 0] axi_awsize_i , //!< AXI write burst size
input [ 2-1: 0] axi_awburst_i , //!< AXI write burst type
input [ 2-1: 0] axi_awlock_i , //!< AXI write lock type
input [ 4-1: 0] axi_awcache_i , //!< AXI write cache type
input [ 3-1: 0] axi_awprot_i , //!< AXI write protection type
input axi_awvalid_i , //!< AXI write address valid
output axi_awready_o , //!< AXI write ready
// axi write data channel
input [ AXI_IW-1: 0] axi_wid_i , //!< AXI write data ID
input [ AXI_DW-1: 0] axi_wdata_i , //!< AXI write data
input [ AXI_SW-1: 0] axi_wstrb_i , //!< AXI write strobes
input axi_wlast_i , //!< AXI write last
input axi_wvalid_i , //!< AXI write valid
output axi_wready_o , //!< AXI write ready
// axi write response channel
output [ AXI_IW-1: 0] axi_bid_o , //!< AXI write response ID
output reg [ 2-1: 0] axi_bresp_o , //!< AXI write response
output reg axi_bvalid_o , //!< AXI write response valid
input axi_bready_i , //!< AXI write response ready
// axi read address channel
input [ AXI_IW-1: 0] axi_arid_i , //!< AXI read address ID
input [ AXI_AW-1: 0] axi_araddr_i , //!< AXI read address
input [ 4-1: 0] axi_arlen_i , //!< AXI read burst length
input [ 3-1: 0] axi_arsize_i , //!< AXI read burst size
input [ 2-1: 0] axi_arburst_i , //!< AXI read burst type
input [ 2-1: 0] axi_arlock_i , //!< AXI read lock type
input [ 4-1: 0] axi_arcache_i , //!< AXI read cache type
input [ 3-1: 0] axi_arprot_i , //!< AXI read protection type
input axi_arvalid_i , //!< AXI read address valid
output axi_arready_o , //!< AXI read address ready
// axi read data channel
output [ AXI_IW-1: 0] axi_rid_o , //!< AXI read response ID
output reg [ AXI_DW-1: 0] axi_rdata_o , //!< AXI read data
output reg [ 2-1: 0] axi_rresp_o , //!< AXI read response
output reg axi_rlast_o , //!< AXI read last
output reg axi_rvalid_o , //!< AXI read response valid
input axi_rready_i , //!< AXI read response ready
// RP system read/write channel
output [ AXI_AW-1: 0] sys_addr_o , //!< system bus read/write address.
output [ AXI_DW-1: 0] sys_wdata_o , //!< system bus write data.
output reg [ AXI_SW-1: 0] sys_sel_o , //!< system bus write byte select.
output reg sys_wen_o , //!< system bus write enable.
output reg sys_ren_o , //!< system bus read enable.
input [ AXI_DW-1: 0] sys_rdata_i , //!< system bus read data.
input sys_err_i , //!< system bus error indicator.
input sys_ack_i //!< system bus acknowledge signal.
);
//---------------------------------------------------------------------------------
//
// AXI slave Module
wire ack ;
reg [ 6-1: 0] ack_cnt ;
reg rd_do ;
reg [ AXI_IW-1: 0] rd_arid ;
reg [ AXI_AW-1: 0] rd_araddr ;
reg rd_error ;
wire rd_errorw ;
reg wr_do ;
reg [ AXI_IW-1: 0] wr_awid ;
reg [ AXI_AW-1: 0] wr_awaddr ;
reg [ AXI_IW-1: 0] wr_wid ;
reg [ AXI_DW-1: 0] wr_wdata ;
reg wr_error ;
wire wr_errorw ;
assign wr_errorw = (axi_awlen_i != 4'h0) || (axi_awsize_i != 3'b010); // error if write burst and more/less than 4B transfer
assign rd_errorw = (axi_arlen_i != 4'h0) || (axi_arsize_i != 3'b010); // error if read burst and more/less than 4B transfer
always @(posedge axi_clk_i) begin
if (axi_rstn_i == 1'b0) begin
rd_do <= 1'b0 ;
rd_error <= 1'b0 ;
end
else begin
if (axi_arvalid_i && !rd_do && !axi_awvalid_i && !wr_do) // accept just one read request - write has priority
rd_do <= 1'b1 ;
else if (axi_rready_i && rd_do && ack)
rd_do <= 1'b0 ;
if (axi_arvalid_i && axi_arready_o) begin // latch ID and address
rd_arid <= axi_arid_i ;
rd_araddr <= axi_araddr_i ;
rd_error <= rd_errorw ;
end
end
end
always @(posedge axi_clk_i) begin
if (axi_rstn_i == 1'b0) begin
wr_do <= 1'b0 ;
wr_error <= 1'b0 ;
end
else begin
if (axi_awvalid_i && !wr_do && !rd_do) // accept just one write request - if idle
wr_do <= 1'b1 ;
else if (axi_bready_i && wr_do && ack)
wr_do <= 1'b0 ;
if (axi_awvalid_i && axi_awready_o) begin // latch ID and address
wr_awid <= axi_awid_i ;
wr_awaddr <= axi_awaddr_i ;
wr_error <= wr_errorw ;
end
if (axi_wvalid_i && wr_do) begin // latch ID and write data
wr_wid <= axi_wid_i ;
wr_wdata <= axi_wdata_i ;
end
end
end
assign axi_awready_o = !wr_do && !rd_do ;
assign axi_wready_o = (wr_do && axi_wvalid_i) || (wr_errorw && axi_wvalid_i) ;
assign axi_bid_o = wr_awid ;
//assign axi_bresp_o = {wr_error,1'b0} ; // 2'b10 SLVERR
//assign axi_bvalid_o = (sys_wen_o && axi_bready_i) || (wr_error && axi_bready_i) ;
assign axi_arready_o = !rd_do && !wr_do && !axi_awvalid_i ;
assign axi_rid_o = rd_arid ;
//assign axi_rdata_o = sys_rdata_i ;
always @(posedge axi_clk_i) begin
if (axi_rstn_i == 1'b0) begin
axi_bvalid_o <= 1'b0 ;
axi_bresp_o <= 2'h0 ;
axi_rlast_o <= 1'b0 ;
axi_rvalid_o <= 1'b0 ;
axi_rresp_o <= 2'h0 ;
end
else begin
axi_bvalid_o <= wr_do && ack ;
axi_bresp_o <= {(wr_error || ack_cnt[5]),1'b0} ; // 2'b10 SLVERR 2'b00 OK
axi_rlast_o <= rd_do && ack ;
axi_rvalid_o <= rd_do && ack ;
axi_rresp_o <= {(rd_error || ack_cnt[5]),1'b0} ; // 2'b10 SLVERR 2'b00 OK
axi_rdata_o <= sys_rdata_i ;
end
end
// acknowledge protection
always @(posedge axi_clk_i) begin
if (axi_rstn_i == 1'b0) begin
ack_cnt <= 6'h0 ;
end
else begin
if ((axi_arvalid_i && axi_arready_o) || (axi_awvalid_i && axi_awready_o)) // rd || wr request
ack_cnt <= 6'h1 ;
else if (ack)
ack_cnt <= 6'h0 ;
else if (|ack_cnt)
ack_cnt <= ack_cnt + 6'h1 ;
end
end
assign ack = sys_ack_i || ack_cnt[5] || (rd_do && rd_errorw) || (wr_do && wr_errorw); // bus acknowledge or timeout or error
//------------------------------------------
// Simple slave interface
always @(posedge axi_clk_i) begin
if (axi_rstn_i == 1'b0) begin
sys_wen_o <= 1'b0 ;
sys_ren_o <= 1'b0 ;
sys_sel_o <= {AXI_SW{1'b0}} ;
end
else begin
sys_wen_o <= wr_do && axi_wvalid_i && !wr_errorw ;
sys_ren_o <= axi_arvalid_i && axi_arready_o && !rd_errorw ;
sys_sel_o <= {AXI_SW{1'b1}} ;
end
end
assign sys_addr_o = rd_do ? rd_araddr : wr_awaddr ;
assign sys_wdata_o = wr_wdata ;
endmodule

View File

@ -0,0 +1,128 @@
/**
* $Id: bus_clk_bridge.v 961 2014-01-21 11:40:39Z matej.oblak $
*
* @brief Red Pitaya system bus clock crossing bridge.
*
* @Author Matej Oblak
*
* (c) Red Pitaya http://www.redpitaya.com
*
* This part of code is written in Verilog hardware description language (HDL).
* Please visit http://en.wikipedia.org/wiki/Verilog
* for more details on the language used herein.
*/
/**
* GENERAL DESCRIPTION:
*
* Clock domain bridge for system bus.
*
*
* /------\
* SYSTEM | | PROCESSING
* BUS <-----> | SYNC | <-----> BUS
* | |
* \------/
*
*
* System bus runs on one clock domain while processing runs on separate. To
* simplify transition of writing and reading data this bridge was created.
*
*/
module bus_clk_bridge
(
// system bus
input sys_clk_i , //!< bus clock
input sys_rstn_i , //!< bus reset - active low
input [ 32-1: 0] sys_addr_i , //!< bus address
input [ 32-1: 0] sys_wdata_i , //!< bus write data
input [ 4-1: 0] sys_sel_i , //!< bus write byte select
input sys_wen_i , //!< bus write enable
input sys_ren_i , //!< bus read enable
output [ 32-1: 0] sys_rdata_o , //!< bus read data
output sys_err_o , //!< bus error indicator
output sys_ack_o , //!< bus acknowledge signal
// Destination bus
input clk_i , //!< clock
input rstn_i , //!< reset - active low
output reg [ 32-1: 0] addr_o , //!< address
output reg [ 32-1: 0] wdata_o , //!< write data
output wen_o , //!< write enable
output ren_o , //!< read enable
input [ 32-1: 0] rdata_i , //!< read data
input err_i , //!< error indicator
input ack_i //!< acknowledge signal
);
//---------------------------------------------------------------------------------
// Synchronize signals between clock domains
reg sys_rd ;
reg sys_wr ;
reg sys_do ;
reg [ 2-1: 0] sys_sync ;
reg sys_done ;
reg dst_do ;
reg [ 2-1: 0] dst_sync ;
reg dst_done ;
always @(posedge sys_clk_i) begin
if (sys_rstn_i == 1'b0) begin
sys_rd <= 1'b0 ;
sys_wr <= 1'b0 ;
sys_do <= 1'b0 ;
sys_sync <= 2'h0 ;
sys_done <= 1'b0 ;
end
else begin
if ((sys_do == sys_done) && (sys_wen_i || sys_ren_i)) begin
addr_o <= sys_addr_i ;
wdata_o <= sys_wdata_i ;
sys_rd <= sys_ren_i ;
sys_wr <= sys_wen_i ;
sys_do <= !sys_do ;
end
sys_sync <= {sys_sync[0], dst_done};
sys_done <= sys_sync[1];
end
end
always @(posedge clk_i) begin
if (rstn_i == 1'b0) begin
dst_do <= 1'b0 ;
dst_sync <= 2'h0 ;
dst_done <= 1'b0 ;
end
else begin
dst_sync <= {dst_sync[0], sys_do};
dst_do <= dst_sync[1];
if (ack_i && (dst_do != dst_done))
dst_done <= dst_do;
end
end
assign ren_o = sys_rd && (dst_sync[1]^dst_do);
assign wen_o = sys_wr && (dst_sync[1]^dst_do);
assign sys_rdata_o = rdata_i ;
assign sys_err_o = err_i ;
assign sys_ack_o = sys_done ^ sys_sync[1] ;
endmodule

View File

@ -0,0 +1,111 @@
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: WUT
// Engineer: Jakub Matyas
//
// Create Date: 03/02/2023 01:39:08 PM
// Design Name:
// Module Name: spi2threewire
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module spi2threewire (
output ps_sclk_i,
input ps_sclk_o,
input ps_sclk_t,
output ps_mosi_i,
input ps_mosi_o,
input ps_mosi_t,
output ps_miso_i,
input ps_miso_o,
input ps_miso_t,
output ps_ss_i,
input [2:0] ps_ss,
input ps_ss_t,
output o_ss,
output o_sclk,
inout sdio
);
assign ps_sclk_i = 1'b0;
assign ps_mosi_i = 1'b0;
assign ps_ss_i = 1'b1;
reg [3:0] bit_count = 'd0;
// rd_wr_n - whether it will be READ transaction or WRITE
// first bit of the command
reg rd_wr_n = 'd0;
reg sdio_buffer_direction = 'd0;
wire s_sclk;
wire s_csn;
wire s_sdio_buffer_direction;
assign s_sclk = ps_sclk_o;
assign s_csn = ps_ss[0];
assign o_ss = s_csn;
// 1 if there is a SPI tranmsission going on (CS_N is LOW)
// AND transmission is of READ type
// 0 otherwise
assign s_sdio_buffer_direction = sdio_buffer_direction & ~s_csn;
always @(posedge s_sclk or posedge s_csn) begin
if (s_csn == 1'b1) begin
// after the transmission, fill bit counter with ZEROS
// and zero transmission type (rd_wr_n)
bit_count <= 4'd0;
rd_wr_n <= 1'b0;
end else begin
// on every rising edge increment bit counter
// sample first bit to get the knowledge of the transmission type
bit_count <= (bit_count < 4'd15) ? bit_count + 1'b1 : bit_count;
if (bit_count == 4'b0)
rd_wr_n <= ps_mosi_o;
end
end
always @(negedge s_sclk or posedge s_csn) begin
if (s_csn == 1'b1)
sdio_buffer_direction <= 1'b0;
else begin
if (bit_count == 4'd8)
// after the 8th bit, on falling edge,
// set the SDIO buffer direction
// accordingly to the transmission type
sdio_buffer_direction <= rd_wr_n;
end
end
IOBUF IOBUF_inst (
.O(ps_miso_i),
.IO(sdio),
.I(ps_mosi_o),
.T(s_sdio_buffer_direction) // 3-state enable input, high=input (from ext), low=output
);
OBUFT sclk_buf (
.O(o_sclk),
.I(ps_sclk_o),
.T('b0)
);
endmodule

View File

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

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

View File

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

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

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

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

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

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

31
fast-servo/u-boot.patch Normal file
View File

@ -0,0 +1,31 @@
diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile
index 480269fa60..64b20e4200 100644
--- a/arch/arm/dts/Makefile
+++ b/arch/arm/dts/Makefile
@@ -339,6 +339,7 @@ dtb-$(CONFIG_ARCH_ZYNQ) += \
zynq-cse-nor.dtb \
zynq-cse-qspi-single.dtb \
zynq-dlc20-rev1.0.dtb \
+ zynq-fast-servo.dtb \
zynq-microzed.dtb \
zynq-minized.dtb \
zynq-picozed.dtb \
diff --git a/configs/xilinx_zynq_virt_defconfig b/configs/xilinx_zynq_virt_defconfig
index 474abc7f6b..6e6bbd4aab 100644
--- a/configs/xilinx_zynq_virt_defconfig
+++ b/configs/xilinx_zynq_virt_defconfig
@@ -80,6 +80,7 @@ CONFIG_CMD_MTDPARTS_SPREAD=y
CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES=y
CONFIG_CMD_UBI=y
CONFIG_OF_BOARD=y
+CONFIG_SYS_CONFIG_NAME="zynq-fast-servo"
CONFIG_OF_LIST="zynq-zc702 zynq-zc706 zynq-zc770-xm010 zynq-zc770-xm011 zynq-zc770-xm011-x16 zynq-zc770-xm012 zynq-zc770-xm013 zynq-cc108 zynq-microzed zynq-minized zynq-picozed zynq-zed zynq-zturn zynq-zturn-v5 zynq-zybo zynq-zybo-z7 zynq-dlc20-rev1.0"
CONFIG_ENV_IS_NOWHERE=y
CONFIG_ENV_IS_IN_FAT=y
diff --git a/include/configs/zynq-fast-servo.h b/include/configs/zynq-fast-servo.h
new file mode 100644
index 0000000000..0aa486a2b7
--- /dev/null
+++ b/include/configs/zynq-fast-servo.h
@@ -0,0 +1 @@
+#include <configs/zynq-common.h>

View File

@ -18,16 +18,16 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1703961334,
"narHash": "sha256-M1mV/Cq+pgjk0rt6VxoyyD+O8cOUiai8t9Q6Yyq4noY=",
"lastModified": 1723938990,
"narHash": "sha256-9tUadhnZQbWIiYVXH8ncfGXGvkNq3Hag4RCBEMUk7MI=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "b0d36bd0a420ecee3bc916c91886caca87c894e9",
"rev": "c42fcfbdfeae23e68fc520f9182dde9f38ad1890",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"ref": "nixos-24.05",
"repo": "nixpkgs",
"type": "github"
}
@ -56,7 +56,43 @@
"root": {
"inputs": {
"nixpkgs": "nixpkgs",
"not-os": "not-os"
"not-os": "not-os",
"src-migen": "src-migen",
"src-misoc": "src-misoc"
}
},
"src-migen": {
"flake": false,
"locked": {
"lastModified": 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"
}
}
},

514
flake.nix
View File

@ -1,136 +1,216 @@
{
description = "Firmware for Sinara Fast-Servo based on Not-OS and Linien";
inputs.nixpkgs.url = github:NixOS/nixpkgs/nixos-unstable;
inputs.nixpkgs.url = github:NixOS/nixpkgs/nixos-24.05;
inputs.not-os.url = github:cleverca22/not-os;
inputs.not-os.inputs.nixpkgs.follows = "nixpkgs";
outputs = { self, nixpkgs, not-os }:
inputs.src-migen = { url = github:m-labs/migen; flake = false; };
inputs.src-misoc = { type = "git"; url = "https://github.com/m-labs/misoc.git"; submodules = true; flake = false; };
outputs = { self, nixpkgs, not-os, src-migen, src-misoc }:
let
pkgs = import nixpkgs { system = "x86_64-linux"; };
not-os-cfg = not-os-configured.config.system;
pkgs = import nixpkgs { system = "x86_64-linux"; overlays = [ crosspkgs-overlay ]; };
pkgs-armv7l = pkgs.pkgsCross.zynq-armv7l-linux;
fsbl-support = ./fast-servo/fsbl-support;
patched-not-os = pkgs.applyPatches {
name = "not-os-patched";
src = not-os;
patches = [
./pr-28.patch
./pr-29.patch
./not-os-patches/network.patch
./not-os-patches/pr-28.patch
./not-os-patches/pr-29.patch
./not-os-patches/pr-30.patch
./not-os-patches/pr-31.patch
./not-os-patches/pr-33.patch
];
};
gnu-platform = "arm-none-eabi";
binutils-pkg = { zlib, extraConfigureFlags ? [] }: pkgs.stdenv.mkDerivation rec {
basename = "binutils";
version = "2.30";
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";
crossSystem = {
system = "armv7l-linux";
linux-kernel = {
name = "zynq";
baseConfig = "multi_v7_defconfig";
target = "uImage";
installTarget = "uImage";
autoModules = false;
DTB = true;
makeFlags = [ "LOADADDR=0x8000" ];
};
};
gcc-pkg = { gmp, mpfr, libmpc, platform-binutils, extraConfigureFlags ? [] }: pkgs.stdenv.mkDerivation rec {
basename = "gcc";
version = "9.1.0";
name = "${basename}-${gnu-platform}-${version}";
src = pkgs.fetchurl {
url = "https://ftp.gnu.org/gnu/gcc/gcc-${version}/gcc-${version}.tar.xz";
sha256 = "1817nc2bqdc251k0lpc51cimna7v68xjrnvqzvc50q3ax4s6i9kr";
crosspkgs-overlay = (self: super: {
pkgsCross = super.pkgsCross // {
zynq-baremetal = import super.path {
system = "x86_64-linux";
crossSystem = {
config = "arm-none-eabihf";
libc = "newlib";
gcc.cpu = "cortex-a9";
gcc.fpu = "vfpv3";
};
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;
};
zynq-armv7l-linux = import super.path {
system = "x86_64-linux";
inherit crossSystem;
};
};
});
migen = pkgs.python3Packages.buildPythonPackage rec {
name = "migen";
src = src-migen;
format = "pyproject";
nativeBuildInputs = [ pkgs.python3Packages.setuptools ];
propagatedBuildInputs = [ pkgs.python3Packages.colorama ];
};
newlib-pkg = { platform-binutils, platform-gcc }: pkgs.stdenv.mkDerivation rec {
pname = "newlib";
version = "3.1.0";
src = pkgs.fetchurl {
url = "ftp://sourceware.org/pub/newlib/newlib-${version}.tar.gz";
sha256 = "0ahh3n079zjp7d9wynggwrnrs27440aac04340chf1p9476a2kzv";
misoc = pkgs.python3Packages.buildPythonPackage {
name = "misoc";
src = src-misoc;
propagatedBuildInputs = with pkgs.python3Packages; [ jinja2 numpy migen pyserial asyncserial ];
};
nativeBuildInputs = [ platform-binutils platform-gcc ];
configureFlags = [
"--target=${gnu-platform}"
"--with-cpu=cortex-a9"
"--with-fpu=vfpv3"
"--with-float=hard"
"--with-mode=thumb"
"--enable-interwork"
"--disable-multilib"
"--disable-newlib-supplied-syscalls"
"--with-gnu-ld"
"--with-gnu-as"
"--disable-newlib-io-float"
"--disable-werror"
vivado = pkgs.buildFHSEnv {
name = "vivado";
targetPkgs = pkgs: with pkgs; let
# Apply patch from https://github.com/nix-community/nix-environments/pull/54
# to fix ncurses libtinfo.so's soname issue
ncurses' = ncurses5.overrideAttrs (old: {
configureFlags = old.configureFlags ++ [ "--with-termlib" ];
postFixup = "";
});
in [
libxcrypt-legacy
(ncurses'.override { unicodeSupport = false; })
zlib
libuuid
xorg.libSM
xorg.libICE
xorg.libXrender
xorg.libX11
xorg.libXext
xorg.libXtst
xorg.libXi
freetype
fontconfig
];
dontFixup = true;
profile = "set -e; source /opt/Xilinx/Vivado/2022.2/settings64.sh";
runScript = "vivado";
};
gnutoolchain = rec {
binutils-bootstrap = pkgs.callPackage binutils-pkg { };
gcc-bootstrap = pkgs.callPackage gcc-pkg {
platform-binutils = binutils-bootstrap;
extraConfigureFlags = [ "--disable-libgcc" ];
pyrp3 = pkgs-armv7l.python3Packages.buildPythonPackage rec {
pname = "pyrp3";
version = "1.2.0";
pyproject = true;
src = pkgs.fetchFromGitHub {
owner = "linien-org";
repo = "pyrp3";
rev = "v${version}";
hash = "sha256-43TTlpJ5SMAjQM71bNVvrWQyciRXM3zpuA/Dw41AEgU=";
};
newlib = pkgs.callPackage newlib-pkg {
platform-binutils = binutils-bootstrap;
platform-gcc = gcc-bootstrap;
patches = ./fast-servo/linien-pyrp3-monitor.patch;
nativeBuildInputs = with pkgs-armv7l.python3Packages; [
setuptools wheel setuptools-scm
] ++ (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 {
extraConfigureFlags = [ "--with-lib-path=${newlib}/arm-none-eabi/lib" ];
linien-server = pkgs-armv7l.python3Packages.buildPythonPackage rec {
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 {
platform-binutils = binutils;
extraConfigureFlags = [ "--enable-newlib" "--with-headers=${newlib}/arm-none-eabi/include" ];
fast-servo-gateware = pkgs.stdenv.mkDerivation rec {
name = "fast-servo-gateware";
inherit (pkgs.python3Packages.linien-common) src;
prePatch = ''
mkdir -p fast_servo/gateware
cp -r ${./fast-servo/linien-gateware}/. fast_servo/gateware
'';
patches = [
fast-servo/linien-fast-servo-gateware.patch
fast-servo/linien-fast-servo-server.patch
];
nativeBuildInputs = [
(pkgs.python3.withPackages(ps: [
migen misoc
(ps.linien-common.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 {
@ -156,24 +236,63 @@
hardeningDisable = [ "fortify" ];
};
fsbl = { board ? "zc706" }: pkgs.stdenv.mkDerivation {
board-package-set = { board }: let
not-os-configured = (import patched-not-os {
inherit nixpkgs;
extraModules = [
"${patched-not-os}/zynq_image.nix"
] ++ pkgs.lib.optionals (board == "fast-servo") [
({ 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;
fsbl = pkgs.stdenv.mkDerivation {
name = "${board}-fsbl";
src = pkgs.fetchFromGitHub {
owner = "Xilinx";
repo = "embeddedsw";
rev = "65c849ed46c88c67457e1fc742744f96db968ff1";
sha256 = "1rvl06ha40dzd6s9aa4sylmksh4xb9dqaxq462lffv1fdk342pda";
rev = "xilinx_v2022.2";
sha256 = "sha256-UDz9KK/Hw3qM1BAeKif30rE8Bi6C2uvuZlvyvtJCMfw=";
};
patches = [ ./fsbl.patch ];
nativeBuildInputs = [
pkgs.gnumake
gnutoolchain.binutils
gnutoolchain.gcc
pkgs.pkgsCross.zynq-baremetal.buildPackages.binutils
pkgs.pkgsCross.zynq-baremetal.buildPackages.gcc
];
patchPhase = ''
patch -p1 -i ${./fsbl.patch}
postUnpack = ''
mkdir -p $sourceRoot/lib/sw_apps/zynq_fsbl/misc/fast-servo
cp $sourceRoot/lib/sw_apps/zynq_fsbl/misc/zc706/* $sourceRoot/lib/sw_apps/zynq_fsbl/misc/fast-servo
cp ${fsbl-support}/* $sourceRoot/lib/sw_apps/zynq_fsbl/misc/fast-servo
'';
patches = [] ++ pkgs.lib.optional (board == "fast-servo") ./fast-servo/fsbl.patch;
postPatch = ''
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 = ''
cd lib/sw_apps/zynq_fsbl/src
@ -187,17 +306,20 @@
dontFixup = true;
};
u-boot = { board ? "zc706" }: pkgs.pkgsCross.armv7l-hf-multiplatform.buildUBoot {
u-boot = (pkgs-armv7l.buildUBoot {
name = "${board}-u-boot";
defconfig = "xilinx_zynq_virt_defconfig";
patches = [] ++ pkgs.lib.optional (board == "fast-servo") ./fast-servo/u-boot.patch;
preConfigure = ''
export DEVICE_TREE=zynq-${board}
'';
extraConfig = ''
CONFIG_SYS_PROMPT="${board}-boot> "
CONFIG_AUTOBOOT=y
CONFIG_BOOTCOMMAND="${builtins.replaceStrings [ "\n" ] [ "; " ] ''
setenv bootargs 'root=/dev/mmcblk0p2 console=ttyPS0,115200n8 systemConfig=${builtins.unsafeDiscardStringContext not-os-cfg.build.toplevel}'
setenv bootargs 'root=/dev/mmcblk0p2 console=ttyPS0,115200n8 systemConfig=${builtins.unsafeDiscardStringContext not-os-build.toplevel}'
fatload mmc 0 0x6400000 uImage
fatload mmc 0 0x8000000 devicetree.dtb
fatload mmc 0 0x8000000 ${board}.dtb
fatload mmc 0 0xA400000 uRamdisk.image.gz
bootm 0x6400000 0xA400000 0x8000000
''}"
@ -206,17 +328,27 @@
'';
extraMeta.platforms = [ "armv7l-linux" ];
filesToInstall = [ "u-boot.elf" ];
};
}).overrideAttrs (oldAttrs: {
postUnpack = ''
cp ${fast-servo/fast-servo.dts} $sourceRoot/arch/arm/dts/zynq-fast-servo.dts
'';
postInstall = ''
mkdir -p $out/dts
cp arch/arm/dts/zynq-fast-servo.dts $out/dts
cp arch/arm/dts/zynq-zc706.dts $out/dts
cp arch/arm/dts/zynq-7000.dtsi $out/dts
'';
});
bootimage = { board ? "zc706" }: pkgs.runCommand "${board}-bootimage"
bootimage = pkgs.runCommand "${board}-bootimage"
{
buildInputs = [ mkbootimage ];
}
''
bifdir=`mktemp -d`
cd $bifdir
ln -s ${fsbl { inherit board; }}/fsbl.elf fsbl.elf
ln -s ${u-boot { inherit board; }}/u-boot.elf u-boot.elf
ln -s ${fsbl}/fsbl.elf fsbl.elf
ln -s ${u-boot}/u-boot.elf u-boot.elf
cat > boot.bif << EOF
the_ROM_image:
{
@ -229,76 +361,34 @@
echo file binary-dist $out/boot.bin >> $out/nix-support/hydra-build-products
'';
# Pinned qemu version due to networking errors in recent version 8.2.0
qemu = pkgs.qemu.overrideAttrs (oldAttrs: rec {
version = "8.1.3";
src = pkgs.fetchurl {
url = "https://download.qemu.org/qemu-${version}.tar.xz";
hash = "sha256-Q8wXaAQQVYb3T5A5jzTp+FeH3/QA07ZA2B93efviZbs=";
};
});
not-os-configured = (import patched-not-os {
inherit nixpkgs;
extraModules = [
"${patched-not-os}/zynq_image.nix"
];
system = "x86_64-linux";
crossSystem.system = "armv7l-linux";
});
not-os-qemu = { board ? "zc706" }: let
qemuScript = ''
#!/bin/bash
export PATH=${qemu}/bin:$PATH
IMGDIR=$(mktemp -d /tmp/not-os-qemu-XXXXXX)
BASE=$(realpath $(dirname $0))
qemu-img create -F raw -f qcow2 -b $BASE/sd-image.img $IMGDIR/sd-overlay.qcow2 512M
# 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
qemu-system-arm \
-M xilinx-zynq-a9 \
-serial /dev/null \
-serial stdio \
-display none \
-dtb $BASE/devicetree.dtb \
-kernel $BASE/uImage \
-initrd $BASE/uRamdisk.image.gz \
-drive file=$IMGDIR/sd-overlay.qcow2,if=sd,format=qcow2 \
-append "root=/dev/mmcblk0p2 console=ttyPS0,115200n8 systemConfig=${builtins.unsafeDiscardStringContext not-os-cfg.build.toplevel}";
rm -rf $IMGDIR
'';
in pkgs.runCommand "not-os-qemu" {
inherit qemuScript;
passAsFile = [ "qemuScript" ];
preferLocalBuild = true;
dtb = pkgs.runCommand "${board}-dtb"
{
buildInputs = [ pkgs.gcc pkgs.dtc ];
}
''
mkdir $out
cd $out
cp -s ${not-os-cfg.build.kernel}/uImage .
cp -s ${not-os-cfg.build.uRamdisk}/initrd uRamdisk.image.gz
cp -s ${not-os-cfg.build.kernel}/dtbs/zynq-zc706.dtb devicetree.dtb
cp -s ${sd-image { inherit board; }}/sd-image/sd-image.img .
ln -sv ${not-os-cfg.build.toplevel} toplevel
cp $qemuScriptPath qemu-script
chmod +x qemu-script
patchShebangs qemu-script
mkdir -p $out
cp ${u-boot}/dts/zynq-${board}.dts .
if [ ${board} == "zc706" ]; then
mv zynq-${board}.dts zynq-${board}-top.dts
cp ${u-boot}/dts/zynq-7000.dtsi .
gcc -E -nostdinc -undef -D__DTS__ -x assembler-with-cpp -o zynq-${board}.dts zynq-${board}-top.dts
fi
dtc -I dts -O dtb -o ${board}.dtb zynq-${board}.dts
cp ${board}.dtb $out
'';
sd-image = { board ? "zc706" }: let
sd-image = let
rootfsImage = pkgs.callPackage (pkgs.path + "/nixos/lib/make-ext4-fs.nix") {
storePaths = [ not-os-cfg.build.toplevel ];
storePaths = [ not-os-build.toplevel ];
volumeLabel = "ROOT";
};
# Current firmware (kernel, bootimage, etc..) takes ~18MB
firmwareSize = 30;
firmwarePartitionOffset = 8;
in pkgs.stdenv.mkDerivation {
name = "sd-image";
name = "${board}-sd-image";
nativeBuildInputs = with pkgs; [ dosfstools mtools libfaketime util-linux parted ];
buildCommand = ''
mkdir -p $out/nix-support $out/sd-image
@ -330,27 +420,71 @@
faketime "1970-01-01 00:00:00" mkfs.vfat -n BOOT firmware_part.img
mkdir firmware
cp ${bootimage { inherit board; }}/boot.bin firmware/
cp ${not-os-cfg.build.kernel}/uImage firmware/
cp ${not-os-cfg.build.uRamdisk}/initrd firmware/uRamdisk.image.gz
cp ${not-os-cfg.build.kernel}/dtbs/zynq-zc706.dtb firmware/devicetree.dtb
cp ${bootimage}/boot.bin firmware/
cp ${dtb}/${board}.dtb firmware/
cp ${not-os-build.kernel}/uImage firmware/
cp ${not-os-build.uRamdisk}/initrd firmware/uRamdisk.image.gz
(cd firmware; mcopy -psvm -i ../firmware_part.img ./* ::)
dd conv=notrunc if=firmware_part.img of=$img seek=$START count=$SECTORS
'';
};
not-os-qemu = let
qemuScript = ''
#!/bin/bash
export PATH=${pkgs.qemu}/bin:$PATH
IMGDIR=$(mktemp -d /tmp/not-os-qemu-XXXXXX)
BASE=$(realpath $(dirname $0))
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
# See: https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/821854273/Running+Bare+Metal+Applications+on+QEMU
qemu-system-arm \
-M xilinx-zynq-a9 \
-m 1024 \
$([ ${board} = "zc706" ] && echo "-serial /dev/null") -serial stdio \
-display none \
-kernel $BASE/u-boot.elf \
-sd $IMGDIR/sd-overlay.qcow2
rm -rf $IMGDIR
'';
in pkgs.runCommand "${board}-qemu" {
inherit qemuScript;
passAsFile = [ "qemuScript" ];
preferLocalBuild = true;
}
''
mkdir $out
cd $out
cp -s ${u-boot}/u-boot.elf .
cp -s ${sd-image}/sd-image/sd-image.img .
cp $qemuScriptPath qemu-script
chmod +x qemu-script
patchShebangs qemu-script
'';
in {
"${board}-fsbl" = fsbl;
"${board}-u-boot" = u-boot;
"${board}-bootimage" = bootimage;
"${board}-dtb" = dtb;
"${board}-sd-image" = sd-image;
"${board}-qemu" = not-os-qemu;
};
in rec {
packages.x86_64-linux = {
inherit mkbootimage;
inherit migen misoc vivado;
};
packages.armv7l-linux = {
zc706-u-boot = u-boot { board = "zc706"; };
zc706-fsbl = fsbl { board = "zc706"; };
zc706-bootimage = bootimage { board = "zc706"; };
zc706-qemu = not-os-qemu { board = "zc706"; };
zc706-sd-image = sd-image { board = "zc706"; };
zc706-not-os = not-os-cfg.build.zynq_image;
};
inherit fast-servo-gateware linien-server;
} //
(board-package-set { board = "zc706"; }) //
(board-package-set { board = "fast-servo"; });
hydraJobs = packages.x86_64-linux // packages.armv7l-linux;
};

View File

@ -1,31 +0,0 @@
diff --git a/lib/sw_apps/zynq_fsbl/src/Makefile b/lib/sw_apps/zynq_fsbl/src/Makefile
index 0e3ccdf1c5..a5b02f386e 100644
--- a/lib/sw_apps/zynq_fsbl/src/Makefile
+++ b/lib/sw_apps/zynq_fsbl/src/Makefile
@@ -71,11 +71,14 @@ endif
all: $(EXEC)
$(EXEC): $(LIBS) $(OBJS) $(INCLUDES)
- cp $(BSP_DIR)/$(BOARD)/ps7_init.* .
$(LINKER) $(LD1FLAGS) -o $@ $(OBJS) $(LDFLAGS)
rm -rf $(OBJS)
-
-
+
+.PHONY: ps7_init
+
+ps7_init:
+ cp $(BSP_DIR)/$(BOARD)/ps7_init.* .
+
$(LIBS):
echo "Copying BSP files"
$(BSP_DIR)/copy_bsp.sh $(BOARD) $(CC)
@@ -86,7 +89,7 @@ $(LIBS):
make -C $(BSP_DIR) -k all "CC=armcc" "AR=armar" "C_FLAGS= -O2 -c" "EC_FLAGS=--debug --wchar32"; \
fi;
-%.o:%.c
+%.o:%.c ps7_init
$(CC) $(CC_FLAGS) $(CFLAGS) $(ECFLAGS) -c $< -o $@ $(INCLUDEPATH)
%.o:%.S

View File

@ -0,0 +1,58 @@
diff --git a/configuration.nix b/configuration.nix
index 010c487..2d08009 100644
--- a/configuration.nix
+++ b/configuration.nix
@@ -1,4 +1,4 @@
-{ pkgs, ... }:
+{ pkgs, lib, ... }:
{
imports = [ ./qemu.nix ];
@@ -7,10 +7,16 @@
environment.etc = {
"ssh/authorized_keys.d/root" = {
text = ''
- ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC34wZQFEOGkA5b0Z6maE3aKy/ix1MiK1D0Qmg4E9skAA57yKtWYzjA23r5OCF4Nhlj1CuYd6P1sEI/fMnxf+KkqqgW3ZoZ0+pQu4Bd8Ymi3OkkQX9kiq2coD3AFI6JytC6uBi6FaZQT5fG59DbXhxO5YpZlym8ps1obyCBX0hyKntD18RgHNaNM+jkQOhQ5OoxKsBEobxQOEdjIowl2QeEHb99n45sFr53NFqk3UCz0Y7ZMf1hSFQPuuEC/wExzBBJ1Wl7E1LlNA4p9O3qJUSadGZS4e5nSLqMnbQWv2icQS/7J8IwY0M8r1MsL8mdnlXHUofPlG1r4mtovQ2myzOx clever@nixos
- ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDKITUnIETct0d1Ky7iEofM8BV/U9ViuAd72abm26ibhkVKYuLlIvNBtf7+fsyaHR3cc4kmiUz26co4LV2q10HLO7nua7Ry0QhtPvPnpudandB4LbV4ieW1cqcWcPpsM1GssUZhZthbkwLf7h2exojqVj8vqPm5RaBl1eULXaPTldCiSe5ZxNuVbm3qT8Lfc2E3ifKT6A7WqZN00f1+YSnaA9uy0VgVDReDqyujAZaKGUwSa2G8eqzN3guN7VcBZek2p1v1n0EwpFdBxzT3Ncqh5wIYPNn084q5lU13TAjw+tTO7Q059e4HFLaR24w8NT60BrO1dbGYLbjWNri1G3pz root@router
+ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCMALVC8RDTHec+PC8y1s3tcpUAODgq6DEzQdHDf/cyvDMfmCaPiMxfIdmkns5lMa03hymIfSmLUF0jFFDc7biRp7uf9AAXNsrTmplHii0l0McuOOZGlSdZM4eL817P7UwJqFMxJyFXDjkubhQiX6kp25Kfuj/zLnupRCaiDvE7ho/xay6Jrv0XLz935TPDwkc7W1asLIvsZLheB+sRz9SMOb9gtrvk5WXZl5JTOFOLu+JaRwQLHL/xdcHJTOod7tqHYfpoC5JHrEwKzbhTOwxZBQBfTQjQktKENQtBxXHTe71rUEWfEZQGg60/BC4BrRmh4qJjlJu3v4VIhC7SSHn1 root
+ ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBNdIiLvP2hmDUFyyE0oLOIXrjrMdWWpBV9/gPR5m4AiARx4JkufIDZzmptdYQ5FhJORJ4lluPqp7dAmahoSwg4lv9Di0iNQpHMJvNGZLHYKM1H1FWCCFIEDJ8bD4SVfrDg== root
+ ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBF/YybP+fQ0J+bNqM5Vgx5vDmVqVWsgUdF1moUxghv7d73GZAFaM6IFBdrXTAa33AwnWwDPMrTgP1V6SXBkb3ciJo/lD1urJGbydbSI5Ksq9d59wvOeANvyWYrQw6+eqTQ== sb
+ ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBFkmOCQ3BQh3qUjLtfdqyeBsx8rkk/QYlzB0TMrnfn6waLN6yKfPC3WVFv4zN5kNKb/OayvqDa+zfkKe85e/oIPQQKflF7GrCHdssz33DCnW90cz532E6iqG1pjeZjID2A== flo
+ ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICAranL376soiSJ0kxdYNrwElcaZPW1heLFjs8Y7n0jT linuswck
'';
mode = "0444";
};
+ "resolv.conf".text = lib.mkForce ''
+ nameserver 192.168.1.1
+ '';
};
}
diff --git a/runit.nix b/runit.nix
index d7b0bf3..67cff43 100644
--- a/runit.nix
+++ b/runit.nix
@@ -7,8 +7,8 @@ let
Port 22
PidFile /run/sshd.pid
Protocol 2
- PermitRootLogin yes
- PasswordAuthentication yes
+ PermitRootLogin prohibit-password
+ PasswordAuthentication no
AuthorizedKeysFile /etc/ssh/authorized_keys.d/%u
'';
compat = pkgs.runCommand "runit-compat" {} ''
@@ -31,10 +31,10 @@ in
"runit/1".source = pkgs.writeScript "1" ''
#!${pkgs.runtimeShell}
${lib.optionalString config.not-os.simpleStaticIp ''
- ip addr add 10.0.2.15 dev eth0
+ ip addr add 103.206.98.205 dev eth0
ip link set eth0 up
- ip route add 10.0.2.0/24 dev eth0
- ip route add default via 10.0.2.2 dev eth0
+ ip route add 103.206.98.200/29 dev eth0
+ ip route add default via 103.206.98.200 dev eth0
''}
mkdir /bin/
ln -s ${pkgs.runtimeShell} /bin/sh

295
not-os-patches/pr-28.patch Normal file
View File

@ -0,0 +1,295 @@
diff --git a/base.nix b/base.nix
index 7eaee32..9aa338e 100644
--- a/base.nix
+++ b/base.nix
@@ -27,6 +27,11 @@ with lib;
description = "enable rngd";
default = false;
};
+ not-os.sd = mkOption {
+ type = types.bool;
+ default = false;
+ description = "enable sd image support";
+ };
not-os.simpleStaticIp = mkOption {
type = types.bool;
default = false;
@@ -84,17 +89,25 @@ with lib;
};
environment.etc = {
"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.writeClosure [ pkgs.bash ]}); do if test -d $i; then echo $i; fi; done)
cat > $out << EOF
- build-use-sandbox = true
+ auto-optimise-store = true
build-users-group = nixbld
- build-sandbox-paths = /bin/sh=${pkgs.runtimeShell} $(echo $extraPaths)
- build-max-jobs = 1
- build-cores = 4
+ cores = 0
+ extra-sandbox-paths = /bin/sh=${pkgs.runtimeShell} $(echo $extraPaths)
+ max-jobs = auto
+ sandbox = true
+ trusted-users = root
EOF
'';
+ "ssl/certs/ca-certificates.crt".source = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt";
+ "ssl/certs/ca-bundle.crt".source = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt";
bashrc.text = "export PATH=/run/current-system/sw/bin";
- profile.text = "export PATH=/run/current-system/sw/bin";
+ profile.text = ''
+ export PATH=/run/current-system/sw/bin
+ export EDITOR=nano
+ export NIX_PATH="nixpkgs=/nix/var/nix/profiles/per-user/root/channels/nixos:nixos-config=/etc/nixos/configuration.nix:/nix/var/nix/profiles/per-user/root/channels"
+ '';
"resolv.conf".text = "nameserver 10.0.2.3";
passwd.text = ''
root:x:0:0:System administrator:/root:/run/current-system/sw/bin/bash
diff --git a/runit.nix b/runit.nix
index d7b0bf3..70353a1 100644
--- a/runit.nix
+++ b/runit.nix
@@ -65,7 +65,6 @@ in
'';
"service/nix/run".source = pkgs.writeScript "nix" ''
#!${pkgs.runtimeShell}
- nix-store --load-db < /nix/store/nix-path-registration
nix-daemon
'';
}
diff --git a/stage-1.nix b/stage-1.nix
index 331fecd..aa5148e 100644
--- a/stage-1.nix
+++ b/stage-1.nix
@@ -117,11 +117,6 @@ let
plymouth --show-splash
''}
-
- for x in ${lib.concatStringsSep " " config.boot.initrd.kernelModules}; do
- modprobe $x
- done
-
root=/dev/vda
realroot=tmpfs
for o in $(cat /proc/cmdline); do
@@ -164,7 +159,9 @@ let
mkdir -p /mnt/nix/store/
- ${if config.not-os.nix then ''
+ ${if config.not-os.sd && config.not-os.nix then ''
+ mount $root /mnt
+ '' else if config.not-os.nix then ''
# make the store writeable
mkdir -p /mnt/nix/.ro-store /mnt/nix/.overlay-store /mnt/nix/store
mount $root /mnt/nix/.ro-store -t squashfs
@@ -190,6 +187,11 @@ let
initialRamdisk = pkgs.makeInitrd {
contents = [ { object = bootStage1; symlink = "/init"; } ];
};
+ # Use for zynq_image
+ uRamdisk = pkgs.makeInitrd {
+ makeUInitrd = true;
+ contents = [ { object = bootStage1; symlink = "/init"; } ];
+ };
in
{
options = {
@@ -205,6 +207,7 @@ in
config = {
system.build.bootStage1 = bootStage1;
system.build.initialRamdisk = initialRamdisk;
+ system.build.uRamdisk = uRamdisk;
system.build.extraUtils = extraUtils;
boot.initrd.availableKernelModules = [ ];
boot.initrd.kernelModules = [ "tun" "loop" "squashfs" ] ++ (lib.optional config.not-os.nix "overlay");
diff --git a/stage-2-init.sh b/stage-2-init.sh
index 6cc08e2..0c854c4 100644
--- a/stage-2-init.sh
+++ b/stage-2-init.sh
@@ -19,4 +19,7 @@ mount -t tmpfs tmpfs /dev/shm
$systemConfig/activate
+# Run any user-specified commands.
+@runtimeShell@ @postBootCommands@
+
exec runit
diff --git a/stage-2.nix b/stage-2.nix
index c61f9d6..fbdf0fd 100644
--- a/stage-2.nix
+++ b/stage-2.nix
@@ -20,6 +20,19 @@ with lib;
example = "256m";
type = types.str;
};
+ postBootCommands = mkOption {
+ default = "";
+ example = "rm -f /var/log/messages";
+ type = types.lines;
+ description = lib.mdDoc ''
+ Shell commands to be executed just before runit is started.
+ '';
+ };
+ };
+ networking.hostName = mkOption {
+ default = "";
+ type = types.strMatching
+ "^$|^[[:alnum:]]([[:alnum:]_-]{0,61}[[:alnum:]])?$";
};
};
config = {
@@ -28,6 +41,9 @@ with lib;
isExecutable = true;
path = config.system.path;
inherit (pkgs) runtimeShell;
+ postBootCommands = pkgs.writeText "local-cmds" ''
+ ${config.boot.postBootCommands}
+ '';
};
};
}
diff --git a/zynq_image.nix b/zynq_image.nix
index 3fa23ab..069fe89 100644
--- a/zynq_image.nix
+++ b/zynq_image.nix
@@ -1,66 +1,89 @@
-{ config, pkgs, ... }:
+{ lib, config, pkgs, ... }:
+with lib;
let
- # dont use overlays for the qemu, it causes a lot of wasted time on recompiles
- x86pkgs = import pkgs.path { system = "x86_64-linux"; };
- customKernel = pkgs.linux.override {
+ customKernel = (pkgs.linux_6_6.override {
extraConfig = ''
OVERLAY_FS y
+ MEDIA_SUPPORT n
+ FB n
+ DRM n
+ SOUND n
+ SQUASHFS 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
'';
- };
+ }).overrideAttrs (oa: {
+ postInstall = ''
+ if [ -e arch/arm/boot/uImage ]; then
+ cp arch/arm/boot/uImage $out
+ fi
+ ${oa.postInstall}
+ '';
+ });
customKernelPackages = pkgs.linuxPackagesFor customKernel;
in {
imports = [ ./arm32-cross-fixes.nix ];
boot.kernelPackages = customKernelPackages;
nixpkgs.system = "armv7l-linux";
- system.build.zynq_image = let
- cmdline = "root=/dev/mmcblk0 console=ttyPS0,115200n8 systemConfig=${builtins.unsafeDiscardStringContext config.system.build.toplevel}";
- qemuScript = ''
- #!/bin/bash -v
- export PATH=${x86pkgs.qemu}/bin:$PATH
- set -x
- base=$(dirname $0)
-
- cp $base/root.squashfs /tmp/
- chmod +w /tmp/root.squashfs
- truncate -s 64m /tmp/root.squashfs
-
- qemu-system-arm \
- -M xilinx-zynq-a9 \
- -serial /dev/null \
- -serial stdio \
- -display none \
- -dtb $base/zynq-zc702.dtb \
- -kernel $base/zImage \
- -initrd $base/initrd \
- -drive file=/tmp/root.squashfs,if=sd,format=raw \
- -append "${cmdline}"
- '';
- in pkgs.runCommand "zynq_image" {
- inherit qemuScript;
- passAsFile = [ "qemuScript" ];
+ networking.hostName = "zynq";
+ not-os.sd = true;
+ not-os.simpleStaticIp = true;
+ system.build.zynq_image = pkgs.runCommand "zynq_image" {
preferLocalBuild = true;
} ''
mkdir $out
cd $out
- cp -s ${config.system.build.squashfs} root.squashfs
- cp -s ${config.system.build.kernel}/*zImage .
- cp -s ${config.system.build.initialRamdisk}/initrd initrd
- cp -s ${config.system.build.kernel}/dtbs/zynq-zc702.dtb .
+ cp -s ${config.system.build.kernel}/uImage .
+ cp -s ${config.system.build.uRamdisk}/initrd uRamdisk.image.gz
+ cp -s ${config.system.build.kernel}/dtbs/zynq-zc706.dtb devicetree.dtb
ln -sv ${config.system.build.toplevel} toplevel
- cp $qemuScriptPath qemu-script
- chmod +x qemu-script
- patchShebangs qemu-script
- ls -ltrh
- '';
- system.build.rpi_image_tar = pkgs.runCommand "dist.tar" {} ''
- mkdir -p $out/nix-support
- tar -cvf $out/dist.tar ${config.system.build.rpi_image}
- echo "file binary-dist $out/dist.tar" >> $out/nix-support/hydra-build-products
'';
- environment.systemPackages = [ pkgs.strace ];
- environment.etc."service/getty/run".source = pkgs.writeShellScript "getty" ''
- agetty ttyPS0 115200
+ environment = {
+ systemPackages = with pkgs; [ inetutils wget gnugrep nano vim ];
+ etc = {
+ "service/getty/run".source = pkgs.writeShellScript "getty" ''
+ hostname ${config.networking.hostName}
+ exec setsid agetty ttyPS0 115200
+ '';
+ "pam.d/other".text = ''
+ auth sufficient pam_permit.so
+ account required pam_permit.so
+ password required pam_permit.so
+ session optional pam_env.so
+ '';
+ "security/pam_env.conf".text = "";
+ };
+ };
+ boot.postBootCommands = lib.mkIf config.not-os.sd ''
+ # On the first boot do some maintenance tasks
+ if [ -f /nix-path-registration ]; then
+ set -euo pipefail
+ set -x
+ # Figure out device names for the boot device and root filesystem.
+ rootPart=$(${pkgs.utillinux}/bin/findmnt -n -o SOURCE /)
+ bootDevice=$(lsblk -npo PKNAME $rootPart)
+ partNum=$(lsblk -npo MAJ:MIN $rootPart | ${pkgs.gawk}/bin/awk -F: '{print $2}')
+
+ # Resize the root partition and the filesystem to fit the disk
+ echo ",+," | sfdisk -N$partNum --no-reread $bootDevice
+ ${pkgs.parted}/bin/partprobe
+ ${pkgs.e2fsprogs}/bin/resize2fs $rootPart
+
+ # Register the contents of the initial Nix store
+ nix-store --load-db < /nix-path-registration
+
+ # nixos-rebuild also requires a "system" profile and an /etc/NIXOS tag.
+ touch /etc/NIXOS
+ nix-env -p /nix/var/nix/profiles/system --set /run/current-system
+
+ # Prevents this from running on later boots.
+ rm -f /nix-path-registration
+ fi
'';
- environment.etc."pam.d/other".text = "";
}

135
not-os-patches/pr-30.patch Normal file
View File

@ -0,0 +1,135 @@
diff --git a/base.nix b/base.nix
index 7eaee32..622cbf1 100644
--- a/base.nix
+++ b/base.nix
@@ -120,10 +120,6 @@ with lib;
root:x:0:
nixbld:x:30000:nixbld1,nixbld10,nixbld2,nixbld3,nixbld4,nixbld5,nixbld6,nixbld7,nixbld8,nixbld9
'';
- "ssh/ssh_host_rsa_key.pub".source = ./ssh/ssh_host_rsa_key.pub;
- "ssh/ssh_host_rsa_key" = { mode = "0600"; source = ./ssh/ssh_host_rsa_key; };
- "ssh/ssh_host_ed25519_key.pub".source = ./ssh/ssh_host_ed25519_key.pub;
- "ssh/ssh_host_ed25519_key" = { mode = "0600"; source = ./ssh/ssh_host_ed25519_key; };
};
boot.kernelParams = [ "systemConfig=${config.system.build.toplevel}" ];
boot.kernelPackages = lib.mkDefault (if pkgs.system == "armv7l-linux" then pkgs.linuxPackages_rpi1 else pkgs.linuxPackages);
diff --git a/gen_keys b/gen_keys
deleted file mode 100755
index ee586a2..0000000
--- a/gen_keys
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/bin/sh
-mkdir ssh
-ssh-keygen -t rsa -b 4096 -f ssh/ssh_host_rsa_key -N ""
-ssh-keygen -t ed25519 -f ssh/ssh_host_ed25519_key -N ""
diff --git a/runit.nix b/runit.nix
index d7b0bf3..6d602b6 100644
--- a/runit.nix
+++ b/runit.nix
@@ -2,7 +2,6 @@
let
sshd_config = pkgs.writeText "sshd_config" ''
- HostKey /etc/ssh/ssh_host_rsa_key
HostKey /etc/ssh/ssh_host_ed25519_key
Port 22
PidFile /run/sshd.pid
@@ -30,6 +29,13 @@ in
{
"runit/1".source = pkgs.writeScript "1" ''
#!${pkgs.runtimeShell}
+
+ ED25519_KEY="/etc/ssh/ssh_host_ed25519_key"
+
+ if [ ! -f $ED25519_KEY ]; then
+ ${pkgs.openssh}/bin/ssh-keygen -t ed25519 -f $ED25519_KEY -N ""
+ fi
+
${lib.optionalString config.not-os.simpleStaticIp ''
ip addr add 10.0.2.15 dev eth0
ip link set eth0 up
diff --git a/ssh/ssh_host_ed25519_key b/ssh/ssh_host_ed25519_key
deleted file mode 100644
index 62f3b04..0000000
--- a/ssh/ssh_host_ed25519_key
+++ /dev/null
@@ -1,7 +0,0 @@
------BEGIN OPENSSH PRIVATE KEY-----
-b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
-QyNTUxOQAAACCyu5b2+49W47G9KYQj+7xz1YuY3w3Iz1kb/eIgNWPF7wAAAJhmBZVCZgWV
-QgAAAAtzc2gtZWQyNTUxOQAAACCyu5b2+49W47G9KYQj+7xz1YuY3w3Iz1kb/eIgNWPF7w
-AAAEBALOVU4aPZln0n7z7AR5jOoVnT7OhWAJiROqTw9ecEILK7lvb7j1bjsb0phCP7vHPV
-i5jfDcjPWRv94iA1Y8XvAAAAEGNsZXZlckBhbWQtbml4b3MBAgMEBQ==
------END OPENSSH PRIVATE KEY-----
diff --git a/ssh/ssh_host_ed25519_key.pub b/ssh/ssh_host_ed25519_key.pub
deleted file mode 100644
index c636ae4..0000000
--- a/ssh/ssh_host_ed25519_key.pub
+++ /dev/null
@@ -1 +0,0 @@
-ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILK7lvb7j1bjsb0phCP7vHPVi5jfDcjPWRv94iA1Y8Xv clever@amd-nixos
diff --git a/ssh/ssh_host_rsa_key b/ssh/ssh_host_rsa_key
deleted file mode 100644
index d9c3b46..0000000
--- a/ssh/ssh_host_rsa_key
+++ /dev/null
@@ -1,51 +0,0 @@
------BEGIN RSA PRIVATE KEY-----
-MIIJKAIBAAKCAgEAxTB2amEQdRnxKKoTpm81Eydd0gSgiotd0Ujeg+eEkArLwlWv
-6gjoeNEzcNH8tZ0g3sjk1SVheZNxdHWCXqJnL/EIpoGn8VNW7pgRP1ZgW48wPjJ7
-dN8eve/28d2QCDYEkZNDTjHzDEHP/TxngjA6lli0KX6SfJbKUmqR/kdn8A5NpsjM
-BmjQ/UkMTAH/KG3HhSHRoljHFsyfKw917a3uO9ahLiEnFih36/V9anjljboEZAux
-XKNFUJFWkn+QPGLnPQtrP85ZUtSEFiwjOCcjCctps+miRJwZsNHE2erqelJbJb7v
-Cq+paoffxc27U7dhvLoz2f9XalW4Sj8mL45kyysrN4WBSDxi1znPjxD6PuNsabCe
-TBisHj2M09Zv7hZIoR53Jv6cjwZoML5MN6VA2yc/OAoYvDAJET/ZRPkl8tzzvMXo
-Y+bfyUitYA3FJjBInFm+mmVkHTqi/V7SwFKWGXRhAO2JU0cUXUrDyI7OKnNS4Vue
-h5O7UHGhtBvoFLDpkr9GJwNJNZXtNdK77eQXPDkv0k2qQcLZQLGRR4hBTIL9GAgE
-3nlCGs6bNw+OgaiWMqcLwoe8IBeq0WDrjRDEuyoIOREAQYZ0twYrhvT5rLXhz9IJ
-nUyn7P7uX4/i2tDWy3iPHJHNtFSD2lLA+xuXA6xoW1REfL3lCpIHZtpopP8CAwEA
-AQKCAgEAjbNYtPNRd0UQJq+pdUWe90enxP8sOsMRxQ4/ULxzZ2tKpzkaM+z42bFD
-7QQJPJ1QfKgSwRSeqlYJBq5W5BiCXFIybCzp+aJw6v3+DuzMS59nBJsUWpTnq4gg
-hgg4s53VxKL1j+CXDqzQgOMCYuyzfUz7EoJxU/SsKXOJvBemGjy9EmhjLQvvesQe
-gRRCPtQ8t2/pDGgNkVWz36a5kPYXJ4sBwntychrcqoR7/qIoG6Ob+iTo7HArpEz8
-0EO465wLHbPx+yUWzU4IKULIgFaneCdjqzTuNa2TTJxBgHOu0f4Sn9pIPv6imPpR
-FPzVa8BxDMUl87bpI3G8ACbHEw+ZX52wxC5/149ofu9jxBiGxODsmCGullIsGnEH
-F0PhA2kJzzb/MPcfZRGTvp0kbP9i3DM1yTa2vLSWT2hCi94zpRRiWMgN4azwvQeA
-o/KLlQ78hRu8wdJ5lwn5/iDpDr13TN5cHc7uhf/bVdwOcS9uSMAZvdIqazThQhgy
-G3AF5oIg/8MYz/pGwZg4aUmLTXB8O/Xgqtj5yUduMxR/vChZiKWHNt6EWT1VMHKs
-ktVBiLUZvp8kfWqSNVcLjt7tI2+Dwy2hNIPpRXZOu7cSf0A0YsZlcB/MLWBKKtMk
-mnYL1+rFTuR9TB6YkmDWwRqTHTEtyaXPADRX9j8Y0kF0Qd0JATECggEBAPp1+P5m
-wWMn2xOuBb+Znv036O+NOnQ+OPP04lFXwSHUsR6BMPJDaA2B3n+15vGCxzMLNQsl
-qn44WiUm2hv8BwO9DkFm/VpB9yj+30gnP6RXThPUsO6msN1XTa+F6GnnoJ8vRfnO
-9+iRU97Owwi8IGoHeVlsXRKhbi6cIJ0Y711b6uN97mBnOB+ig0F7L2lHrRRVYO3R
-SPpvZunsksZEoxdNGM4qTbhVjFve1gXWHNzzqDGzCqwnPWynVE8jEjM3jEp5GRKo
-jIEEN4k1SBI5Ovou07qogLgtsZnudxlJCDSgLITlJbCMwluZ+sjpxu6GIZrbNtYt
-yaCS+wwMvZYuWbcCggEBAMmM4kv2Na9Y272/oRIh5J14op4qMBWOqjXTdAX0WhrD
-ay/+s77t6Gq/oMgmulqQLLgZcGkrz7Z8DWfdNoSxZvQQcftr3CHrgRiZvyFzvhRN
-bnk3vTAT1Ay1nRFOmHsciOGVI8EijRVIunFJu2r4aIfQ6RUpBV16RwMk9CYjYcA1
-DAYc+IEDfH9SFmWAkO2/X9Gv7616fvAQsIjT+lSTkM6SPpvvwW7g/X3sM138ATJm
-8EcBbT7NvTmGbVSDYhzSyPc/DfZXnNhSMXPZrbwRJQNhUzL26TsOJUCzzD9yhwAC
-JTOON3VBqE3IRlKVlts5bghDcCxxFVK87U2pR6BvrvkCggEAWmTboc2qPEQ1MEwd
-bQJfvFpCarrY/v06Buo6CEuYu8IMzsqnxLgJRN67U/Jt0Hp3tHd2BHjqqLVj64az
-L2hti67fB0HJbJrkPlqGcX8g3ApadpPL68YjjS8mLZQxxo8/jFQ+eCN3m+tfjsmm
-4G8tb7cU1+5hRQkYQCA/MRO/yD0VcFeSAh8exWQc5TQ1b1TcJbuOySZApYoxZXnp
-mz9IcW905WulM0NE7h9ltSOKtUAHUzCgSHO9Gorlxc4NkoiYzIQaRX6pfyLrfEzL
-nzAilgryhaqtEkwDjl/fgjO2j2/DwY8GZErZFsBjH8In9wxX8pDtoK1T2O1TSA0N
-G7fMzwKCAQA1omgWDs76eor/U59pU9uijBe6Pz/MfMqOyFZ3vy67MIW1n/H1PRo8
-TgJbQPMWZod/9kUTt7TuutRWb2eyqALdsAKlBW7vF9yiz0ctf791Z6WeXFbcFGq5
-dxr1IBUzrcQ/Q5DgNHGW2GPFAfn93Vzzx4Q/PUtQNNnw3EScYY4BuBwbBFqc+nCG
-8TFEkZH/so2tH0SIxbBB8i8IOmDDYQGH9yLyHDs9ZmIOwGxq9kTbRMlsG9UWgWl5
-hWxSsSPKx8zy/rSYeXgjmLvQOH0jLuzKmXuqdEpcjMcdELupprCGMAv2TEI10eMX
-z9Pm5ife7sl5KXkQWodyHRSJNiL5br8BAoIBADu7tRChFC5oplnjQ2LYNbS58pv3
-+44RLBe6pZjiHTo9lSRmS+ymRrVoGyJWHEsS1eWjYZseuLjgQ0GuegF7fpeqqIST
-gXRaJ3OkjBWXtSNt48zsaWUMUO6qI8V7viMmxnzWskELaoHJTmOQSUXS9/L0/MFz
-1vhe6VN+xxlb0+x2if326RGJBIrDwInnTcMoIT0kPo1t9HWvs1pO29Qkg3Zellmg
-iEarmJVdr9WO26j72e1IYBauorVQHG9rqdv6YOdtvqKSqqh/Axm3G2HAXKJd7s9T
-FZYTE/OZsUWzEbRv73ZbzDFhva3BbHAHV71y4Uyllk85/PQ5qXISkf84gM4=
------END RSA PRIVATE KEY-----
diff --git a/ssh/ssh_host_rsa_key.pub b/ssh/ssh_host_rsa_key.pub
deleted file mode 100644
index 63dbd02..0000000
--- a/ssh/ssh_host_rsa_key.pub
+++ /dev/null
@@ -1 +0,0 @@
-ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDFMHZqYRB1GfEoqhOmbzUTJ13SBKCKi13RSN6D54SQCsvCVa/qCOh40TNw0fy1nSDeyOTVJWF5k3F0dYJeomcv8QimgafxU1bumBE/VmBbjzA+Mnt03x697/bx3ZAINgSRk0NOMfMMQc/9PGeCMDqWWLQpfpJ8lspSapH+R2fwDk2myMwGaND9SQxMAf8obceFIdGiWMcWzJ8rD3Xtre471qEuIScWKHfr9X1qeOWNugRkC7Fco0VQkVaSf5A8Yuc9C2s/zllS1IQWLCM4JyMJy2mz6aJEnBmw0cTZ6up6Ulslvu8Kr6lqh9/FzbtTt2G8ujPZ/1dqVbhKPyYvjmTLKys3hYFIPGLXOc+PEPo+42xpsJ5MGKwePYzT1m/uFkihHncm/pyPBmgwvkw3pUDbJz84Chi8MAkRP9lE+SXy3PO8xehj5t/JSK1gDcUmMEicWb6aZWQdOqL9XtLAUpYZdGEA7YlTRxRdSsPIjs4qc1LhW56Hk7tQcaG0G+gUsOmSv0YnA0k1le010rvt5Bc8OS/STapBwtlAsZFHiEFMgv0YCATeeUIazps3D46BqJYypwvCh7wgF6rRYOuNEMS7Kgg5EQBBhnS3BiuG9PmsteHP0gmdTKfs/u5fj+La0NbLeI8ckc20VIPaUsD7G5cDrGhbVER8veUKkgdm2mik/w== clever@amd-nixos

View File

@ -0,0 +1,28 @@
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" ''

1105
not-os-patches/pr-33.patch Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,184 +0,0 @@
diff --git a/base.nix b/base.nix
index 7eaee32..f767d5e 100644
--- a/base.nix
+++ b/base.nix
@@ -27,6 +27,11 @@ with lib;
description = "enable rngd";
default = false;
};
+ not-os.sd = mkOption {
+ type = types.bool;
+ default = false;
+ description = "enable sd image support";
+ };
not-os.simpleStaticIp = mkOption {
type = types.bool;
default = false;
diff --git a/stage-1.nix b/stage-1.nix
index 331fecd..85fda30 100644
--- a/stage-1.nix
+++ b/stage-1.nix
@@ -164,7 +164,9 @@ let
mkdir -p /mnt/nix/store/
- ${if config.not-os.nix then ''
+ ${if config.not-os.sd && config.not-os.nix then ''
+ mount $root /mnt
+ '' else if config.not-os.nix then ''
# make the store writeable
mkdir -p /mnt/nix/.ro-store /mnt/nix/.overlay-store /mnt/nix/store
mount $root /mnt/nix/.ro-store -t squashfs
@@ -190,6 +192,11 @@ let
initialRamdisk = pkgs.makeInitrd {
contents = [ { object = bootStage1; symlink = "/init"; } ];
};
+ # Use for zynq_image
+ uRamdisk = pkgs.makeInitrd {
+ makeUInitrd = true;
+ contents = [ { object = bootStage1; symlink = "/init"; } ];
+ };
in
{
options = {
@@ -205,6 +212,7 @@ in
config = {
system.build.bootStage1 = bootStage1;
system.build.initialRamdisk = initialRamdisk;
+ system.build.uRamdisk = uRamdisk;
system.build.extraUtils = extraUtils;
boot.initrd.availableKernelModules = [ ];
boot.initrd.kernelModules = [ "tun" "loop" "squashfs" ] ++ (lib.optional config.not-os.nix "overlay");
diff --git a/stage-2.nix b/stage-2.nix
index c61f9d6..4e30d4b 100644
--- a/stage-2.nix
+++ b/stage-2.nix
@@ -21,6 +21,11 @@ with lib;
type = types.str;
};
};
+ networking.hostName = mkOption {
+ default = "";
+ type = types.strMatching
+ "^$|^[[:alnum:]]([[:alnum:]_-]{0,61}[[:alnum:]])?$";
+ };
};
config = {
system.build.bootStage2 = pkgs.substituteAll {
diff --git a/zynq_image.nix b/zynq_image.nix
index 3fa23ab..695d876 100644
--- a/zynq_image.nix
+++ b/zynq_image.nix
@@ -1,66 +1,63 @@
{ config, pkgs, ... }:
let
- # dont use overlays for the qemu, it causes a lot of wasted time on recompiles
- x86pkgs = import pkgs.path { system = "x86_64-linux"; };
- customKernel = pkgs.linux.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 = ''
OVERLAY_FS y
'';
- };
- customKernelPackages = pkgs.linuxPackagesFor customKernel;
+ }).overrideAttrs (oa: {
+ postInstall = ''
+ cp arch/arm/boot/uImage $out
+ ${oa.postInstall}
+ '';
+ });
+ customKernelPackages = crosspkgs.linuxPackagesFor customKernel;
in {
imports = [ ./arm32-cross-fixes.nix ];
boot.kernelPackages = customKernelPackages;
nixpkgs.system = "armv7l-linux";
- system.build.zynq_image = let
- cmdline = "root=/dev/mmcblk0 console=ttyPS0,115200n8 systemConfig=${builtins.unsafeDiscardStringContext config.system.build.toplevel}";
- qemuScript = ''
- #!/bin/bash -v
- export PATH=${x86pkgs.qemu}/bin:$PATH
- set -x
- base=$(dirname $0)
-
- cp $base/root.squashfs /tmp/
- chmod +w /tmp/root.squashfs
- truncate -s 64m /tmp/root.squashfs
-
- qemu-system-arm \
- -M xilinx-zynq-a9 \
- -serial /dev/null \
- -serial stdio \
- -display none \
- -dtb $base/zynq-zc702.dtb \
- -kernel $base/zImage \
- -initrd $base/initrd \
- -drive file=/tmp/root.squashfs,if=sd,format=raw \
- -append "${cmdline}"
- '';
- in pkgs.runCommand "zynq_image" {
- inherit qemuScript;
- passAsFile = [ "qemuScript" ];
+ networking.hostName = "zynq";
+ not-os.sd = true;
+ not-os.simpleStaticIp = true;
+ system.build.zynq_image = pkgs.runCommand "zynq_image" {
preferLocalBuild = true;
} ''
mkdir $out
cd $out
- cp -s ${config.system.build.squashfs} root.squashfs
- cp -s ${config.system.build.kernel}/*zImage .
- cp -s ${config.system.build.initialRamdisk}/initrd initrd
- cp -s ${config.system.build.kernel}/dtbs/zynq-zc702.dtb .
+ cp -s ${config.system.build.kernel}/uImage .
+ cp -s ${config.system.build.uRamdisk}/initrd uRamdisk.image.gz
+ cp -s ${config.system.build.kernel}/dtbs/zynq-zc706.dtb devicetree.dtb
ln -sv ${config.system.build.toplevel} toplevel
- cp $qemuScriptPath qemu-script
- chmod +x qemu-script
- patchShebangs qemu-script
- ls -ltrh
- '';
- system.build.rpi_image_tar = pkgs.runCommand "dist.tar" {} ''
- mkdir -p $out/nix-support
- tar -cvf $out/dist.tar ${config.system.build.rpi_image}
- echo "file binary-dist $out/dist.tar" >> $out/nix-support/hydra-build-products
'';
- environment.systemPackages = [ pkgs.strace ];
- environment.etc."service/getty/run".source = pkgs.writeShellScript "getty" ''
- agetty ttyPS0 115200
- '';
- environment.etc."pam.d/other".text = "";
+ environment = {
+ systemPackages = with pkgs; [ strace inetutils ];
+ etc = {
+ "service/getty/run".source = pkgs.writeShellScript "getty" ''
+ hostname ${config.networking.hostName}
+ agetty ttyPS0 115200
+ '';
+ "pam.d/other".text = ''
+ auth sufficient pam_permit.so
+ account required pam_permit.so
+ password required pam_permit.so
+ session optional pam_env.so
+ '';
+ "security/pam_env.conf".text = "";
+ };
+ };
}