nix-servo/fast-servo/linien-gateware/cores/spi_phy.py

142 lines
5.1 KiB
Python
Raw Permalink Normal View History

2024-02-28 14:47:38 +08:00
# 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,
)