diff --git a/args_demo.py b/args_demo.py index 13bcd231d423dfb4c8e0252b95104a5b19534ee8..1c5a6a28c8ebcaff995b88dd0e568d870463b5cc 100644 --- a/args_demo.py +++ b/args_demo.py @@ -1,24 +1,24 @@ #! /usr/bin/env python3 -############################################################################### -# -# Copyright (C) 2016 +# ########################################################################## +# Copyright 2020 # ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> # P.O.Box 2, 7990 AA Dwingeloo, The Netherlands # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# http://www.apache.org/licenses/LICENSE-2.0 # +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ########################################################################## + +# ########################################################################## # Author Date # PD mrt 2017 # diff --git a/args_logger.py b/args_logger.py index 6d3e83fcd80e922d4d01d34e6454706dbdd88fae..0e865ab7dbcb35cbf604780b3e02aebd3a425d38 100644 --- a/args_logger.py +++ b/args_logger.py @@ -1,3 +1,25 @@ +# ########################################################################## +# Copyright 2020 +# ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ########################################################################## + +# ########################################################################## + + + import os import logging diff --git a/gen_bus.py b/gen_bus.py index 1a01c0e9aa5ea3dbe88459fe8afa994cfef9006a..854d3d396a618e4e3d623d3ed563bc38c61edc55 100755 --- a/gen_bus.py +++ b/gen_bus.py @@ -1,3 +1,21 @@ +# ########################################################################## +# Copyright 2020 +# ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ########################################################################## + ################################################################################# # # diff --git a/gen_c_config.py b/gen_c_config.py old mode 100644 new mode 100755 index 1c3171c9832bc96bec4233819338cd0e7d5b5085..e18ed76c861c6952cbb79ae6d175e13cf85d1d65 --- a/gen_c_config.py +++ b/gen_c_config.py @@ -1,23 +1,23 @@ #! /usr/bin/env python3 -############################################################################### -# -# Copyright (C) 2017 -# CSIRO (Commonwealth Scientific and Industrial Research Organization) <http://www.csiro.au/> -# GPO Box 1700, Canberra, ACT 2601, Australia -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. +# ########################################################################## +# Copyright 2020 +# ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands # -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# http://www.apache.org/licenses/LICENSE-2.0 # +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ########################################################################## + +# ########################################################################## # Author Date Version comments # Keith Bengsotn Nov 2018 Original # Pieter Donker Apr 2020 add logging and changed output path @@ -35,7 +35,7 @@ import os from argparse import ArgumentParser from args_logger import MyLogger -from py_args_lib import RAM, FIFO, Register, FPGALibrary, ceil_pow2, c_word_sz +from py_args_lib import RAM, FIFO, Register, FPGALibrary, ceil_pow2, WIDTH_IN_BYTES def gen_c_config(fpga, fpga_name, out_dir): @@ -55,15 +55,15 @@ def gen_c_config(fpga, fpga_name, out_dir): pname = peripheral.name() logger.debug('pname=%s', pname) count = peripheral.number_of_peripherals() - base = int(periph_info['base'] / c_word_sz) + base = int(periph_info['base'] / WIDTH_IN_BYTES) typ = periph_info['type'] if use_avalon: - span = max(int(8 / c_word_sz), ceil_pow2(int(periph_info['span'] / c_word_sz))) # span can be incorrect (bug in pyargslib?) + span = max(int(8 / WIDTH_IN_BYTES), ceil_pow2(int(periph_info['span'] / WIDTH_IN_BYTES))) # span can be incorrect (bug in pyargslib?) txt = '# peripheral={} start=0x{:04X} span=0x{:04X} count={:02} idx={} stop=0x{:04X}'.format( pname, base, span, count, p_num, base + count * span) else: - span = int(periph_info['span'] / c_word_sz) # span can be incorrect (bug in pyargslib?) + span = int(periph_info['span'] / WIDTH_IN_BYTES) # span can be incorrect (bug in pyargslib?) txt = '# peripheral={} start=0x{:04X} span=0x{:04X} type={} count={:02} idx={} stop=0x{:04X}'.format( pname, base, span, typ, count, p_num, base + count * span) @@ -79,7 +79,7 @@ def gen_c_config(fpga, fpga_name, out_dir): out.append('# RAM-SLAVE={:20}'.format(slave.name())) ram_base = base - ram_len = int(slave.address_length()) + ram_len = int(slave.address_length() / WIDTH_IN_BYTES) ram_name = 'data' access = slave.access_mode() # width = slave.width() # Should be slave.user_width() ?? @@ -106,7 +106,7 @@ def gen_c_config(fpga, fpga_name, out_dir): else: out.append('# FIFO-SLAVE={:20}'.format(slave.name())) fifo_base = base - fifo_len = int(slave.address_length()) + fifo_len = int(slave.address_length() / WIDTH_IN_BYTES) fifo_name = 'data' access = slave.access_mode() # width = slave.width() # Should be slave.user_width() ?? @@ -128,19 +128,21 @@ def gen_c_config(fpga, fpga_name, out_dir): if slave.user_defined_name(): out.append('# REG-SLAVE={} no.slaves={} len={} (base=0x{:X})'.format( slave.user_defined_name(), - slave.number_of_slaves(), int(slave.address_length()), - slave.base_address())) - #int(slave.base_address() / c_word_sz))) + slave.number_of_slaves(), + int(slave.address_length() / WIDTH_IN_BYTES), + int(slave.base_address() / WIDTH_IN_BYTES))) + #int(slave.base_address() / WIDTH_IN_BYTES))) else: out.append('# REG-SLAVE={} no.slaves={} len={} (base=0x{:X})'.format( - slave.name(), slave.number_of_slaves(), int(slave.address_length()), - slave.base_address())) - #int(slave.base_address() / c_word_sz))) + slave.name(), slave.number_of_slaves(), + int(slave.address_length() / WIDTH_IN_BYTES), + int(slave.base_address() / WIDTH_IN_BYTES))) + #int(slave.base_address() / WIDTH_IN_BYTES))) # Fields that have a non-unity 'number_of_fields' specifier may # become RAM at the start of the slave instances for ram in slave.rams: - ram_base = int(ram.base_address() / c_word_sz) + base + ram_base = int(ram.base_address() / WIDTH_IN_BYTES) + base ram_len = int(ram.number_of_fields()) ram_name = ram.name() access = ram.access_mode() @@ -167,16 +169,16 @@ def gen_c_config(fpga, fpga_name, out_dir): field_base = base if slave.rams: - field_base += int(slave.base_address() / c_word_sz) + field_base += int(slave.base_address() / WIDTH_IN_BYTES) # All other fields (with unity 'number_of_fields' attribute) - slave_length = int(slave.address_length() / c_word_sz) + slave_length = int(slave.address_length() / WIDTH_IN_BYTES) for i in range(0, num_slaves): for fld in slave.fields: bit_lo = fld.bit_offset() bit_hi = bit_lo + fld.width() - 1 # field_base = f.base_address - field_offset = int(fld.address_offset() / c_word_sz) + field_offset = int(fld.address_offset() / WIDTH_IN_BYTES) field_name = fld.name() access = fld.access_mode() diff --git a/gen_doc.py b/gen_doc.py index 0cb24655b39b7b591be2d79403a4133de9a0a175..69c36170830fb57b40900ecab93b12e25d804fde 100755 --- a/gen_doc.py +++ b/gen_doc.py @@ -1,25 +1,26 @@ #! /usr/bin/env python3 -############################################################################### -# -# Copyright (C) 2016 +# ########################################################################## +# Copyright 2020 # ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> # P.O.Box 2, 7990 AA Dwingeloo, The Netherlands # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# http://www.apache.org/licenses/LICENSE-2.0 # +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ########################################################################## + +# ########################################################################## # Author Date # PD feb 2017 +# PD sep 2020, update and cleanup # ############################################################################### @@ -54,7 +55,6 @@ def gen_reg_tables(subsection, group_fields): Returns the subsection with fully formatted variable width tables for a field group Needs to support field splitting in the case when field width exceeds 16 - """ c_max_chars = 64 char_sum = 0 @@ -64,15 +64,15 @@ def gen_reg_tables(subsection, group_fields): # iterate through fields and break whenever max chars has been exceeded # print("New field group") for field in group_fields[::-1]: - i = i+1 + i = i + 1 field_name = field.name() if field.group_name() is None else field.name().split(field.group_name() + '_')[-1] char_sum = char_sum + len(field_name) if char_sum > c_max_chars: char_sum = len(field_name) bit_bounds.append(last_bit_boundary) last_bit_boundary = field.bit_offset() - if (bit_bounds[-1]-last_bit_boundary) > 16: - bit_bounds.append(bit_bounds[-1]-16) # still limit to max of 16 + if (bit_bounds[-1] - last_bit_boundary) > 16: + bit_bounds.append(bit_bounds[-1] - 16) # still limit to max of 16 last_bit_boundary = bit_bounds[-1] # print("field {} upper {} lower {}".format(field.name(), str(field.bit_offset() + field.width() -1), str(field.bit_offset()))) # print(*bit_bounds) @@ -85,56 +85,54 @@ def gen_reg_tables(subsection, group_fields): # generate columns for fields, mostly useful for gaps, can make it less bulky than the column dictionary for i in range(1, nof_tables): # starts from second bound col_list = [] - nof_cols = bit_bounds[i-1]-bit_bounds[i]+1 # nof bits + bit label column - group_table = Tabular('|c'*nof_cols+'|') + nof_cols = bit_bounds[i - 1] - bit_bounds[i] + 1 # nof bits + bit label column + group_table = Tabular('|c' * nof_cols + '|') group_table.add_hline() group_table.add_row((MultiColumn(nof_cols, align='|c|', data='Addr: {}h'.format(str(hex(field.address_offset()))[2:])),)) group_table.add_hline() - # group_table.add_row(('Bit',*range(bit_bounds[i-1]-1,bit_bounds[i]-1,-1))) - row = ['Bit'] + [str(bit) for bit in range(bit_bounds[i-1]-1, bit_bounds[i]-1, -1)] + row = ['Bit'] + [str(bit) for bit in range(bit_bounds[i - 1] - 1, bit_bounds[i] - 1, -1)] group_table.add_row(row) group_table.add_hline() - gap_bit = bit_bounds[i-1] - 1 # next available bit, inclusive + gap_bit = bit_bounds[i - 1] - 1 # next available bit, inclusive end_bit = bit_bounds[i] - # print("Table {} bounding {} and {}".format(str(i),str(gap_bit+1), str(end_bit))) + # print("Table {} bounding {} and {}".format(str(i),str(gap_bit + 1), str(end_bit))) for field in group_fields[::-1]: field_name = field.name() if field.group_name() is None else field.name().split(field.group_name() + '_')[-1] upper_bit = field.bit_offset() + field.width() - 1 # inclusive # print("field {} has upper bit {} gap bit is {}".format(field_name,str(upper_bit), str(gap_bit))) if upper_bit < gap_bit: - gap_width = min(gap_bit - upper_bit, nof_cols-1) + gap_width = min(gap_bit - upper_bit, nof_cols - 1) col_list.append(MultiColumn(gap_width, align='|c|', data='RES')) - gap_bit = max(upper_bit, bit_bounds[i]-1) # gap_bit-(nof_cols-1)) + gap_bit = max(upper_bit, bit_bounds[i] - 1) # gap_bit-(nof_cols-1)) # print("added gap before field {} of width {}".format(field_name, str(gap_width))) - if gap_bit == (end_bit-1): + if gap_bit == (end_bit - 1): break # print("field {} bit offset {} should be more or equal to {} and upper bit {} should be less than {}".format( # field_name, str(field.bit_offset()), str(bit_bounds[i]), str(upper_bit), str(bit_bounds[i-1]))) - if field.bit_offset() >= end_bit and upper_bit < bit_bounds[i-1]: # field fully contained + if field.bit_offset() >= end_bit and upper_bit < bit_bounds[i - 1]: # field fully contained col_list.append(MultiColumn(field.width(), align='|c|', data=field_name)) # print("added complete field {} of width {}".format(field_name, str(field.width()))) - gap_bit = field.bit_offset()-1 + gap_bit = field.bit_offset() - 1 elif upper_bit >= end_bit and field.bit_offset() < end_bit: # upper partial - col_list.append(MultiColumn(upper_bit - bit_bounds[i]+1, align='|c|', data=field_name)) - # print("added upper partial for field {} of width {}".format(field_name, str(upper_bit - bit_bounds[i]+1))) + col_list.append(MultiColumn(upper_bit - bit_bounds[i] + 1, align='|c|', data=field_name)) + # print("added upper partial for field {} of width {}".format(field_name, str(upper_bit - bit_bounds[i] + 1))) gap_bit = bit_bounds[i] - 1 # end of table break - elif upper_bit >= bit_bounds[i-1] and field.bit_offset() < bit_bounds[i-1]: # lower partial field - col_list.append(MultiColumn(bit_bounds[i-1]-field.bit_offset(), align='|c|', data=field_name)) + elif upper_bit >= bit_bounds[i - 1] and field.bit_offset() < bit_bounds[i - 1]: # lower partial field + col_list.append(MultiColumn(bit_bounds[i - 1] - field.bit_offset(), align='|c|', data=field_name)) # print("added lower partial for field {} of width {}".format(field_name, str(bit_bounds[i-1]-field.bit_offset()))) - gap_bit = field.bit_offset()-1 + gap_bit = field.bit_offset() - 1 if field.bit_offset() == (bit_bounds[i]): break if gap_bit != (bit_bounds[i] - 1): # bottom gap - gap_width = max(0, gap_bit - (bit_bounds[i]-1)) + gap_width = max(0, gap_bit - (bit_bounds[i] - 1)) col_list.append(MultiColumn(gap_width, align='|c|', data='RES')) # print("added gap after field {} of width {}".format(field_name, str(gap_width))) row = ['Name'] + col_list group_table.add_row(row) - # group_table.add_row(('Name',*col_list,))# add group_table.add_hline() subsection.append(group_table) subsection.append(NewLine()) @@ -172,11 +170,6 @@ def main(): except IOError: logger.error("config file '{}' does not exist".format('??')) # filename)) -# class SamePage(Environment): - # """ A class to wrap a section in same page environment """ - # packages = [Package('MiniPage')] - # escape = False # not sure - class FPGADocumentation(object): def __init__(self, fpga_name, fpga_lib): @@ -192,10 +185,6 @@ class FPGADocumentation(object): logger.debug("'%s' does not exist, making it now", self.out_dir) os.makedirs(self.out_dir) - # self.fpga_lib = fpga_lib - # self.fpga_filename = "./systems/{}.fpga.yaml".format(fpganame) - # self.config = yaml.load(open(self.fpga_filename, "r")) - geometry_options = {"tmargin": "1cm", "lmargin": "2.5cm"} self.doc = Document(geometry_options=geometry_options) self.doc.packages.add(Package('hyperref', 'bookmarks')) # (Command('usepackage','bookmarks','hyperref')) @@ -204,6 +193,7 @@ class FPGADocumentation(object): self.doc.preamble.append(Command('date', NoEscape(r'\today'))) self.doc.append(NoEscape(r'\maketitle')) self.doc.append(NewLine()) + self.doc.append(NewLine()) self.doc.append(bold('FPGA design description\n')) self.doc.append(self.fpga.fpga_description) self.doc.append(NewLine()) @@ -213,9 +203,6 @@ class FPGADocumentation(object): self.doc.append(NewLine()) self.doc.append(Command('tableofcontents')) self.doc.append(NewPage()) - # self.doc = Documentation(self.config['fpga_name']) - # self.system = System(self.fpga_filename) - # self.fpga = fpga def __del__(self): del self.doc @@ -230,61 +217,19 @@ class FPGADocumentation(object): self.doc.append(MediumText(bold('Slave Port Map'))) self.doc.append(NewLine()) self.doc.append(NewLine()) - fpga_system_table = Tabular('|c|c|c|c|c|') + fpga_system_table = Tabular('|r|r|l|c|r|') fpga_system_table.add_hline() - fpga_system_table.add_row(('Hex', 'Range (Bytes)', 'Slave Port', 'Protocol', 'Port No.')) + fpga_system_table.add_row(('Base byte address', 'Range (Bytes)', 'Slave Port', 'Protocol', 'Port No.')) fpga_system_table.add_hline() for slave_port, slave_dict in self.fpga.address_map.items(): - fpga_system_table.add_row((str(hex(slave_dict['base'])), str(slave_dict['span']), slave_port, slave_dict['type'], slave_dict['port_index'])) + fpga_system_table.add_row(('0x{:08x}'.format(slave_dict['base']), slave_dict['span'], slave_port, slave_dict['type'], slave_dict['port_index'])) fpga_system_table.add_hline() self.doc.append(fpga_system_table) for periph_name, periph in self.fpga.peripherals.items(): self.peripheral_fill(periph, periph_name) - # with self.doc.create(Section("Peripherals.")): - # added_instances = [] - # for peri_name, peri_class in self.fpga.peripherals.items():#sorted(self.fpga.peripherals.items()): - # if peri_class.name() in added_instances: - # continue - # added_instances.append(peri_class.name()) - # - # with self.doc.create(Section(peri_class.name(), numbering=True)): - # # self.doc.append(peri_class.get_kv('peripheral_description').replace('"', '')) - # self.doc.append(peri_class.get_description().replace('"', '')) - # self.doc.append(NewLine()) - # - # #self.doc.append(MediumText(bold("slave ports."))) - # - # for val_info, val_type in ((peri_class.registers, 'Registers'), - # (peri_class.rams, 'Rams'), - # (peri_class.fifos, 'Fifos')): - # - # if len(val_info) == 0: - # continue - # - # #self.doc.add(text=val_type, size="medium") - # - # added_val_types = [] - # for key, val in sorted(val_info.items()): - # if val.name() in added_val_types: - # continue - # added_val_types.append(val.name()) - # - # with self.doc.create(Subsection("{} slave.".format(val.name().lower()), numbering=True)): - # if val.get_kv('slave_description') is not None: - # self.doc.append(val.get_kv('slave_description').replace('"', '')) - # added_fields = [] - # for field_key, field_val in sorted(val.fields.items()): - # real_name = field_val.name().strip().split('.')[0] - # if real_name in added_fields: - # continue - # added_fields.append(real_name) - # with self.doc.create(Subsubsection("{} field.".format("{}".format(real_name)), numbering=True)): - # self.doc.append(field_val.get_kv('field_description').replace('"', '') ) - # #self.doc.append(NewLine()) - def make_pdf(self): stdout = sys.stdout # keep a handle on the real standard output sys.stdout = StringIO() @@ -301,28 +246,16 @@ class FPGADocumentation(object): periph_subsection = Section(periph_name, numbering=True) periph_subsection.append(periph.get_description().replace('""', '')) periph_reg_section = Subsection("{} register slave".format(periph_name), numbering=False) - periph_reg_table = Tabular('|c|c|c|c|') + periph_reg_table = Tabular('|r|r|r|l|c|') periph_reg_table.add_hline() - periph_reg_table.add_row(('Base Address', 'Range', 'Register group', 'Number of Slaves')) + periph_reg_table.add_row(('Base-addr', 'Addr-offset', 'Range', 'Reg-group', 'N-Slaves')) periph_reg_table.add_hline() - # slave_subsections = ("{} slaves".format(periph_name), numbering=False) - # slave_subsections = [] - # slave_subsections.append(NewLine()) - # slave_subsections.append(MediumText(bold("Slave Ports for peripheral " + periph_name + "\n"))) slave_subsections = Subsection("Slave Ports for peripheral \'{}\'".format(periph_name), numbering=False) for slave in periph.slaves: - - # self.doc.add(text=val_type, size="medium") - - # added_val_types = [] - # for key, val in sorted(val_info.items()): - # if val.name() in added_val_types: - # continue - # added_val_types.append(val.name()) - slave_subsection = Subsection("Slave Port: {} ({})".format(slave.name(), 'Register block' if isinstance(slave, Register) else 'RAM' if isinstance(slave, RAM) else 'FIFO'), numbering=True) + slave_type = 'Register block' if isinstance(slave, Register) else 'RAM' if isinstance(slave, RAM) else 'FIFO' + slave_subsection = Subsection("Slave Port: {} ({})".format(slave.name(), slave_type), numbering=True) slave_subsection.append(slave.get_kv('slave_description')) slave_subsection.append(NewLine()) - # slave_subsection.append("Slave Type: {}".format('REGISTER' if isinstance(slave, Register) else 'RAM' if isinstance(slave, RAM) else 'FIFO')) slave_subsection.append(NewLine()) slave_subsection.append("Address Length: {} bytes".format(str(slave.address_length()))) slave_subsection.append(NewLine()) @@ -330,17 +263,13 @@ class FPGADocumentation(object): slave_subsection.append(NewLine()) slave_subsection.append(NewLine()) - # if val_type == 'Registers': if isinstance(slave, Register): # expand registers and fields + periph_reg_table.add_row((slave.base_address(), '', slave.address_length(), slave.name(), slave.number_of_slaves())) + periph_reg_table.add_hline() for ram in slave.rams: - periph_reg_table.add_row((str(ram.base_address()), str(ram.number_of_fields()), ram.name() + ' (RAM)', str(slave.number_of_slaves()))) + periph_reg_table.add_row(('', ram.address_offset(), ram.number_of_fields() * WIDTH_IN_BYTES, '>> {} (RAM)'.format(ram.name()), slave.number_of_slaves())) periph_reg_table.add_hline() - periph_reg_table.add_row((str(slave.base_address()), str(slave.address_length()), slave.name(), str(slave.number_of_slaves()))) - periph_reg_table.add_hline() added_field_groups = [] - # with self.doc.create(Subsection("{} Register Fields".format(val.name().lower()), numbering=True)): - # if val.get_kv('slave_description') is not None: - # slave_subsection.append(val.get_kv('slave_description').replace('"', '')) # generate register table i.e. by word group_address = -1 @@ -349,27 +278,21 @@ class FPGADocumentation(object): if field.address_offset() != group_address: group_address = field.address_offset() group_list.append(field) - # addr_name = field.group_name() if field.group_name() != "None" else field.name() - - # slave_table.add_row(str(hex(field.address_offset())), addr_name) - # slave_table.add_hline() c_max_rows = 30 - nof_cols = ceil(len(group_list)/c_max_rows) # register table has max length of 40 + nof_cols = ceil(len(group_list) / c_max_rows) # register table has max length of 40 nof_rows = min(len(group_list), c_max_rows) - slave_table = Tabular('|c|c|'*nof_cols) + slave_table = Tabular('|c|c|' * nof_cols) slave_table.add_hline() - # slave_table.add_row((*['Hex','Field Group']*nof_cols)) - slave_table.add_row(['Hex', 'Field Group']*nof_cols) + slave_table.add_row(['Hex', 'Field Group'] * nof_cols) slave_table.add_hline() for i in range(nof_rows): row = [] for j in range(nof_cols): - if i+c_max_rows*j < len(group_list): + if i + c_max_rows * j < len(group_list): field.group_name() if field.group_name() is not None else field.name() - row.extend([str(hex(group_list[i+c_max_rows*j].address_offset())), group_list[i+c_max_rows*j].name()]) + row.extend([str(hex(group_list[i + c_max_rows * j].address_offset())), group_list[i + c_max_rows * j].name()]) else : row.extend(['', '']) - # slave_table.add_row(*row) slave_table.add_row(row) slave_table.add_hline() @@ -378,11 +301,8 @@ class FPGADocumentation(object): group_address = -1 for field in slave.fields: - # if field.group_name() is None or field.group_name() != last_group: # base on group_address instead - # print("field {} address {} bit{}".format(field.name(), str(field.address_offset()), str(field.bit_offset()))) if field.address_offset() != group_address: group_address = field.address_offset() - # group_page = MiniPage() group_subsection = Subsection('{} {}'.format(str(hex(field.address_offset())), field.name() if field.group_name() is None else field.group_name()), numbering=False) group_fields = [field for field in slave.fields if field.address_offset() == group_address] if len(group_fields) > 10: @@ -390,12 +310,11 @@ class FPGADocumentation(object): group_subsection = gen_reg_tables(group_subsection, group_fields) for field in group_fields[::-1]: field_name = field.name() if field.group_name() is None else field.name().split(field.group_name() + '_')[-1] - bit_string = "Bit {}".format(str(field.bit_offset())) if field.width() == 1 else "Bits {}:{}".format(str(field.bit_offset()+field.width()-1), str(field.bit_offset())) + bit_string = "Bit {}".format(str(field.bit_offset())) if field.width() == 1 else "Bits {}:{}".format(str(field.bit_offset() + field.width() - 1), str(field.bit_offset())) group_subsection.append(bold("{}\t\t{} ({}):".format(bit_string, field_name, field.access_mode()))) group_subsection.append("\t\t{}".format(field.field_description())) group_subsection.append(NewLine()) group_subsection.append(NewLine()) - # group_page.append(group_subsection) slave_subsection.append(group_subsection) else: # RAM or FIFO slave_subsection.append("Data width: {}".format(slave.width())) @@ -408,11 +327,8 @@ class FPGADocumentation(object): self.doc.append(periph_subsection) if any([isinstance(slave, Register) for slave in periph.slaves]): self.doc.append(periph_reg_section) - # for i in range(len(slave_subsections)): - # self.doc.append(slave_subsections[i]) self.doc.append(slave_subsections) - # self.doc.append(periph_section) self.doc.append(NewPage()) @@ -426,13 +342,9 @@ class PeripheralDocumentation(object): try: os.stat(self.out_dir) except FileNotFoundError: - # logger.debug("$ARGS_DIR = %s", os.getenv('ARGS_DIR')) logger.debug("'%s' does not exist, making it now", self.out_dir) os.makedirs(self.out_dir) - # self.peripheral_filename = "./peripherals/{}.peripheral.yaml".format(peripheralname) - # self.config = yaml.load(open(self.peripheral_filename, "r")) - geometry_options = {"tmargin": "1cm", "lmargin": "2.5cm"} self.doc = Document(font_size='small', geometry_options=geometry_options) self.doc.packages.add(Package('hyperref', 'bookmarks')) @@ -455,29 +367,12 @@ class PeripheralDocumentation(object): self.doc.append(NewPage()) def fill(self): - # with self.doc.create(Section("{} library.".format(self.config['hdl_library_name']))): - # with self.doc.create(Section("{} library".format(self.periph_lib_name))): - # main_section = Section("{} library".format(self.periph_lib_name)) - # self.doc.append(LargeText(bold('{} library'.format(self.periph_lib_name)))) - # periph_section = Section("Peripherals", numbering = False) - # i = 1 - # for periph_name in self.periph_lib['peripherals'].keys(): - # self.doc.append("{} {}".format(str(i), periph_name)) - # i = i+1 - # self.doc.append(NewLine()) - # with self.doc.create(Section("Peripherals")): added_instances = [] - # for peri_info in self.config['peripherals']: - # peri_class = Peripheral(peri_info) for periph_name, periph in self.periph_lib['peripherals'].items(): if periph_name in added_instances: continue added_instances.append(periph_name) - - # with self.doc.create(Section(periph_name, numbering=True)): - # with self.doc.create(Subsection(periph_name, numbering=True)): - # self.doc.append(peri_class.get_kv('peripheral_description').replace('"', '')) self.doc.append(NewPage()) periph_subsection = Section(periph_name, numbering=True) periph_subsection.append(periph.get_description().replace('""', '')) @@ -489,56 +384,29 @@ class PeripheralDocumentation(object): periph_subsection.append(NewLine()) periph_subsection.append(NewLine()) periph_system_table = Tabular('|c|c|c|c|') - # periph_system_table.add_row((MultiColumn(4,data=MediumText(bold('System Map'))),)) periph_system_table.add_hline() periph_system_table.add_row(('Hex', 'Range (Bytes)', 'Slave Port', 'Protocol')) periph_system_table.add_hline() - # peripheral system address map dummyFPGA = FPGA(None) dummyFPGA.peripherals.update({periph_name: periph}) dummyFPGA.create_address_map() - # for slave in periph.slaves: for slave_port, slave_dict in dummyFPGA.address_map.items(): periph_system_table.add_row((str(hex(slave_dict['base'])), str(slave_dict['span']), slave_port, slave_dict['type'])) periph_system_table.add_hline() periph_subsection.append(periph_system_table) - # self.doc.append(periph.get_description().replace('""','')) - # self.doc.append(NewLine()) - - # self.doc.append(MediumText(bold("slave ports."))) - - # for val_info, val_type in ((periph.registers, 'Registers'), - # (periph.rams, 'Rams'), - # (periph.fifos, 'Fifos')): periph_reg_section = Subsection("{} register slave".format(periph_name), numbering=False) periph_reg_table = Tabular('|c|c|c|c|') periph_reg_table.add_hline() periph_reg_table.add_row(('Base Address', 'Range', 'Register group', 'Number of Slaves')) periph_reg_table.add_hline() - # slave_subsections = ("{} slaves".format(periph_name), numbering=False) - # slave_subsections = [] - # slave_subsections.append(NewLine()) - # slave_subsections.append(MediumText(bold("Slave Ports for peripheral " + periph_name + "\n"))) slave_subsections = Subsection("Slave Ports for peripheral \'{}\'".format(periph_name), numbering=False) for slave in periph.slaves: - - # if len(val_info) == 0: # not sure what this is for - # continue - - #self.doc.add(text=val_type, size="medium") - - # added_val_types = [] - # for key, val in sorted(val_info.items()): - # if val.name() in added_val_types: - # continue - # added_val_types.append(val.name()) slave_subsection = Subsection("Slave Port: {} ({})".format(slave.name(), 'Register block' if isinstance(slave, Register) else 'RAM' if isinstance(slave, RAM) else 'FIFO'), numbering=True) slave_subsection.append(slave.get_kv('slave_description')) slave_subsection.append(NewLine()) - # slave_subsection.append("Slave Type: {}".format('REGISTER' if isinstance(slave, Register) else 'RAM' if isinstance(slave, RAM) else 'FIFO')) slave_subsection.append(NewLine()) slave_subsection.append("Address Length: {}".format(str(slave.address_length()))) slave_subsection.append(NewLine()) @@ -546,17 +414,13 @@ class PeripheralDocumentation(object): slave_subsection.append(NewLine()) slave_subsection.append(NewLine()) - # if val_type == 'Registers': if isinstance(slave, Register): # expand registers and fields for ram in slave.rams: - periph_reg_table.add_row((str(ram.base_address()), str(ram.number_of_fields()*WIDTH_IN_BYTES), ram.name() + ' (RAM)', str(slave.number_of_slaves()))) + periph_reg_table.add_row((str(ram.base_address()), str(ram.number_of_fields() * WIDTH_IN_BYTES), ram.name() + ' (RAM)', str(slave.number_of_slaves()))) periph_reg_table.add_hline() periph_reg_table.add_row((str(slave.base_address()), str(slave.address_length()), slave.name(), str(slave.number_of_slaves()))) periph_reg_table.add_hline() added_field_groups = [] - # with self.doc.create(Subsection("{} Register Fields".format(val.name().lower()), numbering=True)): - # if val.get_kv('slave_description') is not None: - # slave_subsection.append(val.get_kv('slave_description').replace('"', '')) # generate register table i.e. by word group_address = -1 @@ -565,28 +429,23 @@ class PeripheralDocumentation(object): if field.address_offset() != group_address: group_address = field.address_offset() group_list.append(field) - # addr_name = field.group_name() if field.group_name() != "None" else field.name() - # slave_table.add_row(str(hex(field.address_offset())), addr_name) - # slave_table.add_hline() c_max_rows = 30 - nof_cols = ceil(len(group_list)/c_max_rows) # register table has max length of c_max_rows + nof_cols = ceil(len(group_list) / c_max_rows) # register table has max length of c_max_rows nof_rows = min(len(group_list), c_max_rows) - slave_table = Tabular('|c|c|'*nof_cols) + slave_table = Tabular('|c|c|' * nof_cols) slave_table.add_hline() - slave_table.add_row(['Hex', 'Field Group']*nof_cols) - # slave_table.add_row((*['Hex','Field Group']*nof_cols)) + slave_table.add_row(['Hex', 'Field Group'] * nof_cols) slave_table.add_hline() for i in range(nof_rows): row = [] for j in range(nof_cols): - if i+c_max_rows*j < len(group_list): + if i + c_max_rows * j < len(group_list): field.group_name() if field.group_name() is not None else field.name() - row.extend([str(hex(group_list[i+c_max_rows*j].address_offset())), group_list[i+c_max_rows*j].name()]) + row.extend([str(hex(group_list[i + c_max_rows * j].address_offset())), group_list[i + c_max_rows * j].name()]) else : row.extend(['', '']) slave_table.add_row(row) - # slave_table.add_row(*row) slave_table.add_hline() slave_subsection.append(slave_table) @@ -594,24 +453,20 @@ class PeripheralDocumentation(object): group_address = -1 for field in slave.fields: - # if field.group_name() is None or field.group_name() != last_group: # base on group_address instead - # print("field {} address {} bit{}".format(field.name(), str(field.address_offset()), str(field.bit_offset()))) if field.address_offset() != group_address: group_address = field.address_offset() - # group_page = MiniPage() - group_subsection = Subsection('{} {}'.format(str(hex(field.address_offset())), field.name() if field.group_name() is None else field.group_name()),numbering=False) + group_subsection = Subsection('{} {}'.format(str(hex(field.address_offset())), field.name() if field.group_name() is None else field.group_name()), numbering=False) group_fields = [field for field in slave.fields if field.address_offset() == group_address] if len(group_fields) > 10: slave_subsection.append(NewPage()) group_subsection = gen_reg_tables(group_subsection, group_fields) for field in group_fields[::-1]: field_name = field.name() if field.group_name() is None else field.name().split(field.group_name() + '_')[-1] - bit_string = "Bit {}".format(str(field.bit_offset())) if field.width() == 1 else "Bits {}:{}".format(str(field.bit_offset()+field.width()-1), str(field.bit_offset())) + bit_string = "Bit {}".format(str(field.bit_offset())) if field.width() == 1 else "Bits {}:{}".format(str(field.bit_offset() + field.width() - 1), str(field.bit_offset())) group_subsection.append(bold("{}\t\t{} ({}):".format(bit_string, field_name, field.access_mode()))) group_subsection.append("\t\t{}".format(field.field_description())) group_subsection.append(NewLine()) group_subsection.append(NewLine()) - # group_page.append(group_subsection) slave_subsection.append(group_subsection) else: # RAM or FIFO slave_subsection.append("Data width: {}".format(slave.width())) @@ -624,18 +479,14 @@ class PeripheralDocumentation(object): self.doc.append(periph_subsection) if any([isinstance(slave, Register) for slave in periph.slaves]): self.doc.append(periph_reg_section) - # for i in range(len(slave_subsections)): - # self.doc.append(slave_subsections[i]) self.doc.append(slave_subsections) - # self.doc.append(periph_section) self.doc.append(NewPage()) def make_pdf(self): stdout = sys.stdout # keep a handle on the real standard output sys.stdout = StringIO() try: - # self.doc.generate_pdf('{}'.format(self.periph_lib_name), clean_tex=False, silent=True) self.doc.generate_pdf(os.path.join(self.out_dir, self.periph_lib_name), clean_tex=True) time.sleep(0.5) except CalledProcessError: diff --git a/gen_fpgamap_py.py b/gen_fpgamap_py.py index bcf84ac016b804e161106b388560629bbc625bdd..bc6c40dae8a9fcc31396929548708378cafd3941 100755 --- a/gen_fpgamap_py.py +++ b/gen_fpgamap_py.py @@ -1,23 +1,23 @@ #! /usr/bin/env python3 -############################################################################### -# -# Copyright (C) 2017 -# CSIRO (Commonwealth Scientific and Industrial Research Organization) <http://www.csiro.au/> -# GPO Box 1700, Canberra, ACT 2601, Australia -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. +# ########################################################################## +# Copyright 2020 +# ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands # -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# http://www.apache.org/licenses/LICENSE-2.0 # +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ########################################################################## + +# ########################################################################## # Author Date Version comments # John Matthews Dec 2017 Original # Pieter Donker Mrt 2020 add logging diff --git a/gen_hdl.py b/gen_hdl.py index bc063c9a0b7afdfa644e8d186062133cdb8339ad..d36ae02bcf3dd466717ceb247f557f2f69b36b83 100755 --- a/gen_hdl.py +++ b/gen_hdl.py @@ -1,24 +1,24 @@ #! /usr/bin/env python3 -############################################################################### -# -# Copyright (C) 2016 +# ########################################################################## +# Copyright 2020 # ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> # P.O.Box 2, 7990 AA Dwingeloo, The Netherlands # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# http://www.apache.org/licenses/LICENSE-2.0 # +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ########################################################################## + +# ########################################################################## # Author Date # PD apr 2020 Original # diff --git a/gen_rom_mmap.py b/gen_rom_mmap.py index 971ff64b533a9ad5a74d363f8b69676daa415feb..075a5c63729f98ffeb320f208b7c656a70704601 100755 --- a/gen_rom_mmap.py +++ b/gen_rom_mmap.py @@ -1,23 +1,23 @@ #! /usr/bin/env python3 -############################################################################### -# -# Copyright (C) 2017 -# CSIRO (Commonwealth Scientific and Industrial Research Organization) <http://www.csiro.au/> -# GPO Box 1700, Canberra, ACT 2601, Australia +# ########################################################################## +# Copyright 2020 +# ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# http://www.apache.org/licenses/LICENSE-2.0 # +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ########################################################################## + +# ########################################################################## # Author Date Version comments # Pieter Donker June 2020 first version # @@ -33,15 +33,17 @@ import os import logging from argparse import ArgumentParser from args_logger import MyLogger -from py_args_lib import FPGA, RAM, FIFO, Register, PeripheralLibrary, FPGALibrary, ceil_pow2, c_word_sz +from py_args_lib import FPGA, RAM, FIFO, Register, PeripheralLibrary, FPGALibrary, ceil_pow2, WIDTH_IN_BYTES import pprint + def make_mask(width, offset=0): _hi_bit = offset + width - 1 _lo_bit = offset _mask_str = 'b[{}:{}]'.format(_hi_bit, _lo_bit) return _mask_str + def gen_fpga_map(fpga, fpga_name): _map_str = [] @@ -49,20 +51,19 @@ def gen_fpga_map(fpga, fpga_name): # pprint.pprint(fpga.address_map) print("Including slave ports for {}:".format(fpga_name)) for slave_port_name, slave_port_info in fpga.address_map.items(): - + if slave_port_info['periph_num'] > 0: continue - + peripheral = slave_port_info['peripheral'] slave = slave_port_info['slave'] base = int(slave_port_info['base']) - base_word = int(base / c_word_sz) + base_word = int(base / WIDTH_IN_BYTES) slavename = slave.name() user_def_name = slave.user_defined_name().upper() - if isinstance(slave, RAM): - print(' RAM {} at 0x{:X}-bytes 0x{:X}-words "{}"'.format(slave_port_name, base, base_word, user_def_name)) + print(' RAM {:23s} at 0x{:08x}(bytes) 0x{:04x}(words) "{}"'.format(slave_port_name, base, base_word, user_def_name)) if 'data' in slavename: slavename = slavename.replace('data', '').strip('_') _map_str.append(' {:12s} {:12s} {:16s} {:7s} 0x{:08x} {:6d} {:>5s} {:>10s} {:>5s} {:20s}'.format( @@ -77,9 +78,9 @@ def gen_fpga_map(fpga, fpga_name): str(slave.number_of_slaves()), user_def_name )) - + elif isinstance(slave, FIFO): - print(' FIFO {} at 0x{:X}-bytes 0x{:X}-words "{}"'.format(slave_port_name, base, base_word, user_def_name)) + print(' FIFO {:23s} at 0x{:08x}(bytes) 0x{:04x}(words) "{}"'.format(slave_port_name, base, base_word, user_def_name)) if 'data' in slavename: slavename = slavename.replace('data', '').strip('_') _map_str.append(' {:12s} {:12s} {:16s} {:7s} 0x{:08x} {:6d} {:>5s} {:>10s} {:>5s} {:20s}'.format( @@ -96,12 +97,12 @@ def gen_fpga_map(fpga, fpga_name): )) elif isinstance(slave, Register): - print(' REG {} at 0x{:X}-bytes 0x{:X}-words "{}"'.format(slave_port_name, base, base_word, user_def_name)) + print(' REG {:23s} at 0x{:08x}(bytes) 0x{:04x}(words) "{}"'.format(slave_port_name, base, base_word, user_def_name)) done = [] number_of_slaves = str(slave.number_of_slaves()) for r in slave.rams: - r_base = base_word + int(r.address_offset() / c_word_sz) - + r_base = base_word + int(r.address_offset() / WIDTH_IN_BYTES) + field_name = r.name().strip('0123456789') if field_name in done: continue @@ -109,7 +110,7 @@ def gen_fpga_map(fpga, fpga_name): if field_name in slavename: slavename = slavename.replace(field_name, '').strip('_') done.append(field_name) - + _map_str.append(' {:12s} {:12s} {:16s} {:7s} 0x{:08x} {:6d} {:>5s} {:>10s} {:>5s} {:20s}'.format( peripheral.name(), slavename, @@ -127,9 +128,9 @@ def gen_fpga_map(fpga, fpga_name): done = [] number_of_slaves = str(slave.number_of_slaves()) for f in slave.fields: - f_base = base_word + int(f.address_offset() / c_word_sz) + f_base = base_word + int(f.address_offset() / WIDTH_IN_BYTES) name = "{}_{}_{}".format(peripheral.name(), slave.name(), f.name()) - + field_name = f.name().strip('0123456789') if field_name in done: continue @@ -173,8 +174,8 @@ def gen_fpga_map(fpga, fpga_name): eth1g tse status REG 0x00000400 1024 RO b[31:0] AVS_ETH_0_TSE eth1g eth status REG 0x00000020 12 RO b[31:0] AVS_ETH_0_REG eth1g eth data RAM 0x00000800 1024 RW - AVS_ETH_0_RAM - ppsh ppsh status REG 0x000000EC 1 RO b[31:0] PIO_PPS - ppsh ppsh control REG 0x000000ED 1 RW b[31:0] PIO_PPS + ppsh ppsh status REG 0x000000EC 1 RO b[31:0] PIO_PPS + ppsh ppsh control REG 0x000000ED 1 RW b[31:0] PIO_PPS epcs epcs addr REG 0x000000D0 1 WO b[23:0] REG_EPCS epcs epcs rden REG 0x000000D1 1 WO b[0:0] REG_EPCS epcs epcs read_bit REG 0x000000D2 1 WO b[0:0] REG_EPCS @@ -198,7 +199,7 @@ def gen_fpga_map(fpga, fpga_name): _map_info.append('#') _map_info.append('# col1 col2 col3 col4 col5 col6 col7 col8 col9 col10') _map_info.append('# ----------- ----------- --------------- ----- ---------- ----- ---- --------- ---- ----------------') - + out_dir = os.path.join(os.getenv('ARGS_BUILD_DIR'), fpga.board_name.replace('uniboard','unb'), 'args', fpga_name, 'c') try: os.stat(out_dir) @@ -239,5 +240,5 @@ if __name__ == '__main__': # Here we select the FPGA YAML that matches up with the supplied fpga command line argument fpga_lib = FPGALibrary(root_dir=libRootDir, use_avalon_base_addr=use_avalon) fpga = fpga_lib.get_fpga(fpga_name) - + gen_fpga_map(fpga, fpga_name) diff --git a/gen_slave.py b/gen_slave.py index f0fedc0bd46e9b9b5a4663ad19cf30fe593c0883..0fb451da8762a9bfb5ddd74060c42b0d3280a7cd 100755 --- a/gen_slave.py +++ b/gen_slave.py @@ -1,3 +1,21 @@ +# ########################################################################## +# Copyright 2020 +# ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ########################################################################## + import os import sys import copy diff --git a/py_args_lib/fpga.py b/py_args_lib/fpga.py index 844d30f79c266fa3f601794dff6717eadeb1f012..478b7bf500995222492bf442959ed2692fe5b87c 100644 --- a/py_args_lib/fpga.py +++ b/py_args_lib/fpga.py @@ -1,22 +1,22 @@ -############################################################################### -# -# Copyright (C) 2016 +# ########################################################################## +# Copyright 2020 # ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> # P.O.Box 2, 7990 AA Dwingeloo, The Netherlands # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# http://www.apache.org/licenses/LICENSE-2.0 # +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ########################################################################## + +# ########################################################################## # Author Date # HJ jan 2017 Original # EK feb 2017 @@ -63,7 +63,7 @@ class FPGA(object): self.nof_lite = 0 self.nof_full = 0 self.address_map = collections.OrderedDict() - logger.debug("***FPGA object instantiation: creating for {}".format(file_path_name)) + logger.debug("***FPGA object instantiation: creating for %s", file_path_name) if 'boards' in self.file_path_name: fpn_split = self.file_path_name.split('/') @@ -89,18 +89,11 @@ class FPGA(object): """Read the FPGA information from the file_path_name file.""" logger.debug("Load FPGA from '%s'", file_path_name) - fpga_config = yaml.load(open(file_path_name, 'r')) + fpga_config = yaml.full_load(open(file_path_name, 'r')) self.valid_file_type = True return fpga_config - # def read_used_peripherals(self): - # self.fpga_name = self.fpga_config['fpga_name'] - - # for peripheral_config in self.fpga_config['peripherals']: - # component_name = peripheral_config['peripheral_name'] if '/' not in peripheral_config['peripheral_name'] else peripheral_config['peripheral_name'].split('/')[1] - # component_lib = None if '/' not in peripheral_config['peripheral_name'] else peripheral_config['peripheral_name'].split('/')[0] - def create_fpga(self): """ Create a FPGA object based on the information in the fpga_config """ logger.debug("Creating FPGA") @@ -145,7 +138,7 @@ class FPGA(object): value = parameter_set['value'] logger.debug("eval of name=%s and value=%s not posible", name, value) - logger.debug("parameters={}".format(self.parameters)) + logger.debug("parameters=%s", str(self.parameters)) for peripheral_config in self.fpga_config['peripherals']: # (Deep)Copy the peripheral from the library in order to avoid creating a reference @@ -156,26 +149,26 @@ class FPGA(object): peripheral_from_lib = copy.deepcopy(self.peri_lib.find_peripheral(component_name, component_lib, self.fpga_name)) if peripheral_from_lib is None: - logger.error("Peripheral component '{}' referenced in {}.fpga.yaml not found in peripheral library {}" - .format(component_name, self.fpga_name, '\'' + component_lib + '\'' if component_lib is not None else '')) + logger.error("Peripheral component '%s' referenced in %s.fpga.yaml not found in peripheral library '%s'", + component_name, self.fpga_name, component_lib if component_lib is not None else '') sys.exit() logger.debug(" Finding %s", peripheral_from_lib.name()) if 'parameter_overrides' in peripheral_config: - logger.debug("parameters={}".format(peripheral_config['parameter_overrides'])) + logger.debug("parameters=%s", str(peripheral_config['parameter_overrides'])) for parameter_set in peripheral_config['parameter_overrides']: name = parameter_set['name'] value = parameter_set['value'] peripheral_from_lib.parameter(key=name, val=self._eval(value)) if 'slave_port_names' in peripheral_config: - logger.debug("slave_port_names={}".format(peripheral_config['slave_port_names'])) + logger.debug("slave_port_names=%s", peripheral_config['slave_port_names']) for slave_nr, slave_port_name in enumerate(peripheral_config['slave_port_names']): peripheral_from_lib.set_user_defined_slavename(slave_nr, slave_port_name) if 'lock_base_address' in peripheral_config: - logger.debug("lock_base_address={}".format(peripheral_config['lock_base_address'])) + logger.debug("lock_base_address=%s", str(peripheral_config['lock_base_address'])) self.locked_base_addresses[peripheral_from_lib.name()] = peripheral_config['lock_base_address'] peripheral_from_lib.number_of_peripherals(number_of_peripherals) @@ -306,6 +299,7 @@ class FPGA(object): if slave.user_defined_name(): try: base_addr = avalon_base_addr[slave.user_defined_name()] + slave.base_address(base_addr) except: logger.warn("base address for username '%s' not found", slave.user_defined_name()) @@ -317,10 +311,8 @@ class FPGA(object): ram_span = int(slave.base_address() - slave.rams[0].base_address()) if any(slave.rams) else 0 slave_span = int(slave.address_length() * slave.number_of_slaves() * max(ram_span, 1)) - logger.debug('REG-not-IP slave.address_len=%d * slave.number_of_slaves=%d * ram_span=%d', - slave.address_length(), slave.number_of_slaves(), ram_span) - logger.debug("REG Slave %s has span 0x%x", peripheral.name() + '_' + slave.name() , slave_span) - + logger.debug('REG-not-IP slave.address_len=%d * slave.number_of_slaves=%d * ram_span=%d', slave.address_length(), slave.number_of_slaves(), ram_span) + logger.debug("REG Slave %s_%s has span 0x%x", peripheral.name(), slave.name() , slave_span) if peripheral.number_of_peripherals() > 1: addr_map_name.append(str(periph_num)) @@ -336,9 +328,8 @@ class FPGA(object): slave_span = int(ceil_pow2(max(slave.address_length() * slave.number_of_slaves(), 4096))) # slave.address_length()*slave.number_of_slaves()# - logger.debug('REG-IP slave.address_len=%d * slave.number_of_slaves=%d', - slave.address_length(), slave.number_of_slaves()) - logger.debug("REG-IP Slave %s has span 0x%x", peripheral.name() + '_' + slave.name() , slave_span) + logger.debug('REG-IP slave.address_len=%d * slave.number_of_slaves=%d', slave.address_length(), slave.number_of_slaves()) + logger.debug("REG-IP Slave %s_%s has span 0x%x", peripheral.name(), slave.name() , slave_span) slave_port_name = '_'.join(addr_map_name) @@ -349,10 +340,10 @@ class FPGA(object): elif isinstance(slave, RAM): addr_map_name.append('ram') - size_in_bytes = np.ceil(slave.width()/c_byte_w)*slave.address_length()*ceil_pow2(slave.number_of_slaves()) + size_in_bytes = slave.address_length() * ceil_pow2(slave.number_of_slaves()) slave_span = ceil_pow2(max(size_in_bytes, 4096)) - logger.debug("RAM Slave %s has span 0x%x", peripheral.name() + '_' + slave.name() , slave_span) + logger.debug("RAM Slave %s_%s has span 0x%x", peripheral.name(), slave.name() , slave_span) if peripheral.number_of_peripherals() > 1: addr_map_name.append(str(periph_num)) @@ -365,10 +356,10 @@ class FPGA(object): elif isinstance(slave, FIFO): addr_map_name.append('fifo') - size_in_bytes = np.ceil(slave.width()/c_byte_w)*slave.address_length() + size_in_bytes = slave.address_length() slave_span = int(ceil_pow2(max(size_in_bytes, 4096))) - logger.debug("FIFO Slave %s has span 0x%x", peripheral.name() + '_' + slave.name() , slave_span) + logger.debug("FIFO Slave %s_%s has span 0x%x", peripheral.name(), slave.name() , slave_span) if peripheral.number_of_peripherals() > 1: addr_map_name.append(str(periph_num)) @@ -379,14 +370,13 @@ class FPGA(object): 'peripheral': peripheral, 'periph_num': periph_num, 'slave': slave} return 0 - def create_address_map(self): """ Preserves order of entry from fpga.yaml Based on vivado limitations, minimum span is 4kB Configurable ranges are 4k, 8k, 16k, 32k, 64k i.e. 2^(12,13,14,15,16) There is a maximum of one register group per peripheral """ - logger.debug("create_address_map('{:s}')".format(self.fpga_name)) + logger.debug("create_address_map('%s')", self.fpga_name) # Largest peripheral will determine spacing between peripheral base addresses largest_addr_range = 4096 # minimal allowed address-decode spacing with Xilinx interconnect @@ -400,8 +390,8 @@ class FPGA(object): # Ensure peripheral base is aligned to address decode lowest_free_addr = int(np.ceil(lowest_free_addr / peripheral_spacing) * peripheral_spacing) - logger.debug('** PERIPHERAL: {:21s} base_addr=0x{:08x} [occupied size=0x{:04x}]'.format( - peripheral.name()[:20], lowest_free_addr, peripheral.reg_len)) + logger.debug('** PERIPHERAL: %21s base_addr=0x%08x [occupied size=0x%04x]', + peripheral.name()[:20], lowest_free_addr, peripheral.reg_len) # assigned_reg = False # _nof_regs = sum([isinstance(slave, Register) for slave in peripheral.slaves]) @@ -420,7 +410,7 @@ class FPGA(object): self.nof_lite = self.nof_lite - 1 lowest_free_addr = register_base + (slave.base_address() if not any(slave.rams) else slave.rams[0].base_address()) ram_span = slave.base_address() - slave.rams[0].base_address() if any(slave.rams) else 0 - slave_span = slave.address_length()*slave.number_of_slaves()+ram_span + slave_span = slave.address_length() * slave.number_of_slaves() + ram_span _name_list = [peripheral.name(), slave.name(), slave_type] if peripheral.number_of_peripherals() > 1: @@ -437,8 +427,8 @@ class FPGA(object): elif isinstance(slave, Register) and getattr(slave, 'isIP', False): slave_type = 'regip' - slave_span = ceil_pow2(max(slave.address_length()*slave.number_of_slaves(), 4096)) # slave.address_length()*slave.number_of_slaves()# - lowest_free_addr = int(np.ceil(lowest_free_addr/slave_span)*slave_span) + slave_span = ceil_pow2(max(slave.address_length() * slave.number_of_slaves(), 4096)) # slave.address_length()*slave.number_of_slaves()# + lowest_free_addr = int(np.ceil(lowest_free_addr / slave_span) * slave_span) _name_list = [peripheral.name(), slave.name(), slave_type] slave_port_name = '_'.join(_name_list) @@ -454,11 +444,11 @@ class FPGA(object): elif isinstance(slave, RAM): slave_type = 'ram' - size_in_bytes = np.ceil(slave.width()/c_byte_w)*slave.address_length()*ceil_pow2(slave.number_of_slaves()) + size_in_bytes = slave.address_length() * ceil_pow2(slave.number_of_slaves()) slave_span = ceil_pow2(max(size_in_bytes, 4096)) - logger.debug("Slave %s has span 0x%x", peripheral.name() + '_' + slave.name() , slave_span) + logger.debug("Slave %s_%s has span 0x%x", peripheral.name(), slave.name() , slave_span) # slave_name = slave.name() + ('_{}'.format(slave_no) if slave.number_of_slaves() >1 else '') - lowest_free_addr = int(np.ceil(lowest_free_addr/slave_span)*slave_span) + lowest_free_addr = int(np.ceil(lowest_free_addr / slave_span) * slave_span) _name_list = [peripheral.name(), slave.name(), slave_type] if peripheral.number_of_peripherals() > 1: @@ -473,10 +463,10 @@ class FPGA(object): elif isinstance(slave, FIFO): slave_type = 'fifo' - size_in_bytes = np.ceil(slave.width()/c_byte_w)*slave.address_length() + size_in_bytes = slave.address_length() slave_span = ceil_pow2(max(size_in_bytes, 4096)) for i in range(slave.number_of_slaves()): - lowest_free_addr = int(np.ceil(lowest_free_addr/slave_span)*slave_span) + lowest_free_addr = int(np.ceil(lowest_free_addr / slave_span) * slave_span) _name_list = [peripheral.name(), slave.name(), slave_type] if peripheral.number_of_peripherals() > 1: @@ -537,12 +527,12 @@ class FPGALibrary(object): continue # skip, no matching file extension try : # try to read yaml file - library_config = yaml.load(open(os.path.join(root, name), 'r')) + library_config = yaml.full_load(open(os.path.join(root, name), 'r')) except yaml.YAMLError as exc: - logger.error('Failed parsing YAML file "{}". Check file for YAML syntax errors'.format(name)) + logger.error('Failed parsing YAML file "%s". Check file for YAML syntax errors', name) if hasattr(exc, 'problem_mark'): mark = exc.problem_mark - logger.error("Error position: (%s:%s)" % (mark.line+1, mark.column+1)) + logger.error("Error position: (%s:%s)", mark.line + 1, mark.column + 1) #logger.error('ERROR:\n' + sys.exc_info()[1]) raise ARGSYamlError continue @@ -559,7 +549,7 @@ class FPGALibrary(object): # looks a valid library self.library[lib_name] = {'file_path': root, 'file_path_name': os.path.join(root, name), 'peripherals': {}} toc = time.time() - logger.debug("FPGALibrary os.walk took %.4f seconds", toc-tic) + logger.debug("FPGALibrary os.walk took %.4f seconds", (toc - tic)) self.peripheral_lib = PeripheralLibrary(self.root_dir) #self.read_fpga_files() @@ -574,11 +564,11 @@ class FPGALibrary(object): file_path_names = [file_path_names] for fpn in file_path_names: - logger.debug("Creating ARGS FPGA object from {}".format(fpn)) + logger.debug("Creating ARGS FPGA object from %s", fpn) tic = time.time() fpga = FPGA(fpn, periph_lib=self.peripheral_lib, use_avalon_base_addr=self.use_avalon_base_addr) toc = time.time() - logger.debug("fpga creation for %s took %.4f seconds", fpn, toc-tic) + logger.debug("fpga creation for %s took %.4f seconds", fpn, (toc - tic)) fpga.show_overview() self.library[fpga.fpga_name].update({'fpga': fpga}) for lib, peripheral in fpga.peripherals.items(): diff --git a/py_args_lib/peripheral.py b/py_args_lib/peripheral.py index 71b7d771943a50e723b73274ec6f2b2240f45008..8b2e4959d861437af18bd2bc692b8d9f9f7dba97 100644 --- a/py_args_lib/peripheral.py +++ b/py_args_lib/peripheral.py @@ -1,28 +1,29 @@ -############################################################################### -# -# Copyright (C) 2016 +# ########################################################################## +# Copyright 2020 # ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> # P.O.Box 2, 7990 AA Dwingeloo, The Netherlands # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# http://www.apache.org/licenses/LICENSE-2.0 # +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ########################################################################## + +# ########################################################################## # Author Date # HJ jan 2017 Original # EK feb 2017 # PD feb 2017 # PD feb 2019 +# PD feb 2020, cleanup and update for only byte adresses # ############################################################################### @@ -77,15 +78,7 @@ class Peripheral(BaseObject): self.extract_config() def get_slave(self, name): - # for reg in self.registers.values(): - # if name == reg.name() or reg.user_defined_name(): - # return reg - # for ram in self.rams.values(): - # if name == ram.name() or ram.user_defined_name(): - # return ram - # for fifo in self.fifos.values(): - # if name == fifo.name() or fifo.user_defined_name(): - # return fifo + for slave in self.slaves: if name == slave.name() or slave.user_defined_name(): return slave @@ -201,17 +194,14 @@ class Peripheral(BaseObject): sys.exit() i = 0 - if slave_info.get('slave_type','').upper() in VALID_SLAVE_TYPES: + if slave_info.get('slave_type', '').upper() in VALID_SLAVE_TYPES: number_of_slaves = slave_info.get('number_of_slaves', DEFAULT_NUMBER_OF_SLAVES) fields = [] if 'fields' in slave_info: - # for field_info in slave_info['fields']: # list of addresses defaults = {} - # logger.debug("slave_info['fields'] = %s", str(slave_info['fields'])) for field_group in slave_info['fields']: if isinstance(field_group, dict): # labelled field group - # logger.debug('field_group=%s', str(field_group)) (group_label, v) = field_group.popitem() field_group = v elif len(field_group) > 1: # unlabelled field group @@ -223,7 +213,6 @@ class Peripheral(BaseObject): logger.debug('group_label=%s', str(group_label)) for field_info in field_group: - # logger.debug("field_info=%s", str(field_info)) # get defaults dictionary if exists for field group if field_info.get('field_defaults', None) is not None: @@ -237,8 +226,6 @@ class Peripheral(BaseObject): field_name = field_info['field_name'] logger.debug("%s, info= %s", field_name, str(field_info)) try : - # PD print(f'field_name={field_name} _slave_type={_slave_type}') - # field = Field(field_name, _slave_type) field = Field(field_name, field_info) except ARGSNameError: logger.error("Invalid name '%s' for field in *.peripheral.yaml", field_name) @@ -254,8 +241,6 @@ class Peripheral(BaseObject): continue if key.lower() in VALID_FIELD_KEYS: # if valid attribute key, apply value to attribute eval("field.{}(val)".format(key.lower())) - # logger.debug("*.peripheral.yaml: field %s %s is %s", - # field.name(), key, str(eval("field.{}()".format(key.lower())))) else: logger.error("Unknown key %s in *.peripheral.yaml", key) sys.exit() @@ -272,7 +257,6 @@ class Peripheral(BaseObject): field_info['field_name'], str(key), str(val)) if field.success: - # fields[field_name] = deepcopy(field) fields.append(deepcopy(field)) else: logger.error("*.peripheral.yaml: field '%s' not succesfully added to fields", field_name) @@ -309,7 +293,6 @@ class Peripheral(BaseObject): _val = str(val) # first replace all knowns parameter names with its assigned value for key1, val1 in self._parameters.items(): - # logger.debug("key={}, val={}".format(key1, val1)) # if val is a dict, in vhdl it's a struct if isinstance(val1, dict): for key2, val2 in val1.items(): @@ -321,7 +304,6 @@ class Peripheral(BaseObject): if key1 in _val: logger.debug("replace %s with %s", key1, str(val1)) _val = _val.replace(key1, str(val1)) - # logger.debug("_val={}".format(_val)) if val is None: logger.error("key set to invalid value %s in *.peripheral.yaml", _val) sys.exit() @@ -361,9 +343,6 @@ class Peripheral(BaseObject): register.slave_span = slave_span if protocol is not None and protocol.upper() in ['LITE', 'FULL']: register.protocol = protocol.upper() - # else : - # logger.error("*.peripheral.yaml: Invalid user setting {} for slave {}".format(protocol, name)) - # sys.exit() self.registers['slave_{}'.format(slave_nr)] = register self.slaves.append(register) @@ -380,7 +359,6 @@ class Peripheral(BaseObject): def add_fifo(self, slave_nr, name, field, number_of_slaves): """ add FIFO to peripheral """ - # fifo = FIFO(name, field) fifo = deepcopy(self.init_slave('FIFO', name, field)) fifo.number_of_slaves(number_of_slaves) self.fifos['slave_{}'.format(slave_nr)] = fifo @@ -425,8 +403,6 @@ class Peripheral(BaseObject): def eval_fifo(self): """ Evaluate the paramters and the nof_inst of the peripheral """ - # for fifo in self.fifos.values(): - # print(type(fifo)) for slave in self.slaves: if isinstance(slave, FIFO): # Evaluate the fields @@ -435,18 +411,17 @@ class Peripheral(BaseObject): continue fifo = slave fifo.number_of_slaves(val=self._eval(fifo.number_of_slaves())) - logger.debug(" -FIFO depth str: %s", fifo.number_of_fields()) - fifo.address_length(val=ceil_pow2(self._eval(fifo.number_of_fields()))) - logger.debug(" -FIFO depth eval: %s", fifo.address_length()) - logger.debug(" -FIFO width str: %s", fifo.width()) + logger.debug(" -FIFO depth (fields): %s", fifo.number_of_fields()) + fifo.address_length(val=ceil_pow2(self._eval(fifo.number_of_fields())) * WIDTH_IN_BYTES) # address_length in bytes + logger.debug(" -FIFO depth (bytes): %s", fifo.address_length()) + logger.debug(" -FIFO width (bits): %s", fifo.width()) def eval_ram(self): """Evaluate the parameters and the nof_inst of the peripheral in order to define the real address_length and width of the RAM. For example: address_length = c_nof_weights*c_nof_signal_paths - witdh = c_weights_w*c_nof_complex """ + witdh = c_weights_w*N_COMPLEX """ - # for ram in self.rams.values(): for slave in self.slaves: # Evaluate the fields and see if there are field that have to be repeated. if isinstance(slave, RAM): @@ -462,56 +437,40 @@ class Peripheral(BaseObject): ram.number_of_slaves(val=self._eval(ram.number_of_slaves())) - # for ram in self.rams.values(): for slave in self.slaves: # Evaluate the fields and see if there are field that have to be repeated. if isinstance(slave, RAM): ram = slave else: continue - # ram.number_of_slaves(val=self._eval(ram.nof_inst())) - # for field in ram.fields: - logger.debug(" -RAM depth str: %s", ram.number_of_fields()) + logger.debug(" -RAM depth (fields): %s", ram.number_of_fields()) # Here the variables are used to evaluate the true value for the depth # parameter(taking int account the nof_inst as well) - ram.address_length(val=ceil_pow2(self._eval(ram.number_of_fields()))) - logger.debug(" -RAM depth eval: %d", ram.address_length()) + ram.address_length(val=ceil_pow2(self._eval(ram.number_of_fields())) * WIDTH_IN_BYTES) # address_length in bytes + logger.debug(" -RAM depth (bytes): %d", ram.address_length()) - logger.debug(" -RAM width str: %s", ram.width()) + logger.debug(" -RAM width (bits): %s", ram.width()) # Here the variables are used to evaluate the true value for the width parameter. - # field.width(val=self._eval(field.width())) - # ram.width(val=self._eval(field.width())) - # ram.default(val=self._eval(field.default())) ram.user_depth(val=self._eval(ram.user_depth())) ram.user_width(val=self._eval(ram.user_width())) ram.update_address_length() - # ram.access_mode(val=self._eval(field.access_mode())) - logger.debug(" -RAM width eval: %d", ram.width()) + logger.debug(" -RAM width eval: %d (bits)", ram.width()) logger.debug(" %s access_mode: %s", ram.name(), ram.access_mode()) - logger.debug(" %s depth: %d", ram.name(), ram.address_length()) - logger.debug(" %s width: %d", ram.name(), ram.user_width()) + logger.debug(" %s depth: %d (bytes)", ram.name(), ram.address_length()) + logger.debug(" %s width: %d (bits)", ram.name(), ram.user_width()) def eval_register(self): """Evaluate the register address_length based on the evaluation of the fields, nof registers and the nof_inst.""" - # for parameter in self.parameters: - # Here the parameters of the peripheral are promoted to real python variables - # exec("%s = %d" % (parameter, eval(str(self.parameters[parameter])))) + logger.debug("Number of registers = %d", len(self.registers.items())) - # for i in range(len(self.registers.values())):#register in self.registers.values(): - # try: - # register = self.registers['slave_{}'.format(i)] - # logger.debug(" Register slave %s ", register.name()) - # except KeyError: - # continue - base_addr = 0 + for slave in self.slaves: if isinstance(slave, Register): register = slave else : continue logger.debug("evaluate %s", register.name()) - # register.number_of_slaves(val=self._eval(register.number_of_slaves())) # Evaluate the fields and see if there are field that have to be repeated. fields_eval = [] @@ -535,9 +494,7 @@ class Peripheral(BaseObject): elif field.number_of_fields() >= REG_MAX_FIELDS: register.rams.append(field) else : - fields_eval.append(field) - - #fields_eval.append(field) + fields_eval.append(field) self.eval_fields(fields_eval) self.eval_fields(register.rams) @@ -550,10 +507,11 @@ class Peripheral(BaseObject): register.name('_'.join(register_name)) # set base addresses for reg fields implemented as RAM + base_addr = 0 for field in register.rams: - base_addr = ceil(base_addr / ceil_pow2(field.number_of_fields() * WIDTH_IN_BYTES)) * ceil_pow2(field.number_of_fields() * WIDTH_IN_BYTES) # lowest possible base_addr + base_addr = ceil(base_addr / (ceil_pow2(field.number_of_fields()) * WIDTH_IN_BYTES)) * ceil_pow2(field.number_of_fields()) * WIDTH_IN_BYTES # lowest possible base_addr + base_addr = base_addr + ceil_pow2(field.number_of_fields()) * WIDTH_IN_BYTES * register.number_of_slaves() # new base address field.base_address(base_addr) - base_addr = base_addr + ceil_pow2(field.number_of_fields() * WIDTH_IN_BYTES) * register.number_of_slaves() # new base address # ### Assigned Address and bits to register fields # 1st pass for manually set address fields @@ -584,7 +542,7 @@ class Peripheral(BaseObject): while (lowest_free_addr) in occupied_addresses: lowest_free_addr = lowest_free_addr + WIDTH_IN_BYTES - if len(set(occupied_bits)) < len(occupied_bits) or any([bit > (DATA_WIDTH-1) or bit < 0 for bit in occupied_bits]): + if len(set(occupied_bits)) < len(occupied_bits) or any([bit > (DATA_WIDTH - 1) or bit < 0 for bit in occupied_bits]): logger.error('*.peripheral.yaml: Manually assigned bits for field %s is outside of data width or contains bit collisions', field.name() if field.group_name() is None else "group " + field.group_name()) logger.error("{}".format(str(occupied_bits))) @@ -612,7 +570,7 @@ class Peripheral(BaseObject): if field.bit_offset() == UNASSIGNED_BIT: free_bit = 0 - while any([i in occupied_bits for i in range(free_bit, free_bit + field.width()+1)]): # bit is occupied + while any([i in occupied_bits for i in range(free_bit, free_bit + field.width() + 1)]): # bit is occupied free_bit = free_bit + 1 # try next bit if free_bit == DEFAULT_WIDTH: # 31 didn't work logger.error('*.peripheral.yaml: No suitable gap available for automatic bit offset assignment of field%s', @@ -621,7 +579,6 @@ class Peripheral(BaseObject): break field.bit_offset(free_bit) occupied_bits = occupied_bits + list(range(field.bit_offset(), field.bit_offset() + field.width())) - # logger.warning("*.peripheral.yaml: Final field {} addr {} [{}-{}]".format(field.name(), str(field.address_offset()), str(field.bit_offset()+field.width()-1),str(field.bit_offset()))) # re-sort fields to be ordered by address and bit offsets fields_eval.sort(key=lambda x: x.address_offset()) @@ -636,11 +593,8 @@ class Peripheral(BaseObject): sorted_fields.extend(sorted(dummy_group, key=lambda x: x.bit_offset())) register.fields = sorted_fields # Update the fields with evaluated fields - # self.eval_fields(register.fields) - # self.eval_fields(register.rams) register.update_address_length() # Estimate the new address_length after evaluation of the fields and nof_inst - # logger.info(" %s address_length: %d", register.name(), register.address_length()) - # logger.info("slave %s has base_address %d", register.name(), register.base_address()) + logger.info(" %s address_length: %d", register.name(), register.address_length()) register.base_address(base_addr) base_addr = base_addr + register.address_length() * register.number_of_slaves() @@ -672,7 +626,6 @@ class Peripheral(BaseObject): if self.number_of_peripherals() > 1: logger.debug(" number_of_peripheral_instances=%d", self.number_of_peripherals()) logger.debug(" RAM and REG:") - # for ram in self.rams.values(): for ram in self.slaves: if not isinstance(ram, RAM): continue @@ -682,22 +635,17 @@ class Peripheral(BaseObject): logger.debug(" fields:") # first make list with address_offset as first item to print later fields orderd on address. fields = [] - # for field_val in ram.fields.values(): fields.append([ram.address_offset(), ram.name()]) for _offset, _name in sorted(fields): field = ram logger.debug(" %-20s:", _name) - # if field.number_of_fields() > 1: - # logger.debug(" number_of_fields=%s", str(field.number_of_fields())) logger.debug(" width=%-2s number_of_fields=%s", str(field.width()), str(field.number_of_fields())) - # for reg in self.registers.values(): for reg in self.slaves: if not isinstance(reg, Register): continue - # logger.debug("reg_fields=%s", str(reg.fields)) logger.debug(" %-20s:", reg.name()) if reg.number_of_slaves() > 1: logger.debug(" number_of_slaves=%-3s", str(reg.number_of_slaves())) @@ -707,9 +655,6 @@ class Peripheral(BaseObject): for field in reg.fields: logger.debug(" %-20s", field.name()) - # if field.number_of_fields() > 1: - # logger.debug(" number_of_fields=%s", str(field.number_of_fields())) - logger.debug(" width=%-2s address_offset=0x%02x access_mode=%-4s reset_value=%-4s radix=%s", str(field.width()), field.address_offset(), field.access_mode(), str(field.reset_value()), field.radix()) logger.debug(" bit_offset=%-2s number_of_fields=%-4s side_effect=%-4s software_value=%-4s", @@ -743,16 +688,16 @@ class PeripheralLibrary(object): if 'tools' in root: # skip tools dir continue - dirs[:] = [d for d in dirs if path_string(root+d) not in exclude and '.svn' not in d] + dirs[:] = [d for d in dirs if path_string(root + d) not in exclude and '.svn' not in d] for name in files: if self.file_extension in name and name[0] != '.': try : - library_config = yaml.load(open(os.path.join(root, name), 'r')) + library_config = yaml.full_load(open(os.path.join(root, name), 'r')) except yaml.YAMLError as exc: logger.error('Failed parsing YAML file "{}". Check file for YAML syntax errors'.format(name)) if hasattr(exc, 'problem_mark'): mark = exc.problem_mark - logger.error("Error position: (%s:%s)" % (mark.line+1, mark.column+1)) + logger.error("Error position: (%s:%s)" % (mark.line + 1, mark.column + 1)) raise ARGSYamlError continue @@ -780,17 +725,12 @@ class PeripheralLibrary(object): self.library.update({lib_name: {'file_path': root, 'file_path_name': os.path.join(root, name), 'peripherals': collections.OrderedDict(), - 'description': library_config.get('hdl_library_description', "") - } - }) + 'description': library_config.get('hdl_library_description', "")}}) else : logger.error("More than one instance of args peripheral library '%s' found under %s", lib_name, root_dir) logger.error("\nConflicting files:\n\t%s\n\t%s", self.library[lib_name]['file_path_name'], os.path.join(root, name)) sys.exit() - # list of peripheral configurations that are read from the available peripheral files - #self.read_peripheral_files() - def get_file_path_name(self, lib_name): """ return peripheral library file_path_name if found else None @@ -805,14 +745,13 @@ class PeripheralLibrary(object): """Read the peripheral information from all peripheral files that were found in the root_dir tree.""" self.peripherals = {} if file_path_names is None: - # file_path_names = self.file_path_names file_path_names = [lib_dict['file_path_name'] for lib_dict in self.library.values()] elif not isinstance(file_path_names, list): file_path_names = [file_path_names] for fpn in file_path_names: logger.debug("Load peripheral(s) from '%s'", fpn) - library_config = yaml.load(open(fpn, 'r')) + library_config = yaml.full_load(open(fpn, 'r')) for peripheral_config in library_config['peripherals']: try : peripheral = deepcopy(Peripheral(peripheral_config)) @@ -848,15 +787,12 @@ class PeripheralLibrary(object): sys.exit() return None else : - # TODO.PD: matching_libs = [] # try to find unique instance of peripheral, failing that look for local for lib in self.library: - # periph_names.extend(list(self.library[lib]['peripherals'].keys())) if periph_name in self.library[lib]['peripherals']: matching_libs.append(lib) - # matches = len([name for name in periph_names if name == periph_name]) matches = len(matching_libs) if matches > 1: if fpga_library is not None and fpga_library in matching_libs: @@ -876,9 +812,6 @@ class PeripheralLibrary(object): logger.error("No matching peripherals for '%s' found under %s", periph_name, self.root_dir) sys.exit() - # if peripheral_library is None: - # return self.peripherals.get(name, None) - # return peripheral_library.get(name, None) return None def show_overview(self, header=True): diff --git a/py_args_lib/peripheral_lib/args_errors.py b/py_args_lib/peripheral_lib/args_errors.py index 10e7a852c87ea8c8f88dffcf77c329a58c9c186f..4c3183613222ca8fd6a5211ea424ca450d762688 100644 --- a/py_args_lib/peripheral_lib/args_errors.py +++ b/py_args_lib/peripheral_lib/args_errors.py @@ -1,3 +1,21 @@ +# ########################################################################## +# Copyright 2020 +# ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ########################################################################## + import logging diff --git a/py_args_lib/peripheral_lib/base_object.py b/py_args_lib/peripheral_lib/base_object.py index 8a9f331751723535f63879a791a518422f46bd53..b25841111cc4491ddd881170f1ef98b3ed2864ad 100644 --- a/py_args_lib/peripheral_lib/base_object.py +++ b/py_args_lib/peripheral_lib/base_object.py @@ -1,28 +1,29 @@ -############################################################################### -# -# Copyright (C) 2016 +# ########################################################################## +# Copyright 2020 # ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> # P.O.Box 2, 7990 AA Dwingeloo, The Netherlands # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# http://www.apache.org/licenses/LICENSE-2.0 # +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ########################################################################## + +# ########################################################################## # Author Date # HJ jan 2017 Original # EK feb 2017 # PD feb 2017 # ############################################################################### + import logging import re import sys diff --git a/py_args_lib/peripheral_lib/common_func.py b/py_args_lib/peripheral_lib/common_func.py index 12bafe574b189c271bd6d63ad2793d6e4141e3d7..fe2f19f7c8842fef12c76d26056b291fbb7e9ddd 100644 --- a/py_args_lib/peripheral_lib/common_func.py +++ b/py_args_lib/peripheral_lib/common_func.py @@ -1,29 +1,26 @@ -############################################################################### -# -# Copyright (C) 2012 +# ########################################################################## +# Copyright 2020 # ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> # P.O.Box 2, 7990 AA Dwingeloo, The Netherlands # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# http://www.apache.org/licenses/LICENSE-2.0 # -############################################################################### +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ########################################################################## -"""Common definitions +""" +Common definitions """ -################################################################################ # System imports import os @@ -31,10 +28,8 @@ import math # do not use numpy in common, to avoid making common to elaborate import re -################################################################################ # Functions - def ceil_log2(num): """ Return integer ceil value of log2(num) """ return int(math.ceil(math.log(int(num), 2))) diff --git a/py_args_lib/peripheral_lib/constants.py b/py_args_lib/peripheral_lib/constants.py index b8ac4378c02b344f9b6250a2ae15ff7eb3abc91b..a6acaf4a44aa7ab8ececcce01bd228372469a6b7 100644 --- a/py_args_lib/peripheral_lib/constants.py +++ b/py_args_lib/peripheral_lib/constants.py @@ -1,15 +1,42 @@ -""" +# ########################################################################## +# Copyright 2020 +# ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ########################################################################## + +# ########################################################################## +# Author Date +# PD feb 2017, nov 2019 +# +############################################################################### + +""" Constants used by peripheral.py and fpga.py this constants can be used in the yaml files """ c_byte_w = 8 c_word_w = 32 -c_word_sz = 4 c_nof_complex = 2 +BYTE_WIDTH = c_byte_w +WORD_WIDTH = c_word_w +N_COMPLEX = c_nof_complex + VALID_SCHEMA_NAME = ['args'] VALID_SCHEMA_TYPES = ['system', 'peripheral'] @@ -36,7 +63,7 @@ UNASSIGNED_ADDRESS = 16384 UNASSIGNED_BIT = 32 DEFAULT_WIDTH = c_word_w -WIDTH_IN_BYTES = int(c_word_w/c_byte_w) +WIDTH_IN_BYTES = int(c_word_w / c_byte_w) DEFAULT_BIT_OFFSET = UNASSIGNED_BIT DEFAULT_ACCESS_MODE = 'RW' DEFAULT_SIDE_EFFECT = None @@ -51,3 +78,5 @@ DATA_WIDTH = 32 DEFAULT_ADDRESS_LENGTH = 1 REG_MAX_FIELDS = 32 + + diff --git a/py_args_lib/peripheral_lib/field.py b/py_args_lib/peripheral_lib/field.py index 5c9264bf38bf80dd3985e9181e0cc39edafe63a3..876864ebf166e7337237bcfa73cc51aab2852a4a 100644 --- a/py_args_lib/peripheral_lib/field.py +++ b/py_args_lib/peripheral_lib/field.py @@ -1,22 +1,22 @@ -############################################################################### -# -# Copyright (C) 2016 +# ########################################################################## +# Copyright 2020 # ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> # P.O.Box 2, 7990 AA Dwingeloo, The Netherlands # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# http://www.apache.org/licenses/LICENSE-2.0 # +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ########################################################################## + +# ########################################################################## # Author Date # HJ jan 2017 Original # EK feb 2017 @@ -42,21 +42,18 @@ class Field(BaseObject): self.name(name) - # self._valid_keys = ['width', 'bit_offset', 'access_mode', 'side_effect', 'address_offset', 'number_of_fields', - # 'reset_value', 'software_value', 'radix', 'field_description', 'field_name', 'default', 'user_width'] - self._valid_dict = {'width': {'max': 32, 'min': 1}, - 'bit_offset': {'max': UNASSIGNED_BIT, 'min': 0}, - 'access_mode': {}, - 'side_effect': {}, - 'address_offset': {'max': 16384, 'min': 0, 'word_aligned': True}, - 'number_of_fields': {'max': 262144, 'min': 1}, - 'reset_value': {'max': 131071}, - 'software_value': {}, - 'radix': {}, - 'field_description': {}, - 'field_name': {}, - 'user_width': {'max': 2048, 'min': 32} - } + self._valid_dict = {'width' : {'max': 32, 'min': 1}, + 'bit_offset' : {'max': UNASSIGNED_BIT, 'min': 0}, + 'access_mode' : {}, + 'side_effect' : {}, + 'address_offset' : {'max': 16384, 'min': 0, 'word_aligned': True}, + 'number_of_fields' : {'max': 262144, 'min': 1}, + 'reset_value' : {'max': 131071}, + 'software_value' : {}, + 'radix' : {}, + 'field_description' : {}, + 'field_name' : {}, + 'user_width' : {'max': 2048, 'min': 32}} self._args.update({'width' : DEFAULT_WIDTH, 'bit_offset' : DEFAULT_BIT_OFFSET, @@ -160,7 +157,7 @@ class Field(BaseObject): return self._as_str('side_effect').upper() def address_offset(self, val=None): - """ set/get address offset of field + """ set/get address offset of field in bytes val: if not None set address offset of field return: actual address offset of field """ if val is not None: @@ -218,6 +215,7 @@ class Field(BaseObject): return self._as_int('user_width', default=32) def base_address(self, val=None): + """ set/get base_address in bytes """ if val is not None: if mod(val, WIDTH_IN_BYTES): # don't need check here if tool calcs are correct logger.error("Base address for field {} is not word aligned".format(field.name())) diff --git a/py_args_lib/peripheral_lib/fifo.py b/py_args_lib/peripheral_lib/fifo.py index 079aae8f6cd3ed4ecb3027a6358be5cc202dad59..af569f8cd3872609787fe6a38fc79c0f4d458e86 100644 --- a/py_args_lib/peripheral_lib/fifo.py +++ b/py_args_lib/peripheral_lib/fifo.py @@ -1,22 +1,22 @@ -############################################################################### -# -# Copyright (C) 2016 +# ########################################################################## +# Copyright 2020 # ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> # P.O.Box 2, 7990 AA Dwingeloo, The Netherlands # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# http://www.apache.org/licenses/LICENSE-2.0 # +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ########################################################################## + +# ########################################################################## # Author Date # HJ jan 2017 Original # EK feb 2017 @@ -24,124 +24,70 @@ # ############################################################################### -from math import ceil import logging -from constants import c_word_w, c_nof_complex, VALID_FIFO_ACCESS_MODES -from common_func import ceil_pow2, ceil_log2 -from base_object import BaseObject +from constants import VALID_FIFO_ACCESS_MODES, WIDTH_IN_BYTES +from common_func import ceil_pow2 from field import Field -from register import Register from args_errors import ARGSModeError logger = logging.getLogger('main.periph.fifo') -# TODO: use BaseObject class FIFO(Field): """ A FIFO is a specific set of Fields - A FIFO is a Field that is repeated address_length times + A FIFO is a Field that is repeated address_length times """ def __init__(self, name, settings): super().__init__(name, settings) self.set_kv('type', 'FIFO') self.name(name) self.description = "" - # self.number_of_fifos = 1 - #self.fifo_fields = [] if self.access_mode() not in VALID_FIFO_ACCESS_MODES: logger.error("'%s' not a valid access mode for slaves of type FIFO. Valid modes include %s", self.access_mode(), VALID_FIFO_ACCESS_MODES) raise ARGSModeError - + self.tx_fifo_vacancy = Field(name="fifo_status", - settings={ - 'width': 32, + settings={'width': 32, 'access_mode': "RO", 'address_offset': 0x8, 'reset_value': 0, 'field_description': "Transmit Data FIFO Vacancy (TDFV). Width N equal to C_S_AXI_DATA_WIDTH" - }) - self.rx_fifo_occupancy = Field(name="fifo_status", - settings={ - 'width': 16, + }) + self.rx_fifo_occupancy = Field(name="fifo_status", + settings={'width': 16, 'access_mode': "RO", 'address_offset': 0x1C, 'reset_value': 0, 'field_description': "Receive Data FIFO Occupancy (RDFO). Number of locations in use for data storage" - }) - self.rx_length = Field(name="fifo_status", - settings={ - 'width': 23, + }) + self.rx_length = Field(name="fifo_status", + settings={'width': 23, 'access_mode': "RO", 'address_offset': 0x24, 'reset_value': 0, 'field_description': "Receive Length Register (RLR). The number of bytes of the corresponding receive data stored in the receive data FIFO" - }) - - # fifo_fields["fifo_status"] = Field(name="fifo_status", - # settings={ - # 'width': 4, - # 'mode': "RO", - # 'offset': 0x0, - # 'default': 0, - # 'descr': "fifo status register. Bit 0: Fifo Full Bit 1: Fifo Empty" - # }) - - # fifo_fields["fifo_used_w"] = Field(name="fifo_used_w", - # settings={ - # 'width': 32, - # 'mode': "RO", - # 'offset': 0x4, - # 'default': 0, - # 'descr': "fifo used words register." - # }) + }) - # fifo_fields["fifo_read_reg"] = Field(name="fifo_read_reg", - # settings={ - # 'width': settings['width'], - # 'mode': "RO", - # 'offset': 0x8, - # 'default': 0, - # 'descr': "fifo read register." - # }) - - # fifo_fields["fifo_write_reg"] = Field(name="fifo_write_reg", - # settings={ - # 'width': settings['width'], - # 'mode': "WO", - # 'offset': 0xC, - # 'default': 0, - # 'descr': "fifo write register." - # }) - - # self.register = Register("FIFO Register", fifo_fields) - # self.address_length = settings['address_length'] - def set_mon_fields(): """ fifo_fields are set based on FIFO access mode if side effect 'MON' is configured """ - + def number_of_slaves(self, val=None): """ set/get number of slaves """ if val is not None: self.set_kv('number_of_slaves', val) return return self._as_int('number_of_slaves') - + def update_address_length(self): - """ update total address_length of Register - """ - # if len(self.fields) == 0: - # return - n_words = 0 - # for field in self.fields.values(): - # n_words += ceil_pow2(int(ceil(float(field.width()) / c_word_w)) * field.number_of_fields()) - #logger.debug("n_words=%d", n_words) - n_words = ceil_pow2(self.number_of_fields()) - self.set_kv('address_length', n_words) + """ update total address_length of Register in bytes """ + n_fields = ceil_pow2(self.number_of_fields()) + self.set_kv('address_length', n_fields * WIDTH_IN_BYTES) - def address_length(self, val=None): - """ set/get address_length of register - val: if not None set address_length of register - return: address_length of register """ + def address_length(self, val=None): + """ set/get address_length of register in bytes + val: if not None set address_length of register + return: address_length of register + """ if val is not None: return self.set_kv('address_length', val) - return self._as_int('address_length', default=1) \ No newline at end of file + return self._as_int('address_length', default=WIDTH_IN_BYTES) diff --git a/py_args_lib/peripheral_lib/ram.py b/py_args_lib/peripheral_lib/ram.py index 7de7f1167008d32b04190dba5ea7956e335e93c0..b8f25cd6376708a893c3924af1eaa1daa03a3276 100644 --- a/py_args_lib/peripheral_lib/ram.py +++ b/py_args_lib/peripheral_lib/ram.py @@ -1,26 +1,27 @@ -############################################################################### -# -# Copyright (C) 2016 +# ########################################################################## +# Copyright 2020 # ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> # P.O.Box 2, 7990 AA Dwingeloo, The Netherlands # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# http://www.apache.org/licenses/LICENSE-2.0 # +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ########################################################################## + +# ########################################################################## # Author Date # HJ jan 2017 Original # EK feb 2017 # PD feb 2017 +# PD sep 2020 cleanup code # ############################################################################### @@ -34,6 +35,8 @@ from field import Field logger = logging.getLogger('main.perip.ram') +MIN_BRAM_DEPTH = 128 + class RAM(Field): """ A RAM is a Field that is repeated address_length times """ @@ -54,30 +57,24 @@ class RAM(Field): return self._as_int('number_of_slaves') def user_depth(self, val=None): + """ val: depth in bytes """ if val is not None: - if val < 1024: - logger.error("Calculated user depth %d for BRAM %s is invalid. Minimum BRAM depth is 1024", val, self.name()) + if val < MIN_BRAM_DEPTH: + logger.error("Calculated user depth %d for BRAM %s is invalid. Minimum BRAM depth is %d", val, self.name(), MIN_BRAM_DEPTH) self.set_kv('user_depth', val) return return self._as_int('user_depth', self.address_length()) def update_address_length(self): - """ update total address_length of Register - """ - # if len(self.fields) == 0: - # return - n_words = 0 - # for field in self.fields.values(): - # n_words += ceil_pow2(int(ceil(float(field.width()) / c_word_w)) * field.number_of_fields()) - # logger.debug("n_words=%d", n_words) - n_words = ceil_pow2(self.number_of_fields()) - self.user_depth(n_words * self.width() / self.user_width()) - self.set_kv('address_length', n_words) + """ update total address_length of Register in bytes """ + n_fields = ceil_pow2(self.number_of_fields()) + self.user_depth(n_fields * self.width() / self.user_width()) + self.set_kv('address_length', n_fields * WIDTH_IN_BYTES) def address_length(self, val=None): - """ set/get address_length of register + """ set/get address_length of register in bytes val: if not None set address_length of register return: address_length of register """ if val is not None: return self.set_kv('address_length', val) - return self._as_int('address_length', default=1) + return self._as_int('address_length', default=WIDTH_IN_BYTES) diff --git a/py_args_lib/peripheral_lib/register.py b/py_args_lib/peripheral_lib/register.py index 88e3c60ff5a6774f76bc3f896e1d93c21774fe0c..58422da4829d2930baff6aa8e46a3c8710f516c1 100644 --- a/py_args_lib/peripheral_lib/register.py +++ b/py_args_lib/peripheral_lib/register.py @@ -1,22 +1,22 @@ -############################################################################### -# -# Copyright (C) 2016 +# ########################################################################## +# Copyright 2020 # ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> # P.O.Box 2, 7990 AA Dwingeloo, The Netherlands # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# http://www.apache.org/licenses/LICENSE-2.0 # +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ########################################################################## + +# ########################################################################## # Author Date # HJ jan 2017 Original # EK feb 2017 @@ -44,7 +44,7 @@ class Register(BaseObject): self.set_kv('type', 'REG') self.name(name) - self.fields = [] if fields is None else fields + self.fields = [] if fields is None else fields self.rams = [] @@ -80,21 +80,23 @@ class Register(BaseObject): return False def update_address_length(self): - """ update total address_length of Register - """ - if len(self.fields) == 0: + """ update total address_length of Register in bytes """ + if len(self.fields) == 0 and len(self.rams) == 0: + self.set_kv('address_length', 0) return + n_bytes = 0 - # for field in self.fields: #.values(): - # n_words += int(ceil_pow2(int(ceil(float(field.width()) / c_word_w)) * field.number_of_fields())) - # logger.debug("n_words=%d", n_words) - # n_words = ceil_pow2(n_words) # round up to power of 2 - # n_bytes = self.fields[-1].address_offset()+WIDTH_IN_BYTES - n_bytes = max(max([_field.address_offset() for _field in self.fields]) + WIDTH_IN_BYTES, self.slave_span if self.slave_span is not None else 0) + if any(self.fields): + n_bytes += max(max([_field.address_offset() for _field in self.fields]) + WIDTH_IN_BYTES, self.slave_span if self.slave_span is not None else 0) + + if any(self.rams): + #n_bytes += max(max([_field.address_offset() for _field in self.rams]) + WIDTH_IN_BYTES, self.slave_span if self.slave_span is not None else 0) + n_bytes += ceil_pow2(self.rams[0].number_of_fields()) * WIDTH_IN_BYTES + self.set_kv('address_length', n_bytes) def address_length(self, val=None): - """ set/get address_length of register + """ set/get address_length of register in bytes val: if not None set address_length of register return: address_length of register """ if val is not None: @@ -107,4 +109,4 @@ class Register(BaseObject): def base_address(self, val=None): if val is not None: return self.set_kv('base_address', val) - return self._as_int('base_address', default=1) \ No newline at end of file + return self._as_int('base_address', default=0) \ No newline at end of file diff --git a/qsys.reg b/qsys.reg deleted file mode 100644 index 705186b387743ba2bd4fd03b0f6e76e4d285fbd4..0000000000000000000000000000000000000000 Binary files a/qsys.reg and /dev/null differ diff --git a/unb1_minimal_sopc.build.reg b/unb1_minimal_sopc.build.reg deleted file mode 100644 index 74d09a28b3fcf3b487723136d8ff67df485aed07..0000000000000000000000000000000000000000 Binary files a/unb1_minimal_sopc.build.reg and /dev/null differ diff --git a/uniboard_rom_system_info.py b/uniboard_rom_system_info.py index bab353589fc4541c4030fdfcf70f35a6bcac3488..1ad0f3563e4ca43670b37da829aaba7cbf3de3bf 100755 --- a/uniboard_rom_system_info.py +++ b/uniboard_rom_system_info.py @@ -1,23 +1,23 @@ #! /usr/bin/env python3 -############################################################################### -# -# Copyright (C) 2016 +# ########################################################################## +# Copyright 2020 # ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> # P.O.Box 2, 7990 AA Dwingeloo, The Netherlands # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. +# http://www.apache.org/licenses/LICENSE-2.0 # +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ########################################################################## + +# ########################################################################## # Author Date # PD feb 2017 # @@ -82,23 +82,23 @@ class MemoryMapper(object): self.map.append({'name': name, 'base_address': base_address, 'end_address': end_address, - 'size': size * c_word_sz, + 'size': size * WIDTH_IN_BYTES, 'nof_instances': nof_instances, 'hide_in_reg_file': hide_in_reg_file}) logger.debug("add(): %08x, %08x, %d, %s, %d, %s", - base_address, end_address, (size * c_word_sz), name, nof_instances, str(hide_in_reg_file)) + base_address, end_address, (size * WIDTH_IN_BYTES), name, nof_instances, str(hide_in_reg_file)) else: _base_address = self._find_start_addr(size*nof_instances) self.map.append({'name': name, 'base_address': _base_address, 'end_address': _base_address+(size*nof_instances), - 'size': size * c_word_sz, + 'size': size * WIDTH_IN_BYTES, 'nof_instances': nof_instances, 'hide_in_reg_file': hide_in_reg_file}) logger.debug("add(): %08x, %08x, %d, %s, %d, %s", - _base_address, _base_address+(size*nof_instances), size * c_word_sz, name, nof_instances, str(hide_in_reg_file)) + _base_address, _base_address+(size*nof_instances), size * WIDTH_IN_BYTES, name, nof_instances, str(hide_in_reg_file)) def _find_start_addr(self, size): """ look for the next address where the size (in bytes) will fit """