Autogeneration framework architecture

Softblocks

Wrappers

How wrapper, config, desc, vhdl entities, test benches are generated

Config_d entries

common.python.configs.pad(name, spaces=19)[source]

Pad the right of a name with spaces until it is at least spaces long

common.python.configs.all_subclasses(cls)[source]

Recursively find all the subclasses of cls

class common.python.configs.BlockConfig(name, type, number, ini_path, site=None)[source]

The config for a single Block

name = None

The name of the Block, like LUT

number = None

The number of instances Blocks that will be created, like 8

module_path = None

The path to the module that holds this block ini

ini_path = None

The path to the ini file for this Block, relative to ROOT

block_address = None

The Block section of the register address space

site = None

If the type == sfp, which site number

entity = None

The VHDL entity name, like lut

type = None

Is the block soft, sfp, fmc or dma?

constraints = None

Any constraints?

ip = None

Does the block require IP?

description = None

The description, like “Lookup table”

fields = None

All the child fields

block_suffixes = None

Are there any suffixes?

register_addresses(block_counters)[source]

Register this block in the address space

filter_fields(regex, matching=True)[source]

Filter our child fields by typ. If not matching return those that don’t match

generateInterfaceConstraints()[source]

Generate MGT Pints constraints

class common.python.configs.RegisterConfig(name, number=-1, prefix='', extension='')[source]

A low level register name and number backing this field

name = None

The name of the register, like INPA_DLY

number = None

The register number relative to Block, like 9

extension = None

For an extension field, the register path

class common.python.configs.BusEntryConfig(name, bus, index)[source]

A bus entry belonging to a field

name = None

The name of the register, like INPA_DLY

bus = None

The bus the output is on, like bit

index = None

The bus index, like 5

class common.python.configs.FieldConfig(name, number, type, description, extra_config)[source]

The config for a single Field of a Block

type_regex = None

Regex for matching a type string to this field

name = None

The name of the field relative to it’s Block, like INPA

number = None

The number of instances Blocks that will be created, like 8

type = None

The complete type string, like param lut

description = None

The long description of the field

registers = None

The list of registers this field uses

bus_entries = None

The list of bus entries this field has

wstb = None

If a write strobe is required, set wstb to 1

extension = None

Store the extension register info

extra_config_lines = None

All the other extra config items

parse_extra_config(extra_config)[source]

Produce any extra config lines from self.kwargs

register_addresses(counters)[source]

Create registers using the FieldCounter object

address_line()[source]

Produce the line that should go in the registers file after name

config_line()[source]

Produce the line that should go in the config file after name

numbered_registers()[source]

Filter self.registers, only producing registers with a number (not those that are purely extension registers)

class common.python.configs.BitOutFieldConfig(name, number, type, description, extra_config)[source]

These fields represent a single entry on the bit bus

register_addresses(counters)[source]

Create registers using the FieldCounter object

class common.python.configs.PosOutFieldConfig(name, number, type, description, extra_config)[source]

These fields represent a position output

register_addresses(counters)[source]

Create registers using the FieldCounter object

parse_extra_config(extra_config)[source]

Produce any extra config lines from self.kwargs

config_line()[source]

Produce the line that should go in the config file after name

class common.python.configs.ExtOutFieldConfig(name, number, type, description, extra_config)[source]

These fields represent a ext output

register_addresses(counters)[source]

Create registers using the FieldCounter object

class common.python.configs.ExtOutTimeFieldConfig(name, number, type, description, extra_config)[source]

These fields represent a ext output timestamp, which requires two registers

register_addresses(counters)[source]

Create registers using the FieldCounter object

class common.python.configs.TableFieldConfig(name, number, type, description, extra_config)[source]

These fields represent a table field

words = None

How many 32-bit words per line?

register_addresses(counters)[source]

Create registers using the FieldCounter object

config_line()[source]

Produce the line that should go in the config file after name

parse_extra_config(extra_config)[source]

Produce any extra config lines from self.kwargs

class common.python.configs.TableShortFieldConfig(name, number, type, description, extra_config)[source]

These fields represent a table field

lines = None

How many lines in the table?

parse_extra_config(extra_config)[source]

Produce any extra config lines from self.kwargs

register_addresses(counters)[source]

Create registers using the FieldCounter object

class common.python.configs.ParamFieldConfig(name, number, type, description, extra_config)[source]

These fields represent all other set/get parameters backed with a single register

register_addresses(counters)[source]

Create registers using the FieldCounter object

class common.python.configs.EnumParamFieldConfig(name, number, type, description, extra_config)[source]

An enum field with its integer entries and string values

parse_extra_config(extra_config)[source]

Produce any extra config lines from self.kwargs

class common.python.configs.UintParamFieldConfig(name, number, type, description, extra_config)[source]

A special These fields represent all other set/get parameters backed with a single register

parse_extra_config(extra_config)[source]

Produce any extra config lines from self.kwargs

config_line()[source]

Produce the line that should go in the config file after name

class common.python.configs.ScalarParamFieldConfig(name, number, type, description, extra_config)[source]

A special Read config for reading the different config of a read scalar

parse_extra_config(extra_config)[source]

Produce any extra config lines from self.kwargs

config_line()[source]

Produce the line that should go in the config file after name

class common.python.configs.BitMuxFieldConfig(name, number, type, description, extra_config)[source]

These fields represent a single entry on the pos bus

register_addresses(counters)[source]

Create registers using the FieldCounter object

class common.python.configs.PosMuxFieldConfig(name, number, type, description, extra_config)[source]

The fields represent a position input multiplexer selection

register_addresses(counters)[source]

Create registers using the FieldCounter object

class common.python.configs.TimeFieldConfig(name, number, type, description, extra_config)[source]

The fields represent a configurable timer parameter

register_addresses(counters)[source]

Create registers using the FieldCounter object

class common.python.configs.TargetSiteConfig(name, info)[source]

The config for the target sites

type_regex = None

Regex for matching a type string to this field

name = None

The type of target site (SFP/FMC etc)

number = None

The info i in a string such as “3, i, io, o”

Test benches

A generic outline is common across the testbenches for the different blocks. There are four main areas of required functionality: Assigning signals, reading expected data, assigning inputs to the UUT and reading the outputs and comparing the outputs.

A template can therefore be used to autogenerate the testbench, with this common functionality, with the modifications required for use with the different blocks.

Required signals in the block

Python code used has extracted the different signals which are required from the .block.ini file for each block. Using this information, register signals are produced in the testbench for each signal, using the names from the INI file. However, not all signals are used in the same manner. Therefore the field type of each signal is also read to determine the size of the required register for each signals. This is also used to determine whether the signal is an input or an output signal. Each output signal requires a register signal similar to the the inputs, however they also require wire signals for use with the UUT, this is differentiated by the suffix “_UUT” and an error register which is differentiated by the suffix “_error”.

Integer signals are also declared for holding the file identifier, the $fscanf return value and the timestamp.

Read expected.csv

From the .timing.ini file within the block, a CSV file is generated which describes how the UUT should behave under certain inputs at different times. The first line of the file contains strings with the names of each of the signals, the first column being the timestamp data. All other lines contain numeric data for the timestamp, inputs and corresponding outputs.

The file is opened in the testbench and read line by line. The first line, containing the names of the signals is discarded. The numeric data is then read, when the timestamp value is equal to that in the file the values are assigned to the corresponding registers in the testbench. The data in the file is ordered in the same way as the .block.ini file so iterating through the signals in order, will assign the data to the correct registers.

Assign signals

The inputs to the entity for the block will have the same name as for those used in the testbench. It is therefore straightforward to connect the signals. The registers with the same name as the outputs are being used for holding the expected values, therefore the wire signals with the suffix “_uut” are used to read the output signals.

Compare output signals

To verify the correct functionality of the block, the outputted values will need to be compared to the expected values. A simple comparison is implemented, if the two signals are not equal, set that output’s error signal to one and display an error message to the user.