forked from M-Labs/nix-servo
add fast-servo gateware support files
This commit is contained in:
parent
e4dcc0e84a
commit
cd9590503c
5
fast-servo/linien-gateware/README.md
Normal file
5
fast-servo/linien-gateware/README.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
## Source Repository
|
||||||
|
Files in this directory were copied from [elhep/Fast-Servo-Frimware](https://github.com/elhep/Fast-Servo-Firmware/tree/master/fast_servo/gateware).
|
||||||
|
|
||||||
|
## Commit ID
|
||||||
|
The files were copied from commit ID [7fae40c](https://github.com/elhep/Fast-Servo-Firmware/commit/7fae40c0f872a91218be378f8289b98b1e366729).
|
3
fast-servo/linien-gateware/__init__.py
Normal file
3
fast-servo/linien-gateware/__init__.py
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
|
verilog_dir = os.path.join(os.path.abspath(os.path.dirname(__file__)), "verilog")
|
0
fast-servo/linien-gateware/cores/__init__.py
Normal file
0
fast-servo/linien-gateware/cores/__init__.py
Normal file
179
fast-servo/linien-gateware/cores/adc.py
Normal file
179
fast-servo/linien-gateware/cores/adc.py
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
# This file is part of Fast Servo Software Package.
|
||||||
|
#
|
||||||
|
# Copyright (C) 2023 Jakub Matyas
|
||||||
|
# Warsaw University of Technology <jakubk.m@gmail.com>
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from migen import *
|
||||||
|
from migen.genlib.cdc import MultiReg
|
||||||
|
from misoc.interconnect.csr import AutoCSR, CSRStatus, CSRStorage
|
||||||
|
|
||||||
|
|
||||||
|
class _CRG(Module):
|
||||||
|
def __init__(self, platform, dco_clk, dco_freq=200e6):
|
||||||
|
self.clock_domains.cd_dco = ClockDomain()
|
||||||
|
self.clock_domains.cd_dco2x = ClockDomain()
|
||||||
|
self.clock_domains.cd_dco2d = ClockDomain()
|
||||||
|
dco_clk_p, dco_clk_n = dco_clk
|
||||||
|
|
||||||
|
dco_clk_buf = Signal()
|
||||||
|
self.specials += Instance(
|
||||||
|
"IBUFGDS", i_I=dco_clk_p, i_IB=dco_clk_n, o_O=dco_clk_buf
|
||||||
|
)
|
||||||
|
|
||||||
|
# # #
|
||||||
|
clk_feedback = Signal()
|
||||||
|
clk_feedback_buf = Signal()
|
||||||
|
|
||||||
|
clk_dco = Signal()
|
||||||
|
clk_dco2x = Signal()
|
||||||
|
clk_dco2d = Signal()
|
||||||
|
self.locked = Signal()
|
||||||
|
|
||||||
|
platform.add_period_constraint(dco_clk_p, 1e9 / dco_freq)
|
||||||
|
self.specials += [
|
||||||
|
Instance(
|
||||||
|
"PLLE2_BASE",
|
||||||
|
p_BANDWIDTH="OPTIMIZED",
|
||||||
|
p_DIVCLK_DIVIDE=1,
|
||||||
|
p_CLKFBOUT_PHASE=0.0,
|
||||||
|
p_CLKFBOUT_MULT=4, # VCO @ 800 MHz
|
||||||
|
p_CLKIN1_PERIOD=(1e9 / dco_freq),
|
||||||
|
p_REF_JITTER1=0.01,
|
||||||
|
p_STARTUP_WAIT="FALSE",
|
||||||
|
i_CLKIN1=dco_clk_buf,
|
||||||
|
i_PWRDWN=0,
|
||||||
|
i_RST=ResetSignal("sys"),
|
||||||
|
i_CLKFBIN=clk_feedback_buf,
|
||||||
|
o_CLKFBOUT=clk_feedback,
|
||||||
|
p_CLKOUT0_DIVIDE=4,
|
||||||
|
p_CLKOUT0_PHASE=0.0,
|
||||||
|
p_CLKOUT0_DUTY_CYCLE=0.5,
|
||||||
|
o_CLKOUT0=clk_dco, # 200 MHz <- dco_clk
|
||||||
|
p_CLKOUT1_DIVIDE=2,
|
||||||
|
p_CLKOUT1_PHASE=0.0,
|
||||||
|
p_CLKOUT1_DUTY_CYCLE=0.5,
|
||||||
|
o_CLKOUT1=clk_dco2x, # 400 MHZ <- 2 * dco_clk = 2*200 MHz
|
||||||
|
p_CLKOUT2_DIVIDE=8,
|
||||||
|
p_CLKOUT2_PHASE=0.0,
|
||||||
|
p_CLKOUT2_DUTY_CYCLE=0.5,
|
||||||
|
o_CLKOUT2=clk_dco2d, # 100 MHz <- dco_clk / 2 = 200 MHz / 2
|
||||||
|
o_LOCKED=self.locked,
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
self.specials += Instance("BUFG", i_I=clk_feedback, o_O=clk_feedback_buf)
|
||||||
|
self.specials += Instance("BUFG", i_I=clk_dco, o_O=self.cd_dco.clk)
|
||||||
|
self.specials += Instance("BUFG", i_I=clk_dco2d, o_O=self.cd_dco2d.clk)
|
||||||
|
self.specials += Instance("BUFG", i_I=clk_dco2x, o_O=self.cd_dco2x.clk)
|
||||||
|
|
||||||
|
|
||||||
|
class ADC(Module, AutoCSR):
|
||||||
|
def __init__(self, platform, dco_freq=200e6):
|
||||||
|
adc_pads = platform.request("adc")
|
||||||
|
afe_pads = platform.request("adc_afe")
|
||||||
|
|
||||||
|
self.frame_csr = CSRStatus(4)
|
||||||
|
self.data_ch0 = CSRStatus(16)
|
||||||
|
self.data_ch1 = CSRStatus(16)
|
||||||
|
|
||||||
|
self.tap_delay = CSRStorage(5)
|
||||||
|
self.bitslip_csr = CSRStorage(1)
|
||||||
|
|
||||||
|
self.afe_ctrl = CSRStorage(4)
|
||||||
|
|
||||||
|
tap_delay_val = Signal(5)
|
||||||
|
bitslip = Signal()
|
||||||
|
bitslip_re_dco_2d = Signal()
|
||||||
|
|
||||||
|
ch1_gain_x10 = Signal()
|
||||||
|
ch2_gain_x10 = Signal()
|
||||||
|
ch1_shdn = Signal()
|
||||||
|
ch2_shdn = Signal()
|
||||||
|
|
||||||
|
self.data_out = [Signal(16, reset_less=True), Signal(16, reset_less=True)]
|
||||||
|
self.s_frame = Signal(4)
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
# DCO clock coming from LTC2195
|
||||||
|
# dco_clk = Record([("p", 1), ("n", 1)])
|
||||||
|
dco_clk =(adc_pads.dco_p, adc_pads.dco_n)
|
||||||
|
self.comb += [
|
||||||
|
# dco_clk.p.eq(adc_pads.dco_p),
|
||||||
|
# dco_clk.n.eq(adc_pads.dco_n),
|
||||||
|
tap_delay_val.eq(self.tap_delay.storage),
|
||||||
|
Cat(ch1_gain_x10, ch2_gain_x10, ch1_shdn, ch2_shdn).eq(
|
||||||
|
self.afe_ctrl.storage
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
self.submodules._crg = _CRG(platform, dco_clk, dco_freq)
|
||||||
|
|
||||||
|
self.specials += MultiReg(self.bitslip_csr.re, bitslip_re_dco_2d, "dco2d")
|
||||||
|
self.sync.dco2d += [
|
||||||
|
bitslip.eq(Mux(bitslip_re_dco_2d, self.bitslip_csr.storage, 0))
|
||||||
|
]
|
||||||
|
|
||||||
|
self.comb += [
|
||||||
|
self.frame_csr.status.eq(self.s_frame),
|
||||||
|
self.data_ch0.status.eq(self.data_out[0]),
|
||||||
|
self.data_ch1.status.eq(self.data_out[1]),
|
||||||
|
]
|
||||||
|
|
||||||
|
self.comb += [
|
||||||
|
afe_pads.ch1_gain.eq(ch1_gain_x10),
|
||||||
|
afe_pads.ch2_gain.eq(ch2_gain_x10),
|
||||||
|
afe_pads.nshdn_ch1.eq(~ch1_shdn),
|
||||||
|
afe_pads.nshdn_ch2.eq(~ch2_shdn),
|
||||||
|
]
|
||||||
|
|
||||||
|
dummy = Signal(8)
|
||||||
|
dummy_idelay_rdy = Signal()
|
||||||
|
|
||||||
|
self.specials += Instance(
|
||||||
|
"LTC2195",
|
||||||
|
i_rst_in=ResetSignal("sys"),
|
||||||
|
i_clk200=ClockSignal("idelay"),
|
||||||
|
i_DCO=ClockSignal("dco"),
|
||||||
|
i_DCO_2D=ClockSignal("dco2d"),
|
||||||
|
i_FR_in_p=adc_pads.frame_p,
|
||||||
|
i_FR_in_n=adc_pads.frame_n,
|
||||||
|
i_D0_in_p=adc_pads.data0_p,
|
||||||
|
i_D0_in_n=adc_pads.data0_n,
|
||||||
|
i_D1_in_p=adc_pads.data1_p,
|
||||||
|
i_D1_in_n=adc_pads.data1_n,
|
||||||
|
i_bitslip=bitslip,
|
||||||
|
i_delay_val=tap_delay_val,
|
||||||
|
o_ADC0_out=self.data_out[1], # LANES swapped on hardware
|
||||||
|
o_ADC1_out=self.data_out[0],
|
||||||
|
o_FR_out=self.s_frame,
|
||||||
|
o_o_data_from_pins=dummy,
|
||||||
|
o_idelay_rdy=dummy_idelay_rdy,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class AUX_ADC_CTRL(Module, AutoCSR):
|
||||||
|
def __init__(self, platform):
|
||||||
|
adc_aux_pads = platform.request("aux_adc")
|
||||||
|
|
||||||
|
self.adc_aux_ctrl = CSRStorage(5)
|
||||||
|
|
||||||
|
self.comb += [
|
||||||
|
adc_aux_pads.diff_n.eq(~self.adc_aux_ctrl.storage[0]),
|
||||||
|
adc_aux_pads.a.eq(self.adc_aux_ctrl.storage[1:4]),
|
||||||
|
adc_aux_pads.range.eq(self.adc_aux_ctrl.storage[4]),
|
||||||
|
]
|
84
fast-servo/linien-gateware/cores/dac.py
Normal file
84
fast-servo/linien-gateware/cores/dac.py
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
# This file is part of Fast Servo Software Package.
|
||||||
|
#
|
||||||
|
# Copyright (C) 2023 Jakub Matyas
|
||||||
|
# Warsaw University of Technology <jakubk.m@gmail.com>
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from migen import *
|
||||||
|
from misoc.interconnect.csr import AutoCSR, CSRStorage
|
||||||
|
from migen.genlib.io import DDROutput
|
||||||
|
|
||||||
|
|
||||||
|
class DAC(Module, AutoCSR):
|
||||||
|
def __init__(self, platform):
|
||||||
|
dac_pads = platform.request("dac")
|
||||||
|
dac_afe_pads = platform.request("dac_afe")
|
||||||
|
self.dac_ctrl = CSRStorage(3)
|
||||||
|
self.output_value_ch0 = CSRStorage(14)
|
||||||
|
self.output_value_ch1 = CSRStorage(14)
|
||||||
|
|
||||||
|
manual_override = Signal()
|
||||||
|
ch0_pd = Signal()
|
||||||
|
ch1_pd = Signal()
|
||||||
|
|
||||||
|
output_data_ch0 = Signal(14)
|
||||||
|
output_data_ch1 = Signal(14)
|
||||||
|
|
||||||
|
self.data_in = [Signal(14, reset_less=True), Signal(14, reset_less=True)]
|
||||||
|
platform.add_period_constraint(dac_pads.dclkio, 10.0)
|
||||||
|
|
||||||
|
self.comb += [
|
||||||
|
Cat(manual_override, ch0_pd, ch1_pd).eq(self.dac_ctrl.storage),
|
||||||
|
dac_pads.rst.eq(ResetSignal("sys")),
|
||||||
|
dac_afe_pads.ch1_pd_n.eq(~ch0_pd),
|
||||||
|
dac_afe_pads.ch2_pd_n.eq(~ch1_pd),
|
||||||
|
output_data_ch0.eq(
|
||||||
|
Mux(manual_override, self.output_value_ch0.storage, self.data_in[0])
|
||||||
|
),
|
||||||
|
output_data_ch1.eq(
|
||||||
|
Mux(manual_override, self.output_value_ch1.storage, self.data_in[1])
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
# data
|
||||||
|
for lane in range(14):
|
||||||
|
self.specials += DDROutput(
|
||||||
|
i1 = output_data_ch0[lane],
|
||||||
|
i2 = output_data_ch1[lane],
|
||||||
|
o = dac_pads.data[lane],
|
||||||
|
clk = ClockSignal("dco2d")
|
||||||
|
)
|
||||||
|
|
||||||
|
# clock forwarding
|
||||||
|
self.specials += DDROutput(
|
||||||
|
i1 = 0b0,
|
||||||
|
i2 = 0b1,
|
||||||
|
o = dac_pads.dclkio,
|
||||||
|
clk = ClockSignal("dco2d"),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class AUX_DAC_CTRL(Module, AutoCSR):
|
||||||
|
def __init__(self, platform):
|
||||||
|
dac_aux_pads = platform.request("aux_dac")
|
||||||
|
|
||||||
|
self.dac_aux_ctrl = CSRStorage(3)
|
||||||
|
|
||||||
|
self.comb += [
|
||||||
|
dac_aux_pads.nclr.eq(~self.dac_aux_ctrl.storage[0]),
|
||||||
|
dac_aux_pads.bin.eq(self.dac_aux_ctrl.storage[1]),
|
||||||
|
dac_aux_pads.nldac.eq(~self.dac_aux_ctrl.storage[2]),
|
||||||
|
]
|
385
fast-servo/linien-gateware/cores/pitaya_ps.py
Normal file
385
fast-servo/linien-gateware/cores/pitaya_ps.py
Normal file
@ -0,0 +1,385 @@
|
|||||||
|
# Copyright 2014-2015 Robert Jördens <jordens@gmail.com>
|
||||||
|
# Copyright 2018-2022 Benjamin Wiegand <benjamin.wiegand@physik.hu-berlin.de>
|
||||||
|
# Copyright 2021-2022 Bastian Leykauf <leykauf@physik.hu-berlin.de>
|
||||||
|
# Copyright 2023 Jakub Matyas
|
||||||
|
# Warsaw University of Technology <jakubk.m@gmail.com>
|
||||||
|
#
|
||||||
|
# This file is part of Fast Servo Software Package and is based on Linien.
|
||||||
|
#
|
||||||
|
# Linien is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Linien is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with Linien. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from functools import reduce
|
||||||
|
from operator import or_
|
||||||
|
|
||||||
|
from migen import (
|
||||||
|
DIR_M_TO_S,
|
||||||
|
DIR_S_TO_M,
|
||||||
|
Cat,
|
||||||
|
ClockSignal,
|
||||||
|
If,
|
||||||
|
Instance,
|
||||||
|
Module,
|
||||||
|
Record,
|
||||||
|
Replicate,
|
||||||
|
ResetSignal,
|
||||||
|
Signal,
|
||||||
|
)
|
||||||
|
from misoc.interconnect import csr_bus, wishbone
|
||||||
|
|
||||||
|
sys_layout = [
|
||||||
|
("rstn", 1, DIR_M_TO_S),
|
||||||
|
("clk", 1, DIR_M_TO_S),
|
||||||
|
("addr", 32, DIR_M_TO_S),
|
||||||
|
("wdata", 32, DIR_M_TO_S),
|
||||||
|
("sel", 4, DIR_M_TO_S),
|
||||||
|
("wen", 1, DIR_M_TO_S),
|
||||||
|
("ren", 1, DIR_M_TO_S),
|
||||||
|
("rdata", 32, DIR_S_TO_M),
|
||||||
|
("err", 1, DIR_S_TO_M),
|
||||||
|
("ack", 1, DIR_S_TO_M),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
axi_layout = [
|
||||||
|
("arvalid", 1),
|
||||||
|
("awvalid", 1),
|
||||||
|
("bready", 1),
|
||||||
|
("rready", 1),
|
||||||
|
("wlast", 1),
|
||||||
|
("wvalid", 1),
|
||||||
|
("arid", 12),
|
||||||
|
("awid", 12),
|
||||||
|
("wid", 12),
|
||||||
|
("arburst", 2),
|
||||||
|
("arlock", 2),
|
||||||
|
("arsize", 3),
|
||||||
|
("awburst", 2),
|
||||||
|
("awlock", 2),
|
||||||
|
("awsize", 3),
|
||||||
|
("arprot", 3),
|
||||||
|
("awprot", 3),
|
||||||
|
("araddr", 32),
|
||||||
|
("awaddr", 32),
|
||||||
|
("wdata", 32),
|
||||||
|
("arcache", 4),
|
||||||
|
("arlen", 4),
|
||||||
|
("arqos", 4),
|
||||||
|
("awcache", 4),
|
||||||
|
("awlen", 4),
|
||||||
|
("awqos", 4),
|
||||||
|
("wstrb", 4),
|
||||||
|
("aclk", 1),
|
||||||
|
("arready", 1),
|
||||||
|
("awready", 1),
|
||||||
|
("bvalid", 1),
|
||||||
|
("rlast", 1),
|
||||||
|
("rvalid", 1),
|
||||||
|
("wready", 1),
|
||||||
|
("bid", 12),
|
||||||
|
("rid", 12),
|
||||||
|
("bresp", 2),
|
||||||
|
("rresp", 2),
|
||||||
|
("rdata", 32),
|
||||||
|
("arstn", 1),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class PitayaPS(Module):
|
||||||
|
def __init__(self, cpu):
|
||||||
|
self.fclk = Signal(4)
|
||||||
|
self.frstn = Signal(4)
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
self.submodules.axi = Axi2Sys()
|
||||||
|
axi = self.axi.axi
|
||||||
|
self.comb += [
|
||||||
|
axi.aclk.eq(self.fclk[0]),
|
||||||
|
axi.arstn.eq(self.frstn[0]),
|
||||||
|
]
|
||||||
|
|
||||||
|
self.specials += Instance(
|
||||||
|
"system_processing_system7_0_0",
|
||||||
|
io_MIO=cpu.mio,
|
||||||
|
io_PS_CLK=cpu.ps_clk,
|
||||||
|
io_PS_PORB=cpu.ps_porb,
|
||||||
|
io_PS_SRSTB=cpu.ps_srstb,
|
||||||
|
io_DDR_Addr=cpu.DDR_addr,
|
||||||
|
io_DDR_BankAddr=cpu.DDR_ba,
|
||||||
|
io_DDR_CAS_n=cpu.DDR_cas_n,
|
||||||
|
io_DDR_Clk_n=cpu.DDR_ck_n,
|
||||||
|
io_DDR_Clk=cpu.DDR_ck_p,
|
||||||
|
io_DDR_CKE=cpu.DDR_cke,
|
||||||
|
io_DDR_CS_n=cpu.DDR_cs_n,
|
||||||
|
io_DDR_DM=cpu.DDR_dm,
|
||||||
|
io_DDR_DQ=cpu.DDR_dq,
|
||||||
|
io_DDR_DQS_n=cpu.DDR_dqs_n,
|
||||||
|
io_DDR_DQS=cpu.DDR_dqs_p,
|
||||||
|
io_DDR_ODT=cpu.DDR_odt,
|
||||||
|
io_DDR_RAS_n=cpu.DDR_ras_n,
|
||||||
|
io_DDR_DRSTB=cpu.DDR_reset_n,
|
||||||
|
io_DDR_WEB=cpu.DDR_we_n,
|
||||||
|
io_DDR_VRN=cpu.ddr_vrn,
|
||||||
|
io_DDR_VRP=cpu.ddr_vrp,
|
||||||
|
o_FCLK_CLK0=self.fclk[0],
|
||||||
|
o_FCLK_CLK1=self.fclk[1],
|
||||||
|
o_FCLK_CLK2=self.fclk[2],
|
||||||
|
o_FCLK_CLK3=self.fclk[3],
|
||||||
|
o_FCLK_RESET0_N=self.frstn[0],
|
||||||
|
o_FCLK_RESET1_N=self.frstn[1],
|
||||||
|
o_FCLK_RESET2_N=self.frstn[2],
|
||||||
|
o_FCLK_RESET3_N=self.frstn[3],
|
||||||
|
i_M_AXI_GP0_ACLK=axi.aclk,
|
||||||
|
o_M_AXI_GP0_ARVALID=axi.arvalid,
|
||||||
|
o_M_AXI_GP0_AWVALID=axi.awvalid,
|
||||||
|
o_M_AXI_GP0_BREADY=axi.bready,
|
||||||
|
o_M_AXI_GP0_RREADY=axi.rready,
|
||||||
|
o_M_AXI_GP0_WLAST=axi.wlast,
|
||||||
|
o_M_AXI_GP0_WVALID=axi.wvalid,
|
||||||
|
o_M_AXI_GP0_ARID=axi.arid,
|
||||||
|
o_M_AXI_GP0_AWID=axi.awid,
|
||||||
|
o_M_AXI_GP0_WID=axi.wid,
|
||||||
|
o_M_AXI_GP0_ARBURST=axi.arburst,
|
||||||
|
o_M_AXI_GP0_ARLOCK=axi.arlock,
|
||||||
|
o_M_AXI_GP0_ARSIZE=axi.arsize,
|
||||||
|
o_M_AXI_GP0_AWBURST=axi.awburst,
|
||||||
|
o_M_AXI_GP0_AWLOCK=axi.awlock,
|
||||||
|
o_M_AXI_GP0_AWSIZE=axi.awsize,
|
||||||
|
o_M_AXI_GP0_ARPROT=axi.arprot,
|
||||||
|
o_M_AXI_GP0_AWPROT=axi.awprot,
|
||||||
|
o_M_AXI_GP0_ARADDR=axi.araddr,
|
||||||
|
o_M_AXI_GP0_AWADDR=axi.awaddr,
|
||||||
|
o_M_AXI_GP0_WDATA=axi.wdata,
|
||||||
|
o_M_AXI_GP0_ARCACHE=axi.arcache,
|
||||||
|
o_M_AXI_GP0_ARLEN=axi.arlen,
|
||||||
|
o_M_AXI_GP0_ARQOS=axi.arqos,
|
||||||
|
o_M_AXI_GP0_AWCACHE=axi.awcache,
|
||||||
|
o_M_AXI_GP0_AWLEN=axi.awlen,
|
||||||
|
o_M_AXI_GP0_AWQOS=axi.awqos,
|
||||||
|
o_M_AXI_GP0_WSTRB=axi.wstrb,
|
||||||
|
i_M_AXI_GP0_ARREADY=axi.arready,
|
||||||
|
i_M_AXI_GP0_AWREADY=axi.awready,
|
||||||
|
i_M_AXI_GP0_BVALID=axi.bvalid,
|
||||||
|
i_M_AXI_GP0_RLAST=axi.rlast,
|
||||||
|
i_M_AXI_GP0_RVALID=axi.rvalid,
|
||||||
|
i_M_AXI_GP0_WREADY=axi.wready,
|
||||||
|
i_M_AXI_GP0_BID=axi.bid,
|
||||||
|
i_M_AXI_GP0_RID=axi.rid,
|
||||||
|
i_M_AXI_GP0_BRESP=axi.bresp,
|
||||||
|
i_M_AXI_GP0_RRESP=axi.rresp,
|
||||||
|
i_M_AXI_GP0_RDATA=axi.rdata,
|
||||||
|
i_SPI0_SS_I=0,
|
||||||
|
# i_SPI0_SS_I=spi.ss_i,
|
||||||
|
# o_SPI0_SS_O=spi.ss_o,
|
||||||
|
# o_SPI0_SS_T=spi.ss_t,
|
||||||
|
# o_SPI0_SS1_O=spi.ss1_o,
|
||||||
|
# o_SPI0_SS2_O=spi.ss2_o,
|
||||||
|
i_SPI0_SCLK_I=0,
|
||||||
|
# i_SPI0_SCLK_I=spi.sclk_i,
|
||||||
|
# o_SPI0_SCLK_O=spi.sclk_o,
|
||||||
|
# o_SPI0_SCLK_T=spi.sclk_t,
|
||||||
|
i_SPI0_MOSI_I=0,
|
||||||
|
# i_SPI0_MOSI_I=spi.mosi_i,
|
||||||
|
# o_SPI0_MOSI_O=spi.mosi_o,
|
||||||
|
# o_SPI0_MOSI_T=spi.mosi_t,
|
||||||
|
i_SPI0_MISO_I=0,
|
||||||
|
# i_SPI0_MISO_I=spi.miso_i,
|
||||||
|
# o_SPI0_MISO_O=spi.miso_o,
|
||||||
|
# o_SPI0_MISO_T=spi.miso_t,
|
||||||
|
i_USB0_VBUS_PWRFAULT=0,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class Axi2Sys(Module):
|
||||||
|
def __init__(self):
|
||||||
|
self.sys = Record(sys_layout)
|
||||||
|
self.axi = Record(axi_layout)
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
self.comb += [self.sys.clk.eq(self.axi.aclk), self.sys.rstn.eq(self.axi.arstn)]
|
||||||
|
|
||||||
|
self.specials += Instance(
|
||||||
|
"axi_slave",
|
||||||
|
p_AXI_DW=32,
|
||||||
|
p_AXI_AW=32,
|
||||||
|
p_AXI_IW=12,
|
||||||
|
i_axi_clk_i=self.axi.aclk,
|
||||||
|
i_axi_rstn_i=self.axi.arstn,
|
||||||
|
i_axi_awid_i=self.axi.awid,
|
||||||
|
i_axi_awaddr_i=self.axi.awaddr,
|
||||||
|
i_axi_awlen_i=self.axi.awlen,
|
||||||
|
i_axi_awsize_i=self.axi.awsize,
|
||||||
|
i_axi_awburst_i=self.axi.awburst,
|
||||||
|
i_axi_awlock_i=self.axi.awlock,
|
||||||
|
i_axi_awcache_i=self.axi.awcache,
|
||||||
|
i_axi_awprot_i=self.axi.awprot,
|
||||||
|
i_axi_awvalid_i=self.axi.awvalid,
|
||||||
|
o_axi_awready_o=self.axi.awready,
|
||||||
|
i_axi_wid_i=self.axi.wid,
|
||||||
|
i_axi_wdata_i=self.axi.wdata,
|
||||||
|
i_axi_wstrb_i=self.axi.wstrb,
|
||||||
|
i_axi_wlast_i=self.axi.wlast,
|
||||||
|
i_axi_wvalid_i=self.axi.wvalid,
|
||||||
|
o_axi_wready_o=self.axi.wready,
|
||||||
|
o_axi_bid_o=self.axi.bid,
|
||||||
|
o_axi_bresp_o=self.axi.bresp,
|
||||||
|
o_axi_bvalid_o=self.axi.bvalid,
|
||||||
|
i_axi_bready_i=self.axi.bready,
|
||||||
|
i_axi_arid_i=self.axi.arid,
|
||||||
|
i_axi_araddr_i=self.axi.araddr,
|
||||||
|
i_axi_arlen_i=self.axi.arlen,
|
||||||
|
i_axi_arsize_i=self.axi.arsize,
|
||||||
|
i_axi_arburst_i=self.axi.arburst,
|
||||||
|
i_axi_arlock_i=self.axi.arlock,
|
||||||
|
i_axi_arcache_i=self.axi.arcache,
|
||||||
|
i_axi_arprot_i=self.axi.arprot,
|
||||||
|
i_axi_arvalid_i=self.axi.arvalid,
|
||||||
|
o_axi_arready_o=self.axi.arready,
|
||||||
|
o_axi_rid_o=self.axi.rid,
|
||||||
|
o_axi_rdata_o=self.axi.rdata,
|
||||||
|
o_axi_rresp_o=self.axi.rresp,
|
||||||
|
o_axi_rlast_o=self.axi.rlast,
|
||||||
|
o_axi_rvalid_o=self.axi.rvalid,
|
||||||
|
i_axi_rready_i=self.axi.rready,
|
||||||
|
o_sys_addr_o=self.sys.addr,
|
||||||
|
o_sys_wdata_o=self.sys.wdata,
|
||||||
|
o_sys_sel_o=self.sys.sel,
|
||||||
|
o_sys_wen_o=self.sys.wen,
|
||||||
|
o_sys_ren_o=self.sys.ren,
|
||||||
|
i_sys_rdata_i=self.sys.rdata,
|
||||||
|
i_sys_err_i=self.sys.err,
|
||||||
|
i_sys_ack_i=self.sys.ack,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class SysInterconnect(Module):
|
||||||
|
def __init__(self, master, *slaves):
|
||||||
|
cs = Signal(max=len(slaves)) if len(slaves) != 1 else Signal()
|
||||||
|
self.comb += cs.eq(master.addr[20:23])
|
||||||
|
rets = []
|
||||||
|
for i, s in enumerate(slaves):
|
||||||
|
sel = Signal()
|
||||||
|
self.comb += [
|
||||||
|
sel.eq(cs == i),
|
||||||
|
s.clk.eq(master.clk),
|
||||||
|
s.rstn.eq(master.rstn),
|
||||||
|
s.addr.eq(master.addr),
|
||||||
|
s.wdata.eq(master.wdata),
|
||||||
|
s.sel.eq(master.sel),
|
||||||
|
s.wen.eq(sel & master.wen),
|
||||||
|
s.ren.eq(sel & master.ren),
|
||||||
|
]
|
||||||
|
ret = Cat(s.err, s.ack, s.rdata)
|
||||||
|
rets.append(Replicate(sel, len(ret)) & ret)
|
||||||
|
self.comb += Cat(master.err, master.ack, master.rdata).eq(reduce(or_, rets))
|
||||||
|
|
||||||
|
|
||||||
|
class Sys2Wishbone(Module):
|
||||||
|
def __init__(self):
|
||||||
|
self.wishbone = wb = wishbone.Interface()
|
||||||
|
self.sys = sys = Record(sys_layout)
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
sys2 = Record(sys_layout)
|
||||||
|
|
||||||
|
self.specials += Instance(
|
||||||
|
"bus_clk_bridge",
|
||||||
|
i_sys_clk_i=sys.clk,
|
||||||
|
i_sys_rstn_i=sys.rstn,
|
||||||
|
i_sys_addr_i=sys.addr,
|
||||||
|
i_sys_wdata_i=sys.wdata,
|
||||||
|
i_sys_sel_i=sys.sel,
|
||||||
|
i_sys_wen_i=sys.wen,
|
||||||
|
i_sys_ren_i=sys.ren,
|
||||||
|
o_sys_rdata_o=sys.rdata,
|
||||||
|
o_sys_err_o=sys.err,
|
||||||
|
o_sys_ack_o=sys.ack,
|
||||||
|
i_clk_i=ClockSignal(),
|
||||||
|
i_rstn_i=~ResetSignal(),
|
||||||
|
o_addr_o=sys2.addr,
|
||||||
|
o_wen_o=sys2.wen,
|
||||||
|
o_ren_o=sys2.ren,
|
||||||
|
o_wdata_o=sys2.wdata,
|
||||||
|
i_rdata_i=sys2.rdata,
|
||||||
|
i_err_i=sys2.err,
|
||||||
|
i_ack_i=sys2.ack,
|
||||||
|
)
|
||||||
|
self.sync += [
|
||||||
|
If(
|
||||||
|
sys2.ren | sys2.wen,
|
||||||
|
wb.cyc.eq(1),
|
||||||
|
wb.adr.eq(sys2.addr[2:]),
|
||||||
|
wb.we.eq(sys2.wen),
|
||||||
|
wb.dat_w.eq(sys2.wdata),
|
||||||
|
).Elif(wb.ack, wb.cyc.eq(0))
|
||||||
|
]
|
||||||
|
self.comb += [
|
||||||
|
wb.stb.eq(wb.cyc),
|
||||||
|
sys2.rdata.eq(wb.dat_r),
|
||||||
|
sys2.ack.eq(wb.ack),
|
||||||
|
sys2.err.eq(wb.err),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class SysCDC(Module):
|
||||||
|
def __init__(self, cd_target="sys"):
|
||||||
|
self.source = Record(sys_layout)
|
||||||
|
self.target = Record(sys_layout)
|
||||||
|
|
||||||
|
self.specials += Instance(
|
||||||
|
"bus_clk_bridge",
|
||||||
|
i_sys_clk_i=self.source.clk,
|
||||||
|
i_sys_rstn_i=self.source.rstn,
|
||||||
|
i_sys_addr_i=self.source.addr,
|
||||||
|
i_sys_wdata_i=self.source.wdata,
|
||||||
|
i_sys_sel_i=self.source.sel,
|
||||||
|
i_sys_wen_i=self.source.wen,
|
||||||
|
i_sys_ren_i=self.source.ren,
|
||||||
|
o_sys_rdata_o=self.source.rdata,
|
||||||
|
o_sys_err_o=self.source.err,
|
||||||
|
o_sys_ack_o=self.source.ack,
|
||||||
|
i_clk_i=self.target.clk,
|
||||||
|
i_rstn_i=self.target.rstn,
|
||||||
|
o_addr_o=self.target.addr,
|
||||||
|
o_wdata_o=self.target.wdata,
|
||||||
|
o_wen_o=self.target.wen,
|
||||||
|
o_ren_o=self.target.ren,
|
||||||
|
i_rdata_i=self.target.rdata,
|
||||||
|
i_err_i=self.target.err,
|
||||||
|
i_ack_i=self.target.ack,
|
||||||
|
)
|
||||||
|
self.comb += [
|
||||||
|
self.target.clk.eq(ClockSignal(cd_target)),
|
||||||
|
self.target.rstn.eq(~ResetSignal(cd_target)),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class Sys2CSR(Module):
|
||||||
|
def __init__(self):
|
||||||
|
self.csr = csr_bus.Interface()
|
||||||
|
self.sys = Record(sys_layout)
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
stb = Signal()
|
||||||
|
self.sync += [
|
||||||
|
stb.eq(self.sys.wen | self.sys.ren),
|
||||||
|
self.csr.adr.eq(self.sys.addr[2:]),
|
||||||
|
self.csr.we.eq(self.sys.wen),
|
||||||
|
self.csr.dat_w.eq(self.sys.wdata),
|
||||||
|
self.sys.ack.eq(stb),
|
||||||
|
self.sys.rdata.eq(self.csr.dat_r),
|
||||||
|
]
|
193
fast-servo/linien-gateware/cores/ps7.py
Normal file
193
fast-servo/linien-gateware/cores/ps7.py
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
# This file is part of Fast Servo Software Package.
|
||||||
|
#
|
||||||
|
# Copyright (C) 2023 Jakub Matyas
|
||||||
|
# Warsaw University of Technology <jakubk.m@gmail.com>
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from migen import *
|
||||||
|
|
||||||
|
|
||||||
|
class PS7(Module):
|
||||||
|
def __init__(self, platform, ps7_name=None):
|
||||||
|
self.frstn = Signal()
|
||||||
|
self.ps7_tcl = []
|
||||||
|
self.platform = platform
|
||||||
|
|
||||||
|
self.ps7_name = "Zynq" if ps7_name is None else ps7_name
|
||||||
|
|
||||||
|
ps7_clk = platform.request("ps7_clk")
|
||||||
|
ps7_porb = platform.request("ps7_porb")
|
||||||
|
ps7_srstb = platform.request("ps7_srstb")
|
||||||
|
ps7_mio = platform.request("ps7_mio")
|
||||||
|
ps7_ddram = platform.request("ps7_ddram")
|
||||||
|
|
||||||
|
self.cpu_params = dict(
|
||||||
|
# Clk / Rst.
|
||||||
|
io_PS_CLK = ps7_clk,
|
||||||
|
io_PS_PORB = ps7_porb,
|
||||||
|
io_PS_SRSTB = ps7_srstb,
|
||||||
|
|
||||||
|
# MIO.
|
||||||
|
io_MIO = ps7_mio,
|
||||||
|
|
||||||
|
# DDRAM.
|
||||||
|
io_DDR_Addr = ps7_ddram.addr,
|
||||||
|
io_DDR_BankAddr = ps7_ddram.ba,
|
||||||
|
io_DDR_CAS_n = ps7_ddram.cas_n,
|
||||||
|
io_DDR_Clk_n = ps7_ddram.ck_n,
|
||||||
|
io_DDR_Clk = ps7_ddram.ck_p,
|
||||||
|
io_DDR_CKE = ps7_ddram.cke,
|
||||||
|
io_DDR_CS_n = ps7_ddram.cs_n,
|
||||||
|
io_DDR_DM = ps7_ddram.dm,
|
||||||
|
io_DDR_DQ = ps7_ddram.dq,
|
||||||
|
io_DDR_DQS_n = ps7_ddram.dqs_n,
|
||||||
|
io_DDR_DQS = ps7_ddram.dqs_p,
|
||||||
|
io_DDR_ODT = ps7_ddram.odt,
|
||||||
|
io_DDR_RAS_n = ps7_ddram.ras_n,
|
||||||
|
io_DDR_DRSTB = ps7_ddram.reset_n,
|
||||||
|
io_DDR_WEB = ps7_ddram.we_n,
|
||||||
|
io_DDR_VRN = ps7_ddram.vrn,
|
||||||
|
io_DDR_VRP = ps7_ddram.vrp,
|
||||||
|
|
||||||
|
# USB0.
|
||||||
|
# i_USB0_VBUS_PWRFAULT = 0,
|
||||||
|
|
||||||
|
# Fabric Clk / Rst.
|
||||||
|
# o_FCLK_CLK0 = ClockSignal("ps7"),
|
||||||
|
o_FCLK_RESET0_N = self.frstn
|
||||||
|
)
|
||||||
|
|
||||||
|
self.set_ps7(name=self.ps7_name,
|
||||||
|
config={
|
||||||
|
**self.platform.ps7_config
|
||||||
|
})
|
||||||
|
|
||||||
|
def add_ps7_config(self, config):
|
||||||
|
# Config must be provided as a config, value dict.
|
||||||
|
assert isinstance(config, dict)
|
||||||
|
# Add configs to PS7.
|
||||||
|
self.ps7_tcl.append("set_property -dict [list \\")
|
||||||
|
for config, value in config.items():
|
||||||
|
self.ps7_tcl.append("CONFIG.{} {} \\".format(config, '{{' + str(value) + '}}'))
|
||||||
|
self.ps7_tcl.append(f"] [get_ips {self.ps7_name}]")
|
||||||
|
|
||||||
|
def set_ps7(self, name=None, config=None, preset=None):
|
||||||
|
self.ps7_name = name
|
||||||
|
self.ps7_tcl.append(f"set ps7 [create_ip -vendor xilinx.com -name processing_system7 -module_name {self.ps7_name}]")
|
||||||
|
self.add_ps7_config(config)
|
||||||
|
|
||||||
|
def add_axi_gp_master(self, interface):
|
||||||
|
# assert type(interface) is Axi2Sys
|
||||||
|
|
||||||
|
axi_interface = interface
|
||||||
|
|
||||||
|
self.cpu_params.update({
|
||||||
|
# AXI GP clk.
|
||||||
|
f"i_M_AXI_GP0_ACLK" : axi_interface.aclk,
|
||||||
|
|
||||||
|
# AXI GP aw.
|
||||||
|
f"o_M_AXI_GP0_AWVALID" : axi_interface.awvalid,
|
||||||
|
f"i_M_AXI_GP0_AWREADY" : axi_interface.awready,
|
||||||
|
f"o_M_AXI_GP0_AWADDR" : axi_interface.awaddr,
|
||||||
|
f"o_M_AXI_GP0_AWBURST" : axi_interface.awburst,
|
||||||
|
f"o_M_AXI_GP0_AWLEN" : axi_interface.awlen,
|
||||||
|
f"o_M_AXI_GP0_AWSIZE" : axi_interface.awsize,
|
||||||
|
f"o_M_AXI_GP0_AWID" : axi_interface.awid,
|
||||||
|
f"o_M_AXI_GP0_AWLOCK" : axi_interface.awlock,
|
||||||
|
f"o_M_AXI_GP0_AWPROT" : axi_interface.awprot,
|
||||||
|
f"o_M_AXI_GP0_AWCACHE" : axi_interface.awcache,
|
||||||
|
f"o_M_AXI_GP0_AWQOS" : axi_interface.awqos,
|
||||||
|
|
||||||
|
# AXI GP w.
|
||||||
|
f"o_M_AXI_GP0_WVALID" : axi_interface.wvalid,
|
||||||
|
f"o_M_AXI_GP0_WLAST" : axi_interface.wlast,
|
||||||
|
f"i_M_AXI_GP0_WREADY" : axi_interface.wready,
|
||||||
|
f"o_M_AXI_GP0_WID" : axi_interface.wid,
|
||||||
|
f"o_M_AXI_GP0_WDATA" : axi_interface.wdata,
|
||||||
|
f"o_M_AXI_GP0_WSTRB" : axi_interface.wstrb,
|
||||||
|
|
||||||
|
# AXI GP b.
|
||||||
|
f"i_M_AXI_GP0_BVALID" : axi_interface.bvalid,
|
||||||
|
f"o_M_AXI_GP0_BREADY" : axi_interface.bready,
|
||||||
|
f"i_M_AXI_GP0_BID" : axi_interface.bid,
|
||||||
|
f"i_M_AXI_GP0_BRESP" : axi_interface.bresp,
|
||||||
|
|
||||||
|
# AXI GP ar.
|
||||||
|
f"o_M_AXI_GP0_ARVALID" : axi_interface.arvalid,
|
||||||
|
f"i_M_AXI_GP0_ARREADY" : axi_interface.arready,
|
||||||
|
f"o_M_AXI_GP0_ARADDR" : axi_interface.araddr,
|
||||||
|
f"o_M_AXI_GP0_ARBURST" : axi_interface.arburst,
|
||||||
|
f"o_M_AXI_GP0_ARLEN" : axi_interface.arlen,
|
||||||
|
f"o_M_AXI_GP0_ARID" : axi_interface.arid,
|
||||||
|
f"o_M_AXI_GP0_ARLOCK" : axi_interface.arlock,
|
||||||
|
f"o_M_AXI_GP0_ARSIZE" : axi_interface.arsize,
|
||||||
|
f"o_M_AXI_GP0_ARPROT" : axi_interface.arprot,
|
||||||
|
f"o_M_AXI_GP0_ARCACHE" : axi_interface.arcache,
|
||||||
|
f"o_M_AXI_GP0_ARQOS" : axi_interface.arqos,
|
||||||
|
|
||||||
|
# AXI GP r.
|
||||||
|
f"i_M_AXI_GP0_RVALID" : axi_interface.rvalid,
|
||||||
|
f"o_M_AXI_GP0_RREADY" : axi_interface.rready,
|
||||||
|
f"i_M_AXI_GP0_RLAST" : axi_interface.rlast,
|
||||||
|
f"i_M_AXI_GP0_RID" : axi_interface.rid,
|
||||||
|
f"i_M_AXI_GP0_RRESP" : axi_interface.rresp,
|
||||||
|
f"i_M_AXI_GP0_RDATA" : axi_interface.rdata,
|
||||||
|
})
|
||||||
|
|
||||||
|
def add_i2c_emio(self, platform, i2c_name, i2c_number):
|
||||||
|
ps7_i2c_pads = platform.request(i2c_name, i2c_number) #, loose=True)
|
||||||
|
if ps7_i2c_pads is not None:
|
||||||
|
o_i2c_scl = Signal()
|
||||||
|
i_i2c_scl = Signal()
|
||||||
|
t_i2c_scl = Signal()
|
||||||
|
o_i2c_sda = Signal()
|
||||||
|
i_i2c_sda = Signal()
|
||||||
|
t_i2c_sda = Signal()
|
||||||
|
|
||||||
|
self.specials += Instance("IOBUF",
|
||||||
|
i_T = t_i2c_sda,
|
||||||
|
i_I = o_i2c_sda,
|
||||||
|
io_IO = ps7_i2c_pads.sda,
|
||||||
|
o_O = i_i2c_sda,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.specials += Instance("IOBUF",
|
||||||
|
i_T = t_i2c_scl,
|
||||||
|
i_I = o_i2c_scl,
|
||||||
|
io_IO = ps7_i2c_pads.scl,
|
||||||
|
o_O = i_i2c_scl,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.cpu_params.update({
|
||||||
|
f"i_I2C{i2c_number}_SCL_I" : i_i2c_scl,
|
||||||
|
f"o_I2C{i2c_number}_SCL_T" : t_i2c_scl,
|
||||||
|
f"o_I2C{i2c_number}_SCL_O" : o_i2c_scl,
|
||||||
|
|
||||||
|
f"i_I2C{i2c_number}_SDA_I" : i_i2c_sda,
|
||||||
|
f"o_I2C{i2c_number}_SDA_T" : t_i2c_sda,
|
||||||
|
f"o_I2C{i2c_number}_SDA_O" : o_i2c_sda,
|
||||||
|
})
|
||||||
|
|
||||||
|
def do_finalize(self):
|
||||||
|
if len(self.ps7_tcl):
|
||||||
|
self.ps7_tcl += [
|
||||||
|
f"upgrade_ip [get_ips {self.ps7_name}]",
|
||||||
|
f"generate_target all [get_ips {self.ps7_name}]",
|
||||||
|
f"synth_ip [get_ips {self.ps7_name}]"
|
||||||
|
]
|
||||||
|
self.platform.toolchain.pre_synthesis_commands += self.ps7_tcl
|
||||||
|
|
||||||
|
self.specials += Instance(self.ps7_name, **self.cpu_params)
|
141
fast-servo/linien-gateware/cores/spi_phy.py
Normal file
141
fast-servo/linien-gateware/cores/spi_phy.py
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
# This file is part of Fast Servo Software Package.
|
||||||
|
#
|
||||||
|
# Copyright (C) 2023 Jakub Matyas
|
||||||
|
# Warsaw University of Technology <jakubk.m@gmail.com>
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from enum import Enum
|
||||||
|
|
||||||
|
from migen import *
|
||||||
|
|
||||||
|
|
||||||
|
class SpiInterface(Enum):
|
||||||
|
ADC = 0
|
||||||
|
DAC = 1
|
||||||
|
|
||||||
|
|
||||||
|
class SpiPhy(Module):
|
||||||
|
def __init__(self, spi_type, ps7_spi_pads):
|
||||||
|
assert isinstance(spi_type, SpiInterface)
|
||||||
|
|
||||||
|
self.ps_ss = Signal(3, reset_less=True)
|
||||||
|
|
||||||
|
self.ps_miso_o = Signal()
|
||||||
|
self.ps_miso_t = Signal()
|
||||||
|
self.ps_mosi_o = Signal()
|
||||||
|
self.ps_mosi_t = Signal()
|
||||||
|
self.ps_sclk_o = Signal()
|
||||||
|
self.ps_sclk_t = Signal()
|
||||||
|
self.ps_sclk_i = Signal()
|
||||||
|
self.ps_mosi_i = Signal()
|
||||||
|
self.ps_miso_i = Signal()
|
||||||
|
self.ps_ss_i = Signal()
|
||||||
|
self.ps_ss_t = Signal()
|
||||||
|
|
||||||
|
if spi_type.name == "ADC":
|
||||||
|
|
||||||
|
cs_translated = Signal(4, reset_less=True)
|
||||||
|
|
||||||
|
main_adc_miso = Signal(reset_less=True)
|
||||||
|
aux_adc_miso_a = Signal(reset_less=True)
|
||||||
|
aux_adc_miso_b = Signal(reset_less=True)
|
||||||
|
aux_dac_miso = Signal(reset_less=True)
|
||||||
|
|
||||||
|
miso_signals = [main_adc_miso, aux_adc_miso_a, aux_adc_miso_b, aux_dac_miso]
|
||||||
|
|
||||||
|
# MAIN ADC
|
||||||
|
self.specials += Instance("OBUFT", i_I=self.ps_sclk_o, i_T=self.ps_sclk_t, o_O=ps7_spi_pads.sclk)
|
||||||
|
self.specials += Instance("OBUFT", i_I=self.ps_mosi_o, i_T=self.ps_mosi_t, o_O=ps7_spi_pads.mosi)
|
||||||
|
self.specials += Instance("IBUF", i_I=ps7_spi_pads.miso, o_O=main_adc_miso)
|
||||||
|
|
||||||
|
# AUX ADC
|
||||||
|
self.specials += Instance("OBUFT", i_I=self.ps_sclk_o, i_T=self.ps_sclk_t, o_O=ps7_spi_pads.aux_adc_sclk)
|
||||||
|
self.specials += Instance("IBUF", i_I=ps7_spi_pads.aux_adc_miso_a, o_O=aux_adc_miso_a)
|
||||||
|
self.specials += Instance("IBUF", i_I=ps7_spi_pads.aux_adc_miso_b, o_O=aux_adc_miso_b)
|
||||||
|
|
||||||
|
# AUX DAC
|
||||||
|
self.specials += Instance("OBUFT", i_I=self.ps_sclk_o, i_T=self.ps_sclk_t, o_O=ps7_spi_pads.aux_dac_sclk)
|
||||||
|
self.specials += Instance("OBUFT", i_I=self.ps_mosi_o, i_T=self.ps_mosi_t, o_O=ps7_spi_pads.aux_dac_mosi)
|
||||||
|
self.specials += Instance("IBUF", i_I=ps7_spi_pads.aux_dac_miso, o_O=aux_dac_miso)
|
||||||
|
|
||||||
|
cases = {}
|
||||||
|
# for i in range(4):
|
||||||
|
# case_mask = ~(1 << i) & 0xF
|
||||||
|
# print(f"Case mask: 0b{case_mask:04b}")
|
||||||
|
# cases[i + 1] = [
|
||||||
|
# cs_translated.eq(case_mask),
|
||||||
|
# self.ps_miso_i.eq(miso_signals[i])
|
||||||
|
# ]
|
||||||
|
|
||||||
|
cases[0b001] = [
|
||||||
|
cs_translated.eq(0b1110),
|
||||||
|
self.ps_miso_i.eq(main_adc_miso),
|
||||||
|
]
|
||||||
|
|
||||||
|
cases[0b010] = [
|
||||||
|
cs_translated.eq(0b1101),
|
||||||
|
self.ps_miso_i.eq(aux_adc_miso_a),
|
||||||
|
]
|
||||||
|
|
||||||
|
cases[0b011] = [
|
||||||
|
cs_translated.eq(0b1011),
|
||||||
|
self.ps_miso_i.eq(aux_adc_miso_b),
|
||||||
|
]
|
||||||
|
cases[0b100] = [
|
||||||
|
cs_translated.eq(0b0111),
|
||||||
|
self.ps_miso_i.eq(aux_dac_miso),
|
||||||
|
]
|
||||||
|
|
||||||
|
cases["default"] = [
|
||||||
|
cs_translated.eq(0b1111),
|
||||||
|
self.ps_miso_i.eq(0b1),
|
||||||
|
]
|
||||||
|
|
||||||
|
self.comb += [
|
||||||
|
self.ps_ss_i.eq(1),
|
||||||
|
Case(self.ps_ss, cases),
|
||||||
|
|
||||||
|
ps7_spi_pads.cs.eq(cs_translated[0]),
|
||||||
|
|
||||||
|
# only one CS line physically available to AUX ADC
|
||||||
|
ps7_spi_pads.aux_adc_cs.eq(cs_translated[1] & cs_translated[2]),
|
||||||
|
ps7_spi_pads.aux_dac_miso.eq(cs_translated[3]),
|
||||||
|
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
self.specials += Instance(
|
||||||
|
"spi2threewire",
|
||||||
|
o_ps_sclk_i = self.ps_sclk_i,
|
||||||
|
i_ps_sclk_o = self.ps_sclk_o,
|
||||||
|
i_ps_sclk_t = self.ps_sclk_t,
|
||||||
|
|
||||||
|
o_ps_mosi_i = self.ps_mosi_i,
|
||||||
|
i_ps_mosi_o = self.ps_mosi_o,
|
||||||
|
i_ps_mosi_t = self.ps_mosi_t,
|
||||||
|
|
||||||
|
o_ps_miso_i = self.ps_miso_i,
|
||||||
|
i_ps_miso_o = self.ps_miso_o,
|
||||||
|
i_ps_miso_t = self.ps_miso_t,
|
||||||
|
|
||||||
|
o_ps_ss_i = self.ps_ss_i,
|
||||||
|
i_ps_ss = self.ps_ss,
|
||||||
|
i_ps_ss_t = self.ps_ss_t,
|
||||||
|
|
||||||
|
o_o_ss = ps7_spi_pads.cs,
|
||||||
|
o_o_sclk = ps7_spi_pads.sclk,
|
||||||
|
io_sdio = ps7_spi_pads.sdio,
|
||||||
|
)
|
||||||
|
|
336
fast-servo/linien-gateware/fast_servo_platform.py
Normal file
336
fast-servo/linien-gateware/fast_servo_platform.py
Normal file
@ -0,0 +1,336 @@
|
|||||||
|
# This file is part of Fast Servo Software Package.
|
||||||
|
#
|
||||||
|
# Copyright (C) 2022-2023 Jakub Matyas
|
||||||
|
# Warsaw University of Technology <jakubk.m@gmail.com>
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from migen.build.generic_platform import *
|
||||||
|
from migen.build.xilinx import XilinxPlatform
|
||||||
|
|
||||||
|
import os
|
||||||
|
from fast_servo.gateware import verilog_dir
|
||||||
|
|
||||||
|
|
||||||
|
# IOs ----------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
_io = [
|
||||||
|
# Front panel LEDs
|
||||||
|
("fp_led", 0, Pins("G7"), IOStandard("LVCMOS25")),
|
||||||
|
("fp_led", 1, Pins("G8"), IOStandard("LVCMOS25")),
|
||||||
|
("fp_led", 2, Pins("G2"), IOStandard("LVCMOS25")),
|
||||||
|
("fp_led", 3, Pins("G3"), IOStandard("LVCMOS25")),
|
||||||
|
|
||||||
|
# LEDs
|
||||||
|
("user_led", 0, Pins("AB16"), IOStandard("LVCMOS33")),
|
||||||
|
("user_led", 1, Pins("AA14"), IOStandard("LVCMOS33")),
|
||||||
|
("user_led", 2, Pins("AA15"), IOStandard("LVCMOS33")),
|
||||||
|
|
||||||
|
# ETH LEDs
|
||||||
|
("eth_led", 0, Pins("V11"), IOStandard("LVCMOS33")),
|
||||||
|
("eth_led", 1, Pins("U13"), IOStandard("LVCMOS33")),
|
||||||
|
|
||||||
|
("from_eth_phy", 0, Pins("J3"), IOStandard("LVCMOS18")),
|
||||||
|
("from_eth_phy", 1, Pins("K8"), IOStandard("LVCMOS18")),
|
||||||
|
|
||||||
|
|
||||||
|
# CLK 100 MHz from oscillator
|
||||||
|
("clk100", 0, Pins("Y14"), IOStandard("LVCMOS33")),
|
||||||
|
|
||||||
|
# MGT clk from on-board Si5338A
|
||||||
|
("mgt_clk1", 0,
|
||||||
|
Subsignal("p", Pins("U5")),
|
||||||
|
Subsignal("n", Pins("V5")),
|
||||||
|
IOStandard("LVDS_25"),
|
||||||
|
),
|
||||||
|
|
||||||
|
# FCLK125 from on-board Si5338A
|
||||||
|
("fclk125", 0, Pins("K2"), IOStandard("LVCMOS18")),
|
||||||
|
|
||||||
|
# # ADC CLK
|
||||||
|
# ("fpga_clk", 0,
|
||||||
|
# Subsignal("p", Pins("C6")),
|
||||||
|
# Subsignal("n", Pins("C5")),
|
||||||
|
# IOStandard("LVDS_25"),
|
||||||
|
# ),
|
||||||
|
|
||||||
|
# DAC CLK
|
||||||
|
("fpga_clk", 1,
|
||||||
|
Subsignal("p", Pins("J7")),
|
||||||
|
Subsignal("n", Pins("J6")),
|
||||||
|
IOStandard("LVDS_25"),
|
||||||
|
),
|
||||||
|
|
||||||
|
# MAIN ADC LT2195
|
||||||
|
("adc", 0,
|
||||||
|
Subsignal("data0_p", Pins("F7 B7 E4 D1"), IOStandard("LVDS_25")),
|
||||||
|
Subsignal("data0_n", Pins("E7 B6 E3 C1"), IOStandard("LVDS_25")),
|
||||||
|
Subsignal("data1_p", Pins("A2 D5 F2 D7"), IOStandard("LVDS_25")),
|
||||||
|
Subsignal("data1_n", Pins("A1 C4 F1 D6"), IOStandard("LVDS_25")),
|
||||||
|
Subsignal("dco_p", Pins("B4"), IOStandard("LVDS_25")),
|
||||||
|
Subsignal("dco_n", Pins("B3"), IOStandard("LVDS_25")),
|
||||||
|
Subsignal("frame_p", Pins("B2"), IOStandard("LVDS_25")),
|
||||||
|
Subsignal("frame_n", Pins("B1"), IOStandard("LVDS_25"))
|
||||||
|
),
|
||||||
|
|
||||||
|
# ADC AFE
|
||||||
|
("adc_afe", 0,
|
||||||
|
Subsignal("ch1_gain", Pins("AA12"), IOStandard("LVCMOS33")),
|
||||||
|
Subsignal("ch2_gain", Pins("AB11"), IOStandard("LVCMOS33")),
|
||||||
|
Subsignal("nshdn_ch1", Pins("G4"), IOStandard("LVCMOS25")),
|
||||||
|
Subsignal("nshdn_ch2", Pins("F4"), IOStandard("LVCMOS25")),
|
||||||
|
),
|
||||||
|
|
||||||
|
# P5 R5 N1 N4 L2 P6 N3 R4 P1 L1 M3 M4 U2 T2
|
||||||
|
# MAIN DAC AD9117
|
||||||
|
("dac", 0,
|
||||||
|
Subsignal("data",
|
||||||
|
Pins("T2 U2 M4 M3 L1 P1 R4 N3 P6 L2 N4 N1 R5 P5"),
|
||||||
|
IOStandard("LVCMOS18")),
|
||||||
|
Subsignal("dclkio", Pins("U1"), IOStandard("LVCMOS18")),
|
||||||
|
Subsignal("rst", Pins("T1"), IOStandard("LVCMOS18")),
|
||||||
|
),
|
||||||
|
|
||||||
|
# DAC AFE
|
||||||
|
("dac_afe", 0,
|
||||||
|
Subsignal("ch1_pd_n", Pins("L5")),
|
||||||
|
Subsignal("ch2_pd_n", Pins("L4")),
|
||||||
|
IOStandard("LVCMOS18"),
|
||||||
|
),
|
||||||
|
|
||||||
|
# AUXILIARY ADC
|
||||||
|
("aux_adc", 0,
|
||||||
|
Subsignal("diff_n", Pins("W18")),
|
||||||
|
Subsignal("a", Pins("AB18 AB19 W17")),
|
||||||
|
Subsignal("range", Pins("U19")),
|
||||||
|
IOStandard("LVCMOS33")
|
||||||
|
),
|
||||||
|
|
||||||
|
# AUXILIARY DAC
|
||||||
|
("aux_dac", 0,
|
||||||
|
Subsignal("nclr", Pins("V19")),
|
||||||
|
Subsignal("bin", Pins("AA19")),
|
||||||
|
Subsignal("nldac", Pins("AB21")),
|
||||||
|
IOStandard("LVCMOS33")
|
||||||
|
),
|
||||||
|
|
||||||
|
# ADC SPI
|
||||||
|
("spi", 0,
|
||||||
|
Subsignal("sclk", Pins("J1"), IOStandard("LVCMOS18")),
|
||||||
|
Subsignal("mosi", Pins("J5"), IOStandard("LVCMOS18")),
|
||||||
|
Subsignal("miso", Pins("K5"), IOStandard("LVCMOS18")),
|
||||||
|
Subsignal("cs", Pins("J2"), IOStandard("LVCMOS18")),
|
||||||
|
Subsignal("aux_adc_sclk", Pins("AB22"), IOStandard("LVCMOS33")),
|
||||||
|
Subsignal("aux_adc_miso_a", Pins("Y18"), IOStandard("LVCMOS33")),
|
||||||
|
Subsignal("aux_adc_miso_b", Pins("AA16"), IOStandard("LVCMOS33")),
|
||||||
|
Subsignal("aux_adc_cs", Pins("Y19"), IOStandard("LVCMOS33")),
|
||||||
|
Subsignal("aux_dac_sclk", Pins("V18"), IOStandard("LVCMOS33")),
|
||||||
|
Subsignal("aux_dac_mosi", Pins("U17"), IOStandard("LVCMOS33")),
|
||||||
|
Subsignal("aux_dac_miso", Pins("U18"), IOStandard("LVCMOS33")),
|
||||||
|
Subsignal("aux_dac_cs", Pins("AA20"), IOStandard("LVCMOS33")),
|
||||||
|
),
|
||||||
|
|
||||||
|
# DAC SPI
|
||||||
|
("spi", 1,
|
||||||
|
Subsignal("sclk", Pins("K3"), IOStandard("LVCMOS18")),
|
||||||
|
Subsignal("sdio", Pins("R2"), IOStandard("LVCMOS18")),
|
||||||
|
Subsignal("cs", Pins("R3"), IOStandard("LVCMOS18")),
|
||||||
|
# Subsignal("sclk_aux", Pins("V18"), IOStandard("LVCMOS33")),
|
||||||
|
# Subsignal("mosi_aux", Pins("U17"), IOStandard("LVCMOS33")),
|
||||||
|
# Subsignal("miso_aux", Pins("U18"), IOStandard("LVCMOS33")),
|
||||||
|
# Subsignal("cs_aux", Pins("AA20"), IOStandard("LVCMOS33")),
|
||||||
|
),
|
||||||
|
#Pins("Y15 AB14 AB13 V13 V14 V15 U12 W13 W12 R17 W15 AB17 Y12 Y13 V16 W16 AA17 Y17"),
|
||||||
|
("gpio", 0,
|
||||||
|
Subsignal("n", Pins("Y15 AB14 AB13 V13 V14 V15 U12 W13"), IOStandard("LVCMOS33")),
|
||||||
|
Subsignal("p", Pins("W12 R17 W15 AB17 Y12 Y13 V16 W16"), IOStandard("LVCMOS33")),
|
||||||
|
),
|
||||||
|
|
||||||
|
# PS7
|
||||||
|
("ps7_clk", 0, Pins("_" * 1)),
|
||||||
|
("ps7_porb", 0, Pins("_" * 1)),
|
||||||
|
("ps7_srstb", 0, Pins("_" * 1)),
|
||||||
|
("ps7_mio", 0, Pins("_" * 54)),
|
||||||
|
("ps7_ddram", 0,
|
||||||
|
Subsignal("addr", Pins("_" * 15)),
|
||||||
|
Subsignal("ba", Pins("_" * 3)),
|
||||||
|
Subsignal("cas_n", Pins("_" * 1)),
|
||||||
|
Subsignal("ck_n", Pins("_" * 1)),
|
||||||
|
Subsignal("ck_p", Pins("_" * 1)),
|
||||||
|
Subsignal("cke", Pins("_" * 1)),
|
||||||
|
Subsignal("cs_n", Pins("_" * 1)),
|
||||||
|
Subsignal("dm", Pins("_" * 4)),
|
||||||
|
Subsignal("dq", Pins("_" * 32)),
|
||||||
|
Subsignal("dqs_n", Pins("_" * 4)),
|
||||||
|
Subsignal("dqs_p", Pins("_" * 4)),
|
||||||
|
Subsignal("odt", Pins("_" * 1)),
|
||||||
|
Subsignal("ras_n", Pins("_" * 1)),
|
||||||
|
Subsignal("reset_n", Pins("_" * 1)),
|
||||||
|
Subsignal("we_n", Pins("_" * 1)),
|
||||||
|
Subsignal("vrn", Pins("_" * 1)),
|
||||||
|
Subsignal("vrp", Pins("_" * 1)),
|
||||||
|
|
||||||
|
),
|
||||||
|
|
||||||
|
# I2C0 to Si5340 on Fast Servo
|
||||||
|
("ps7_i2c", 0,
|
||||||
|
Subsignal("sda", Pins("M2")),
|
||||||
|
Subsignal("scl", Pins("M1")),
|
||||||
|
IOStandard("LVCMOS18")
|
||||||
|
),
|
||||||
|
|
||||||
|
# Si540 nRST
|
||||||
|
("nrst", 0, Pins("M7"), IOStandard("LVCMOS18")),
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
_connector_eem = [
|
||||||
|
("eem", {
|
||||||
|
"d0_cc_n": "C3",
|
||||||
|
"d0_cc_p": "D3",
|
||||||
|
"d1_n": "A4",
|
||||||
|
"d1_p": "A5",
|
||||||
|
"d2_n": "F6",
|
||||||
|
"d2_p": "G6",
|
||||||
|
"d3_n": "A6",
|
||||||
|
"d3_p": "A7",
|
||||||
|
"d4_n": "E5",
|
||||||
|
"d4_p": "F5",
|
||||||
|
"d5_n": "H3",
|
||||||
|
"d5_p": "H4",
|
||||||
|
"d6_n": "B8",
|
||||||
|
"d6_p": "C8",
|
||||||
|
"d7_n": "D8",
|
||||||
|
"d7_p": "E8",
|
||||||
|
}),
|
||||||
|
]
|
||||||
|
|
||||||
|
_connector_gpio = [
|
||||||
|
("gpio", {
|
||||||
|
"qspi_io3": "Y15",
|
||||||
|
"qspi_io2": "AB14",
|
||||||
|
"qspi_io1": "AB13",
|
||||||
|
"qspi_io0": "V13",
|
||||||
|
"qspi_clk": "V14",
|
||||||
|
"qspi_ncs": "V15",
|
||||||
|
"hrtim_che1": "U12",
|
||||||
|
"hrtim_che2": "W13",
|
||||||
|
"hrtim_cha1": "W12",
|
||||||
|
"hrtim_cha2": "R17",
|
||||||
|
"lptim2_out": "W15",
|
||||||
|
"uart4_tx": "AB17",
|
||||||
|
"spi1_mosi": "Y12",
|
||||||
|
"spi1_miso": "Y13",
|
||||||
|
"spi1_nss": "V16",
|
||||||
|
"spi1_sck": "W16",
|
||||||
|
"i2c1_sda": "AA17",
|
||||||
|
"i2c1_scl": "Y17",
|
||||||
|
})
|
||||||
|
]
|
||||||
|
|
||||||
|
# PS7 config ---------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
ps7_config_board_preset = {
|
||||||
|
"PCW_PRESET_BANK0_VOLTAGE" : "LVCMOS 3.3V",
|
||||||
|
"PCW_PRESET_BANK1_VOLTAGE" : "LVCMOS 1.8V",
|
||||||
|
"PCW_CRYSTAL_PERIPHERAL_FREQMHZ" : "33.333333",
|
||||||
|
"PCW_QSPI_PERIPHERAL_ENABLE" : "1",
|
||||||
|
"PCW_QSPI_GRP_SINGLE_SS_ENABLE" : "1",
|
||||||
|
"PCW_SINGLE_QSPI_DATA_MODE" : "x4",
|
||||||
|
"PCW_QSPI_QSPI_IO" : "MIO 1 .. 6",
|
||||||
|
"PCW_QSPI_GRP_FBCLK_ENABLE" : "1",
|
||||||
|
|
||||||
|
# SD Card
|
||||||
|
"PCW_SD0_PERIPHERAL_ENABLE" : "1",
|
||||||
|
"PCW_SD0_SD0_IO" : "MIO 40 .. 45",
|
||||||
|
"PCW_MIO_40_PULLUP" : "disabled",
|
||||||
|
"PCW_MIO_41_PULLUP" : "disabled",
|
||||||
|
"PCW_MIO_42_PULLUP" : "disabled",
|
||||||
|
"PCW_MIO_43_PULLUP" : "disabled",
|
||||||
|
"PCW_MIO_44_PULLUP" : "disabled",
|
||||||
|
"PCW_MIO_45_PULLUP" : "disabled",
|
||||||
|
|
||||||
|
# UART
|
||||||
|
"PCW_UART0_PERIPHERAL_ENABLE" : "1",
|
||||||
|
"PCW_UART0_UART0_IO" : "MIO 10 .. 11",
|
||||||
|
|
||||||
|
# ETHERNET
|
||||||
|
"PCW_ACT_ENET0_PERIPHERAL_FREQMHZ" : "125",
|
||||||
|
"PCW_ENET0_PERIPHERAL_CLKSRC" : "ARM PLL",
|
||||||
|
"PCW_ENET0_PERIPHERAL_ENABLE" : "1",
|
||||||
|
"PCW_ENET0_ENET0_IO" : "MIO 16 .. 27",
|
||||||
|
"PCW_ENET0_GRP_MDIO_ENABLE" : "1",
|
||||||
|
"PCW_ENET0_GRP_MDIO_IO" : "MIO 52 .. 53",
|
||||||
|
"PCW_ENET_RESET_ENABLE" : "1",
|
||||||
|
"PCW_ENET0_RESET_ENABLE" : "1",
|
||||||
|
"PCW_ENET0_RESET_IO" : "MIO 50",
|
||||||
|
|
||||||
|
# USB
|
||||||
|
"PCW_USB0_PERIPHERAL_ENABLE" : "1",
|
||||||
|
"PCW_USB0_USB0_IO" : "MIO 28 .. 39",
|
||||||
|
"PCW_USB_RESET_ENABLE" : "1",
|
||||||
|
"PCW_USB0_RESET_ENABLE" : "1",
|
||||||
|
"PCW_USB0_RESET_IO" : "MIO 51",
|
||||||
|
|
||||||
|
"PCW_WDT_PERIPHERAL_ENABLE" : "1",
|
||||||
|
"PCW_TTC0_PERIPHERAL_ENABLE" : "1", # TTC0 required for Linux
|
||||||
|
|
||||||
|
# I2C
|
||||||
|
"PCW_I2C_RESET_ENABLE" : "0",
|
||||||
|
"PCW_I2C_RESET_POLARITY" : "Active Low",
|
||||||
|
|
||||||
|
# I2C0
|
||||||
|
"PCW_I2C0_I2C0_IO" : "EMIO",
|
||||||
|
"PCW_I2C0_PERIPHERAL_ENABLE" : "1",
|
||||||
|
"PCW_I2C0_GRP_INT_ENABLE" : "1",
|
||||||
|
"PCW_I2C0_GRP_INT_IO" : "EMIO",
|
||||||
|
|
||||||
|
# I2C1
|
||||||
|
"PCW_I2C1_PERIPHERAL_ENABLE" : "1",
|
||||||
|
"PCW_I2C1_I2C1_IO" : "MIO 48 .. 49",
|
||||||
|
"PCW_I2C1_I2C1_IO" : "MIO 12 .. 13",
|
||||||
|
"PCW_I2C1_PERIPHERAL_ENABLE" : "1",
|
||||||
|
|
||||||
|
"PCW_UIPARAM_DDR_MEMORY_TYPE" : "DDR 3 (Low Voltage)",
|
||||||
|
"PCW_UIPARAM_DDR_PARTNO" : "MT41J256M16 RE-125",
|
||||||
|
"PCW_GPIO_MIO_GPIO_ENABLE" : "1",
|
||||||
|
|
||||||
|
"PCW_FPGA0_PERIPHERAL_FREQMHZ" : "100",
|
||||||
|
"PCW_EN_CLK0_PORT" : "0", # dont use FCLK0
|
||||||
|
}
|
||||||
|
|
||||||
|
class Platform(XilinxPlatform):
|
||||||
|
default_clk_name = "clk100"
|
||||||
|
default_clk_period = 10.0
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
XilinxPlatform.__init__(self, "xc7z015-clg485-1", _io, _connector_gpio + _connector_eem, toolchain="vivado")
|
||||||
|
ps7_config = ps7_config_board_preset
|
||||||
|
self.ps7_config = ps7_config
|
||||||
|
|
||||||
|
verilog_sources = os.listdir(verilog_dir)
|
||||||
|
self.add_sources(verilog_dir, *verilog_sources)
|
||||||
|
|
||||||
|
def do_finalize(self, fragment):
|
||||||
|
try:
|
||||||
|
XilinxPlatform.do_finalize(self, fragment)
|
||||||
|
self.add_period_constraint(self.lookup_request(self.default_clk_name, loose=True), self.default_clk_period)
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
except ConstraintError:
|
||||||
|
pass
|
290
fast-servo/linien-gateware/fast_servo_soc.py
Normal file
290
fast-servo/linien-gateware/fast_servo_soc.py
Normal file
@ -0,0 +1,290 @@
|
|||||||
|
# This file is part of Fast Servo Software Package.
|
||||||
|
#
|
||||||
|
# Copyright (C) 2023 Jakub Matyas
|
||||||
|
# Warsaw University of Technology <jakubk.m@gmail.com>
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
from migen import *
|
||||||
|
from misoc.interconnect import csr_bus
|
||||||
|
from misoc.interconnect.csr import AutoCSR, CSRStorage
|
||||||
|
|
||||||
|
from fast_servo.gateware.cores.adc import ADC, AUX_ADC_CTRL
|
||||||
|
from fast_servo.gateware.cores.dac import AUX_DAC_CTRL, DAC
|
||||||
|
from fast_servo.gateware.cores.pitaya_ps import Axi2Sys, Sys2CSR, SysCDC, SysInterconnect
|
||||||
|
from fast_servo.gateware.cores.ps7 import PS7
|
||||||
|
from fast_servo.gateware.cores.spi_phy import SpiInterface, SpiPhy
|
||||||
|
|
||||||
|
|
||||||
|
class CRG(Module):
|
||||||
|
def __init__(self, platform):
|
||||||
|
self.ps_rst = Signal()
|
||||||
|
self.locked = Signal()
|
||||||
|
self.clock_domains.cd_sys = ClockDomain()
|
||||||
|
self.clock_domains.cd_sys_double = ClockDomain()
|
||||||
|
self.clock_domains.cd_idelay = ClockDomain()
|
||||||
|
|
||||||
|
# # #
|
||||||
|
|
||||||
|
# Clk.
|
||||||
|
clk100 = platform.request("clk100")
|
||||||
|
platform.add_period_constraint(clk100, 10.0)
|
||||||
|
self.clkin = clk100
|
||||||
|
clk100_buf = Signal()
|
||||||
|
self.specials += Instance("IBUFG", i_I=clk100, o_O=clk100_buf)
|
||||||
|
|
||||||
|
clk_feedback = Signal()
|
||||||
|
clk_feedback_buf = Signal()
|
||||||
|
|
||||||
|
clk_sys = Signal()
|
||||||
|
clk_idelay = Signal()
|
||||||
|
|
||||||
|
self.specials += [
|
||||||
|
Instance(
|
||||||
|
"PLLE2_BASE",
|
||||||
|
p_BANDWIDTH="OPTIMIZED",
|
||||||
|
p_DIVCLK_DIVIDE=1,
|
||||||
|
p_CLKFBOUT_PHASE=0.0,
|
||||||
|
p_CLKFBOUT_MULT=10,
|
||||||
|
p_CLKIN1_PERIOD=10.0,
|
||||||
|
p_REF_JITTER1=0.01,
|
||||||
|
p_STARTUP_WAIT="FALSE",
|
||||||
|
i_CLKIN1=clk100_buf,
|
||||||
|
i_PWRDWN=0,
|
||||||
|
i_RST=self.ps_rst,
|
||||||
|
i_CLKFBIN=clk_feedback_buf,
|
||||||
|
o_CLKFBOUT=clk_feedback,
|
||||||
|
p_CLKOUT0_DIVIDE=10,
|
||||||
|
p_CLKOUT0_PHASE=0.0,
|
||||||
|
p_CLKOUT0_DUTY_CYCLE=0.5,
|
||||||
|
o_CLKOUT0=clk_sys, # 100 MHz <- sys_clk
|
||||||
|
p_CLKOUT1_DIVIDE=5,
|
||||||
|
p_CLKOUT1_PHASE=0.0,
|
||||||
|
p_CLKOUT1_DUTY_CYCLE=0.5,
|
||||||
|
o_CLKOUT1=clk_idelay, # 200 MHZ <- 2 * sys_clk = 2*100 MHz
|
||||||
|
o_LOCKED=self.locked,
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
self.specials += Instance("BUFG", i_I=clk_feedback, o_O=clk_feedback_buf)
|
||||||
|
self.specials += Instance("BUFG", i_I=clk_sys, o_O=self.cd_sys.clk)
|
||||||
|
self.specials += Instance("BUFG", i_I=clk_idelay, o_O=self.cd_idelay.clk)
|
||||||
|
self.specials += Instance("BUFG", i_I=clk_idelay, o_O=self.cd_sys_double.clk)
|
||||||
|
|
||||||
|
|
||||||
|
# Ignore sys_clk to pll clkin path created by SoC's rst.
|
||||||
|
platform.add_false_path_constraints(self.cd_sys.clk, self.clkin)
|
||||||
|
|
||||||
|
self.specials += Instance("FD", p_INIT=1, i_D=~self.locked, i_C=self.cd_sys.clk, o_Q=self.cd_sys.rst)
|
||||||
|
|
||||||
|
|
||||||
|
class BaseSoC(PS7, AutoCSR):
|
||||||
|
def __init__(self, platform, passthrouh=False):
|
||||||
|
PS7.__init__(self, platform)
|
||||||
|
|
||||||
|
# TODO:
|
||||||
|
# LINIEN SPECIFIC csr_map - in the future should be moved
|
||||||
|
# to csr_devices list
|
||||||
|
self.csr_map = {
|
||||||
|
"adc": 9,
|
||||||
|
"fp_led0": 10,
|
||||||
|
"fp_led1": 11,
|
||||||
|
"fp_led2": 12,
|
||||||
|
"fp_led3": 13,
|
||||||
|
"dac": 14,
|
||||||
|
"adc_aux_ctrl": 15,
|
||||||
|
"dac_aux_ctrl": 16,
|
||||||
|
}
|
||||||
|
self.soc_name = "FastServo"
|
||||||
|
self.interconnect_slaves = []
|
||||||
|
self.csr_devices = []
|
||||||
|
|
||||||
|
self.platform = platform
|
||||||
|
|
||||||
|
self.submodules.crg = CRG(platform)
|
||||||
|
|
||||||
|
# # # AXI to system bus bridge
|
||||||
|
self.submodules.axi2sys = Axi2Sys()
|
||||||
|
self.submodules.sys2csr = Sys2CSR()
|
||||||
|
self.submodules.syscdc = SysCDC()
|
||||||
|
self.add_axi_gp_master(self.axi2sys.axi)
|
||||||
|
|
||||||
|
self.comb += [
|
||||||
|
self.axi2sys.axi.aclk.eq(ClockSignal("sys")),
|
||||||
|
self.axi2sys.axi.arstn.eq(self.frstn),
|
||||||
|
self.syscdc.target.connect(self.sys2csr.sys),
|
||||||
|
]
|
||||||
|
|
||||||
|
# ETH LEDS
|
||||||
|
self.comb += [
|
||||||
|
platform.request("eth_led", 0).eq(platform.request("from_eth_phy", 0)),
|
||||||
|
platform.request("eth_led", 1).eq(platform.request("from_eth_phy", 1)),
|
||||||
|
]
|
||||||
|
|
||||||
|
# I2C0 to Si5340 on Fast Servo
|
||||||
|
self.add_i2c_emio(platform, "ps7_i2c", 0)
|
||||||
|
|
||||||
|
# SPI0 - interface to main ADC and auxiliary ADC
|
||||||
|
self.add_spi_interface(platform, SpiInterface.ADC)
|
||||||
|
|
||||||
|
# SPI1 - interface to main DAC and auxiliary DAC
|
||||||
|
self.add_spi_interface(platform, SpiInterface.DAC)
|
||||||
|
|
||||||
|
# self.add_main_adc(platform)
|
||||||
|
self.submodules.adc = ADC(platform)
|
||||||
|
self.csr_devices.append("adc")
|
||||||
|
|
||||||
|
# self.add_main_dac(platform)
|
||||||
|
self.submodules.dac = DAC(platform)
|
||||||
|
self.csr_devices.append("dac")
|
||||||
|
|
||||||
|
# DEBUG
|
||||||
|
if passthrouh:
|
||||||
|
DAC_DATA_WIDTH = 14
|
||||||
|
for ch in range(2):
|
||||||
|
saturate = Signal()
|
||||||
|
adc_signal = self.adc.data_out[ch]
|
||||||
|
self.comb += [
|
||||||
|
saturate.eq(adc_signal[-3:] != Replicate(adc_signal[-1], 3)),
|
||||||
|
self.dac.data_in[ch].eq(Mux(saturate,
|
||||||
|
Cat(Replicate(~adc_signal[-1], DAC_DATA_WIDTH-1), adc_signal[-1]),
|
||||||
|
adc_signal[:-2]))
|
||||||
|
]
|
||||||
|
|
||||||
|
si_5340_nrst = platform.request("nrst")
|
||||||
|
self.comb += si_5340_nrst.eq(1)
|
||||||
|
|
||||||
|
for i in range(4):
|
||||||
|
led_pin = platform.request("fp_led", i)
|
||||||
|
setattr(self.submodules, f"fp_led{i}", LED(led_pin))
|
||||||
|
self.csr_devices.append(f"fp_led{i}")
|
||||||
|
|
||||||
|
self.submodules.adc_aux_ctrl = AUX_ADC_CTRL(platform)
|
||||||
|
self.csr_devices.append("adc_aux_ctrl")
|
||||||
|
|
||||||
|
self.submodules.dac_aux_ctrl = AUX_DAC_CTRL(platform)
|
||||||
|
self.csr_devices.append("dac_aux_ctrl")
|
||||||
|
|
||||||
|
def add_spi_interface(self, platform, spi_type):
|
||||||
|
assert isinstance(spi_type, SpiInterface)
|
||||||
|
n = spi_type.value
|
||||||
|
|
||||||
|
ps7_spi_pads = platform.request("spi", spi_type.value)
|
||||||
|
spi_phy = SpiPhy(spi_type, ps7_spi_pads)
|
||||||
|
self.submodules += spi_phy
|
||||||
|
|
||||||
|
ps7_config_spi = {
|
||||||
|
f"PCW_SPI{n}_GRP_SS0_ENABLE" : "1",
|
||||||
|
f"PCW_SPI{n}_GRP_SS0_IO" : "EMIO",
|
||||||
|
f"PCW_SPI{n}_GRP_SS1_ENABLE" : "1",
|
||||||
|
f"PCW_SPI{n}_GRP_SS1_IO" : "EMIO",
|
||||||
|
f"PCW_SPI{n}_GRP_SS2_ENABLE" : "1",
|
||||||
|
f"PCW_SPI{n}_GRP_SS2_IO" : "EMIO",
|
||||||
|
f"PCW_SPI{n}_PERIPHERAL_ENABLE" : "1",
|
||||||
|
f"PCW_SPI{n}_SPI{n}_IO" : "EMIO",
|
||||||
|
f"PCW_SPI_PERIPHERAL_CLKSRC" : "IO PLL",
|
||||||
|
f"PCW_SPI_PERIPHERAL_DIVISOR0" : "10",
|
||||||
|
f"PCW_SPI_PERIPHERAL_FREQMHZ" : "166.666666",
|
||||||
|
}
|
||||||
|
self.add_ps7_config(ps7_config_spi)
|
||||||
|
|
||||||
|
self.cpu_params.update({
|
||||||
|
f"o_SPI{n}_MISO_O" : spi_phy.ps_miso_o,
|
||||||
|
f"o_SPI{n}_MISO_T" : spi_phy.ps_miso_t,
|
||||||
|
f"o_SPI{n}_MOSI_O" : spi_phy.ps_mosi_o,
|
||||||
|
f"o_SPI{n}_MOSI_T" : spi_phy.ps_mosi_t,
|
||||||
|
f"o_SPI{n}_SCLK_O" : spi_phy.ps_sclk_o,
|
||||||
|
f"o_SPI{n}_SCLK_T" : spi_phy.ps_sclk_t,
|
||||||
|
|
||||||
|
f"i_SPI{n}_SCLK_I" : spi_phy.ps_sclk_i,
|
||||||
|
f"i_SPI{n}_MOSI_I" : spi_phy.ps_mosi_i,
|
||||||
|
f"i_SPI{n}_MISO_I" : spi_phy.ps_miso_i,
|
||||||
|
f"i_SPI{n}_SS_I" : spi_phy.ps_ss_i,
|
||||||
|
f"o_SPI{n}_SS_O" : spi_phy.ps_ss[0],
|
||||||
|
f"o_SPI{n}_SS1_O" : spi_phy.ps_ss[1],
|
||||||
|
f"o_SPI{n}_SS2_O" : spi_phy.ps_ss[2],
|
||||||
|
f"o_SPI{n}_SS_T" : spi_phy.ps_ss_t,
|
||||||
|
})
|
||||||
|
|
||||||
|
def add_interconnect_slave(self, slave):
|
||||||
|
self.interconnect_slaves.append(slave)
|
||||||
|
|
||||||
|
def get_csr_dev_address(self, name, memory):
|
||||||
|
# TODO: switch to MiSoC-like address retriving from
|
||||||
|
# the list of CSR devices
|
||||||
|
if memory is not None:
|
||||||
|
name = name + "_" + memory.name_override
|
||||||
|
try:
|
||||||
|
return self.csr_map[name]
|
||||||
|
except KeyError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def soc_finalize(self):
|
||||||
|
# Overload this method to customize SystemInterconnect
|
||||||
|
# and csrbanks - especially useful in Linien
|
||||||
|
self.add_interconnect_slave(self.syscdc.source)
|
||||||
|
self.submodules.interconnect = SysInterconnect(
|
||||||
|
self.axi2sys.sys,
|
||||||
|
*self.interconnect_slaves
|
||||||
|
)
|
||||||
|
self.submodules.csrbanks = csr_bus.CSRBankArray(self,
|
||||||
|
self.get_csr_dev_address)
|
||||||
|
self.submodules.csrcon = csr_bus.Interconnect(
|
||||||
|
self.sys2csr.csr, self.csrbanks.get_buses()
|
||||||
|
)
|
||||||
|
|
||||||
|
def do_finalize(self):
|
||||||
|
self.soc_finalize()
|
||||||
|
PS7.do_finalize(self)
|
||||||
|
|
||||||
|
def build(self, *args, **kwargs):
|
||||||
|
self.platform.build(self, *args, **kwargs)
|
||||||
|
|
||||||
|
class LED(Module, AutoCSR):
|
||||||
|
def __init__(self, led):
|
||||||
|
|
||||||
|
self.led_out = CSRStorage(1)
|
||||||
|
|
||||||
|
self.comb += led.eq(self.led_out.storage)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import subprocess
|
||||||
|
from fast_servo.gateware.fast_servo_platform import Platform
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument("--debug", action="store_true", default=False, help="Hardwire ADC data to DAC")
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
|
||||||
|
root_path = os.getcwd()
|
||||||
|
platform = Platform()
|
||||||
|
fast_servo = BaseSoC(platform, passthrouh=args.debug)
|
||||||
|
|
||||||
|
build_dir = "builds/fast_servo_gw_debug" if args.debug else"builds/fast_servo_gw"
|
||||||
|
build_name = "top"
|
||||||
|
fast_servo.build(build_dir=build_dir, build_name=build_name, run=True)
|
||||||
|
os.chdir(os.path.join(root_path, build_dir))
|
||||||
|
with open(f"{build_name}.bif", "w") as f:
|
||||||
|
f.write(f"all:\n{{\n\t{build_name}.bit\n}}")
|
||||||
|
|
||||||
|
cmd = f"bootgen -image {build_name}.bif -arch zynq -process_bitstream bin -w on".split(" ")
|
||||||
|
subprocess.run(cmd)
|
||||||
|
|
||||||
|
|
||||||
|
|
162
fast-servo/linien-gateware/verilog/LTC2195.v
Normal file
162
fast-servo/linien-gateware/verilog/LTC2195.v
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// LTC2195.v
|
||||||
|
//
|
||||||
|
// 8/03/21
|
||||||
|
// Jakub Matyas
|
||||||
|
//
|
||||||
|
// LTC2195 controller.
|
||||||
|
//
|
||||||
|
//
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// `include "timescale.v"
|
||||||
|
`timescale 1ns/1ps // this was in the SelectIO design
|
||||||
|
|
||||||
|
module LTC2195(
|
||||||
|
input rst_in,
|
||||||
|
input clk200,
|
||||||
|
input DCO,
|
||||||
|
input DCO_2D,
|
||||||
|
input FR_in_p,
|
||||||
|
input FR_in_n,
|
||||||
|
input [3:0] D0_in_p,
|
||||||
|
input [3:0] D0_in_n,
|
||||||
|
input [3:0] D1_in_p,
|
||||||
|
input [3:0] D1_in_n,
|
||||||
|
input bitslip,
|
||||||
|
input [4:0] delay_val,
|
||||||
|
|
||||||
|
output reg [15:0] ADC0_out,
|
||||||
|
output reg [15:0] ADC1_out,
|
||||||
|
output reg [3:0] FR_out,
|
||||||
|
output wire [8:0] o_data_from_pins,
|
||||||
|
output idelay_rdy
|
||||||
|
);
|
||||||
|
|
||||||
|
// ///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// // LVDS inputs
|
||||||
|
|
||||||
|
localparam N_BITS = 4;
|
||||||
|
localparam N_LANES = 9; // for each channel 4 lanes + 1 lane for FRAME
|
||||||
|
wire [N_LANES-1:0] data_in_p, data_in_n, data_in_from_pins, data_in_from_pins_delay;
|
||||||
|
assign data_in_p = {FR_in_p, D1_in_p, D0_in_p};
|
||||||
|
assign data_in_n = {FR_in_n, D1_in_n, D0_in_n};
|
||||||
|
assign o_data_from_pins = data_in_from_pins_delay;
|
||||||
|
|
||||||
|
|
||||||
|
wire [N_LANES*4 -1:0] data_out;
|
||||||
|
wire [35:0 ]data_out_mod;
|
||||||
|
|
||||||
|
|
||||||
|
assign data_out_mod = {~data_out[35:24], data_out[23:20], ~data_out[19:16], data_out[15:0]};
|
||||||
|
|
||||||
|
|
||||||
|
always @(posedge DCO_2D) begin
|
||||||
|
ADC0_out <= {
|
||||||
|
data_out_mod[0], data_out_mod[4], data_out_mod[1], data_out_mod[5],
|
||||||
|
data_out_mod[2], data_out_mod[6], data_out_mod[3], data_out_mod[7],
|
||||||
|
data_out_mod[8], data_out_mod[12], data_out_mod[9], data_out_mod[13],
|
||||||
|
data_out_mod[10], data_out_mod[14], data_out_mod[11], data_out_mod[15]
|
||||||
|
};
|
||||||
|
|
||||||
|
ADC1_out <= {
|
||||||
|
data_out_mod[16 + 0], data_out_mod[16 + 4], data_out_mod[16 + 1], data_out_mod[16 + 5],
|
||||||
|
data_out_mod[16 + 2], data_out_mod[16 + 6], data_out_mod[16 + 3], data_out_mod[16 + 7],
|
||||||
|
data_out_mod[16 + 8], data_out_mod[16 + 12], data_out_mod[16 + 9], data_out_mod[16 + 13],
|
||||||
|
data_out_mod[16 + 10], data_out_mod[16 + 14], data_out_mod[16 + 11], data_out_mod[16 + 15]
|
||||||
|
};
|
||||||
|
FR_out <= {data_out_mod[32], data_out_mod[33], data_out_mod[34], data_out_mod[35]}; // value that arrived first is LSB, therefore reversing order
|
||||||
|
end
|
||||||
|
|
||||||
|
wire s_idelay_rdy;
|
||||||
|
IDELAYCTRL IDELAYCTRL_inst (
|
||||||
|
.RDY(s_idelay_rdy), // 1-bit output: Ready output
|
||||||
|
.REFCLK(clk200), // 1-bit input: Reference clock input
|
||||||
|
.RST(s_rst) // 1-bit input: Active high reset input
|
||||||
|
);
|
||||||
|
|
||||||
|
assign idelay_rdy = s_idelay_rdy;
|
||||||
|
|
||||||
|
|
||||||
|
reg s_rst;
|
||||||
|
reg [5:0] rst_cnt;
|
||||||
|
wire serdes_o;
|
||||||
|
|
||||||
|
always @(posedge DCO_2D) begin
|
||||||
|
if (rst_in) begin
|
||||||
|
s_rst <= 1'b1;
|
||||||
|
rst_cnt <= 'b0;
|
||||||
|
end else begin
|
||||||
|
if (rst_cnt == 22)
|
||||||
|
s_rst <= 'b0;
|
||||||
|
else
|
||||||
|
rst_cnt <= rst_cnt + 1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
genvar lane;
|
||||||
|
generate for (lane=0; lane<N_LANES; lane=lane+1) begin
|
||||||
|
IBUFDS #(
|
||||||
|
.DIFF_TERM("TRUE")
|
||||||
|
)
|
||||||
|
ibufds_inst (
|
||||||
|
.I(data_in_p[lane]),
|
||||||
|
.IB(data_in_n[lane]),
|
||||||
|
.O(data_in_from_pins[lane])
|
||||||
|
);
|
||||||
|
IDELAYE2 #(
|
||||||
|
.CINVCTRL_SEL("FALSE"), // Enable dynamic clock inversion (FALSE, TRUE)
|
||||||
|
.DELAY_SRC("IDATAIN"), // Delay input (IDATAIN, DATAIN)
|
||||||
|
.HIGH_PERFORMANCE_MODE("TRUE"), // Reduced jitter ("TRUE"), Reduced power ("FALSE")
|
||||||
|
.IDELAY_TYPE("VAR_LOAD"), // FIXED, VARIABLE, VAR_LOAD, VAR_LOAD_PIPE
|
||||||
|
.IDELAY_VALUE(0), // Input delay tap setting (0-31)
|
||||||
|
.PIPE_SEL("FALSE"), // Select pipelined mode, FALSE, TRUE
|
||||||
|
.REFCLK_FREQUENCY(200.0), // IDELAYCTRL clock input frequency in MHz (190.0-210.0, 290.0-310.0).
|
||||||
|
.SIGNAL_PATTERN("DATA") // DATA, CLOCK input signal
|
||||||
|
)
|
||||||
|
IDELAYE2_inst (
|
||||||
|
.C(clk200),
|
||||||
|
.CE('b0),
|
||||||
|
.CNTVALUEIN(delay_val),
|
||||||
|
.LD(1'b1),
|
||||||
|
.DATAOUT(data_in_from_pins_delay[lane]), // 1-bit output: Delayed data output
|
||||||
|
.IDATAIN(data_in_from_pins[lane]), // 1-bit input: Data input from the I/O
|
||||||
|
.LDPIPEEN (1'b0),
|
||||||
|
.REGRST (1'b0),
|
||||||
|
.CINVCTRL (1'b0)
|
||||||
|
);
|
||||||
|
|
||||||
|
ISERDESE2 #(
|
||||||
|
.DATA_RATE("DDR"),
|
||||||
|
.DATA_WIDTH(3'd4),
|
||||||
|
.INTERFACE_TYPE("NETWORKING"),
|
||||||
|
.IOBDELAY("BOTH"),
|
||||||
|
.SERDES_MODE("MASTER"),
|
||||||
|
.NUM_CE(2'd2)
|
||||||
|
)
|
||||||
|
iserdes_inst (
|
||||||
|
.CE1(1'd1),
|
||||||
|
.CE2(1'd1),
|
||||||
|
.DYNCLKDIVSEL('b0),
|
||||||
|
.DYNCLKSEL('b0),
|
||||||
|
.CLK(DCO),
|
||||||
|
.CLKB(!DCO),
|
||||||
|
.CLKDIV(DCO_2D),
|
||||||
|
// .D(data_in_from_pins[lane]),
|
||||||
|
.DDLY(data_in_from_pins_delay[lane]),
|
||||||
|
.RST(s_rst),
|
||||||
|
.BITSLIP(bitslip),
|
||||||
|
// DATA is MSB first and OUTA is LANE0, so in case of OUTA:
|
||||||
|
// Q1 = D9
|
||||||
|
// Q2 = D11
|
||||||
|
// Q3 = D13
|
||||||
|
// Q4 = D15
|
||||||
|
.Q1(data_out[lane*N_BITS + 3]),
|
||||||
|
.Q2(data_out[lane*N_BITS + 2]),
|
||||||
|
.Q3(data_out[lane*N_BITS + 1]),
|
||||||
|
.Q4(data_out[lane*N_BITS + 0])
|
||||||
|
);
|
||||||
|
end
|
||||||
|
endgenerate
|
||||||
|
|
||||||
|
endmodule
|
265
fast-servo/linien-gateware/verilog/axi_slave.v
Normal file
265
fast-servo/linien-gateware/verilog/axi_slave.v
Normal file
@ -0,0 +1,265 @@
|
|||||||
|
/**
|
||||||
|
* $Id: axi_slave.v 961 2014-01-21 11:40:39Z matej.oblak $
|
||||||
|
*
|
||||||
|
* @brief Red Pitaya symplified AXI slave.
|
||||||
|
*
|
||||||
|
* @Author Matej Oblak
|
||||||
|
*
|
||||||
|
* (c) Red Pitaya http://www.redpitaya.com
|
||||||
|
*
|
||||||
|
* This part of code is written in Verilog hardware description language (HDL).
|
||||||
|
* Please visit http://en.wikipedia.org/wiki/Verilog
|
||||||
|
* for more details on the language used herein.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GENERAL DESCRIPTION:
|
||||||
|
*
|
||||||
|
* AXI slave used also for simple bus master.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* /------\
|
||||||
|
* WR ADDRESS ----> | WR |
|
||||||
|
* WR DATA ----> | | -----------
|
||||||
|
* WR RESPONSE <---- | CH | |
|
||||||
|
* \------/ /--------\
|
||||||
|
* | SIMPLE | ---> WR/RD ADDRRESS
|
||||||
|
* AXI | | ---> WR DATA
|
||||||
|
* | RP | <--- RD DATA
|
||||||
|
* | BUS | <--- ACKNOWLEDGE
|
||||||
|
* /------\ \--------/
|
||||||
|
* RD ADDRESS ----> | RD | |
|
||||||
|
* RD DATA <---- | CH | -----------
|
||||||
|
* \------/
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Because AXI bus is quite complex simplier bus was created.
|
||||||
|
*
|
||||||
|
* It combines write and read channel, where write has bigger priority. Command
|
||||||
|
* is then send forward to red pitaya bus. When wite or read acknowledge is
|
||||||
|
* received AXI response is created and new AXI is accepted.
|
||||||
|
*
|
||||||
|
* To prevent AXI lockups because no response is received, this slave creates its
|
||||||
|
* own after 32 cycles (ack_cnt).
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
module axi_slave
|
||||||
|
#(
|
||||||
|
parameter AXI_DW = 64 , // data width (8,16,...,1024)
|
||||||
|
parameter AXI_AW = 32 , // address width
|
||||||
|
parameter AXI_IW = 8 , // ID width
|
||||||
|
parameter AXI_SW = AXI_DW >> 3 // strobe width - 1 bit for every data byte
|
||||||
|
)
|
||||||
|
(
|
||||||
|
// global signals
|
||||||
|
input axi_clk_i , //!< AXI global clock
|
||||||
|
input axi_rstn_i , //!< AXI global reset
|
||||||
|
|
||||||
|
// axi write address channel
|
||||||
|
input [ AXI_IW-1: 0] axi_awid_i , //!< AXI write address ID
|
||||||
|
input [ AXI_AW-1: 0] axi_awaddr_i , //!< AXI write address
|
||||||
|
input [ 4-1: 0] axi_awlen_i , //!< AXI write burst length
|
||||||
|
input [ 3-1: 0] axi_awsize_i , //!< AXI write burst size
|
||||||
|
input [ 2-1: 0] axi_awburst_i , //!< AXI write burst type
|
||||||
|
input [ 2-1: 0] axi_awlock_i , //!< AXI write lock type
|
||||||
|
input [ 4-1: 0] axi_awcache_i , //!< AXI write cache type
|
||||||
|
input [ 3-1: 0] axi_awprot_i , //!< AXI write protection type
|
||||||
|
input axi_awvalid_i , //!< AXI write address valid
|
||||||
|
output axi_awready_o , //!< AXI write ready
|
||||||
|
|
||||||
|
// axi write data channel
|
||||||
|
input [ AXI_IW-1: 0] axi_wid_i , //!< AXI write data ID
|
||||||
|
input [ AXI_DW-1: 0] axi_wdata_i , //!< AXI write data
|
||||||
|
input [ AXI_SW-1: 0] axi_wstrb_i , //!< AXI write strobes
|
||||||
|
input axi_wlast_i , //!< AXI write last
|
||||||
|
input axi_wvalid_i , //!< AXI write valid
|
||||||
|
output axi_wready_o , //!< AXI write ready
|
||||||
|
|
||||||
|
// axi write response channel
|
||||||
|
output [ AXI_IW-1: 0] axi_bid_o , //!< AXI write response ID
|
||||||
|
output reg [ 2-1: 0] axi_bresp_o , //!< AXI write response
|
||||||
|
output reg axi_bvalid_o , //!< AXI write response valid
|
||||||
|
input axi_bready_i , //!< AXI write response ready
|
||||||
|
|
||||||
|
// axi read address channel
|
||||||
|
input [ AXI_IW-1: 0] axi_arid_i , //!< AXI read address ID
|
||||||
|
input [ AXI_AW-1: 0] axi_araddr_i , //!< AXI read address
|
||||||
|
input [ 4-1: 0] axi_arlen_i , //!< AXI read burst length
|
||||||
|
input [ 3-1: 0] axi_arsize_i , //!< AXI read burst size
|
||||||
|
input [ 2-1: 0] axi_arburst_i , //!< AXI read burst type
|
||||||
|
input [ 2-1: 0] axi_arlock_i , //!< AXI read lock type
|
||||||
|
input [ 4-1: 0] axi_arcache_i , //!< AXI read cache type
|
||||||
|
input [ 3-1: 0] axi_arprot_i , //!< AXI read protection type
|
||||||
|
input axi_arvalid_i , //!< AXI read address valid
|
||||||
|
output axi_arready_o , //!< AXI read address ready
|
||||||
|
|
||||||
|
// axi read data channel
|
||||||
|
output [ AXI_IW-1: 0] axi_rid_o , //!< AXI read response ID
|
||||||
|
output reg [ AXI_DW-1: 0] axi_rdata_o , //!< AXI read data
|
||||||
|
output reg [ 2-1: 0] axi_rresp_o , //!< AXI read response
|
||||||
|
output reg axi_rlast_o , //!< AXI read last
|
||||||
|
output reg axi_rvalid_o , //!< AXI read response valid
|
||||||
|
input axi_rready_i , //!< AXI read response ready
|
||||||
|
|
||||||
|
// RP system read/write channel
|
||||||
|
output [ AXI_AW-1: 0] sys_addr_o , //!< system bus read/write address.
|
||||||
|
output [ AXI_DW-1: 0] sys_wdata_o , //!< system bus write data.
|
||||||
|
output reg [ AXI_SW-1: 0] sys_sel_o , //!< system bus write byte select.
|
||||||
|
output reg sys_wen_o , //!< system bus write enable.
|
||||||
|
output reg sys_ren_o , //!< system bus read enable.
|
||||||
|
input [ AXI_DW-1: 0] sys_rdata_i , //!< system bus read data.
|
||||||
|
input sys_err_i , //!< system bus error indicator.
|
||||||
|
input sys_ack_i //!< system bus acknowledge signal.
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// AXI slave Module
|
||||||
|
wire ack ;
|
||||||
|
reg [ 6-1: 0] ack_cnt ;
|
||||||
|
|
||||||
|
reg rd_do ;
|
||||||
|
reg [ AXI_IW-1: 0] rd_arid ;
|
||||||
|
reg [ AXI_AW-1: 0] rd_araddr ;
|
||||||
|
reg rd_error ;
|
||||||
|
wire rd_errorw ;
|
||||||
|
|
||||||
|
reg wr_do ;
|
||||||
|
reg [ AXI_IW-1: 0] wr_awid ;
|
||||||
|
reg [ AXI_AW-1: 0] wr_awaddr ;
|
||||||
|
reg [ AXI_IW-1: 0] wr_wid ;
|
||||||
|
reg [ AXI_DW-1: 0] wr_wdata ;
|
||||||
|
reg wr_error ;
|
||||||
|
wire wr_errorw ;
|
||||||
|
|
||||||
|
assign wr_errorw = (axi_awlen_i != 4'h0) || (axi_awsize_i != 3'b010); // error if write burst and more/less than 4B transfer
|
||||||
|
assign rd_errorw = (axi_arlen_i != 4'h0) || (axi_arsize_i != 3'b010); // error if read burst and more/less than 4B transfer
|
||||||
|
|
||||||
|
always @(posedge axi_clk_i) begin
|
||||||
|
if (axi_rstn_i == 1'b0) begin
|
||||||
|
rd_do <= 1'b0 ;
|
||||||
|
rd_error <= 1'b0 ;
|
||||||
|
end
|
||||||
|
else begin
|
||||||
|
if (axi_arvalid_i && !rd_do && !axi_awvalid_i && !wr_do) // accept just one read request - write has priority
|
||||||
|
rd_do <= 1'b1 ;
|
||||||
|
else if (axi_rready_i && rd_do && ack)
|
||||||
|
rd_do <= 1'b0 ;
|
||||||
|
|
||||||
|
if (axi_arvalid_i && axi_arready_o) begin // latch ID and address
|
||||||
|
rd_arid <= axi_arid_i ;
|
||||||
|
rd_araddr <= axi_araddr_i ;
|
||||||
|
rd_error <= rd_errorw ;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
always @(posedge axi_clk_i) begin
|
||||||
|
if (axi_rstn_i == 1'b0) begin
|
||||||
|
wr_do <= 1'b0 ;
|
||||||
|
wr_error <= 1'b0 ;
|
||||||
|
end
|
||||||
|
else begin
|
||||||
|
if (axi_awvalid_i && !wr_do && !rd_do) // accept just one write request - if idle
|
||||||
|
wr_do <= 1'b1 ;
|
||||||
|
else if (axi_bready_i && wr_do && ack)
|
||||||
|
wr_do <= 1'b0 ;
|
||||||
|
|
||||||
|
if (axi_awvalid_i && axi_awready_o) begin // latch ID and address
|
||||||
|
wr_awid <= axi_awid_i ;
|
||||||
|
wr_awaddr <= axi_awaddr_i ;
|
||||||
|
wr_error <= wr_errorw ;
|
||||||
|
end
|
||||||
|
|
||||||
|
if (axi_wvalid_i && wr_do) begin // latch ID and write data
|
||||||
|
wr_wid <= axi_wid_i ;
|
||||||
|
wr_wdata <= axi_wdata_i ;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
assign axi_awready_o = !wr_do && !rd_do ;
|
||||||
|
assign axi_wready_o = (wr_do && axi_wvalid_i) || (wr_errorw && axi_wvalid_i) ;
|
||||||
|
assign axi_bid_o = wr_awid ;
|
||||||
|
//assign axi_bresp_o = {wr_error,1'b0} ; // 2'b10 SLVERR
|
||||||
|
//assign axi_bvalid_o = (sys_wen_o && axi_bready_i) || (wr_error && axi_bready_i) ;
|
||||||
|
|
||||||
|
assign axi_arready_o = !rd_do && !wr_do && !axi_awvalid_i ;
|
||||||
|
assign axi_rid_o = rd_arid ;
|
||||||
|
//assign axi_rdata_o = sys_rdata_i ;
|
||||||
|
|
||||||
|
always @(posedge axi_clk_i) begin
|
||||||
|
if (axi_rstn_i == 1'b0) begin
|
||||||
|
axi_bvalid_o <= 1'b0 ;
|
||||||
|
axi_bresp_o <= 2'h0 ;
|
||||||
|
axi_rlast_o <= 1'b0 ;
|
||||||
|
axi_rvalid_o <= 1'b0 ;
|
||||||
|
axi_rresp_o <= 2'h0 ;
|
||||||
|
end
|
||||||
|
else begin
|
||||||
|
axi_bvalid_o <= wr_do && ack ;
|
||||||
|
axi_bresp_o <= {(wr_error || ack_cnt[5]),1'b0} ; // 2'b10 SLVERR 2'b00 OK
|
||||||
|
axi_rlast_o <= rd_do && ack ;
|
||||||
|
axi_rvalid_o <= rd_do && ack ;
|
||||||
|
axi_rresp_o <= {(rd_error || ack_cnt[5]),1'b0} ; // 2'b10 SLVERR 2'b00 OK
|
||||||
|
axi_rdata_o <= sys_rdata_i ;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
// acknowledge protection
|
||||||
|
always @(posedge axi_clk_i) begin
|
||||||
|
if (axi_rstn_i == 1'b0) begin
|
||||||
|
ack_cnt <= 6'h0 ;
|
||||||
|
end
|
||||||
|
else begin
|
||||||
|
if ((axi_arvalid_i && axi_arready_o) || (axi_awvalid_i && axi_awready_o)) // rd || wr request
|
||||||
|
ack_cnt <= 6'h1 ;
|
||||||
|
else if (ack)
|
||||||
|
ack_cnt <= 6'h0 ;
|
||||||
|
else if (|ack_cnt)
|
||||||
|
ack_cnt <= ack_cnt + 6'h1 ;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assign ack = sys_ack_i || ack_cnt[5] || (rd_do && rd_errorw) || (wr_do && wr_errorw); // bus acknowledge or timeout or error
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------
|
||||||
|
// Simple slave interface
|
||||||
|
|
||||||
|
always @(posedge axi_clk_i) begin
|
||||||
|
if (axi_rstn_i == 1'b0) begin
|
||||||
|
sys_wen_o <= 1'b0 ;
|
||||||
|
sys_ren_o <= 1'b0 ;
|
||||||
|
sys_sel_o <= {AXI_SW{1'b0}} ;
|
||||||
|
end
|
||||||
|
else begin
|
||||||
|
sys_wen_o <= wr_do && axi_wvalid_i && !wr_errorw ;
|
||||||
|
sys_ren_o <= axi_arvalid_i && axi_arready_o && !rd_errorw ;
|
||||||
|
sys_sel_o <= {AXI_SW{1'b1}} ;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assign sys_addr_o = rd_do ? rd_araddr : wr_awaddr ;
|
||||||
|
assign sys_wdata_o = wr_wdata ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
endmodule
|
128
fast-servo/linien-gateware/verilog/bus_clk_bridge.v
Normal file
128
fast-servo/linien-gateware/verilog/bus_clk_bridge.v
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
/**
|
||||||
|
* $Id: bus_clk_bridge.v 961 2014-01-21 11:40:39Z matej.oblak $
|
||||||
|
*
|
||||||
|
* @brief Red Pitaya system bus clock crossing bridge.
|
||||||
|
*
|
||||||
|
* @Author Matej Oblak
|
||||||
|
*
|
||||||
|
* (c) Red Pitaya http://www.redpitaya.com
|
||||||
|
*
|
||||||
|
* This part of code is written in Verilog hardware description language (HDL).
|
||||||
|
* Please visit http://en.wikipedia.org/wiki/Verilog
|
||||||
|
* for more details on the language used herein.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GENERAL DESCRIPTION:
|
||||||
|
*
|
||||||
|
* Clock domain bridge for system bus.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* /------\
|
||||||
|
* SYSTEM | | PROCESSING
|
||||||
|
* BUS <-----> | SYNC | <-----> BUS
|
||||||
|
* | |
|
||||||
|
* \------/
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* System bus runs on one clock domain while processing runs on separate. To
|
||||||
|
* simplify transition of writing and reading data this bridge was created.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
module bus_clk_bridge
|
||||||
|
(
|
||||||
|
// system bus
|
||||||
|
input sys_clk_i , //!< bus clock
|
||||||
|
input sys_rstn_i , //!< bus reset - active low
|
||||||
|
input [ 32-1: 0] sys_addr_i , //!< bus address
|
||||||
|
input [ 32-1: 0] sys_wdata_i , //!< bus write data
|
||||||
|
input [ 4-1: 0] sys_sel_i , //!< bus write byte select
|
||||||
|
input sys_wen_i , //!< bus write enable
|
||||||
|
input sys_ren_i , //!< bus read enable
|
||||||
|
output [ 32-1: 0] sys_rdata_o , //!< bus read data
|
||||||
|
output sys_err_o , //!< bus error indicator
|
||||||
|
output sys_ack_o , //!< bus acknowledge signal
|
||||||
|
|
||||||
|
|
||||||
|
// Destination bus
|
||||||
|
input clk_i , //!< clock
|
||||||
|
input rstn_i , //!< reset - active low
|
||||||
|
output reg [ 32-1: 0] addr_o , //!< address
|
||||||
|
output reg [ 32-1: 0] wdata_o , //!< write data
|
||||||
|
output wen_o , //!< write enable
|
||||||
|
output ren_o , //!< read enable
|
||||||
|
input [ 32-1: 0] rdata_i , //!< read data
|
||||||
|
input err_i , //!< error indicator
|
||||||
|
input ack_i //!< acknowledge signal
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
// Synchronize signals between clock domains
|
||||||
|
|
||||||
|
reg sys_rd ;
|
||||||
|
reg sys_wr ;
|
||||||
|
reg sys_do ;
|
||||||
|
reg [ 2-1: 0] sys_sync ;
|
||||||
|
reg sys_done ;
|
||||||
|
reg dst_do ;
|
||||||
|
reg [ 2-1: 0] dst_sync ;
|
||||||
|
reg dst_done ;
|
||||||
|
|
||||||
|
always @(posedge sys_clk_i) begin
|
||||||
|
if (sys_rstn_i == 1'b0) begin
|
||||||
|
sys_rd <= 1'b0 ;
|
||||||
|
sys_wr <= 1'b0 ;
|
||||||
|
sys_do <= 1'b0 ;
|
||||||
|
sys_sync <= 2'h0 ;
|
||||||
|
sys_done <= 1'b0 ;
|
||||||
|
end
|
||||||
|
else begin
|
||||||
|
|
||||||
|
if ((sys_do == sys_done) && (sys_wen_i || sys_ren_i)) begin
|
||||||
|
addr_o <= sys_addr_i ;
|
||||||
|
wdata_o <= sys_wdata_i ;
|
||||||
|
sys_rd <= sys_ren_i ;
|
||||||
|
sys_wr <= sys_wen_i ;
|
||||||
|
sys_do <= !sys_do ;
|
||||||
|
end
|
||||||
|
|
||||||
|
sys_sync <= {sys_sync[0], dst_done};
|
||||||
|
sys_done <= sys_sync[1];
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
always @(posedge clk_i) begin
|
||||||
|
if (rstn_i == 1'b0) begin
|
||||||
|
dst_do <= 1'b0 ;
|
||||||
|
dst_sync <= 2'h0 ;
|
||||||
|
dst_done <= 1'b0 ;
|
||||||
|
end
|
||||||
|
else begin
|
||||||
|
dst_sync <= {dst_sync[0], sys_do};
|
||||||
|
dst_do <= dst_sync[1];
|
||||||
|
|
||||||
|
if (ack_i && (dst_do != dst_done))
|
||||||
|
dst_done <= dst_do;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assign ren_o = sys_rd && (dst_sync[1]^dst_do);
|
||||||
|
assign wen_o = sys_wr && (dst_sync[1]^dst_do);
|
||||||
|
|
||||||
|
|
||||||
|
assign sys_rdata_o = rdata_i ;
|
||||||
|
assign sys_err_o = err_i ;
|
||||||
|
assign sys_ack_o = sys_done ^ sys_sync[1] ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
endmodule
|
111
fast-servo/linien-gateware/verilog/spi2threewire.v
Normal file
111
fast-servo/linien-gateware/verilog/spi2threewire.v
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
`timescale 1ns / 1ps
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Company: WUT
|
||||||
|
// Engineer: Jakub Matyas
|
||||||
|
//
|
||||||
|
// Create Date: 03/02/2023 01:39:08 PM
|
||||||
|
// Design Name:
|
||||||
|
// Module Name: spi2threewire
|
||||||
|
// Project Name:
|
||||||
|
// Target Devices:
|
||||||
|
// Tool Versions:
|
||||||
|
// Description:
|
||||||
|
//
|
||||||
|
// Dependencies:
|
||||||
|
//
|
||||||
|
// Revision:
|
||||||
|
// Revision 0.01 - File Created
|
||||||
|
// Additional Comments:
|
||||||
|
//
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
module spi2threewire (
|
||||||
|
output ps_sclk_i,
|
||||||
|
input ps_sclk_o,
|
||||||
|
input ps_sclk_t,
|
||||||
|
|
||||||
|
output ps_mosi_i,
|
||||||
|
input ps_mosi_o,
|
||||||
|
input ps_mosi_t,
|
||||||
|
|
||||||
|
output ps_miso_i,
|
||||||
|
input ps_miso_o,
|
||||||
|
input ps_miso_t,
|
||||||
|
|
||||||
|
output ps_ss_i,
|
||||||
|
input [2:0] ps_ss,
|
||||||
|
input ps_ss_t,
|
||||||
|
|
||||||
|
output o_ss,
|
||||||
|
output o_sclk,
|
||||||
|
inout sdio
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
assign ps_sclk_i = 1'b0;
|
||||||
|
assign ps_mosi_i = 1'b0;
|
||||||
|
assign ps_ss_i = 1'b1;
|
||||||
|
|
||||||
|
|
||||||
|
reg [3:0] bit_count = 'd0;
|
||||||
|
|
||||||
|
// rd_wr_n - whether it will be READ transaction or WRITE
|
||||||
|
// first bit of the command
|
||||||
|
reg rd_wr_n = 'd0;
|
||||||
|
reg sdio_buffer_direction = 'd0;
|
||||||
|
|
||||||
|
wire s_sclk;
|
||||||
|
wire s_csn;
|
||||||
|
wire s_sdio_buffer_direction;
|
||||||
|
|
||||||
|
assign s_sclk = ps_sclk_o;
|
||||||
|
assign s_csn = ps_ss[0];
|
||||||
|
assign o_ss = s_csn;
|
||||||
|
|
||||||
|
// 1 if there is a SPI tranmsission going on (CS_N is LOW)
|
||||||
|
// AND transmission is of READ type
|
||||||
|
// 0 otherwise
|
||||||
|
assign s_sdio_buffer_direction = sdio_buffer_direction & ~s_csn;
|
||||||
|
|
||||||
|
always @(posedge s_sclk or posedge s_csn) begin
|
||||||
|
if (s_csn == 1'b1) begin
|
||||||
|
// after the transmission, fill bit counter with ZEROS
|
||||||
|
// and zero transmission type (rd_wr_n)
|
||||||
|
bit_count <= 4'd0;
|
||||||
|
rd_wr_n <= 1'b0;
|
||||||
|
end else begin
|
||||||
|
// on every rising edge increment bit counter
|
||||||
|
// sample first bit to get the knowledge of the transmission type
|
||||||
|
bit_count <= (bit_count < 4'd15) ? bit_count + 1'b1 : bit_count;
|
||||||
|
if (bit_count == 4'b0)
|
||||||
|
rd_wr_n <= ps_mosi_o;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
always @(negedge s_sclk or posedge s_csn) begin
|
||||||
|
if (s_csn == 1'b1)
|
||||||
|
sdio_buffer_direction <= 1'b0;
|
||||||
|
else begin
|
||||||
|
if (bit_count == 4'd8)
|
||||||
|
// after the 8th bit, on falling edge,
|
||||||
|
// set the SDIO buffer direction
|
||||||
|
// accordingly to the transmission type
|
||||||
|
sdio_buffer_direction <= rd_wr_n;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
IOBUF IOBUF_inst (
|
||||||
|
.O(ps_miso_i),
|
||||||
|
.IO(sdio),
|
||||||
|
.I(ps_mosi_o),
|
||||||
|
.T(s_sdio_buffer_direction) // 3-state enable input, high=input (from ext), low=output
|
||||||
|
);
|
||||||
|
|
||||||
|
OBUFT sclk_buf (
|
||||||
|
.O(o_sclk),
|
||||||
|
.I(ps_sclk_o),
|
||||||
|
.T('b0)
|
||||||
|
);
|
||||||
|
|
||||||
|
endmodule
|
Loading…
Reference in New Issue
Block a user