soc/cores/icap: Add clk_divider parameter and initial ICAPE3 support (Throught primitive parameters).

Compiles on Ultrascale but still needs to be tested.
This commit is contained in:
Florent Kermarrec 2023-02-10 16:18:00 +01:00
parent 34422d2d91
commit 53e7492bd4

View file

@ -1,9 +1,10 @@
#
# This file is part of LiteX.
#
# Copyright (c) 2019-2021 Florent Kermarrec <florent@enjoy-digital.fr>
# Copyright (c) 2019-2023 Florent Kermarrec <florent@enjoy-digital.fr>
# SPDX-License-Identifier: BSD-2-Clause
import math
from enum import IntEnum
from migen import *
@ -68,7 +69,7 @@ class ICAPCMDs(IntEnum):
BSPI_READ = 0b10010 # BPI/SPI re-initiate bitstream read.
FALL_EDGE = 0b10011 # Switch to negative-edge clocking.
# Xilinx 7-series ----------------------------------------------------------------------------------
# Xilinx 7-series / Ultrascale (Plus) ICAP ---------------------------------------------------------
class ICAP(Module, AutoCSR):
"""ICAP
@ -77,7 +78,7 @@ class ICAP(Module, AutoCSR):
A warm boot can for example be triggered by writing IPROG CMD (0xf) to CMD register (0b100).
"""
def __init__(self, with_csr=True, simulation=False):
def __init__(self, with_csr=True, clk_divider=16, primitive="ICAPE2", simulation=False):
self.write = Signal()
self.read = Signal()
self.done = Signal()
@ -87,11 +88,16 @@ class ICAP(Module, AutoCSR):
# # #
# Create slow ICAP Clk (sys_clk/16).
# Parameters check.
assert primitive in ["ICAPE2", "ICAPE3"]
assert clk_divider > 1
assert math.log2(clk_divider).is_integer()
# Create slow ICAP Clk.
self.clock_domains.cd_icap = ClockDomain()
icap_clk_counter = Signal(4)
icap_clk_counter = Signal(int(math.log2(clk_divider)))
self.sync += icap_clk_counter.eq(icap_clk_counter + 1)
self.sync += self.cd_icap.clk.eq(icap_clk_counter[3])
self.sync += self.cd_icap.clk.eq(icap_clk_counter[-1])
# Generate ICAP bitstream sequence.
self._csib = _csib = Signal(reset=1)
@ -209,18 +215,21 @@ class ICAP(Module, AutoCSR):
# ICAP Instance.
if not simulation:
_i_icape2 = Signal(32)
_o_icape2 = Signal(32)
self.comb += _i_icape2.eq(Cat(*[_i[8*i:8*(i+1)][::-1] for i in range(4)])),
self.comb += _o.eq(Cat(*[_o_icape2[8*i:8*(i+1)][::-1] for i in range(4)])),
self.specials += Instance("ICAPE2",
p_ICAP_WIDTH = "X32",
_i_icape = Signal(32)
_o_icape = Signal(32)
self.comb += _i_icape.eq(Cat(*[_i[8*i:8*(i+1)][::-1] for i in range(4)])),
self.comb += _o.eq(Cat(*[_o_icape[8*i:8*(i+1)][::-1] for i in range(4)])),
self.params = dict()
if primitive == "ICAPE2":
self.params.update(p_ICAP_WIDTH="X32")
self.params.update(
i_CLK = ClockSignal("icap"),
i_CSIB = _csib,
i_RDWRB = _rdwrb,
i_I = _i_icape2,
o_O = _o_icape2,
i_I = _i_icape,
o_O = _o_icape,
)
self.specials += Instance(primitive, **self.params)
# CSR.
if with_csr: