efinix: RGMII phy should be operational (no tested)
PLL infrastructure should be complete now. We can also use DDIO input and outputs. However, there is problem (bug) during P&R: ERROR(1): [Line 52] Block auto_eth_tx_delayed_clk is an output pad but sub-block 1 is not an output pad location. Inderface Designer validation doesn't report any problem. I have a test project with the same configuration (I compared the reports for blocks configuration) and it works.
This commit is contained in:
parent
109dbd1d62
commit
179a8018b3
|
@ -180,15 +180,70 @@ design.create('{2}', '{3}', './../gateware', overwrite=True)
|
||||||
return b
|
return b
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def generate_gpio(self, block, verbose=True):
|
||||||
|
name = block['name']
|
||||||
|
mode = block['mode']
|
||||||
|
cmd = ''
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: {'type': 'GPIO', 'mode': 'OUTPUT', 'location': 'U16', 'size': 4, 'in_reg': 'DDIO_RESYNC', 'out_clk_pin': '', 'is_inclk_inverted': False, 'name': 'auto_ethtx_tx_data_d1', 'name_d2': 'auto_ethtx_tx_data_d2'}
|
||||||
|
|
||||||
|
if mode == 'INPUT':
|
||||||
|
if len(block['location']) == 1:
|
||||||
|
cmd += 'design.create_input_gpio("{}")\n'.format(name)
|
||||||
|
cmd += 'design.assign_pkg_pin("{}","{}")\n'.format(name, block['location'][0])
|
||||||
|
else:
|
||||||
|
cmd += 'design.create_input_gpio("{}",{},0)\n'.format(name, block['size']-1)
|
||||||
|
for i, pad in enumerate(block['location']):
|
||||||
|
cmd += 'design.assign_pkg_pin("{}[{}]","{}")\n'.format(name, i, pad)
|
||||||
|
if 'in_reg' in block:
|
||||||
|
cmd += 'design.set_property("{}","IN_REG","{}")\n'.format(name, block['in_reg'])
|
||||||
|
cmd += 'design.set_property("{}","IN_CLK_PIN","{}")\n\n'.format(name, block['in_clk_pin'])
|
||||||
|
return cmd
|
||||||
|
|
||||||
|
if mode == 'OUTPUT':
|
||||||
|
if len(block['location']) == 1:
|
||||||
|
cmd += 'design.create_output_gpio("{}")\n'.format(name)
|
||||||
|
cmd += 'design.assign_pkg_pin("{}","{}")\n'.format(name, block['location'][0])
|
||||||
|
else:
|
||||||
|
cmd += 'design.create_input_gpio("{}",{},0)\n'.format(name, block['size']-1)
|
||||||
|
for i, pad in enumerate(block['location']):
|
||||||
|
cmd += 'design.assign_pkg_pin("{}[{}]","{}")\n'.format(name, i, pad)
|
||||||
|
if 'out_reg' in block:
|
||||||
|
cmd += 'design.set_property("{}","OUT_REG","{}")\n'.format(name, block['out_reg'])
|
||||||
|
cmd += 'design.set_property("{}","OUT_CLK_PIN","{}")\n\n'.format(name, block['out_clk_pin'])
|
||||||
|
return cmd
|
||||||
|
|
||||||
|
if mode == 'INPUT_CLK':
|
||||||
|
cmd += 'design.create_input_clock_gpio("{}")\n'.format(name)
|
||||||
|
cmd += 'design.set_property("{}","IN_PIN","{}")\n'.format(name, name)
|
||||||
|
cmd += 'design.assign_pkg_pin("{}","{}")\n\n'.format(name, block['location'])
|
||||||
|
return cmd
|
||||||
|
|
||||||
|
if mode == 'OUTPUT_CLK':
|
||||||
|
cmd += 'design.create_clockout_gpio("{}")\n'.format(name)
|
||||||
|
cmd += 'design.set_property("{}","OUT_CLK_PIN","{}")\n'.format(name, name)
|
||||||
|
cmd += 'design.assign_pkg_pin("{}","{}")\n\n'.format(name, block['location'])
|
||||||
|
return cmd
|
||||||
|
|
||||||
|
cmd = '# TODO: ' + str(block) +'\n'
|
||||||
|
return cmd
|
||||||
|
|
||||||
def generate_pll(self, block, verbose=True):
|
def generate_pll(self, block, verbose=True):
|
||||||
name = block['name']
|
name = block['name']
|
||||||
cmd = '# ---------- PLL {} ---------\n'.format(name)
|
cmd = '# ---------- PLL {} ---------\n'.format(name)
|
||||||
cmd += 'design.create_block("{}", block_type="PLL")\n'.format(name)
|
cmd += 'design.create_block("{}", block_type="PLL")\n'.format(name)
|
||||||
cmd += 'design.gen_pll_ref_clock("{}", pll_res="{}", refclk_src="{}", refclk_name="{}", ext_refclk_no="{}")\n\n' \
|
|
||||||
.format(name, block['resource'], block['input_clock'], block['input_clock_name'], block['clock_no'])
|
|
||||||
|
|
||||||
cmd += 'pll_config = {{ "REFCLK_FREQ":"{}" }}\n'.format(block['input_freq'] / 1e6)
|
cmd += 'pll_config = {{ "REFCLK_FREQ":"{}" }}\n'.format(block['input_freq'] / 1e6)
|
||||||
cmd += 'design.set_property("{}", pll_config, block_type="PLL")\n\n'.format(name)
|
|
||||||
|
if block['input_clock'] == 'EXTERNAL':
|
||||||
|
cmd += 'design.gen_pll_ref_clock("{}", pll_res="{}", refclk_src="{}", refclk_name="{}", ext_refclk_no="{}")\n\n' \
|
||||||
|
.format(name, block['resource'], block['input_clock'], block['input_clock_name'], block['clock_no'])
|
||||||
|
else:
|
||||||
|
cmd += 'design.gen_pll_ref_clock("{}", pll_res="{}", refclk_name="{}", refclk_src="CORE")\n'.format(name, block['resource'], block['input_signal'])
|
||||||
|
cmd += 'design.set_property("{}", "CORE_CLK_PIN", "{}", block_type="PLL")\n\n'.format(name, block['input_signal'])
|
||||||
|
|
||||||
|
cmd += 'pll_config = {{ "REFCLK_FREQ":"{}" }}\n'.format(block['input_freq'] / 1e6)
|
||||||
|
cmd += 'design.set_property("{}", pll_config, block_type="PLL")\n\n'.format(name)
|
||||||
|
|
||||||
cmd += 'design.set_property("{}","LOCKED_PIN","{}", block_type="PLL")\n'.format(name, block['locked'])
|
cmd += 'design.set_property("{}","LOCKED_PIN","{}", block_type="PLL")\n'.format(name, block['locked'])
|
||||||
if block['reset'] != '':
|
if block['reset'] != '':
|
||||||
|
@ -198,10 +253,10 @@ design.create('{2}', '{3}', './../gateware', overwrite=True)
|
||||||
for i, clock in enumerate(block['clk_out']):
|
for i, clock in enumerate(block['clk_out']):
|
||||||
if i > 0:
|
if i > 0:
|
||||||
cmd += 'pll_config = {{ "CLKOUT{}_EN":"1", "CLKOUT{}_PIN":"{}" }}\n'.format(i, i, clock[0])
|
cmd += 'pll_config = {{ "CLKOUT{}_EN":"1", "CLKOUT{}_PIN":"{}" }}\n'.format(i, i, clock[0])
|
||||||
cmd += 'design.set_property("{}", pll_config, block_type="PLL")\n\n'.format(name)
|
|
||||||
else:
|
else:
|
||||||
cmd += 'pll_config = {{ "CLKOUT{}_PIN":"{}" }}\n'.format(i, clock[0])
|
cmd += 'pll_config = {{ "CLKOUT{}_PIN":"{}" }}\n'.format(i, clock[0])
|
||||||
cmd += 'design.set_property("{}", pll_config, block_type="PLL")\n\n'.format(name)
|
|
||||||
|
cmd += 'design.set_property("{}", pll_config, block_type="PLL")\n\n'.format(name)
|
||||||
|
|
||||||
cmd += 'target_freq = {\n'
|
cmd += 'target_freq = {\n'
|
||||||
for i, clock in enumerate(block['clk_out']):
|
for i, clock in enumerate(block['clk_out']):
|
||||||
|
@ -215,8 +270,8 @@ design.create('{2}', '{3}', './../gateware', overwrite=True)
|
||||||
cmd += 'print("#### {} ####")\n'.format(name)
|
cmd += 'print("#### {} ####")\n'.format(name)
|
||||||
cmd += 'clksrc_info = design.trace_ref_clock("{}", block_type="PLL")\n'.format(name)
|
cmd += 'clksrc_info = design.trace_ref_clock("{}", block_type="PLL")\n'.format(name)
|
||||||
cmd += 'pprint.pprint(clksrc_info)\n'
|
cmd += 'pprint.pprint(clksrc_info)\n'
|
||||||
cmd += 'clock_source_prop = ["REFCLK_SOURCE", "EXT_CLK", "CLKOUT0_EN", "CLKOUT1_EN","REFCLK_FREQ", "RESOURCE"]\n'
|
cmd += 'clock_source_prop = ["REFCLK_SOURCE", "CORE_CLK_PIN", "EXT_CLK", "CLKOUT0_EN", "CLKOUT1_EN","REFCLK_FREQ", "RESOURCE"]\n'
|
||||||
cmd += 'clock_source_prop += ["M", "N", "O", "CLKOUT0_DIV", "CLKOUT2_DIV", "VCO_FREQ", "PLL_FREQ"]\n'
|
cmd += 'clock_source_prop += ["CLKOUT0_FREQ", "CLKOUT1_FREQ", "CLKOUT2_FREQ"]\n'
|
||||||
cmd += 'prop_map = design.get_property("{}", clock_source_prop, block_type="PLL")\n'.format(name)
|
cmd += 'prop_map = design.get_property("{}", clock_source_prop, block_type="PLL")\n'.format(name)
|
||||||
cmd += 'pprint.pprint(prop_map)\n'
|
cmd += 'pprint.pprint(prop_map)\n'
|
||||||
|
|
||||||
|
@ -228,6 +283,9 @@ design.create('{2}', '{3}', './../gateware', overwrite=True)
|
||||||
for b in self.blocks:
|
for b in self.blocks:
|
||||||
if b['type'] == 'PLL':
|
if b['type'] == 'PLL':
|
||||||
output += self.generate_pll(b)
|
output += self.generate_pll(b)
|
||||||
|
if b['type'] == 'GPIO':
|
||||||
|
output += self.generate_gpio(b)
|
||||||
|
|
||||||
return output
|
return output
|
||||||
|
|
||||||
def footer(self):
|
def footer(self):
|
||||||
|
|
|
@ -18,6 +18,9 @@ class EfinixPlatform(GenericPlatform):
|
||||||
def __init__(self, *args, toolchain="efinity", **kwargs):
|
def __init__(self, *args, toolchain="efinity", **kwargs):
|
||||||
GenericPlatform.__init__(self, *args, **kwargs)
|
GenericPlatform.__init__(self, *args, **kwargs)
|
||||||
|
|
||||||
|
self.pll_available = ['PLL_TL0', 'PLL_TR0', 'PLL_TR1', 'PLL_TR2', 'PLL_TR3', 'PLL_BR0', 'PLL_BR1', 'PLL_BR2', 'PLL_BL0']
|
||||||
|
self.pll_used = []
|
||||||
|
|
||||||
if 'LITEX_ENV_EFINITY' in os.environ:
|
if 'LITEX_ENV_EFINITY' in os.environ:
|
||||||
self.efinity_path = os.environ['LITEX_ENV_EFINITY'].rstrip('/')
|
self.efinity_path = os.environ['LITEX_ENV_EFINITY'].rstrip('/')
|
||||||
os.environ['EFINITY_HOME'] = self.efinity_path
|
os.environ['EFINITY_HOME'] = self.efinity_path
|
||||||
|
@ -55,29 +58,63 @@ class EfinixPlatform(GenericPlatform):
|
||||||
# get_pin_location(p[1])
|
# get_pin_location(p[1])
|
||||||
# not tested with subsignal like get_pin_location(p.clk)
|
# not tested with subsignal like get_pin_location(p.clk)
|
||||||
def get_pin_location(self, sig):
|
def get_pin_location(self, sig):
|
||||||
|
if sig is None:
|
||||||
|
return None
|
||||||
sc = self.constraint_manager.get_sig_constraints()
|
sc = self.constraint_manager.get_sig_constraints()
|
||||||
for s, pins, others, resource in sc:
|
for s, pins, others, resource in sc:
|
||||||
if s == sig:
|
if (s == sig) and (pins[0] != 'X'):
|
||||||
return pins[0]
|
return pins
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def get_pin_name(self, sig):
|
def get_pin_name(self, sig):
|
||||||
|
if sig is None:
|
||||||
|
return None
|
||||||
sc = self.constraint_manager.get_sig_constraints()
|
sc = self.constraint_manager.get_sig_constraints()
|
||||||
for s, pins, others, resource in sc:
|
for s, pins, others, resource in sc:
|
||||||
if s == sig:
|
if s == sig:
|
||||||
return resource[0]
|
if resource[2]:
|
||||||
|
return resource[0] + '_' + resource[2]
|
||||||
|
else:
|
||||||
|
return resource[0]
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def add_iface_io(self, name, size=1):
|
def get_sig_constraint(self, sig):
|
||||||
|
sc = self.constraint_manager.get_sig_constraints()
|
||||||
|
for s, pins, others, resource in sc:
|
||||||
|
if s == sig:
|
||||||
|
return sc
|
||||||
|
return None
|
||||||
|
|
||||||
|
def add_iface_io(self, name, size=1, append=True):
|
||||||
self.add_extension([(name, 0, Pins(size))])
|
self.add_extension([(name, 0, Pins(size))])
|
||||||
tmp = self.request(name)
|
tmp = self.request(name)
|
||||||
# We don't want this IO to be in the interface configuration file as a simple GPIO
|
# We don't want this IO to be in the interface configuration file as a simple GPIO
|
||||||
self.toolchain.specials_gpios.append(tmp)
|
if append:
|
||||||
|
self.toolchain.specials_gpios.append(tmp)
|
||||||
return tmp
|
return tmp
|
||||||
|
|
||||||
def add_iface_ios(self, io):
|
def add_iface_ios(self, io, append=True):
|
||||||
self.add_extension(io)
|
self.add_extension(io)
|
||||||
tmp = self.request(io[0][0])
|
tmp = self.request(io[0][0])
|
||||||
for s in tmp.flatten():
|
if append:
|
||||||
self.toolchain.specials_gpios.append(s)
|
for s in tmp.flatten():
|
||||||
|
self.toolchain.specials_gpios.append(s)
|
||||||
return tmp
|
return tmp
|
||||||
|
|
||||||
|
def del_record_signal(self, record, sig):
|
||||||
|
for pos, (name, item) in enumerate(vars(record).items()):
|
||||||
|
if isinstance(item, Signal):
|
||||||
|
if item == sig:
|
||||||
|
# Two first pos are name and layout
|
||||||
|
del record.layout[pos-2]
|
||||||
|
delattr(record, name)
|
||||||
|
break
|
||||||
|
|
||||||
|
def get_pll_resource(self, name):
|
||||||
|
self.pll_used.append(name)
|
||||||
|
self.pll_available.remove(name)
|
||||||
|
print('Pll used : ' + str(self.pll_used))
|
||||||
|
print('Pll pll_available: ' + str(self.pll_available))
|
||||||
|
|
||||||
|
def get_free_pll_resource(self):
|
||||||
|
return self.pll_available[0]
|
|
@ -0,0 +1,194 @@
|
||||||
|
#
|
||||||
|
# This file is part of LiteEth.
|
||||||
|
#
|
||||||
|
# Copyright (c) 2015-2020 Florent Kermarrec <florent@enjoy-digital.fr>
|
||||||
|
# SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
|
||||||
|
# RGMII PHY for 7-Series Xilinx FPGA
|
||||||
|
|
||||||
|
from migen import *
|
||||||
|
from migen.genlib.resetsync import AsyncResetSynchronizer
|
||||||
|
|
||||||
|
from litex.build.generic_platform import *
|
||||||
|
from litex.soc.cores.clock import *
|
||||||
|
|
||||||
|
from liteeth.common import *
|
||||||
|
from liteeth.phy.common import *
|
||||||
|
|
||||||
|
|
||||||
|
class LiteEthPHYRGMIITX(Module):
|
||||||
|
def __init__(self, platform, pads):
|
||||||
|
self.sink = sink = stream.Endpoint(eth_phy_description(8))
|
||||||
|
|
||||||
|
# # #
|
||||||
|
|
||||||
|
name = platform.get_pin_name(pads.tx_data)
|
||||||
|
pad = platform.get_pin_location(pads.tx_data)
|
||||||
|
name = 'auto_' + name
|
||||||
|
tx_data_d1 = []
|
||||||
|
tx_data_d2 = []
|
||||||
|
# This a workaround, we could use signals with 4 bits but there is
|
||||||
|
# a problem with the Python API that prevents it
|
||||||
|
|
||||||
|
#tx_data_d1 = platform.add_iface_io(name + '_HI', 4)
|
||||||
|
#tx_data_d2 = platform.add_iface_io(name + '_LO', 4)
|
||||||
|
|
||||||
|
for i in range(4):
|
||||||
|
tx_data_d1.append(platform.add_iface_io(name + str(i) + '_HI'))
|
||||||
|
tx_data_d2.append(platform.add_iface_io(name + str(i) + '_LO'))
|
||||||
|
|
||||||
|
block = {'type':'GPIO',
|
||||||
|
'mode':'OUTPUT',
|
||||||
|
'name':name + str(i),
|
||||||
|
#'name':name,
|
||||||
|
'location':[pad[i]],
|
||||||
|
'size':1,
|
||||||
|
#'location':pad,
|
||||||
|
#'size':4,
|
||||||
|
'out_reg':'DDIO_RESYNC',
|
||||||
|
'out_clk_pin':'auto_eth_tx_clk', # -------------------------- TODO
|
||||||
|
'is_inclk_inverted':False
|
||||||
|
}
|
||||||
|
platform.toolchain.ifacewriter.blocks.append(block)
|
||||||
|
|
||||||
|
platform.del_record_signal(pads, pads.tx_data)
|
||||||
|
|
||||||
|
#self.comb += pads.tx_ctl.eq(sink.valid)
|
||||||
|
#self.comb += tx_data_d1.eq(sink.data[0:4])
|
||||||
|
#self.comb += tx_data_d2.eq(sink.data[4:8])
|
||||||
|
#self.comb += sink.ready.eq(1)
|
||||||
|
|
||||||
|
self.comb += [ pads.tx_ctl.eq(sink.valid),
|
||||||
|
tx_data_d1[0].eq(sink.data[0]),
|
||||||
|
tx_data_d1[1].eq(sink.data[1]),
|
||||||
|
tx_data_d1[2].eq(sink.data[2]),
|
||||||
|
tx_data_d1[3].eq(sink.data[3]),
|
||||||
|
tx_data_d2[0].eq(sink.data[4]),
|
||||||
|
tx_data_d2[1].eq(sink.data[5]),
|
||||||
|
tx_data_d2[2].eq(sink.data[6]),
|
||||||
|
tx_data_d2[3].eq(sink.data[7]),
|
||||||
|
sink.ready.eq(1),
|
||||||
|
]
|
||||||
|
|
||||||
|
class LiteEthPHYRGMIIRX(Module):
|
||||||
|
def __init__(self, platform, pads):
|
||||||
|
self.source = source = stream.Endpoint(eth_phy_description(8))
|
||||||
|
|
||||||
|
# # #
|
||||||
|
|
||||||
|
rx_ctl_d = Signal()
|
||||||
|
rx_data = Signal(8)
|
||||||
|
|
||||||
|
# pads.rx_ctl can't be connected to a special GPIO (DDIO) because
|
||||||
|
# of this board layout.
|
||||||
|
|
||||||
|
# Add a DDIO_RESYNC input block with 'auto_eth_rx_clk' as clock
|
||||||
|
name = platform.get_pin_name(pads.rx_data)
|
||||||
|
pad = platform.get_pin_location(pads.rx_data)
|
||||||
|
name = 'auto_' + name
|
||||||
|
rx_data_d1 = []
|
||||||
|
rx_data_d2 = []
|
||||||
|
# This a workaround, we could use signals with 4 bits but there is
|
||||||
|
# a problem with the Python API that prevents it
|
||||||
|
for i in range(4):
|
||||||
|
rx_data_d1.append(platform.add_iface_io(name + str(i) + '_HI'))
|
||||||
|
rx_data_d2.append(platform.add_iface_io(name + str(i) + '_LO'))
|
||||||
|
|
||||||
|
block = {'type':'GPIO',
|
||||||
|
'mode':'INPUT',
|
||||||
|
'name':name + str(i),
|
||||||
|
'location':[pad[i]],
|
||||||
|
'size':1,
|
||||||
|
'in_reg':'DDIO_RESYNC',
|
||||||
|
'in_clk_pin':'auto_eth_rx_clk',
|
||||||
|
'is_inclk_inverted':False
|
||||||
|
}
|
||||||
|
platform.toolchain.ifacewriter.blocks.append(block)
|
||||||
|
|
||||||
|
platform.del_record_signal(pads, pads.rx_data)
|
||||||
|
|
||||||
|
self.comb += rx_data.eq(Cat(rx_data_d1[0], rx_data_d1[1], rx_data_d1[2], rx_data_d1[3],
|
||||||
|
rx_data_d2[0], rx_data_d2[1], rx_data_d2[2], rx_data_d2[3]))
|
||||||
|
|
||||||
|
self.sync += rx_ctl_d.eq(pads.rx_ctl)
|
||||||
|
|
||||||
|
last = Signal()
|
||||||
|
self.comb += last.eq(~pads.rx_ctl & rx_ctl_d)
|
||||||
|
self.sync += [
|
||||||
|
source.valid.eq(pads.rx_ctl),
|
||||||
|
source.data.eq(rx_data)
|
||||||
|
]
|
||||||
|
self.comb += source.last.eq(last)
|
||||||
|
|
||||||
|
class LiteEthPHYRGMIICRG(Module, AutoCSR):
|
||||||
|
def __init__(self, platform, clock_pads, with_hw_init_reset, tx_delay=2e-9, hw_reset_cycles=256):
|
||||||
|
self._reset = CSRStorage()
|
||||||
|
|
||||||
|
# # #
|
||||||
|
|
||||||
|
# Clocks
|
||||||
|
|
||||||
|
self.clock_domains.cd_eth_rx = ClockDomain()
|
||||||
|
self.clock_domains.cd_eth_tx = ClockDomain()
|
||||||
|
self.clock_domains.cd_eth_tx_delayed = ClockDomain(reset_less=True)
|
||||||
|
|
||||||
|
# Add a GPIO block with clock input property
|
||||||
|
# Add a input 'auto_eth_rx_clk' to the top.v
|
||||||
|
clkrx = platform.add_iface_io('auto_eth_rx_clk')
|
||||||
|
block = {'type':'GPIO',
|
||||||
|
'size':1,
|
||||||
|
# Get the location from the original resource
|
||||||
|
'location': platform.get_pin_location(clock_pads.rx)[0],
|
||||||
|
'name':platform.get_pin_name(clkrx),
|
||||||
|
'mode':'INPUT_CLK'
|
||||||
|
}
|
||||||
|
platform.toolchain.ifacewriter.blocks.append(block)
|
||||||
|
self.comb += self.cd_eth_rx.clk.eq(clkrx)
|
||||||
|
|
||||||
|
clktx = platform.add_iface_io('auto_eth_tx_delayed_clk')
|
||||||
|
block = {'type':'GPIO',
|
||||||
|
'size':1,
|
||||||
|
# Get the location from the original resource
|
||||||
|
'location': platform.get_pin_location(clock_pads.tx)[0],
|
||||||
|
'name':platform.get_pin_name(clktx),
|
||||||
|
'mode':'OUTPUT_CLK'
|
||||||
|
}
|
||||||
|
platform.toolchain.ifacewriter.blocks.append(block)
|
||||||
|
self.comb += clktx.eq(self.cd_eth_tx.clk)
|
||||||
|
|
||||||
|
self.submodules.pll = pll = TRIONPLL(platform)
|
||||||
|
# Internal clock must come from a named signal
|
||||||
|
pll.register_clkin(None, 125e6, name='auto_eth_rx_clk')
|
||||||
|
pll.create_clkout(None, 125e6, phase=90, name='auto_eth_tx_delayed_clk')
|
||||||
|
pll.create_clkout(None, 125e6, name='auto_eth_tx_clk')
|
||||||
|
|
||||||
|
platform.delete(clock_pads)
|
||||||
|
|
||||||
|
## Reset
|
||||||
|
#self.reset = reset = Signal()
|
||||||
|
#if with_hw_init_reset:
|
||||||
|
# self.submodules.hw_reset = LiteEthPHYHWReset(cycles=hw_reset_cycles)
|
||||||
|
# self.comb += reset.eq(self._reset.storage | self.hw_reset.reset)
|
||||||
|
#else:
|
||||||
|
# self.comb += reset.eq(self._reset.storage)
|
||||||
|
#if hasattr(clock_pads, "rst_n"):
|
||||||
|
# self.comb += clock_pads.rst_n.eq(~reset)
|
||||||
|
#self.specials += [
|
||||||
|
# AsyncResetSynchronizer(self.cd_eth_tx, reset),
|
||||||
|
# AsyncResetSynchronizer(self.cd_eth_rx, reset),
|
||||||
|
#]
|
||||||
|
|
||||||
|
|
||||||
|
class LiteEthPHYRGMII(Module, AutoCSR):
|
||||||
|
dw = 8
|
||||||
|
tx_clk_freq = 125e6
|
||||||
|
rx_clk_freq = 125e6
|
||||||
|
def __init__(self, platform, clock_pads, pads, with_hw_init_reset=True, tx_delay=2e-9, rx_delay=2e-9,
|
||||||
|
iodelay_clk_freq=200e6, hw_reset_cycles=256):
|
||||||
|
self.submodules.crg = LiteEthPHYRGMIICRG(platform, clock_pads, with_hw_init_reset, tx_delay, hw_reset_cycles)
|
||||||
|
self.submodules.tx = ClockDomainsRenamer("eth_tx")(LiteEthPHYRGMIITX(platform, pads))
|
||||||
|
self.submodules.rx = ClockDomainsRenamer("eth_rx")(LiteEthPHYRGMIIRX(platform, pads))
|
||||||
|
self.sink, self.source = self.tx.sink, self.rx.source
|
||||||
|
|
||||||
|
#if hasattr(pads, "mdc"):
|
||||||
|
# self.submodules.mdio = LiteEthPHYMDIO(pads)
|
|
@ -192,6 +192,12 @@ class ConstraintManager:
|
||||||
|
|
||||||
def delete(self, signal):
|
def delete(self, signal):
|
||||||
for res, obj in self.matched:
|
for res, obj in self.matched:
|
||||||
|
if isinstance(signal, Record):
|
||||||
|
if isinstance(obj, Signal):
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
if isinstance(obj, Record):
|
||||||
|
continue
|
||||||
if obj == signal:
|
if obj == signal:
|
||||||
self.matched.remove((res, obj))
|
self.matched.remove((res, obj))
|
||||||
|
|
||||||
|
@ -280,12 +286,14 @@ class ConstraintManager:
|
||||||
if has_subsignals:
|
if has_subsignals:
|
||||||
for element in resource[2:]:
|
for element in resource[2:]:
|
||||||
if isinstance(element, Subsignal):
|
if isinstance(element, Subsignal):
|
||||||
sig = getattr(obj, element.name)
|
# Because we could have removed one Signal From the record
|
||||||
pins, others = _separate_pins(top_constraints +
|
if hasattr(obj, element.name):
|
||||||
element.constraints)
|
sig = getattr(obj, element.name)
|
||||||
pins = self.connector_manager.resolve_identifiers(pins)
|
pins, others = _separate_pins(top_constraints +
|
||||||
r.append((sig, pins, others,
|
element.constraints)
|
||||||
(name, number, element.name)))
|
pins = self.connector_manager.resolve_identifiers(pins)
|
||||||
|
r.append((sig, pins, others,
|
||||||
|
(name, number, element.name)))
|
||||||
else:
|
else:
|
||||||
pins, others = _separate_pins(top_constraints)
|
pins, others = _separate_pins(top_constraints)
|
||||||
pins = self.connector_manager.resolve_identifiers(pins)
|
pins = self.connector_manager.resolve_identifiers(pins)
|
||||||
|
|
|
@ -53,33 +53,44 @@ class TRIONPLL(Module):
|
||||||
|
|
||||||
self.platform.toolchain.ifacewriter.blocks.append(block)
|
self.platform.toolchain.ifacewriter.blocks.append(block)
|
||||||
|
|
||||||
def register_clkin(self, clkin, freq):
|
def register_clkin(self, clkin, freq, name= ''):
|
||||||
block = self.platform.toolchain.ifacewriter.get_block(self.pll_name)
|
block = self.platform.toolchain.ifacewriter.get_block(self.pll_name)
|
||||||
|
|
||||||
# If clkin has resource, PLL clock input is EXTERNAL
|
|
||||||
# When PLL clock is external, it must not be present in the top file
|
|
||||||
# Add a test on clkin resource here
|
|
||||||
block['input_clock_name'] = self.platform.get_pin_name(clkin)
|
block['input_clock_name'] = self.platform.get_pin_name(clkin)
|
||||||
pin_name = self.platform.get_pin_location(clkin)
|
|
||||||
|
|
||||||
self.platform.delete(clkin)
|
# If clkin has a pin number, PLL clock input is EXTERNAL
|
||||||
|
if self.platform.get_pin_location(clkin):
|
||||||
|
|
||||||
#tpl = "create_clock -name {clk} -period {period} [get_ports {{{clk}}}]"
|
pad_name = self.platform.get_pin_location(clkin)
|
||||||
#sdc = self.platform.toolchain.additional_sdc_commands
|
self.platform.delete(clkin)
|
||||||
#sdc.append(tpl.format(clk=block['input_clock_name'], period=1/freq))
|
|
||||||
|
|
||||||
parser = EfinixDbParser(self.platform.efinity_path, self.platform.device)
|
#tpl = "create_clock -name {clk} -period {period} [get_ports {{{clk}}}]"
|
||||||
(pll_res, clock_no) = parser.get_pll_inst_from_pin(pin_name)
|
#sdc = self.platform.toolchain.additional_sdc_commands
|
||||||
|
#sdc.append(tpl.format(clk=block['input_clock_name'], period=1/freq))
|
||||||
|
|
||||||
|
parser = EfinixDbParser(self.platform.efinity_path, self.platform.device)
|
||||||
|
try:
|
||||||
|
(pll_res, clock_no) = parser.get_pll_inst_from_pin(pad_name)
|
||||||
|
except:
|
||||||
|
self.logger.error("Cannot find a pll with {} as input".format(pad_name))
|
||||||
|
quit()
|
||||||
|
|
||||||
|
block['input_clock'] = 'EXTERNAL'
|
||||||
|
block['resource'] = pll_res
|
||||||
|
block['clock_no'] = clock_no
|
||||||
|
self.logger.info("Clock source: {}, using EXT_CLK{}".format(block['input_clock'], clock_no))
|
||||||
|
self.platform.get_pll_resource(pll_res)
|
||||||
|
else:
|
||||||
|
block['input_clock'] = 'INTERNAL'
|
||||||
|
block['resource'] = self.platform.get_free_pll_resource()
|
||||||
|
block['input_signal'] = name
|
||||||
|
self.logger.info("Clock source: {}".format(block['input_clock']))
|
||||||
|
|
||||||
block['input_clock'] = 'EXTERNAL'
|
|
||||||
block['input_freq'] = freq
|
block['input_freq'] = freq
|
||||||
block['resource'] = pll_res
|
|
||||||
block['clock_no'] = clock_no
|
|
||||||
|
|
||||||
self.logger.info("Using {}".format(pll_res))
|
self.logger.info("Using {}".format(block['resource']))
|
||||||
self.logger.info("Clock source: {}, using EXT_CLK{}".format(block['input_clock'], clock_no))
|
|
||||||
|
|
||||||
def create_clkout(self, cd, freq, phase=0, margin=1e-2, name='', with_reset=False, user_clk=True):
|
def create_clkout(self, cd, freq, phase=0, margin=1e-2, name='', with_reset=False):
|
||||||
assert self.nclkouts < self.nclkouts_max
|
assert self.nclkouts < self.nclkouts_max
|
||||||
|
|
||||||
if name != '':
|
if name != '':
|
||||||
|
@ -87,7 +98,7 @@ class TRIONPLL(Module):
|
||||||
else:
|
else:
|
||||||
clk_out_name = '{}_CLKOUT{}'.format(self.pll_name, self.nclkouts)
|
clk_out_name = '{}_CLKOUT{}'.format(self.pll_name, self.nclkouts)
|
||||||
|
|
||||||
if user_clk == True:
|
if cd != None:
|
||||||
self.platform.add_extension([(clk_out_name, 0, Pins(1))])
|
self.platform.add_extension([(clk_out_name, 0, Pins(1))])
|
||||||
tmp = self.platform.request(clk_out_name)
|
tmp = self.platform.request(clk_out_name)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue