From 94396b98ffe829fc1b90851b46bdbe8fc0578b50 Mon Sep 17 00:00:00 2001 From: Tom Trafford Date: Wed, 1 Sep 2021 16:18:23 +0100 Subject: [PATCH 01/15] Added support for write extensions --- common/python/configs.py | 35 ++++++++++++++++++++++++-- common/python/generate_app.py | 1 + common/templates/block_ctrl.vhd.jinja2 | 2 +- common/templates/config.jinja2 | 6 +++-- common/templates/descriptions.jinja2 | 2 ++ common/templates/registers.jinja2 | 2 ++ 6 files changed, 43 insertions(+), 5 deletions(-) diff --git a/common/python/configs.py b/common/python/configs.py index b50fbb87c..cf6477397 100755 --- a/common/python/configs.py +++ b/common/python/configs.py @@ -127,6 +127,8 @@ def __init__(self, name, type, number, ini_path, site=None): #: All the child fields self.fields = FieldConfig.from_ini( ini, number) # type: List[FieldConfig] + #: List of WriteExtension fields in the block + self.write_extensions=[] #: Are there any suffixes? self.block_suffixes = ini_get(ini, '.', 'block_suffixes', '').split() @@ -172,6 +174,19 @@ def generateInterfaceConstraints(self): if constraint not in self.interfaceConstraints: self.interfaceConstraints.append(constraint) + def generateWriteExtensions(self): + # Iterate through the fields and add any with writeExtension type to the list + for field in self.fields: + if field.type == "extension_write": + w_extension = (field.name, field.registers[0].number) + self.write_extensions.append(w_extension) + # Iterate through the fields, when a writeExtension is specified find its number + for field in self.fields: + for extension in field.extension_write.split(" "): + for w_extension, num in self.write_extensions: + if w_extension == extension: + field.extension_nums.append(num) + def make_getter_setter(config): def getter(self): return getattr(self, "_" + config.name, 0) @@ -190,7 +205,7 @@ def setter(self, v): class RegisterConfig(object): """A low level register name and number backing this field""" - def __init__(self, name, number=-1, prefix='', extension=''): + def __init__(self, name, number=-1, prefix='', extension='', write_extension=''): # type: (str, int, str, str) -> None #: The name of the register, like INPA_DLY self.name = name.replace('.', '_') @@ -200,6 +215,8 @@ def __init__(self, name, number=-1, prefix='', extension=''): self.prefix = prefix #: For an extension field, the register path self.extension = extension + #: If there is a write extension + self.write_extension = write_extension class BusEntryConfig(object): @@ -241,6 +258,9 @@ def __init__(self, name, number, type, description, extra_config): #: Store the extension register info self.extension = extra_config.pop("extension", None) self.extension_reg = extra_config.pop("extension_reg", None) + self.extension_write = extra_config.pop("extension_write", "") + self.extension_nums = [] + self.no_config = 0 #: All the other extra config items self.extra_config_lines = list(self.parse_extra_config(extra_config)) @@ -266,6 +286,8 @@ def make_reg_name(r): if r.number >= 0: result.append(str(r.number)) if r.extension: + if r.write_extension: + result.extend(['W', str(' '.join(str(num) for num in self.extension_nums))]) result.extend(['X', r.extension]) return ' '.join(result) @@ -465,8 +487,17 @@ def register_addresses(self, counters): address = counters.new_field() self.registers.append( - RegisterConfig(self.name, address, extension=self.extension)) + RegisterConfig(self.name, address, extension=self.extension, write_extension=self.extension_write)) +class ExtensionWriteFieldConfig(ParamFieldConfig): + """These fields act in the same way as write record from the VHDL generation + point of view, but do not have a config entry""" + type_regex = "extension_write" + + def register_addresses(self, counters): + # type: (FieldCounter) -> None + super(ExtensionWriteFieldConfig, self).register_addresses(counters) + self.no_config=1 class EnumParamFieldConfig(ParamFieldConfig): """An enum field with its integer entries and string values""" diff --git a/common/python/generate_app.py b/common/python/generate_app.py index 47c09dad6..c48345a17 100755 --- a/common/python/generate_app.py +++ b/common/python/generate_app.py @@ -152,6 +152,7 @@ def implement_blocks(self, ini, path, type): # for carrier block block = BlockConfig(section, type, number, ini_path, siteNumber) block.register_addresses(self.counters) + block.generateWriteExtensions() self.fpga_blocks.append(block) # Copy the fpga_blocks to the server blocks. Most blocks will # be the same between the two, however the block suffixes blocks diff --git a/common/templates/block_ctrl.vhd.jinja2 b/common/templates/block_ctrl.vhd.jinja2 index 9b0cf9e7f..d36c5e06c 100644 --- a/common/templates/block_ctrl.vhd.jinja2 +++ b/common/templates/block_ctrl.vhd.jinja2 @@ -23,7 +23,7 @@ port ( {% for register in field.numbered_registers() %} {% if field in filter_fields("read.*") %} {{ pad(register.name) }} : in std_logic_vector(31 downto 0); - {% elif field in filter_fields ("table|time|(param|write).*")%} + {% elif field in filter_fields ("table|time|extension_write|(param|write).*")%} {{ pad(register.name) }} : out std_logic_vector(31 downto 0); {{ pad(register.name + "_wstb") }} : out std_logic; {% endif %} diff --git a/common/templates/config.jinja2 b/common/templates/config.jinja2 index 34cd4dd21..dd9acfd1e 100644 --- a/common/templates/config.jinja2 +++ b/common/templates/config.jinja2 @@ -17,11 +17,13 @@ {% for field in block.fields %} {# field is a FieldConfig object #} {# insert its name and type (including subtype and options) #} + {% if field.no_config != 1 %} {{ pad(field.name) }} {{ field.config_line() }} - {% for line in field.extra_config_lines %} + {% for line in field.extra_config_lines %} {# some fields line enum and table have extra lines, insert them here #} {{ line }} - {% endfor %} + {% endfor %} + {% endif %} {% endfor %} {# insert a blank line between blocks for readability #} diff --git a/common/templates/descriptions.jinja2 b/common/templates/descriptions.jinja2 index 451d56455..0322438d9 100644 --- a/common/templates/descriptions.jinja2 +++ b/common/templates/descriptions.jinja2 @@ -5,7 +5,9 @@ {% for field in block.fields %} {# field is a FieldConfig object #} {# insert its name and description #} + {% if field.no_config != 1 %} {{ pad(field.name) }} {{ field.description }} + {% endif %} {% endfor %} {# insert a blank line between blocks for readability #} diff --git a/common/templates/registers.jinja2 b/common/templates/registers.jinja2 index 06ad8426d..53366f076 100644 --- a/common/templates/registers.jinja2 +++ b/common/templates/registers.jinja2 @@ -9,7 +9,9 @@ {% for field in block.fields %} {# field is a FieldConfig object #} {# ask it for its register addresses within the block base address #} + {% if field.no_config != 1 %} {{ pad(field.name) }} {{ field.address_line() }} + {% endif %} {% endfor %} {# insert a blank line between blocks for readability #} From e515a2e4b2e7f30ff20eb5d2eb7e0cf262203b98 Mon Sep 17 00:00:00 2001 From: Tom Trafford Date: Thu, 9 Sep 2021 10:28:37 +0100 Subject: [PATCH 02/15] Added read extension support --- common/python/configs.py | 30 +++++++++++++++++++------- common/python/generate_app.py | 2 +- common/templates/block_ctrl.vhd.jinja2 | 2 +- 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/common/python/configs.py b/common/python/configs.py index cf6477397..da83acd64 100755 --- a/common/python/configs.py +++ b/common/python/configs.py @@ -129,6 +129,8 @@ def __init__(self, name, type, number, ini_path, site=None): ini, number) # type: List[FieldConfig] #: List of WriteExtension fields in the block self.write_extensions=[] + #: List of ReadExtension fields in the block + self.read_extensions=[] #: Are there any suffixes? self.block_suffixes = ini_get(ini, '.', 'block_suffixes', '').split() @@ -174,18 +176,25 @@ def generateInterfaceConstraints(self): if constraint not in self.interfaceConstraints: self.interfaceConstraints.append(constraint) - def generateWriteExtensions(self): + def generateCalcExtensions(self): # Iterate through the fields and add any with writeExtension type to the list for field in self.fields: if field.type == "extension_write": w_extension = (field.name, field.registers[0].number) self.write_extensions.append(w_extension) + if field.type == "extension_read": + w_extension = (field.name, field.registers[0].number) + self.read_extensions.append(w_extension) # Iterate through the fields, when a writeExtension is specified find its number for field in self.fields: for extension in field.extension_write.split(" "): for w_extension, num in self.write_extensions: if w_extension == extension: field.extension_nums.append(num) + for extension in field.extension_read.split(" "): + for r_extension, num in self.read_extensions: + if r_extension == extension: + field.extension_nums.append(num) def make_getter_setter(config): def getter(self): @@ -205,8 +214,8 @@ def setter(self, v): class RegisterConfig(object): """A low level register name and number backing this field""" - def __init__(self, name, number=-1, prefix='', extension='', write_extension=''): - # type: (str, int, str, str) -> None + def __init__(self, name, number=-1, prefix='', extension='', write_extension='', read_extension=''): + # type: (str, int, str, str, str, str) -> None #: The name of the register, like INPA_DLY self.name = name.replace('.', '_') #: The register number relative to Block, like 9 @@ -217,6 +226,8 @@ def __init__(self, name, number=-1, prefix='', extension='', write_extension='') self.extension = extension #: If there is a write extension self.write_extension = write_extension + #: If there is a write extension + self.read_extension = read_extension class BusEntryConfig(object): @@ -259,6 +270,7 @@ def __init__(self, name, number, type, description, extra_config): self.extension = extra_config.pop("extension", None) self.extension_reg = extra_config.pop("extension_reg", None) self.extension_write = extra_config.pop("extension_write", "") + self.extension_read = extra_config.pop("extension_read", "") self.extension_nums = [] self.no_config = 0 #: All the other extra config items @@ -288,6 +300,8 @@ def make_reg_name(r): if r.extension: if r.write_extension: result.extend(['W', str(' '.join(str(num) for num in self.extension_nums))]) + if r.read_extension: + result.extend([str(' '.join(str(num) for num in self.extension_nums))]) result.extend(['X', r.extension]) return ' '.join(result) @@ -487,16 +501,16 @@ def register_addresses(self, counters): address = counters.new_field() self.registers.append( - RegisterConfig(self.name, address, extension=self.extension, write_extension=self.extension_write)) + RegisterConfig(self.name, address, extension=self.extension, write_extension=self.extension_write, read_extension=self.extension_read)) -class ExtensionWriteFieldConfig(ParamFieldConfig): +class CalcExtensionFieldConfig(ParamFieldConfig): """These fields act in the same way as write record from the VHDL generation point of view, but do not have a config entry""" - type_regex = "extension_write" + type_regex = "(extension_write|extension_read)" def register_addresses(self, counters): # type: (FieldCounter) -> None - super(ExtensionWriteFieldConfig, self).register_addresses(counters) + super(CalcExtensionFieldConfig, self).register_addresses(counters) self.no_config=1 class EnumParamFieldConfig(ParamFieldConfig): @@ -600,7 +614,7 @@ class TargetSiteConfig(object): type_regex = None def __init__(self, name, info): - # type: (str, int, int, int, str) -> None + # type: (str, str)-> None #: The type of target site (SFP/FMC etc) self.name = name #: The info i in a string such as "3, i, io, o" diff --git a/common/python/generate_app.py b/common/python/generate_app.py index c48345a17..1b72a2fe6 100755 --- a/common/python/generate_app.py +++ b/common/python/generate_app.py @@ -152,7 +152,7 @@ def implement_blocks(self, ini, path, type): # for carrier block block = BlockConfig(section, type, number, ini_path, siteNumber) block.register_addresses(self.counters) - block.generateWriteExtensions() + block.generateCalcExtensions() self.fpga_blocks.append(block) # Copy the fpga_blocks to the server blocks. Most blocks will # be the same between the two, however the block suffixes blocks diff --git a/common/templates/block_ctrl.vhd.jinja2 b/common/templates/block_ctrl.vhd.jinja2 index d36c5e06c..c05fed7d3 100644 --- a/common/templates/block_ctrl.vhd.jinja2 +++ b/common/templates/block_ctrl.vhd.jinja2 @@ -21,7 +21,7 @@ port ( -- Block Parameters {% for field in fields %} {% for register in field.numbered_registers() %} - {% if field in filter_fields("read.*") %} + {% if field in filter_fields("extension_read|read.*") %} {{ pad(register.name) }} : in std_logic_vector(31 downto 0); {% elif field in filter_fields ("table|time|extension_write|(param|write).*")%} {{ pad(register.name) }} : out std_logic_vector(31 downto 0); From 5b8bb55c985de65980ab717641f9f965dca7fadf Mon Sep 17 00:00:00 2001 From: Tom Trafford Date: Wed, 29 Jun 2022 13:44:49 +0100 Subject: [PATCH 03/15] Move to more generic calc_extensions[] attribute --- common/python/configs.py | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/common/python/configs.py b/common/python/configs.py index da83acd64..cfa60ab39 100755 --- a/common/python/configs.py +++ b/common/python/configs.py @@ -127,10 +127,8 @@ def __init__(self, name, type, number, ini_path, site=None): #: All the child fields self.fields = FieldConfig.from_ini( ini, number) # type: List[FieldConfig] - #: List of WriteExtension fields in the block - self.write_extensions=[] - #: List of ReadExtension fields in the block - self.read_extensions=[] + #: List of Extension fields in the block + self.calc_extensions=[] #: Are there any suffixes? self.block_suffixes = ini_get(ini, '.', 'block_suffixes', '').split() @@ -178,22 +176,16 @@ def generateInterfaceConstraints(self): def generateCalcExtensions(self): # Iterate through the fields and add any with writeExtension type to the list - for field in self.fields: - if field.type == "extension_write": - w_extension = (field.name, field.registers[0].number) - self.write_extensions.append(w_extension) - if field.type == "extension_read": - w_extension = (field.name, field.registers[0].number) - self.read_extensions.append(w_extension) + for field in self.filter_fields("extension_.*"): + extension = (field.name, field.registers[0].number) + self.extension=self.name.lower() + self.calc_extensions.append(extension) + # After extensions have been added to self.read_extensions/self.write_extensions # Iterate through the fields, when a writeExtension is specified find its number for field in self.fields: - for extension in field.extension_write.split(" "): - for w_extension, num in self.write_extensions: - if w_extension == extension: - field.extension_nums.append(num) - for extension in field.extension_read.split(" "): - for r_extension, num in self.read_extensions: - if r_extension == extension: + for calc_extension, num in self.calc_extensions: + for extension in field.extension_write.split(" ") + field.extension_read.split(" "): + if calc_extension == extension: field.extension_nums.append(num) def make_getter_setter(config): From 32f3b8258bc5bfbb987b25aa102ae9a425f6a689 Mon Sep 17 00:00:00 2001 From: Tom Trafford Date: Thu, 30 Jun 2022 08:27:36 +0100 Subject: [PATCH 04/15] Added python test to verify config_d for calc_extensions --- common/python/generate_app.py | 13 +++- tests/python/test_calc_extensions.py | 48 ++++++++++++++ .../app-expected/config_d/config | 12 ++++ .../app-expected/config_d/description | 5 ++ .../app-expected/config_d/registers | 64 +++++++++++++++++++ .../calc_extension.app.ini | 6 ++ .../calcextension/calcextension.block.ini | 33 ++++++++++ 7 files changed, 178 insertions(+), 3 deletions(-) create mode 100644 tests/python/test_calc_extensions.py create mode 100644 tests/python/test_data_calc_extensions/app-expected/config_d/config create mode 100644 tests/python/test_data_calc_extensions/app-expected/config_d/description create mode 100644 tests/python/test_data_calc_extensions/app-expected/config_d/registers create mode 100644 tests/python/test_data_calc_extensions/calc_extension.app.ini create mode 100644 tests/python/test_data_calc_extensions/calcextension/calcextension.block.ini diff --git a/common/python/generate_app.py b/common/python/generate_app.py index 1b72a2fe6..9327ccef3 100755 --- a/common/python/generate_app.py +++ b/common/python/generate_app.py @@ -49,13 +49,14 @@ def jinja_env(path): class AppGenerator(object): - def __init__(self, app, app_build_dir): - # type: (str, str) -> None + def __init__(self, app, app_build_dir, testPath=""): + # type: (str, str, str) -> None # Make sure the outputs directory doesn't already exist assert not os.path.exists(app_build_dir), \ "Output dir %r already exists" % app_build_dir self.app_build_dir = app_build_dir self.app_name = app.split('/')[-1].split('.')[0] + self.testPath=testPath # Create a Jinja2 environment in the templates dir self.env = jinja_env(TEMPLATES) # Start from base register 2 to allow for *REG and *DRV spaces @@ -117,7 +118,13 @@ def parse_ini_files(self, app): assert fpga_option in VALID_FPGA_OPTIONS, \ "%r option defined in target ini file is not valid" % fpga_option # Implement the blocks for the soft blocks - self.implement_blocks(app_ini, "modules", "soft") + # If a test path has been given, use it for location of blocks. + # Otherwise blocks should be in moudles directory + if self.testPath: + path=self.testPath + else: + path="modules" + self.implement_blocks(app_ini, path, "soft") def implement_blocks(self, ini, path, type): """Read the ini file and for each section create a new block""" diff --git a/tests/python/test_calc_extensions.py b/tests/python/test_calc_extensions.py new file mode 100644 index 000000000..b614af4ea --- /dev/null +++ b/tests/python/test_calc_extensions.py @@ -0,0 +1,48 @@ +import os +import shutil +import unittest +from common.python.generate_app import AppGenerator + + +TEST_DATA = os.path.join(os.path.dirname(__file__), "test_data_calc_extensions") + + +class TestCalcApp(unittest.TestCase): + maxDiff = None + app_build_dir = None + + @classmethod + def setUpClass(cls): + here = os.path.dirname(__file__) + path= "tests/python/test_data_calc_extensions" + app = os.path.join(here, "test_data_calc_extensions", "calc_extension.app.ini") + cls.app_build_dir = "/tmp/test_app_calc_extensions_build_dir" + if os.path.exists(cls.app_build_dir): + shutil.rmtree(cls.app_build_dir) + cls.expected_dir = os.path.join(here, "test_data_calc_extensions", "app-expected") + AppGenerator(app, cls.app_build_dir, testPath=path) + + @classmethod + def tearDownClass(cls): + if os.path.exists(cls.app_build_dir): + shutil.rmtree(cls.app_build_dir) + + def assertGeneratedEqual(self, *path): + with open(os.path.join(self.expected_dir, *path)) as f: + expected = f.read() + with open(os.path.join(self.app_build_dir, *path)) as f: + actual = f.read() + self.assertMultiLineEqual(expected, actual) + + def test_description(self): + self.assertGeneratedEqual("config_d", "description") + + def test_config(self): + self.assertGeneratedEqual("config_d", "config") + + def test_registers(self): + self.assertGeneratedEqual("config_d", "registers") + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/python/test_data_calc_extensions/app-expected/config_d/config b/tests/python/test_data_calc_extensions/app-expected/config_d/config new file mode 100644 index 000000000..8372daac6 --- /dev/null +++ b/tests/python/test_data_calc_extensions/app-expected/config_d/config @@ -0,0 +1,12 @@ +*METADATA + APPNAME constant =calc_extension + DESIGN string + LAYOUT multiline + EXPORTS multiline + LABEL_CALCEXTENSION1 string + +CALCEXTENSION[1] + TEST param + CENTRE param + RANGE param + diff --git a/tests/python/test_data_calc_extensions/app-expected/config_d/description b/tests/python/test_data_calc_extensions/app-expected/config_d/description new file mode 100644 index 000000000..ea39afcc3 --- /dev/null +++ b/tests/python/test_data_calc_extensions/app-expected/config_d/description @@ -0,0 +1,5 @@ +CALCEXTENSION calculated registers tests + TEST + CENTRE + RANGE + diff --git a/tests/python/test_data_calc_extensions/app-expected/config_d/registers b/tests/python/test_data_calc_extensions/app-expected/config_d/registers new file mode 100644 index 000000000..1bf4e50d1 --- /dev/null +++ b/tests/python/test_data_calc_extensions/app-expected/config_d/registers @@ -0,0 +1,64 @@ +# Register interface definition + +# This special register block is not present in the config file and contains +# fixed register definitions used in the hardware interface. +*REG 0 + # + # FPGA Version and Build Identification Values + # + FPGA_VERSION 0 + FPGA_BUILD 1 + USER_VERSION 2 + # Bit bus readout registers: first write to BIT_READ_RST to capture a + # snapshot of the bit bus and its changes, then read BIT_READ_VALUE 8 times + # to read out bit bus values and change flags. + BIT_READ_RST 3 + BIT_READ_VALUE 4 + + # Position bus readout registers: first write to POS_READ_RST to snapshot + # the position bus and the change set, then read POS_READ_VALUE 32 times to + # read out the positions, and finally read the change set from + # POS_READ_CHANGES. + POS_READ_RST 5 + POS_READ_VALUE 6 + POS_READ_CHANGES 7 + + # The capture set is written by first writing to PCAP_START_WRITE and then + # writing the required changes to PCAP_WRITE + PCAP_START_WRITE 8 + PCAP_WRITE 9 + + # Position capture control + PCAP_ARM 13 + PCAP_DISARM 14 + + # FPGA Capabilities Value + FPGA_CAPABILITIES 15 + + # Range of MAC addresses + MAC_ADDRESS_BASE 16 .. 23 + + +# These registers are used by the kernel driver to read the data capture stream. +# This block is not used by the server, but is here for documentation and other +# automated tools. +*DRV 1 + # This register is used to reset DMA engine. + PCAP_DMA_RESET 0 + # This register is used to initialise DMA engine with first set of + # addresses. + PCAP_DMA_START 1 + # The physical address of each DMA block is written to this register. + PCAP_DMA_ADDR 2 + # This register configures the maximum interval between capture interrupts + PCAP_TIMEOUT 3 + # Interrupt status and acknowledge + PCAP_IRQ_STATUS 4 + # DMA block size in bytes + PCAP_BLOCK_SIZE 6 + +CALCEXTENSION 2 calcextension + TEST 1 X test + CENTRE W 0 2 X centre + RANGE W 0 2 X range + diff --git a/tests/python/test_data_calc_extensions/calc_extension.app.ini b/tests/python/test_data_calc_extensions/calc_extension.app.ini new file mode 100644 index 000000000..8cb6658cc --- /dev/null +++ b/tests/python/test_data_calc_extensions/calc_extension.app.ini @@ -0,0 +1,6 @@ +[.] +description: Test app with only 8 LUTs +target: + +[CALCEXTENSION] +number: 1 diff --git a/tests/python/test_data_calc_extensions/calcextension/calcextension.block.ini b/tests/python/test_data_calc_extensions/calcextension/calcextension.block.ini new file mode 100644 index 000000000..28adc2c9d --- /dev/null +++ b/tests/python/test_data_calc_extensions/calcextension/calcextension.block.ini @@ -0,0 +1,33 @@ +[.] +description: calculated registers tests +entity: calcExtension + +[BOTTOM] +description: +type: extension_write + +[LEFT] +description: +type: extension_read + +[TEST] +description: +type: param +extension: test +extension_read: LEFT + +[CENTRE] +description: +type: param +extension: centre +extension_write: BOTTOM TOP + +[RANGE] +description: +type: param +extension: range +extension_write: BOTTOM TOP + +[TOP] +description: +type: extension_write From 10b894c00fa5b98c2d55be96f0e3ae1b4873646c Mon Sep 17 00:00:00 2001 From: Tom Trafford Date: Thu, 30 Jun 2022 08:50:13 +0100 Subject: [PATCH 05/15] Updated new python test to run with more recent changes --- tests/python/test_calc_extensions.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/python/test_calc_extensions.py b/tests/python/test_calc_extensions.py index b614af4ea..f641fe136 100644 --- a/tests/python/test_calc_extensions.py +++ b/tests/python/test_calc_extensions.py @@ -20,7 +20,9 @@ def setUpClass(cls): if os.path.exists(cls.app_build_dir): shutil.rmtree(cls.app_build_dir) cls.expected_dir = os.path.join(here, "test_data_calc_extensions", "app-expected") - AppGenerator(app, cls.app_build_dir, testPath=path) + cls.app_generator = AppGenerator(app, cls.app_build_dir, testPath=path) + cls.app_generator.generate_all() + @classmethod def tearDownClass(cls): From 7330076e00502ebda7bfabfbd34770a3870ef0c3 Mon Sep 17 00:00:00 2001 From: Tom Trafford Date: Thu, 7 Jul 2022 12:47:17 +0100 Subject: [PATCH 06/15] Updated test to match sim_config from PandABlocks-server --- .../app-expected/config_d/config | 18 +++++-- .../app-expected/config_d/description | 9 +++- .../app-expected/config_d/registers | 13 +++-- .../calc_extension.app.ini | 7 ++- .../dummy/dummy.block.ini | 50 +++++++++++++++++++ .../interval.block.ini} | 14 +----- 6 files changed, 88 insertions(+), 23 deletions(-) create mode 100644 tests/python/test_data_calc_extensions/dummy/dummy.block.ini rename tests/python/test_data_calc_extensions/{calcextension/calcextension.block.ini => interval/interval.block.ini} (59%) diff --git a/tests/python/test_data_calc_extensions/app-expected/config_d/config b/tests/python/test_data_calc_extensions/app-expected/config_d/config index 8372daac6..2a117e27c 100644 --- a/tests/python/test_data_calc_extensions/app-expected/config_d/config +++ b/tests/python/test_data_calc_extensions/app-expected/config_d/config @@ -3,10 +3,22 @@ DESIGN string LAYOUT multiline EXPORTS multiline - LABEL_CALCEXTENSION1 string + LABEL_DUMMY1 string + LABEL_DUMMY2 string + LABEL_DUMMY3 string + LABEL_DUMMY4 string + LABEL_DUMMY5 string + LABEL_INTERVAL1 string + LABEL_INTERVAL2 string + LABEL_INTERVAL3 string -CALCEXTENSION[1] - TEST param +DUMMY[5] + DUMMY_R read + DUMMY_W write + POLY_R read + POLY_W write + +INTERVAL[3] CENTRE param RANGE param diff --git a/tests/python/test_data_calc_extensions/app-expected/config_d/description b/tests/python/test_data_calc_extensions/app-expected/config_d/description index ea39afcc3..95da880d3 100644 --- a/tests/python/test_data_calc_extensions/app-expected/config_d/description +++ b/tests/python/test_data_calc_extensions/app-expected/config_d/description @@ -1,5 +1,10 @@ -CALCEXTENSION calculated registers tests - TEST +DUMMY Dummy test extension registers + DUMMY_R Reads a single register + DUMMY_W Writes a single register + POLY_R Reads a group of registers + POLY_W Writes a group of registers + +INTERVAL Calculated registers interval test CENTRE RANGE diff --git a/tests/python/test_data_calc_extensions/app-expected/config_d/registers b/tests/python/test_data_calc_extensions/app-expected/config_d/registers index 1bf4e50d1..6044d34c2 100644 --- a/tests/python/test_data_calc_extensions/app-expected/config_d/registers +++ b/tests/python/test_data_calc_extensions/app-expected/config_d/registers @@ -57,8 +57,13 @@ # DMA block size in bytes PCAP_BLOCK_SIZE 6 -CALCEXTENSION 2 calcextension - TEST 1 X test - CENTRE W 0 2 X centre - RANGE W 0 2 X range +DUMMY 2 dummy + DUMMY_R 0 1 2 3 X dummy + DUMMY_W 0 1 2 3 W 4 X dummy + POLY_R 0 1 2 3 X poly + POLY_W 0 1 2 3 W 0 1 2 3 4 X poly + +INTERVAL 3 interval + CENTRE W 0 1 X centre + RANGE W 0 1 X range diff --git a/tests/python/test_data_calc_extensions/calc_extension.app.ini b/tests/python/test_data_calc_extensions/calc_extension.app.ini index 8cb6658cc..0167349eb 100644 --- a/tests/python/test_data_calc_extensions/calc_extension.app.ini +++ b/tests/python/test_data_calc_extensions/calc_extension.app.ini @@ -2,5 +2,8 @@ description: Test app with only 8 LUTs target: -[CALCEXTENSION] -number: 1 +[DUMMY] +number: 5 + +[INTERVAL] +number: 3 diff --git a/tests/python/test_data_calc_extensions/dummy/dummy.block.ini b/tests/python/test_data_calc_extensions/dummy/dummy.block.ini new file mode 100644 index 000000000..bac5f8553 --- /dev/null +++ b/tests/python/test_data_calc_extensions/dummy/dummy.block.ini @@ -0,0 +1,50 @@ +[.] +description: Dummy test extension registers +entity: dummy + +[DUMMY_READ_0] +description: +type: extension_read + +[DUMMY_READ_1] +description: +type: extension_read + +[DUMMY_READ_2] +description: +type: extension_read + +[DUMMY_READ_3] +description: +type: extension_read + +[DUMMY_WRITE] +description: +type: extension_write + +[DUMMY_R] +description: Reads a single register +type: read +extension: dummy +extension_read: DUMMY_READ_0 DUMMY_READ_1 DUMMY_READ_2 DUMMY_READ_3 + +[DUMMY_W] +description: Writes a single register +type: write +extension: dummy +extension_read: DUMMY_READ_0 DUMMY_READ_1 DUMMY_READ_2 DUMMY_READ_3 +extension_write: DUMMY_WRITE + +[POLY_R] +description: Reads a group of registers +type: read +extension: poly +extension_read: DUMMY_READ_0 DUMMY_READ_1 DUMMY_READ_2 DUMMY_READ_3 + +[POLY_W] +description: Writes a group of registers +type: write +extension: poly +extension_read: DUMMY_READ_0 DUMMY_READ_1 DUMMY_READ_2 DUMMY_READ_3 +extension_write: DUMMY_READ_0 DUMMY_READ_1 DUMMY_READ_2 DUMMY_READ_3 DUMMY_WRITE + diff --git a/tests/python/test_data_calc_extensions/calcextension/calcextension.block.ini b/tests/python/test_data_calc_extensions/interval/interval.block.ini similarity index 59% rename from tests/python/test_data_calc_extensions/calcextension/calcextension.block.ini rename to tests/python/test_data_calc_extensions/interval/interval.block.ini index 28adc2c9d..a3329714d 100644 --- a/tests/python/test_data_calc_extensions/calcextension/calcextension.block.ini +++ b/tests/python/test_data_calc_extensions/interval/interval.block.ini @@ -1,21 +1,11 @@ [.] -description: calculated registers tests -entity: calcExtension +description: Calculated registers interval test +entity: interval [BOTTOM] description: type: extension_write -[LEFT] -description: -type: extension_read - -[TEST] -description: -type: param -extension: test -extension_read: LEFT - [CENTRE] description: type: param From 584b291a2a9ff78ce767998edfac371c01d66355 Mon Sep 17 00:00:00 2001 From: Tom Trafford Date: Thu, 7 Jul 2022 12:48:01 +0100 Subject: [PATCH 07/15] Fixed Register autogen for multi read and write extensions --- common/python/configs.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/common/python/configs.py b/common/python/configs.py index cfa60ab39..b26baba6a 100755 --- a/common/python/configs.py +++ b/common/python/configs.py @@ -184,9 +184,12 @@ def generateCalcExtensions(self): # Iterate through the fields, when a writeExtension is specified find its number for field in self.fields: for calc_extension, num in self.calc_extensions: - for extension in field.extension_write.split(" ") + field.extension_read.split(" "): + for extension in field.extension_write.split(" "): + if calc_extension == extension: + field.extension_nums.append([num, "write"]) + for extension in field.extension_read.split(" "): if calc_extension == extension: - field.extension_nums.append(num) + field.extension_nums.append([num, "read"]) def make_getter_setter(config): def getter(self): @@ -290,10 +293,16 @@ def make_reg_name(r): if r.number >= 0: result.append(str(r.number)) if r.extension: + # Add register number for any read extensions + for num, ext_type in self.extension_nums: + if ext_type == "read": + result.extend(str(' '.join(str(num) ))) + # If there are write extensions add W and then any register numbers if r.write_extension: - result.extend(['W', str(' '.join(str(num) for num in self.extension_nums))]) - if r.read_extension: - result.extend([str(' '.join(str(num) for num in self.extension_nums))]) + result.extend(['W']) + for num, ext_type in self.extension_nums: + if ext_type == "write": + result.extend(str(' '.join(str(num) ))) result.extend(['X', r.extension]) return ' '.join(result) From b10ed5c5fa1257880a0f2cd30c73cfbe2109d05b Mon Sep 17 00:00:00 2001 From: Tom Trafford Date: Fri, 22 Jul 2022 09:46:36 +0100 Subject: [PATCH 08/15] Added python tests for generation of Ctrl blocks --- tests/python/test_calc_extensions.py | 11 +- .../app-expected/hdl/addr_defines.vhd | 49 ++++++++ .../app-expected/hdl/dummy_ctrl.vhd | 114 ++++++++++++++++++ .../app-expected/hdl/interval_ctrl.vhd | 100 +++++++++++++++ 4 files changed, 271 insertions(+), 3 deletions(-) create mode 100644 tests/python/test_data_calc_extensions/app-expected/hdl/addr_defines.vhd create mode 100644 tests/python/test_data_calc_extensions/app-expected/hdl/dummy_ctrl.vhd create mode 100644 tests/python/test_data_calc_extensions/app-expected/hdl/interval_ctrl.vhd diff --git a/tests/python/test_calc_extensions.py b/tests/python/test_calc_extensions.py index f641fe136..20fe75407 100644 --- a/tests/python/test_calc_extensions.py +++ b/tests/python/test_calc_extensions.py @@ -36,15 +36,20 @@ def assertGeneratedEqual(self, *path): actual = f.read() self.assertMultiLineEqual(expected, actual) - def test_description(self): + def test_calc_extension_description(self): self.assertGeneratedEqual("config_d", "description") - def test_config(self): + def test_calc_extension_config(self): self.assertGeneratedEqual("config_d", "config") - def test_registers(self): + def test_calc_extension_registers(self): self.assertGeneratedEqual("config_d", "registers") + def test_calc_extension_vhd_generation(self): + self.assertGeneratedEqual("hdl", "interval_ctrl.vhd") + self.assertGeneratedEqual("hdl", "dummy_ctrl.vhd") + self.assertGeneratedEqual("hdl", "dummy_ctrl.vhd") + if __name__ == '__main__': unittest.main() diff --git a/tests/python/test_data_calc_extensions/app-expected/hdl/addr_defines.vhd b/tests/python/test_data_calc_extensions/app-expected/hdl/addr_defines.vhd new file mode 100644 index 000000000..aec14dde4 --- /dev/null +++ b/tests/python/test_data_calc_extensions/app-expected/hdl/addr_defines.vhd @@ -0,0 +1,49 @@ +-- AUTOGENERATED +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +package addr_defines is + +-- Functional Address Space Chip Selects + constant REG_CS : natural := 0; + constant DRV_CS : natural := 1; + constant DUMMY_CS : natural := 2; + constant INTERVAL_CS : natural := 3; + +-- Constant for the number of used modules + constant USED_MOD_COUNT : natural := 3; + +-- Block instantiation + constant DUMMY_NUM : natural := 5; + constant INTERVAL_NUM : natural := 3; + +-- Constant equal to the sum of block nums for each bit out signal + constant BIT_BUS_SIZE : natural := 0; + +-- Constant equal to the sum of block_num for each pos out signal + constant POS_BUS_SIZE : natural := 0; + +-- Constant equal to the number of carrier modules + constant CARRIER_MOD_COUNT : natural := 2; + +-- Block Register Address Space + + +-- dummy Block: + constant DUMMY_DUMMY_READ_0_addr : natural := 0; + constant DUMMY_DUMMY_READ_1_addr : natural := 1; + constant DUMMY_DUMMY_READ_2_addr : natural := 2; + constant DUMMY_DUMMY_READ_3_addr : natural := 3; + constant DUMMY_DUMMY_WRITE_addr : natural := 4; + +-- interval Block: + constant INTERVAL_BOTTOM_addr : natural := 0; + constant INTERVAL_TOP_addr : natural := 1; + +end addr_defines; + +package body addr_defines is + + +end addr_defines; diff --git a/tests/python/test_data_calc_extensions/app-expected/hdl/dummy_ctrl.vhd b/tests/python/test_data_calc_extensions/app-expected/hdl/dummy_ctrl.vhd new file mode 100644 index 000000000..4f2afacd8 --- /dev/null +++ b/tests/python/test_data_calc_extensions/app-expected/hdl/dummy_ctrl.vhd @@ -0,0 +1,114 @@ +-- AUTOGENERATED +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +library work; +use work.addr_defines.all; +use work.top_defines.all; + +entity dummy_ctrl is +port ( + -- Clock and Reset + clk_i : in std_logic; + reset_i : in std_logic; + bit_bus_i : in bit_bus_t; + pos_bus_i : in pos_bus_t; + -- Block Parameters + DUMMY_READ_0 : in std_logic_vector(31 downto 0); + DUMMY_READ_1 : in std_logic_vector(31 downto 0); + DUMMY_READ_2 : in std_logic_vector(31 downto 0); + DUMMY_READ_3 : in std_logic_vector(31 downto 0); + DUMMY_WRITE : out std_logic_vector(31 downto 0); + DUMMY_WRITE_wstb : out std_logic; + -- Memory Bus Interface + read_strobe_i : in std_logic; + read_address_i : in std_logic_vector(BLK_AW-1 downto 0); + read_data_o : out std_logic_vector(31 downto 0); + read_ack_o : out std_logic; + + write_strobe_i : in std_logic; + write_address_i : in std_logic_vector(BLK_AW-1 downto 0); + write_data_i : in std_logic_vector(31 downto 0); + write_ack_o : out std_logic +); +end dummy_ctrl; + +architecture rtl of dummy_ctrl is + + +-- Register interface common + +signal read_addr : natural range 0 to (2**read_address_i'length - 1); +signal write_addr : natural range 0 to (2**write_address_i'length - 1); + +begin + + -- Sub-module address decoding + read_addr <= to_integer(unsigned(read_address_i)); + write_addr <= to_integer(unsigned(write_address_i)); + + read_ack_delay : entity work.delay_line + generic map (DW => 1) + port map ( + clk_i => clk_i, + data_i(0) => read_strobe_i, + data_o(0) => read_ack_o, + DELAY_i => RD_ADDR2ACK + ); + + -- Control System Register Interface + REG_WRITE : process(clk_i) + begin + if rising_edge(clk_i) then + -- Zero all the write strobe arrays, we set them below + DUMMY_READ_0_wstb <= '0'; + DUMMY_READ_1_wstb <= '0'; + DUMMY_READ_2_wstb <= '0'; + DUMMY_READ_3_wstb <= '0'; + DUMMY_WRITE_wstb <= '0'; + if (write_strobe_i = '1') then + -- Set the specific write strobe that has come in + case write_addr is + when DUMMY_DUMMY_READ_0_addr => + DUMMY_READ_0 <= write_data_i; + DUMMY_READ_0_wstb <= '1'; + when DUMMY_DUMMY_READ_1_addr => + DUMMY_READ_1 <= write_data_i; + DUMMY_READ_1_wstb <= '1'; + when DUMMY_DUMMY_READ_2_addr => + DUMMY_READ_2 <= write_data_i; + DUMMY_READ_2_wstb <= '1'; + when DUMMY_DUMMY_READ_3_addr => + DUMMY_READ_3 <= write_data_i; + DUMMY_READ_3_wstb <= '1'; + when DUMMY_DUMMY_WRITE_addr => + DUMMY_WRITE <= write_data_i; + DUMMY_WRITE_wstb <= '1'; + when others => + null; + end case; + end if; + end if; + end process; + + -- + -- Status Register Read // NOT dealt with yet! -- Need MUX for read_data(I) + -- find examples that actually have register reads... + -- Current implementation taken from old panda_block_ctrl_template + -- + REG_READ : process(clk_i) + begin + if rising_edge(clk_i) then + case (read_addr) is + when others => + read_data_o <= (others => '0'); + end case; + end if; + end process; + + -- + -- Instantiate Delay Blocks for Bit and Position Bus Fields + -- + +end rtl; diff --git a/tests/python/test_data_calc_extensions/app-expected/hdl/interval_ctrl.vhd b/tests/python/test_data_calc_extensions/app-expected/hdl/interval_ctrl.vhd new file mode 100644 index 000000000..c6f5516f4 --- /dev/null +++ b/tests/python/test_data_calc_extensions/app-expected/hdl/interval_ctrl.vhd @@ -0,0 +1,100 @@ +-- AUTOGENERATED +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +library work; +use work.addr_defines.all; +use work.top_defines.all; + +entity interval_ctrl is +port ( + -- Clock and Reset + clk_i : in std_logic; + reset_i : in std_logic; + bit_bus_i : in bit_bus_t; + pos_bus_i : in pos_bus_t; + -- Block Parameters + BOTTOM : out std_logic_vector(31 downto 0); + BOTTOM_wstb : out std_logic; + TOP : out std_logic_vector(31 downto 0); + TOP_wstb : out std_logic; + -- Memory Bus Interface + read_strobe_i : in std_logic; + read_address_i : in std_logic_vector(BLK_AW-1 downto 0); + read_data_o : out std_logic_vector(31 downto 0); + read_ack_o : out std_logic; + + write_strobe_i : in std_logic; + write_address_i : in std_logic_vector(BLK_AW-1 downto 0); + write_data_i : in std_logic_vector(31 downto 0); + write_ack_o : out std_logic +); +end interval_ctrl; + +architecture rtl of interval_ctrl is + + +-- Register interface common + +signal read_addr : natural range 0 to (2**read_address_i'length - 1); +signal write_addr : natural range 0 to (2**write_address_i'length - 1); + +begin + + -- Sub-module address decoding + read_addr <= to_integer(unsigned(read_address_i)); + write_addr <= to_integer(unsigned(write_address_i)); + + read_ack_delay : entity work.delay_line + generic map (DW => 1) + port map ( + clk_i => clk_i, + data_i(0) => read_strobe_i, + data_o(0) => read_ack_o, + DELAY_i => RD_ADDR2ACK + ); + + -- Control System Register Interface + REG_WRITE : process(clk_i) + begin + if rising_edge(clk_i) then + -- Zero all the write strobe arrays, we set them below + BOTTOM_wstb <= '0'; + TOP_wstb <= '0'; + if (write_strobe_i = '1') then + -- Set the specific write strobe that has come in + case write_addr is + when INTERVAL_BOTTOM_addr => + BOTTOM <= write_data_i; + BOTTOM_wstb <= '1'; + when INTERVAL_TOP_addr => + TOP <= write_data_i; + TOP_wstb <= '1'; + when others => + null; + end case; + end if; + end if; + end process; + + -- + -- Status Register Read // NOT dealt with yet! -- Need MUX for read_data(I) + -- find examples that actually have register reads... + -- Current implementation taken from old panda_block_ctrl_template + -- + REG_READ : process(clk_i) + begin + if rising_edge(clk_i) then + case (read_addr) is + when others => + read_data_o <= (others => '0'); + end case; + end if; + end process; + + -- + -- Instantiate Delay Blocks for Bit and Position Bus Fields + -- + +end rtl; From f8aba748a172f9b9aff337ebf25b4f308c740e0b Mon Sep 17 00:00:00 2001 From: Tom Trafford Date: Fri, 22 Jul 2022 10:03:01 +0100 Subject: [PATCH 09/15] Updated documentation with changes to extensions registers --- docs/reference/block.rst | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/docs/reference/block.rst b/docs/reference/block.rst index 12dfa06d8..c6e5b5702 100644 --- a/docs/reference/block.rst +++ b/docs/reference/block.rst @@ -107,12 +107,18 @@ should be written according to type_ documentation. Subsequent indented lines in the config file are supplied according to the ``type`` value and are documented in `extra_field_keys`. +If ``type`` is set as ``extension_write`` or ``extension_read`` the block is +a hidden register. It has a hardware register but does not generate block +names. + The ``description`` value gives a short (single sentence) description about what the Field does, visible as a tooltip to users. If ``extension`` is specified then this field is configured as an extension -field. If the ``extension_reg`` field is also specified then this field is also -a hardware register. +field. If the ``extension_read`` or ``extension_write`` fields are also +specified then this field does not generate its own hardware register but uses +the specified registers. If fields use extensions an [extension].py needs to +be created. If a signal uses a write strobe ``wstb`` should be set to True. From 4368031d74d126a3a3e3b623378d747e7d26cf6b Mon Sep 17 00:00:00 2001 From: Tom Trafford Date: Mon, 14 Nov 2022 12:12:02 +0000 Subject: [PATCH 10/15] Updated FMC_acq427 extensions --- common/python/configs.py | 7 +- modules/fmc_acq427/extensions/fmc_acq427.py | 24 +-- tests/python/test_calc_extensions.py | 5 +- .../app-expected/config_d/config | 77 +++++++ .../app-expected/config_d/description | 31 +++ .../app-expected/config_d/registers | 31 +++ .../app-expected/hdl/addr_defines.vhd | 18 +- .../app-expected/hdl/fmc_acq427_ctrl.vhd | 200 ++++++++++++++++++ .../calc_extension.app.ini | 3 + .../fmc_acq427/fmc_acq427.block.ini | 196 +++++++++++++++++ 10 files changed, 568 insertions(+), 24 deletions(-) create mode 100644 tests/python/test_data_calc_extensions/app-expected/hdl/fmc_acq427_ctrl.vhd create mode 100644 tests/python/test_data_calc_extensions/fmc_acq427/fmc_acq427.block.ini diff --git a/common/python/configs.py b/common/python/configs.py index b26baba6a..faeb98f75 100755 --- a/common/python/configs.py +++ b/common/python/configs.py @@ -290,8 +290,8 @@ def make_reg_name(r): result = [] if r.prefix: result.append(r.prefix) - if r.number >= 0: - result.append(str(r.number)) + + # The following is used if fields use the extension server if r.extension: # Add register number for any read extensions for num, ext_type in self.extension_nums: @@ -304,6 +304,9 @@ def make_reg_name(r): if ext_type == "write": result.extend(str(' '.join(str(num) ))) result.extend(['X', r.extension]) + else: + if r.number >= 0: + result.append(str(r.number)) return ' '.join(result) if self.registers: diff --git a/modules/fmc_acq427/extensions/fmc_acq427.py b/modules/fmc_acq427/extensions/fmc_acq427.py index f563d648f..6e6454dde 100644 --- a/modules/fmc_acq427/extensions/fmc_acq427.py +++ b/modules/fmc_acq427/extensions/fmc_acq427.py @@ -64,24 +64,6 @@ def write_bits(self, value, byte_ix, offset, width): self.write_output_bits(self.outputs) -class BitReader: - def __init__(self, gpio, offset): - self.gpio = gpio - self.offset = offset - - def read(self, number): - return self.gpio.read_bit(*self.offset) - - -class BitsWriter: - def __init__(self, gpio, offset): - self.gpio = gpio - self.offset = offset - - def write(self, number, value): - self.gpio.write_bits(value, *self.offset) - - # We need a single GPIO controller shared between the ADC and DAC extensions. gpio_helper = GPIO_Helper() @@ -91,7 +73,9 @@ def __init__(self, count): pass def parse_read(self, request): - return BitReader(gpio_helper, lookup_bit_map[request]) + offset = lookup_bit_map[request] + return lambda _: gpio_helper.read_bit(*offset) def parse_write(self, request): - return BitsWriter(gpio_helper, lookup_bit_map[request]) + offset = lookup_bit_map[request] + return lambda _, value: gpio_helper.write_bits(value, *offset) diff --git a/tests/python/test_calc_extensions.py b/tests/python/test_calc_extensions.py index 20fe75407..37761d3c1 100644 --- a/tests/python/test_calc_extensions.py +++ b/tests/python/test_calc_extensions.py @@ -48,7 +48,10 @@ def test_calc_extension_registers(self): def test_calc_extension_vhd_generation(self): self.assertGeneratedEqual("hdl", "interval_ctrl.vhd") self.assertGeneratedEqual("hdl", "dummy_ctrl.vhd") - self.assertGeneratedEqual("hdl", "dummy_ctrl.vhd") + self.assertGeneratedEqual("hdl", "interval_ctrl.vhd") + self.assertGeneratedEqual("hdl", "fmc_acq427_ctrl.vhd") + self.assertGeneratedEqual("hdl", "addr_defines.vhd") + if __name__ == '__main__': diff --git a/tests/python/test_data_calc_extensions/app-expected/config_d/config b/tests/python/test_data_calc_extensions/app-expected/config_d/config index 2a117e27c..7ae810d11 100644 --- a/tests/python/test_data_calc_extensions/app-expected/config_d/config +++ b/tests/python/test_data_calc_extensions/app-expected/config_d/config @@ -11,6 +11,8 @@ LABEL_INTERVAL1 string LABEL_INTERVAL2 string LABEL_INTERVAL3 string + LABEL_FMC_IN1 string + LABEL_FMC_OUT1 string DUMMY[5] DUMMY_R read @@ -22,3 +24,78 @@ INTERVAL[3] CENTRE param RANGE param +FMC_IN[1] + GAIN1 param enum + 0 10V + 1 5V + 2 2.5V + 3 1.25V + GAIN2 param enum + 0 10V + 1 5V + 2 2.5V + 3 1.25V + GAIN3 param enum + 0 10V + 1 5V + 2 2.5V + 3 1.25V + GAIN4 param enum + 0 10V + 1 5V + 2 2.5V + 3 1.25V + GAIN5 param enum + 0 10V + 1 5V + 2 2.5V + 3 1.25V + GAIN6 param enum + 0 10V + 1 5V + 2 2.5V + 3 1.25V + GAIN7 param enum + 0 10V + 1 5V + 2 2.5V + 3 1.25V + GAIN8 param enum + 0 10V + 1 5V + 2 2.5V + 3 1.25V + VAL1 pos_out 4.65661287e-9 0 V + VAL2 pos_out 4.65661287e-9 0 V + VAL3 pos_out 4.65661287e-9 0 V + VAL4 pos_out 4.65661287e-9 0 V + VAL5 pos_out 4.65661287e-9 0 V + VAL6 pos_out 4.65661287e-9 0 V + VAL7 pos_out 4.65661287e-9 0 V + VAL8 pos_out 4.65661287e-9 0 V + TTL bit_out + ADC_B_FITTED read enum + 0 ADC B input fitted + 1 Not fitted + +FMC_OUT[1] + VAL1 pos_mux + VAL2 pos_mux + VAL3 pos_mux + VAL4 pos_mux + GAIN1 param enum + 0 5V + 1 10V + GAIN2 param enum + 0 5V + 1 10V + GAIN3 param enum + 0 5V + 1 10V + GAIN4 param enum + 0 5V + 1 10V + DAC_FITTED read enum + 0 DAC output fitted + 1 Not fitted + diff --git a/tests/python/test_data_calc_extensions/app-expected/config_d/description b/tests/python/test_data_calc_extensions/app-expected/config_d/description index 95da880d3..b6df99710 100644 --- a/tests/python/test_data_calc_extensions/app-expected/config_d/description +++ b/tests/python/test_data_calc_extensions/app-expected/config_d/description @@ -8,3 +8,34 @@ INTERVAL Calculated registers interval test CENTRE RANGE +FMC_IN FMC ACQ427 Module + GAIN1 ADC input gain + GAIN2 ADC input gain + GAIN3 ADC input gain + GAIN4 ADC input gain + GAIN5 ADC input gain + GAIN6 ADC input gain + GAIN7 ADC input gain + GAIN8 ADC input gain + VAL1 ADC Channel 1 Data + VAL2 ADC Channel 2 Data + VAL3 ADC Channel 3 Data] + VAL4 ADC Channel 4 Data + VAL5 ADC Channel 5 Data + VAL6 ADC Channel 6 Data + VAL7 ADC Channel 7 Data + VAL8 ADC Channel 8 Data + TTL 5V TTL input (CLOCK) + ADC_B_FITTED Whether ADC B inputs are connected + +FMC_OUT FMC ACQ427 Module + VAL1 DAC Channel 1 Data + VAL2 DAC Channel 2 Data + VAL3 DAC Channel 3 Data + VAL4 DAC Channel 4 Data + GAIN1 DAC output gain + GAIN2 DAC output gain + GAIN3 DAC output gain + GAIN4 DAC output gain + DAC_FITTED Whether DAC outputs are connected + diff --git a/tests/python/test_data_calc_extensions/app-expected/config_d/registers b/tests/python/test_data_calc_extensions/app-expected/config_d/registers index 6044d34c2..d264d7ade 100644 --- a/tests/python/test_data_calc_extensions/app-expected/config_d/registers +++ b/tests/python/test_data_calc_extensions/app-expected/config_d/registers @@ -67,3 +67,34 @@ INTERVAL 3 interval CENTRE W 0 1 X centre RANGE W 0 1 X range +FMC_IN S4 fmc_acq427 + GAIN1 X adc1_gain + GAIN2 X adc2_gain + GAIN3 X adc3_gain + GAIN4 X adc4_gain + GAIN5 X adc5_gain + GAIN6 X adc6_gain + GAIN7 X adc7_gain + GAIN8 X adc8_gain + VAL1 0 + VAL2 1 + VAL3 2 + VAL4 3 + VAL5 4 + VAL6 5 + VAL7 6 + VAL8 7 + TTL 0 + ADC_B_FITTED X adc_ribbon + +FMC_OUT S4 fmc_acq427 + VAL1 8 + VAL2 9 + VAL3 10 + VAL4 11 + GAIN1 X dac1_gain + GAIN2 X dac2_gain + GAIN3 X dac3_gain + GAIN4 X dac4_gain + DAC_FITTED X dac_ribbon + diff --git a/tests/python/test_data_calc_extensions/app-expected/hdl/addr_defines.vhd b/tests/python/test_data_calc_extensions/app-expected/hdl/addr_defines.vhd index aec14dde4..7487d4633 100644 --- a/tests/python/test_data_calc_extensions/app-expected/hdl/addr_defines.vhd +++ b/tests/python/test_data_calc_extensions/app-expected/hdl/addr_defines.vhd @@ -10,13 +10,15 @@ package addr_defines is constant DRV_CS : natural := 1; constant DUMMY_CS : natural := 2; constant INTERVAL_CS : natural := 3; + constant FMC_CS : natural := 4; -- Constant for the number of used modules - constant USED_MOD_COUNT : natural := 3; + constant USED_MOD_COUNT : natural := 4; -- Block instantiation constant DUMMY_NUM : natural := 5; constant INTERVAL_NUM : natural := 3; + constant FMC_NUM : natural := 1; -- Constant equal to the sum of block nums for each bit out signal constant BIT_BUS_SIZE : natural := 0; @@ -41,6 +43,20 @@ package addr_defines is constant INTERVAL_BOTTOM_addr : natural := 0; constant INTERVAL_TOP_addr : natural := 1; +-- fmc_acq427 Block: + constant FMC_ACQ427_IN_GAIN1_addr : natural := 0; + constant FMC_ACQ427_IN_GAIN2_addr : natural := 1; + constant FMC_ACQ427_IN_GAIN3_addr : natural := 2; + constant FMC_ACQ427_IN_GAIN4_addr : natural := 3; + constant FMC_ACQ427_IN_GAIN5_addr : natural := 4; + constant FMC_ACQ427_IN_GAIN6_addr : natural := 5; + constant FMC_ACQ427_IN_GAIN7_addr : natural := 6; + constant FMC_ACQ427_IN_GAIN8_addr : natural := 7; + constant FMC_ACQ427_OUT_VAL1_addr : natural := 8; + constant FMC_ACQ427_OUT_VAL2_addr : natural := 9; + constant FMC_ACQ427_OUT_VAL3_addr : natural := 10; + constant FMC_ACQ427_OUT_VAL4_addr : natural := 11; + end addr_defines; package body addr_defines is diff --git a/tests/python/test_data_calc_extensions/app-expected/hdl/fmc_acq427_ctrl.vhd b/tests/python/test_data_calc_extensions/app-expected/hdl/fmc_acq427_ctrl.vhd new file mode 100644 index 000000000..8f925edc9 --- /dev/null +++ b/tests/python/test_data_calc_extensions/app-expected/hdl/fmc_acq427_ctrl.vhd @@ -0,0 +1,200 @@ +-- AUTOGENERATED +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +library work; +use work.addr_defines.all; +use work.top_defines.all; + +entity fmc_acq427_ctrl is +port ( + -- Clock and Reset + clk_i : in std_logic; + reset_i : in std_logic; + bit_bus_i : in bit_bus_t; + pos_bus_i : in pos_bus_t; + -- Block Parameters + IN_GAIN1 : out std_logic_vector(31 downto 0); + IN_GAIN1_wstb : out std_logic; + IN_GAIN2 : out std_logic_vector(31 downto 0); + IN_GAIN2_wstb : out std_logic; + IN_GAIN3 : out std_logic_vector(31 downto 0); + IN_GAIN3_wstb : out std_logic; + IN_GAIN4 : out std_logic_vector(31 downto 0); + IN_GAIN4_wstb : out std_logic; + IN_GAIN5 : out std_logic_vector(31 downto 0); + IN_GAIN5_wstb : out std_logic; + IN_GAIN6 : out std_logic_vector(31 downto 0); + IN_GAIN6_wstb : out std_logic; + IN_GAIN7 : out std_logic_vector(31 downto 0); + IN_GAIN7_wstb : out std_logic; + IN_GAIN8 : out std_logic_vector(31 downto 0); + IN_GAIN8_wstb : out std_logic; + OUT_VAL1_from_bus : out std_logic_vector(31 downto 0); + OUT_VAL2_from_bus : out std_logic_vector(31 downto 0); + OUT_VAL3_from_bus : out std_logic_vector(31 downto 0); + OUT_VAL4_from_bus : out std_logic_vector(31 downto 0); + -- Memory Bus Interface + read_strobe_i : in std_logic; + read_address_i : in std_logic_vector(BLK_AW-1 downto 0); + read_data_o : out std_logic_vector(31 downto 0); + read_ack_o : out std_logic; + + write_strobe_i : in std_logic; + write_address_i : in std_logic_vector(BLK_AW-1 downto 0); + write_data_i : in std_logic_vector(31 downto 0); + write_ack_o : out std_logic +); +end fmc_acq427_ctrl; + +architecture rtl of fmc_acq427_ctrl is + +signal OUT_VAL1 : std_logic_vector(31 downto 0); +signal OUT_VAL1_wstb : std_logic; + +signal OUT_VAL2 : std_logic_vector(31 downto 0); +signal OUT_VAL2_wstb : std_logic; + +signal OUT_VAL3 : std_logic_vector(31 downto 0); +signal OUT_VAL3_wstb : std_logic; + +signal OUT_VAL4 : std_logic_vector(31 downto 0); +signal OUT_VAL4_wstb : std_logic; + + +-- Register interface common + +signal read_addr : natural range 0 to (2**read_address_i'length - 1); +signal write_addr : natural range 0 to (2**write_address_i'length - 1); + +begin + + -- Sub-module address decoding + read_addr <= to_integer(unsigned(read_address_i)); + write_addr <= to_integer(unsigned(write_address_i)); + + read_ack_delay : entity work.delay_line + generic map (DW => 1) + port map ( + clk_i => clk_i, + data_i(0) => read_strobe_i, + data_o(0) => read_ack_o, + DELAY_i => RD_ADDR2ACK + ); + + -- Control System Register Interface + REG_WRITE : process(clk_i) + begin + if rising_edge(clk_i) then + -- Zero all the write strobe arrays, we set them below + IN_GAIN1_wstb <= '0'; + IN_GAIN2_wstb <= '0'; + IN_GAIN3_wstb <= '0'; + IN_GAIN4_wstb <= '0'; + IN_GAIN5_wstb <= '0'; + IN_GAIN6_wstb <= '0'; + IN_GAIN7_wstb <= '0'; + IN_GAIN8_wstb <= '0'; + OUT_VAL1_wstb <= '0'; + OUT_VAL2_wstb <= '0'; + OUT_VAL3_wstb <= '0'; + OUT_VAL4_wstb <= '0'; + if (write_strobe_i = '1') then + -- Set the specific write strobe that has come in + case write_addr is + when FMC_ACQ427_IN_GAIN1_addr => + IN_GAIN1 <= write_data_i; + IN_GAIN1_wstb <= '1'; + when FMC_ACQ427_IN_GAIN2_addr => + IN_GAIN2 <= write_data_i; + IN_GAIN2_wstb <= '1'; + when FMC_ACQ427_IN_GAIN3_addr => + IN_GAIN3 <= write_data_i; + IN_GAIN3_wstb <= '1'; + when FMC_ACQ427_IN_GAIN4_addr => + IN_GAIN4 <= write_data_i; + IN_GAIN4_wstb <= '1'; + when FMC_ACQ427_IN_GAIN5_addr => + IN_GAIN5 <= write_data_i; + IN_GAIN5_wstb <= '1'; + when FMC_ACQ427_IN_GAIN6_addr => + IN_GAIN6 <= write_data_i; + IN_GAIN6_wstb <= '1'; + when FMC_ACQ427_IN_GAIN7_addr => + IN_GAIN7 <= write_data_i; + IN_GAIN7_wstb <= '1'; + when FMC_ACQ427_IN_GAIN8_addr => + IN_GAIN8 <= write_data_i; + IN_GAIN8_wstb <= '1'; + when FMC_ACQ427_OUT_VAL1_addr => + OUT_VAL1 <= write_data_i; + OUT_VAL1_wstb <= '1'; + when FMC_ACQ427_OUT_VAL2_addr => + OUT_VAL2 <= write_data_i; + OUT_VAL2_wstb <= '1'; + when FMC_ACQ427_OUT_VAL3_addr => + OUT_VAL3 <= write_data_i; + OUT_VAL3_wstb <= '1'; + when FMC_ACQ427_OUT_VAL4_addr => + OUT_VAL4 <= write_data_i; + OUT_VAL4_wstb <= '1'; + when others => + null; + end case; + end if; + end if; + end process; + + -- + -- Status Register Read // NOT dealt with yet! -- Need MUX for read_data(I) + -- find examples that actually have register reads... + -- Current implementation taken from old panda_block_ctrl_template + -- + REG_READ : process(clk_i) + begin + if rising_edge(clk_i) then + case (read_addr) is + when others => + read_data_o <= (others => '0'); + end case; + end if; + end process; + + -- + -- Instantiate Delay Blocks for Bit and Position Bus Fields + -- + posmux_OUT_VAL1 : entity work.posmux + port map ( + clk_i => clk_i, + pos_bus_i => pos_bus_i, + posn_o => OUT_VAL1_from_bus, + posmux_sel_i => OUT_VAL1 + ); + + posmux_OUT_VAL2 : entity work.posmux + port map ( + clk_i => clk_i, + pos_bus_i => pos_bus_i, + posn_o => OUT_VAL2_from_bus, + posmux_sel_i => OUT_VAL2 + ); + + posmux_OUT_VAL3 : entity work.posmux + port map ( + clk_i => clk_i, + pos_bus_i => pos_bus_i, + posn_o => OUT_VAL3_from_bus, + posmux_sel_i => OUT_VAL3 + ); + + posmux_OUT_VAL4 : entity work.posmux + port map ( + clk_i => clk_i, + pos_bus_i => pos_bus_i, + posn_o => OUT_VAL4_from_bus, + posmux_sel_i => OUT_VAL4 + ); + + +end rtl; diff --git a/tests/python/test_data_calc_extensions/calc_extension.app.ini b/tests/python/test_data_calc_extensions/calc_extension.app.ini index 0167349eb..8729cf2fa 100644 --- a/tests/python/test_data_calc_extensions/calc_extension.app.ini +++ b/tests/python/test_data_calc_extensions/calc_extension.app.ini @@ -7,3 +7,6 @@ number: 5 [INTERVAL] number: 3 + +[FMC] +module: fmc_acq427 diff --git a/tests/python/test_data_calc_extensions/fmc_acq427/fmc_acq427.block.ini b/tests/python/test_data_calc_extensions/fmc_acq427/fmc_acq427.block.ini new file mode 100644 index 000000000..3dfbd6b20 --- /dev/null +++ b/tests/python/test_data_calc_extensions/fmc_acq427/fmc_acq427.block.ini @@ -0,0 +1,196 @@ +[.] +description: FMC ACQ427 Module +entity: fmc_acq427 +extension: +block_suffixes: IN OUT + + +[IN.GAIN1] +type: param enum +description: ADC input gain +extension: adc1_gain +extension_reg: +0: 10V +1: 5V +2: 2.5V +3: 1.25V + +[IN.GAIN2] +type: param enum +description: ADC input gain +extension: adc2_gain +extension_reg: +0: 10V +1: 5V +2: 2.5V +3: 1.25V + +[IN.GAIN3] +type: param enum +description: ADC input gain +extension: adc3_gain +extension_reg: +0: 10V +1: 5V +2: 2.5V +3: 1.25V + +[IN.GAIN4] +type: param enum +description: ADC input gain +extension: adc4_gain +extension_reg: +0: 10V +1: 5V +2: 2.5V +3: 1.25V + +[IN.GAIN5] +type: param enum +description: ADC input gain +extension: adc5_gain +extension_reg: +0: 10V +1: 5V +2: 2.5V +3: 1.25V + +[IN.GAIN6] +type: param enum +description: ADC input gain +extension: adc6_gain +extension_reg: +0: 10V +1: 5V +2: 2.5V +3: 1.25V + +[IN.GAIN7] +type: param enum +description: ADC input gain +extension: adc7_gain +extension_reg: +0: 10V +1: 5V +2: 2.5V +3: 1.25V + +[IN.GAIN8] +type: param enum +description: ADC input gain +extension: adc8_gain +extension_reg: +0: 10V +1: 5V +2: 2.5V +3: 1.25V + +[IN.VAL1] +type: pos_out +description: ADC Channel 1 Data +scale: 4.65661287e-9 +units: V + +[IN.VAL2] +type: pos_out +description: ADC Channel 2 Data +scale: 4.65661287e-9 +units: V + +[IN.VAL3] +type: pos_out +description: ADC Channel 3 Data] +scale: 4.65661287e-9 +units: V + +[IN.VAL4] +type: pos_out +description: ADC Channel 4 Data +scale: 4.65661287e-9 +units: V + +[IN.VAL5] +type: pos_out +description: ADC Channel 5 Data +scale: 4.65661287e-9 +units: V + +[IN.VAL6] +type: pos_out +description: ADC Channel 6 Data +scale: 4.65661287e-9 +units: V + +[IN.VAL7] +type: pos_out +description: ADC Channel 7 Data +scale: 4.65661287e-9 +units: V + +[IN.VAL8] +type: pos_out +description: ADC Channel 8 Data +scale: 4.65661287e-9 +units: V + +[IN.TTL] +type: bit_out +description: 5V TTL input (CLOCK) + +[IN.ADC_B_FITTED] +type: read enum +description: Whether ADC B inputs are connected +extension: adc_ribbon +0: ADC B input fitted +1: Not fitted + +[OUT.VAL1] +type: pos_mux +description: DAC Channel 1 Data + +[OUT.VAL2] +type: pos_mux +description: DAC Channel 2 Data + +[OUT.VAL3] +type: pos_mux +description: DAC Channel 3 Data + +[OUT.VAL4] +type: pos_mux +description: DAC Channel 4 Data + +[OUT.GAIN1] +type: param enum +description: DAC output gain +extension: dac1_gain +0: 5V +1: 10V + +[OUT.GAIN2] +type: param enum +description: DAC output gain +extension: dac2_gain +0: 5V +1: 10V + +[OUT.GAIN3] +type: param enum +description: DAC output gain +extension: dac3_gain +0: 5V +1: 10V + +[OUT.GAIN4] +type: param enum +description: DAC output gain +extension: dac4_gain +0: 5V +1: 10V + +[OUT.DAC_FITTED] +type: read enum +description: Whether DAC outputs are connected +extension: dac_ribbon +0: DAC output fitted +1: Not fitted From 9f5bd968b360a0c049a787bf314eb3407e4ed3c1 Mon Sep 17 00:00:00 2001 From: Tom Trafford Date: Tue, 29 Aug 2023 13:05:15 +0100 Subject: [PATCH 11/15] Change block_ctrl.vhd template to work with extension_read fields --- common/templates/block_ctrl.vhd.jinja2 | 4 ++-- .../app-expected/hdl/dummy_ctrl.vhd | 16 ---------------- 2 files changed, 2 insertions(+), 18 deletions(-) diff --git a/common/templates/block_ctrl.vhd.jinja2 b/common/templates/block_ctrl.vhd.jinja2 index c05fed7d3..1dabf94b3 100644 --- a/common/templates/block_ctrl.vhd.jinja2 +++ b/common/templates/block_ctrl.vhd.jinja2 @@ -82,7 +82,7 @@ begin begin if rising_edge(clk_i) then -- Zero all the write strobe arrays, we set them below -{% for field in filter_fields("read.*", matching=False) %} +{% for field in filter_fields(".*read.*", matching=False) %} {% for register in field.numbered_registers() %} {{ register.name }}_wstb <= '0'; {% endfor %} @@ -90,7 +90,7 @@ begin if (write_strobe_i = '1') then -- Set the specific write strobe that has come in case write_addr is -{% for field in filter_fields("read.*", matching=False) %} +{% for field in filter_fields(".*read.*", matching=False) %} {% for register in field.numbered_registers() %} when {{ entity|upper }}_{{ register.name }}_addr => {{ register.name }} <= write_data_i; diff --git a/tests/python/test_data_calc_extensions/app-expected/hdl/dummy_ctrl.vhd b/tests/python/test_data_calc_extensions/app-expected/hdl/dummy_ctrl.vhd index 4f2afacd8..a7ee3e4c3 100644 --- a/tests/python/test_data_calc_extensions/app-expected/hdl/dummy_ctrl.vhd +++ b/tests/python/test_data_calc_extensions/app-expected/hdl/dummy_ctrl.vhd @@ -62,26 +62,10 @@ begin begin if rising_edge(clk_i) then -- Zero all the write strobe arrays, we set them below - DUMMY_READ_0_wstb <= '0'; - DUMMY_READ_1_wstb <= '0'; - DUMMY_READ_2_wstb <= '0'; - DUMMY_READ_3_wstb <= '0'; DUMMY_WRITE_wstb <= '0'; if (write_strobe_i = '1') then -- Set the specific write strobe that has come in case write_addr is - when DUMMY_DUMMY_READ_0_addr => - DUMMY_READ_0 <= write_data_i; - DUMMY_READ_0_wstb <= '1'; - when DUMMY_DUMMY_READ_1_addr => - DUMMY_READ_1 <= write_data_i; - DUMMY_READ_1_wstb <= '1'; - when DUMMY_DUMMY_READ_2_addr => - DUMMY_READ_2 <= write_data_i; - DUMMY_READ_2_wstb <= '1'; - when DUMMY_DUMMY_READ_3_addr => - DUMMY_READ_3 <= write_data_i; - DUMMY_READ_3_wstb <= '1'; when DUMMY_DUMMY_WRITE_addr => DUMMY_WRITE <= write_data_i; DUMMY_WRITE_wstb <= '1'; From cb49a69acb773d27fa6ba39cfb15ce7d3d47eeb6 Mon Sep 17 00:00:00 2001 From: Tom Trafford Date: Tue, 29 Aug 2023 14:31:06 +0100 Subject: [PATCH 12/15] Tidy code --- common/python/configs.py | 15 +++++++-------- common/python/generate_app.py | 8 ++++---- .../app-expected/config_d/registers | 7 +++++++ 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/common/python/configs.py b/common/python/configs.py index b7f41727f..4dd834f74 100755 --- a/common/python/configs.py +++ b/common/python/configs.py @@ -128,7 +128,7 @@ def __init__(self, name, type, number, ini_path, site=None): self.fields = FieldConfig.from_ini( ini, number) # type: List[FieldConfig] #: List of Extension fields in the block - self.calc_extensions=[] + self.calc_extensions = [] #: Are there any suffixes? self.block_suffixes = ini_get(ini, '.', 'block_suffixes', '').split() @@ -174,11 +174,11 @@ def generateInterfaceConstraints(self): if constraint not in self.interfaceConstraints: self.interfaceConstraints.append(constraint) - def generateCalcExtensions(self): + def generate_calc_extensions(self): # Iterate through the fields and add any with writeExtension type to the list for field in self.filter_fields("extension_.*"): extension = (field.name, field.registers[0].number) - self.extension=self.name.lower() + self.extension = self.name.lower() self.calc_extensions.append(extension) # After extensions have been added to self.read_extensions/self.write_extensions # Iterate through the fields, when a writeExtension is specified find its number @@ -269,7 +269,7 @@ def __init__(self, name, number, type, description, extra_config): self.extension_write = extra_config.pop("extension_write", "") self.extension_read = extra_config.pop("extension_read", "") self.extension_nums = [] - self.no_config = 0 + self.no_config = False #: All the other extra config items self.extra_config_lines = list(self.parse_extra_config(extra_config)) @@ -306,9 +306,8 @@ def make_reg_name(r): if ext_type == "write": result.extend(str(' '.join(str(num) ))) result.extend(['X', r.extension]) - else: - if r.number >= 0: - result.append(str(r.number)) + elif r.number >= 0: + result.append(str(r.number)) return ' '.join(result) if self.registers: @@ -517,7 +516,7 @@ class CalcExtensionFieldConfig(ParamFieldConfig): def register_addresses(self, counters): # type: (FieldCounter) -> None super(CalcExtensionFieldConfig, self).register_addresses(counters) - self.no_config=1 + self.no_config = True class EnumParamFieldConfig(ParamFieldConfig): """An enum field with its integer entries and string values""" diff --git a/common/python/generate_app.py b/common/python/generate_app.py index cfdcd90af..a28408c37 100755 --- a/common/python/generate_app.py +++ b/common/python/generate_app.py @@ -65,7 +65,7 @@ def __init__(self, app, app_build_dir, testPath=""): "Output dir %r already exists" % app_build_dir self.app_build_dir = app_build_dir self.app_name = app.split('/')[-1].split('.')[0] - self.testPath=testPath + self.testPath = testPath # Create a Jinja2 environment in the templates dir self.env = jinja_env(TEMPLATES) # Start from base register 2 to allow for *REG and *DRV spaces @@ -132,9 +132,9 @@ def parse_ini_files(self, app): # If a test path has been given, use it for location of blocks. # Otherwise blocks should be in moudles directory if self.testPath: - path=self.testPath + path = self.testPath else: - path="modules" + path = "modules" self.implement_blocks(app_ini, path, "soft") # Filter option sensitive fields for block in self.server_blocks: @@ -202,7 +202,7 @@ def implement_blocks(self, ini, path, type): # for carrier block block = BlockConfig(section, type, number, ini_path, siteNumber) block.register_addresses(self.counters) - block.generateCalcExtensions() + block.generate_calc_extensions() self.fpga_blocks.append(block) # Copy the fpga_blocks to the server blocks. Most blocks will # be the same between the two, however the block suffixes blocks diff --git a/tests/python/test_data_calc_extensions/app-expected/config_d/registers b/tests/python/test_data_calc_extensions/app-expected/config_d/registers index d264d7ade..40ce873f1 100644 --- a/tests/python/test_data_calc_extensions/app-expected/config_d/registers +++ b/tests/python/test_data_calc_extensions/app-expected/config_d/registers @@ -1,5 +1,9 @@ # Register interface definition +# This must be updated when there are changes that require the driver +# to be updated +DRIVER_COMPAT_VERSION = 1 + # This special register block is not present in the config file and contains # fixed register definitions used in the hardware interface. *REG 0 @@ -56,6 +60,9 @@ PCAP_IRQ_STATUS 4 # DMA block size in bytes PCAP_BLOCK_SIZE 6 + # Kernel driver compatiblity version check register. The value in this + # register must match DRIVER_COMPAT_VERSION. + COMPAT_VERSION 7 DUMMY 2 dummy DUMMY_R 0 1 2 3 X dummy From c31b6c0821a73ff1fe47f44ed3380bd5095f1f35 Mon Sep 17 00:00:00 2001 From: Tom Trafford Date: Fri, 1 Sep 2023 10:52:18 +0100 Subject: [PATCH 13/15] Removed 'extension_reg' and tidied code --- common/python/configs.py | 9 +- common/templates/block_ctrl.vhd.jinja2 | 2 +- common/templates/config.jinja2 | 2 +- common/templates/descriptions.jinja2 | 2 +- common/templates/registers.jinja2 | 2 +- docs/reference/block.rst | 1 - modules/fmc_acq427/extensions/fmc_acq427.py | 1 + modules/fmc_acq427/fmc_acq427.block.ini | 49 ++++++++-- modules/fmc_acq427/hdl/fmc_acq427_wrapper.vhd | 32 +++---- .../app-expected/config_d/registers | 16 ++-- .../app-expected/hdl/addr_defines.vhd | 16 ++-- .../app-expected/hdl/dummy_ctrl.vhd | 8 ++ .../app-expected/hdl/fmc_acq427_ctrl.vhd | 96 +++++++++---------- .../fmc_acq427/fmc_acq427.block.ini | 49 ++++++++-- 14 files changed, 176 insertions(+), 109 deletions(-) diff --git a/common/python/configs.py b/common/python/configs.py index 4dd834f74..78fa468bb 100755 --- a/common/python/configs.py +++ b/common/python/configs.py @@ -178,7 +178,8 @@ def generate_calc_extensions(self): # Iterate through the fields and add any with writeExtension type to the list for field in self.filter_fields("extension_.*"): extension = (field.name, field.registers[0].number) - self.extension = self.name.lower() + if not self.extension: + self.extension = self.name.lower() self.calc_extensions.append(extension) # After extensions have been added to self.read_extensions/self.write_extensions # Iterate through the fields, when a writeExtension is specified find its number @@ -265,7 +266,6 @@ def __init__(self, name, number, type, description, extra_config): self.option_filter = extra_config.pop("if-option", "") #: Store the extension register info self.extension = extra_config.pop("extension", None) - self.extension_reg = extra_config.pop("extension_reg", None) self.extension_write = extra_config.pop("extension_write", "") self.extension_read = extra_config.pop("extension_read", "") self.extension_nums = [] @@ -498,10 +498,7 @@ class ParamFieldConfig(FieldConfig): def register_addresses(self, counters): # type: (FieldCounter) -> None if self.extension: - if self.extension_reg is None: - address = -1 - else: - address = counters.new_field() + address = -1 else: address = counters.new_field() diff --git a/common/templates/block_ctrl.vhd.jinja2 b/common/templates/block_ctrl.vhd.jinja2 index 1dabf94b3..2fb5d5550 100644 --- a/common/templates/block_ctrl.vhd.jinja2 +++ b/common/templates/block_ctrl.vhd.jinja2 @@ -113,7 +113,7 @@ begin begin if rising_edge(clk_i) then case (read_addr) is -{% for field in filter_fields("read.*") %} +{% for field in filter_fields(".*read.*") %} {% for register in field.numbered_registers() %} when {{ entity|upper }}_{{ register.name }}_addr => read_data_o <= {{ register.name }}; diff --git a/common/templates/config.jinja2 b/common/templates/config.jinja2 index dd9acfd1e..0b2d6914a 100644 --- a/common/templates/config.jinja2 +++ b/common/templates/config.jinja2 @@ -17,7 +17,7 @@ {% for field in block.fields %} {# field is a FieldConfig object #} {# insert its name and type (including subtype and options) #} - {% if field.no_config != 1 %} + {% if not field.no_config %} {{ pad(field.name) }} {{ field.config_line() }} {% for line in field.extra_config_lines %} {# some fields line enum and table have extra lines, insert them here #} diff --git a/common/templates/descriptions.jinja2 b/common/templates/descriptions.jinja2 index 0322438d9..9eb5f1690 100644 --- a/common/templates/descriptions.jinja2 +++ b/common/templates/descriptions.jinja2 @@ -5,7 +5,7 @@ {% for field in block.fields %} {# field is a FieldConfig object #} {# insert its name and description #} - {% if field.no_config != 1 %} + {% if not field.no_config %} {{ pad(field.name) }} {{ field.description }} {% endif %} {% endfor %} diff --git a/common/templates/registers.jinja2 b/common/templates/registers.jinja2 index 53366f076..3def7f96f 100644 --- a/common/templates/registers.jinja2 +++ b/common/templates/registers.jinja2 @@ -9,7 +9,7 @@ {% for field in block.fields %} {# field is a FieldConfig object #} {# ask it for its register addresses within the block base address #} - {% if field.no_config != 1 %} + {% if not field.no_config %} {{ pad(field.name) }} {{ field.address_line() }} {% endif %} {% endfor %} diff --git a/docs/reference/block.rst b/docs/reference/block.rst index c6e5b5702..5a78bbc27 100644 --- a/docs/reference/block.rst +++ b/docs/reference/block.rst @@ -94,7 +94,6 @@ look like this: type: type subtype options description: Short description of the Field extension: extension-parameter - extension_reg: wstb: The section name is used to determine the name of the Field in the resulting diff --git a/modules/fmc_acq427/extensions/fmc_acq427.py b/modules/fmc_acq427/extensions/fmc_acq427.py index 6e6454dde..3d91912b4 100644 --- a/modules/fmc_acq427/extensions/fmc_acq427.py +++ b/modules/fmc_acq427/extensions/fmc_acq427.py @@ -62,6 +62,7 @@ def write_bits(self, value, byte_ix, offset, width): value = (value << offset) & mask self.outputs[byte_ix] = (self.outputs[byte_ix] & ~mask) | value self.write_output_bits(self.outputs) + return (value,) # We need a single GPIO controller shared between the ADC and DAC extensions. diff --git a/modules/fmc_acq427/fmc_acq427.block.ini b/modules/fmc_acq427/fmc_acq427.block.ini index eafae98aa..f817937a8 100644 --- a/modules/fmc_acq427/fmc_acq427.block.ini +++ b/modules/fmc_acq427/fmc_acq427.block.ini @@ -5,15 +5,46 @@ type: io interfaces: fmc_io constraints: const/fmc_adc427.xdc const/fmc_dac427.xdc const/fmc_dac427_impl.xdc ip: fmc_acq430_ch_fifo fmc_acq427_dac_fifo -extension: +extension: fmc_acq427 block_suffixes: IN OUT +[IN.GAIN1_REG] +description: +type: extension_write + +[IN.GAIN2_REG] +description: +type: extension_write + +[IN.GAIN3_REG] +description: +type: extension_write + +[IN.GAIN4_REG] +description: +type: extension_write + +[IN.GAIN5_REG] +description: +type: extension_write + +[IN.GAIN6_REG] +description: +type: extension_write + +[IN.GAIN7_REG] +description: +type: extension_write + +[IN.GAIN8_REG] +description: +type: extension_write [IN.GAIN1] type: param enum description: ADC input gain extension: adc1_gain -extension_reg: +extension_write: IN.GAIN1_REG 0: 10V 1: 5V 2: 2.5V @@ -23,7 +54,7 @@ extension_reg: type: param enum description: ADC input gain extension: adc2_gain -extension_reg: +extension_write: IN.GAIN2_REG 0: 10V 1: 5V 2: 2.5V @@ -33,7 +64,7 @@ extension_reg: type: param enum description: ADC input gain extension: adc3_gain -extension_reg: +extension_write: IN.GAIN3_REG 0: 10V 1: 5V 2: 2.5V @@ -43,7 +74,7 @@ extension_reg: type: param enum description: ADC input gain extension: adc4_gain -extension_reg: +extension_write: IN.GAIN4_REG 0: 10V 1: 5V 2: 2.5V @@ -53,7 +84,7 @@ extension_reg: type: param enum description: ADC input gain extension: adc5_gain -extension_reg: +extension_write: IN.GAIN5_REG 0: 10V 1: 5V 2: 2.5V @@ -63,7 +94,7 @@ extension_reg: type: param enum description: ADC input gain extension: adc6_gain -extension_reg: +extension_write: IN.GAIN6_REG 0: 10V 1: 5V 2: 2.5V @@ -73,7 +104,7 @@ extension_reg: type: param enum description: ADC input gain extension: adc7_gain -extension_reg: +extension_write: IN.GAIN7_REG 0: 10V 1: 5V 2: 2.5V @@ -83,7 +114,7 @@ extension_reg: type: param enum description: ADC input gain extension: adc8_gain -extension_reg: +extension_write: IN.GAIN8_REG 0: 10V 1: 5V 2: 2.5V diff --git a/modules/fmc_acq427/hdl/fmc_acq427_wrapper.vhd b/modules/fmc_acq427/hdl/fmc_acq427_wrapper.vhd index a887b9872..2e1917c3f 100644 --- a/modules/fmc_acq427/hdl/fmc_acq427_wrapper.vhd +++ b/modules/fmc_acq427/hdl/fmc_acq427_wrapper.vhd @@ -273,22 +273,22 @@ port map ( bit_bus_i => bit_bus_i, pos_bus_i => pos_bus_i, -- Block Parameters - IN_GAIN1 => gains(0), - IN_GAIN1_wstb => open, - IN_GAIN2 => gains(1), - IN_GAIN2_wstb => open, - IN_GAIN3 => gains(2), - IN_GAIN3_wstb => open, - IN_GAIN4 => gains(3), - IN_GAIN4_wstb => open, - IN_GAIN5 => gains(4), - IN_GAIN5_wstb => open, - IN_GAIN6 => gains(5), - IN_GAIN6_wstb => open, - IN_GAIN7 => gains(6), - IN_GAIN7_wstb => open, - IN_GAIN8 => gains(7), - IN_GAIN8_wstb => open, + IN_GAIN1_REG => gains(0), + IN_GAIN1_REG_wstb => open, + IN_GAIN2_REG => gains(1), + IN_GAIN2_REG_wstb => open, + IN_GAIN3_REG => gains(2), + IN_GAIN3_REG_wstb => open, + IN_GAIN4_REG => gains(3), + IN_GAIN4_REG_wstb => open, + IN_GAIN5_REG => gains(4), + IN_GAIN5_REG_wstb => open, + IN_GAIN6_REG => gains(5), + IN_GAIN6_REG_wstb => open, + IN_GAIN7_REG => gains(6), + IN_GAIN7_REG_wstb => open, + IN_GAIN8_REG => gains(7), + IN_GAIN8_REG_wstb => open, OUT_VAL1_from_bus => CH01_DAC_DATA, OUT_VAL2_from_bus => CH02_DAC_DATA, diff --git a/tests/python/test_data_calc_extensions/app-expected/config_d/registers b/tests/python/test_data_calc_extensions/app-expected/config_d/registers index 40ce873f1..7c8583215 100644 --- a/tests/python/test_data_calc_extensions/app-expected/config_d/registers +++ b/tests/python/test_data_calc_extensions/app-expected/config_d/registers @@ -75,14 +75,14 @@ INTERVAL 3 interval RANGE W 0 1 X range FMC_IN S4 fmc_acq427 - GAIN1 X adc1_gain - GAIN2 X adc2_gain - GAIN3 X adc3_gain - GAIN4 X adc4_gain - GAIN5 X adc5_gain - GAIN6 X adc6_gain - GAIN7 X adc7_gain - GAIN8 X adc8_gain + GAIN1 W 0 X adc1_gain + GAIN2 W 1 X adc2_gain + GAIN3 W 2 X adc3_gain + GAIN4 W 3 X adc4_gain + GAIN5 W 4 X adc5_gain + GAIN6 W 5 X adc6_gain + GAIN7 W 6 X adc7_gain + GAIN8 W 7 X adc8_gain VAL1 0 VAL2 1 VAL3 2 diff --git a/tests/python/test_data_calc_extensions/app-expected/hdl/addr_defines.vhd b/tests/python/test_data_calc_extensions/app-expected/hdl/addr_defines.vhd index 7487d4633..a8a73f4f5 100644 --- a/tests/python/test_data_calc_extensions/app-expected/hdl/addr_defines.vhd +++ b/tests/python/test_data_calc_extensions/app-expected/hdl/addr_defines.vhd @@ -44,14 +44,14 @@ package addr_defines is constant INTERVAL_TOP_addr : natural := 1; -- fmc_acq427 Block: - constant FMC_ACQ427_IN_GAIN1_addr : natural := 0; - constant FMC_ACQ427_IN_GAIN2_addr : natural := 1; - constant FMC_ACQ427_IN_GAIN3_addr : natural := 2; - constant FMC_ACQ427_IN_GAIN4_addr : natural := 3; - constant FMC_ACQ427_IN_GAIN5_addr : natural := 4; - constant FMC_ACQ427_IN_GAIN6_addr : natural := 5; - constant FMC_ACQ427_IN_GAIN7_addr : natural := 6; - constant FMC_ACQ427_IN_GAIN8_addr : natural := 7; + constant FMC_ACQ427_IN_GAIN1_REG_addr : natural := 0; + constant FMC_ACQ427_IN_GAIN2_REG_addr : natural := 1; + constant FMC_ACQ427_IN_GAIN3_REG_addr : natural := 2; + constant FMC_ACQ427_IN_GAIN4_REG_addr : natural := 3; + constant FMC_ACQ427_IN_GAIN5_REG_addr : natural := 4; + constant FMC_ACQ427_IN_GAIN6_REG_addr : natural := 5; + constant FMC_ACQ427_IN_GAIN7_REG_addr : natural := 6; + constant FMC_ACQ427_IN_GAIN8_REG_addr : natural := 7; constant FMC_ACQ427_OUT_VAL1_addr : natural := 8; constant FMC_ACQ427_OUT_VAL2_addr : natural := 9; constant FMC_ACQ427_OUT_VAL3_addr : natural := 10; diff --git a/tests/python/test_data_calc_extensions/app-expected/hdl/dummy_ctrl.vhd b/tests/python/test_data_calc_extensions/app-expected/hdl/dummy_ctrl.vhd index a7ee3e4c3..fcf20abae 100644 --- a/tests/python/test_data_calc_extensions/app-expected/hdl/dummy_ctrl.vhd +++ b/tests/python/test_data_calc_extensions/app-expected/hdl/dummy_ctrl.vhd @@ -85,6 +85,14 @@ begin begin if rising_edge(clk_i) then case (read_addr) is + when DUMMY_DUMMY_READ_0_addr => + read_data_o <= DUMMY_READ_0; + when DUMMY_DUMMY_READ_1_addr => + read_data_o <= DUMMY_READ_1; + when DUMMY_DUMMY_READ_2_addr => + read_data_o <= DUMMY_READ_2; + when DUMMY_DUMMY_READ_3_addr => + read_data_o <= DUMMY_READ_3; when others => read_data_o <= (others => '0'); end case; diff --git a/tests/python/test_data_calc_extensions/app-expected/hdl/fmc_acq427_ctrl.vhd b/tests/python/test_data_calc_extensions/app-expected/hdl/fmc_acq427_ctrl.vhd index 8f925edc9..a37378164 100644 --- a/tests/python/test_data_calc_extensions/app-expected/hdl/fmc_acq427_ctrl.vhd +++ b/tests/python/test_data_calc_extensions/app-expected/hdl/fmc_acq427_ctrl.vhd @@ -15,22 +15,22 @@ port ( bit_bus_i : in bit_bus_t; pos_bus_i : in pos_bus_t; -- Block Parameters - IN_GAIN1 : out std_logic_vector(31 downto 0); - IN_GAIN1_wstb : out std_logic; - IN_GAIN2 : out std_logic_vector(31 downto 0); - IN_GAIN2_wstb : out std_logic; - IN_GAIN3 : out std_logic_vector(31 downto 0); - IN_GAIN3_wstb : out std_logic; - IN_GAIN4 : out std_logic_vector(31 downto 0); - IN_GAIN4_wstb : out std_logic; - IN_GAIN5 : out std_logic_vector(31 downto 0); - IN_GAIN5_wstb : out std_logic; - IN_GAIN6 : out std_logic_vector(31 downto 0); - IN_GAIN6_wstb : out std_logic; - IN_GAIN7 : out std_logic_vector(31 downto 0); - IN_GAIN7_wstb : out std_logic; - IN_GAIN8 : out std_logic_vector(31 downto 0); - IN_GAIN8_wstb : out std_logic; + IN_GAIN1_REG : out std_logic_vector(31 downto 0); + IN_GAIN1_REG_wstb : out std_logic; + IN_GAIN2_REG : out std_logic_vector(31 downto 0); + IN_GAIN2_REG_wstb : out std_logic; + IN_GAIN3_REG : out std_logic_vector(31 downto 0); + IN_GAIN3_REG_wstb : out std_logic; + IN_GAIN4_REG : out std_logic_vector(31 downto 0); + IN_GAIN4_REG_wstb : out std_logic; + IN_GAIN5_REG : out std_logic_vector(31 downto 0); + IN_GAIN5_REG_wstb : out std_logic; + IN_GAIN6_REG : out std_logic_vector(31 downto 0); + IN_GAIN6_REG_wstb : out std_logic; + IN_GAIN7_REG : out std_logic_vector(31 downto 0); + IN_GAIN7_REG_wstb : out std_logic; + IN_GAIN8_REG : out std_logic_vector(31 downto 0); + IN_GAIN8_REG_wstb : out std_logic; OUT_VAL1_from_bus : out std_logic_vector(31 downto 0); OUT_VAL2_from_bus : out std_logic_vector(31 downto 0); OUT_VAL3_from_bus : out std_logic_vector(31 downto 0); @@ -88,14 +88,14 @@ begin begin if rising_edge(clk_i) then -- Zero all the write strobe arrays, we set them below - IN_GAIN1_wstb <= '0'; - IN_GAIN2_wstb <= '0'; - IN_GAIN3_wstb <= '0'; - IN_GAIN4_wstb <= '0'; - IN_GAIN5_wstb <= '0'; - IN_GAIN6_wstb <= '0'; - IN_GAIN7_wstb <= '0'; - IN_GAIN8_wstb <= '0'; + IN_GAIN1_REG_wstb <= '0'; + IN_GAIN2_REG_wstb <= '0'; + IN_GAIN3_REG_wstb <= '0'; + IN_GAIN4_REG_wstb <= '0'; + IN_GAIN5_REG_wstb <= '0'; + IN_GAIN6_REG_wstb <= '0'; + IN_GAIN7_REG_wstb <= '0'; + IN_GAIN8_REG_wstb <= '0'; OUT_VAL1_wstb <= '0'; OUT_VAL2_wstb <= '0'; OUT_VAL3_wstb <= '0'; @@ -103,30 +103,30 @@ begin if (write_strobe_i = '1') then -- Set the specific write strobe that has come in case write_addr is - when FMC_ACQ427_IN_GAIN1_addr => - IN_GAIN1 <= write_data_i; - IN_GAIN1_wstb <= '1'; - when FMC_ACQ427_IN_GAIN2_addr => - IN_GAIN2 <= write_data_i; - IN_GAIN2_wstb <= '1'; - when FMC_ACQ427_IN_GAIN3_addr => - IN_GAIN3 <= write_data_i; - IN_GAIN3_wstb <= '1'; - when FMC_ACQ427_IN_GAIN4_addr => - IN_GAIN4 <= write_data_i; - IN_GAIN4_wstb <= '1'; - when FMC_ACQ427_IN_GAIN5_addr => - IN_GAIN5 <= write_data_i; - IN_GAIN5_wstb <= '1'; - when FMC_ACQ427_IN_GAIN6_addr => - IN_GAIN6 <= write_data_i; - IN_GAIN6_wstb <= '1'; - when FMC_ACQ427_IN_GAIN7_addr => - IN_GAIN7 <= write_data_i; - IN_GAIN7_wstb <= '1'; - when FMC_ACQ427_IN_GAIN8_addr => - IN_GAIN8 <= write_data_i; - IN_GAIN8_wstb <= '1'; + when FMC_ACQ427_IN_GAIN1_REG_addr => + IN_GAIN1_REG <= write_data_i; + IN_GAIN1_REG_wstb <= '1'; + when FMC_ACQ427_IN_GAIN2_REG_addr => + IN_GAIN2_REG <= write_data_i; + IN_GAIN2_REG_wstb <= '1'; + when FMC_ACQ427_IN_GAIN3_REG_addr => + IN_GAIN3_REG <= write_data_i; + IN_GAIN3_REG_wstb <= '1'; + when FMC_ACQ427_IN_GAIN4_REG_addr => + IN_GAIN4_REG <= write_data_i; + IN_GAIN4_REG_wstb <= '1'; + when FMC_ACQ427_IN_GAIN5_REG_addr => + IN_GAIN5_REG <= write_data_i; + IN_GAIN5_REG_wstb <= '1'; + when FMC_ACQ427_IN_GAIN6_REG_addr => + IN_GAIN6_REG <= write_data_i; + IN_GAIN6_REG_wstb <= '1'; + when FMC_ACQ427_IN_GAIN7_REG_addr => + IN_GAIN7_REG <= write_data_i; + IN_GAIN7_REG_wstb <= '1'; + when FMC_ACQ427_IN_GAIN8_REG_addr => + IN_GAIN8_REG <= write_data_i; + IN_GAIN8_REG_wstb <= '1'; when FMC_ACQ427_OUT_VAL1_addr => OUT_VAL1 <= write_data_i; OUT_VAL1_wstb <= '1'; diff --git a/tests/python/test_data_calc_extensions/fmc_acq427/fmc_acq427.block.ini b/tests/python/test_data_calc_extensions/fmc_acq427/fmc_acq427.block.ini index 3dfbd6b20..e9aea35f6 100644 --- a/tests/python/test_data_calc_extensions/fmc_acq427/fmc_acq427.block.ini +++ b/tests/python/test_data_calc_extensions/fmc_acq427/fmc_acq427.block.ini @@ -1,15 +1,46 @@ [.] description: FMC ACQ427 Module entity: fmc_acq427 -extension: +extension: fmc_acq427 block_suffixes: IN OUT +[IN.GAIN1_REG] +description: +type: extension_write + +[IN.GAIN2_REG] +description: +type: extension_write + +[IN.GAIN3_REG] +description: +type: extension_write + +[IN.GAIN4_REG] +description: +type: extension_write + +[IN.GAIN5_REG] +description: +type: extension_write + +[IN.GAIN6_REG] +description: +type: extension_write + +[IN.GAIN7_REG] +description: +type: extension_write + +[IN.GAIN8_REG] +description: +type: extension_write [IN.GAIN1] type: param enum description: ADC input gain extension: adc1_gain -extension_reg: +extension_write: IN.GAIN1_REG 0: 10V 1: 5V 2: 2.5V @@ -19,7 +50,7 @@ extension_reg: type: param enum description: ADC input gain extension: adc2_gain -extension_reg: +extension_write: IN.GAIN2_REG 0: 10V 1: 5V 2: 2.5V @@ -29,7 +60,7 @@ extension_reg: type: param enum description: ADC input gain extension: adc3_gain -extension_reg: +extension_write: IN.GAIN3_REG 0: 10V 1: 5V 2: 2.5V @@ -39,7 +70,7 @@ extension_reg: type: param enum description: ADC input gain extension: adc4_gain -extension_reg: +extension_write: IN.GAIN4_REG 0: 10V 1: 5V 2: 2.5V @@ -49,7 +80,7 @@ extension_reg: type: param enum description: ADC input gain extension: adc5_gain -extension_reg: +extension_write: IN.GAIN5_REG 0: 10V 1: 5V 2: 2.5V @@ -59,7 +90,7 @@ extension_reg: type: param enum description: ADC input gain extension: adc6_gain -extension_reg: +extension_write: IN.GAIN6_REG 0: 10V 1: 5V 2: 2.5V @@ -69,7 +100,7 @@ extension_reg: type: param enum description: ADC input gain extension: adc7_gain -extension_reg: +extension_write: IN.GAIN7_REG 0: 10V 1: 5V 2: 2.5V @@ -79,7 +110,7 @@ extension_reg: type: param enum description: ADC input gain extension: adc8_gain -extension_reg: +extension_write: IN.GAIN8_REG 0: 10V 1: 5V 2: 2.5V From 6c4d56fcb3999fdefcad6f317191bdfcf2d778bc Mon Sep 17 00:00:00 2001 From: Tom Trafford Date: Tue, 19 Sep 2023 10:50:06 +0100 Subject: [PATCH 14/15] Correct return value of fmc_acq427.py write_bits so it returns unmodified value --- modules/fmc_acq427/extensions/fmc_acq427.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/fmc_acq427/extensions/fmc_acq427.py b/modules/fmc_acq427/extensions/fmc_acq427.py index 3d91912b4..e2718e8fd 100644 --- a/modules/fmc_acq427/extensions/fmc_acq427.py +++ b/modules/fmc_acq427/extensions/fmc_acq427.py @@ -59,8 +59,8 @@ def read_bit(self, byte_ix, offset): def write_bits(self, value, byte_ix, offset, width): mask = ((1 << width) - 1) << offset - value = (value << offset) & mask - self.outputs[byte_ix] = (self.outputs[byte_ix] & ~mask) | value + shift_value = (value << offset) & mask + self.outputs[byte_ix] = (self.outputs[byte_ix] & ~mask) | shift_value self.write_output_bits(self.outputs) return (value,) From fda9532ef756bc4802428054205f1c4af74de370 Mon Sep 17 00:00:00 2001 From: Tom Trafford Date: Tue, 19 Sep 2023 14:45:16 +0100 Subject: [PATCH 15/15] Refactored fmc_acq427.py and fixed dac_gain register interaction --- modules/fmc_acq427/extensions/fmc_acq427.py | 45 +++++++++++++-------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/modules/fmc_acq427/extensions/fmc_acq427.py b/modules/fmc_acq427/extensions/fmc_acq427.py index e2718e8fd..a1892698f 100644 --- a/modules/fmc_acq427/extensions/fmc_acq427.py +++ b/modules/fmc_acq427/extensions/fmc_acq427.py @@ -18,20 +18,23 @@ # 2.5 DAC 1 output range # 2.6 DAC 4 output range # 2.7 DAC 3 output range -lookup_bit_map = { +lookup_write_bit_map = { # All the write values are triple: (byte, offset, width) - 'adc1_gain' : (0, 6, 2), - 'adc2_gain' : (0, 4, 2), - 'adc3_gain' : (0, 2, 2), - 'adc4_gain' : (0, 0, 2), - 'adc5_gain' : (1, 6, 2), - 'adc6_gain' : (1, 4, 2), - 'adc7_gain' : (1, 2, 2), - 'adc8_gain' : (1, 0, 2), - 'dac1_gain' : (2, 5, 1), - 'dac2_gain' : (2, 4, 1), - 'dac3_gain' : (2, 7, 1), - 'dac4_gain' : (2, 6, 1), + 'adc1_gain' : ("write_adc_gain", (0, 6, 2)), + 'adc2_gain' : ("write_adc_gain", (0, 4, 2)), + 'adc3_gain' : ("write_adc_gain", (0, 2, 2)), + 'adc4_gain' : ("write_adc_gain", (0, 0, 2)), + 'adc5_gain' : ("write_adc_gain", (1, 6, 2)), + 'adc6_gain' : ("write_adc_gain", (1, 4, 2)), + 'adc7_gain' : ("write_adc_gain", (1, 2, 2)), + 'adc8_gain' : ("write_adc_gain", (1, 0, 2)), + 'dac1_gain' : ("write_dac_gain", (2, 5, 1)), + 'dac2_gain' : ("write_dac_gain", (2, 4, 1)), + 'dac3_gain' : ("write_dac_gain", (2, 7, 1)), + 'dac4_gain' : ("write_dac_gain", (2, 6, 1)), +} + +lookup_read_bit_map = { # The two read values are a pair: (byte, offset) 'dac_ribbon' : (2, 2), 'adc_ribbon' : (2, 3), @@ -62,8 +65,15 @@ def write_bits(self, value, byte_ix, offset, width): shift_value = (value << offset) & mask self.outputs[byte_ix] = (self.outputs[byte_ix] & ~mask) | shift_value self.write_output_bits(self.outputs) + + def write_adc_gain(self, value, *args): + self.write_bits(value, *args) return (value,) + def write_dac_gain(self, *args): + # dac_gains do not write to a register and should not return a value + self.write_bits(*args) + # We need a single GPIO controller shared between the ADC and DAC extensions. gpio_helper = GPIO_Helper() @@ -74,9 +84,10 @@ def __init__(self, count): pass def parse_read(self, request): - offset = lookup_bit_map[request] - return lambda _: gpio_helper.read_bit(*offset) + offsets = lookup_read_bit_map[request] + return lambda _: gpio_helper.read_bit(*offsets) def parse_write(self, request): - offset = lookup_bit_map[request] - return lambda _, value: gpio_helper.write_bits(value, *offset) + action, offsets = lookup_write_bit_map[request] + action = getattr(gpio_helper, action) + return lambda _, value: action(value, *offsets)