From c853eb3cfecb79d9eac7200c312150d150feab8d Mon Sep 17 00:00:00 2001 From: Kevin Dinkel <1225857+dinkelk@users.noreply.github.com> Date: Mon, 18 Nov 2024 16:35:24 -0700 Subject: [PATCH 1/3] Allow ints in generic component formal parameters Previously, for instantiating generic components in the assembly, only variables or strings that passed the Ada style check were allowed. This is overly restrictive. This commit permits the use of raw integers to instantiate generic formal parameters as well. --- gen/models/submodels/generic_unit.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/gen/models/submodels/generic_unit.py b/gen/models/submodels/generic_unit.py index 18279f29..e430919b 100644 --- a/gen/models/submodels/generic_unit.py +++ b/gen/models/submodels/generic_unit.py @@ -66,10 +66,15 @@ def instantiate(self, type): + "'." ) - self.type = ada.formatType(type) - # Calculate type package, if one: - if not ada.isTypePrimitive(self.type): - self.type_package = ada.getPackage(self.type) + try: + # Handle integer formal parameters + self.type = str(int(type)) + except ValueError: + # Handle normal formal parameters + self.type = ada.formatType(type) + # Calculate type package, if one: + if not ada.isTypePrimitive(self.type): + self.type_package = ada.getPackage(self.type) class generic_unit(object): From 5854821b0807066106e12ddecef61f8f13279b05 Mon Sep 17 00:00:00 2001 From: Kevin Dinkel <1225857+dinkelk@users.noreply.github.com> Date: Tue, 19 Nov 2024 09:31:45 -0700 Subject: [PATCH 2/3] Split components declaration into its own package This provides a dedicated package to store assembly component declaration, which also includes tasks and interrupt declaration. The name of this file is _components.ads. By removing these from the overall autocoded .ads we resolve a circular depdendency problem that can sometime arise when a generic component declares types that then need to be provided to it in its Init. In this case, a package that instantiates these types (ie. something like assembly_registers.ads) would depend on the assembly .ads. The assembly .adb would, in turn, depend on that package, creating a circular dependency. Now, the package can selectively import only the _components.ads file, removing its dependency on the entire assembly .ads, and thus removing the circular dependency. --- gen/generators/assembly.py | 1 + gen/models/assembly.py | 24 ++-- gen/templates/assembly/name.adb | 9 ++ gen/templates/assembly/name.ads | 116 +----------------- gen/templates/assembly/name_components.ads | 132 +++++++++++++++++++++ 5 files changed, 158 insertions(+), 124 deletions(-) create mode 100644 gen/templates/assembly/name_components.ads diff --git a/gen/generators/assembly.py b/gen/generators/assembly.py index 04bd0ff1..420dda7a 100644 --- a/gen/generators/assembly.py +++ b/gen/generators/assembly.py @@ -15,6 +15,7 @@ "assembly/name.ads", "assembly/name.adb", "assembly/name.dot", + "assembly/name_components.ads", "assembly/name_commands.ads", "assembly/name_data_products.ads", "assembly/name_data_dependencies.ads", diff --git a/gen/models/assembly.py b/gen/models/assembly.py index 24bc44e7..de55b0ac 100644 --- a/gen/models/assembly.py +++ b/gen/models/assembly.py @@ -607,6 +607,7 @@ def load(self): self.interrupt_list = None # list of interrupts in assembly self.ads_includes = [] self.adb_includes = [] + self.components_ads_includes = [] self.task_dict = {} # Tasks indexed by priority self.task_list = [] # Tasks in order of task number (and priority rank) self.entity_dict = ( @@ -908,7 +909,18 @@ def load_subassembly(name): self.interrupt_list = sorted_interrupts # Store all includes for the assembly: - self.ads_includes.extend( + self.adb_includes.extend( + list( + OrderedDict.fromkeys( + [self.name + "_Components"] + + (["Ada.Synchronous_Task_Control"] + if self.task_list + else []) + ) + ) + ) + self.adb_includes = list(OrderedDict.fromkeys(self.adb_includes)) + self.components_ads_includes.extend( list( OrderedDict.fromkeys( ["Task_Types", "Interrupt_Types"] @@ -929,17 +941,11 @@ def load_subassembly(name): ] ) + (self.generic_type_includes) - + (self.includes) ) ) ) - self.ads_includes = list(OrderedDict.fromkeys(self.ads_includes)) - - # Store all includes for the assembly: - self.adb_includes.extend( - [inc for inc in self.adb_includes if inc not in self.ads_includes] - ) - self.adb_includes = list(OrderedDict.fromkeys(self.adb_includes)) + self.components_ads_includes = list(OrderedDict.fromkeys(self.components_ads_includes)) + self.includes = list(OrderedDict.fromkeys(self.includes)) # Now generate all entity ids each component: if not self.shallow_load: diff --git a/gen/templates/assembly/name.adb b/gen/templates/assembly/name.adb index 0338d07d..22c889e9 100644 --- a/gen/templates/assembly/name.adb +++ b/gen/templates/assembly/name.adb @@ -9,10 +9,19 @@ {% for include in adb_includes %} with {{ include }}; {% endfor %} +{% for include in includes %} +{% if include not in adb_includes %} +pragma Warnings (Off, "unit ""{{ include }}"" is not referenced"); +with {{ include }}; +pragma Warnings (On, "unit ""{{ include }}"" is not referenced"); +{% endif %} +{% endfor %} {% endif %} package body {{ name }} is + use {{ name }}_Components; + {% if component_kind_dict["init_base"] %} procedure Init_Base is begin diff --git a/gen/templates/assembly/name.ads b/gen/templates/assembly/name.ads index 0c3beb97..174b6b23 100644 --- a/gen/templates/assembly/name.ads +++ b/gen/templates/assembly/name.ads @@ -4,29 +4,12 @@ -- Generated from {{ filename }} on {{ time }}. -------------------------------------------------------------------------------- -{% if ads_includes %} --- Includes: -pragma Warnings (Off, "with clause might be moved to body"); -{% for include in ads_includes %} -with {{ include }}; -{% endfor %} -pragma Warnings (On, "with clause might be moved to body"); - -{% endif %} -{% if prepreamble %} --- Pre-Preamble code: -{{ printMultiLine(prepreamble, '', 10000) }} -{% endif %} {% if description %} {{ printMultiLine(description, '-- ') }} {% endif %} package {{ name }} is -{% if preamble %} - - -- Preamble code: -{{ printMultiLine(preamble, ' ', 10000) }} -{% endif %} {% if components %} + ----------------------------------- -- Public Subprograms: ----------------------------------- @@ -65,102 +48,5 @@ package {{ name }} is -- component initialization has been completed and tasks have been started. procedure Set_Up_Components; -{% endif %} -{% if components %} - ----------------------------------- - -- Component Instances: - ----------------------------------- - -- Remove some reference style checking to deal with incorrect capitalization in system packages. - pragma Style_Checks ("-rn"); - -{% for component in components.values() %} -{% if component.instance_description %} -{{ printMultiLine(component.instance_description, ' -- ') }} -{% endif %} -{% macro capfirst(text) %}{{ text[0]|upper}}{{text[1:] }}{% endmacro %} -{% if component.generic %} - package {{ capfirst(component.instance_name) }}_Base_Package is new Component.{{ component.name }} ({{ component.generic.resolved_formal_parameter_call_string() }}); - package {{ capfirst(component.instance_name) }}_Package is new {{ capfirst(component.instance_name) }}_Base_Package.Implementation; -{% endif %} - {{ component.instance_name }} : aliased {% if component.generic %}{{ capfirst(component.instance_name) }}_Package{% else %}Component.{{ component.name }}.Implementation{% endif %}.Instance{% if component.discriminant.parameters %} ({{ component.discriminant.parameter_call_string() }}){% endif %}; -{% endfor %} - -{% endif %} - -- Remove some reference style checking to deal with incorrect capitalization in system packages. - pragma Style_Checks ("+rn"); - -{% if task_list %} - ----------------------------------- - -- Task Creation: - ----------------------------------- -{% for task in task_list %} - -- Instantiation of the {{ task.component_name }} component: - {{ task.component_name }}_{{ task.name }}_Task_Info : aliased Task_Types.Task_Info := ( - Number => {{ task.number }}, - Id => Ada.Task_Identification.Null_Task_Id, - -- The following is initialized by the component itself. - Priority => 0, - Stack_Address => System.Null_Address, - Stack_Size => 0, - Secondary_Stack_Address => System.Null_Address, - Secondary_Stack_Size => 0, - Secondary_Stack_Max_Usage => 0 - ); - {{ task.component_name }}_{{ task.name }}_Task_Signal : aliased Ada.Synchronous_Task_Control.Suspension_Object; - {{ task.component_name }}_{{ task.name }}_Task : Component.{% if task.name != "Active" %}{{ task.component_type }}.{% endif %}{{ task.name }}_Task ( - Task_Data => {{ task.component_name }}_{{ task.name }}_Task_Info'Access, - Class_Self => {{ task.component_name }}'Access, - Signal => {{ task.component_name }}_{{ task.name }}_Task_Signal'Access, - Pri => {{ task.priority }}, - Stack_Size => {{ task.stack_size }}, - Secondary_Stack_Size => {{ task.secondary_stack_size }} - ); - -{% endfor %} - -- List of task infos for all tasks: - Task_List : aliased Task_Types.Task_Info_List := [ -{% for task in task_list %} - -- {{ task.component_name }}.{{ task.name }}: - {{ task.number }} => {{ task.component_name }}_{{ task.name }}_Task_Info'Access{{ "," if not loop.last }} -{% endfor %} - ]; - -{% else %} - -- List of task infos for all tasks: - Task_List : aliased Task_Types.Task_Info_List := [1 .. 0 => null]; -- empty - -{% endif %} -{% if interrupt_list %} - -- Remove some reference style checking to deal with incorrect capitalization in system packages. - pragma Style_Checks ("-rn"); - - -- List of all interrupts used in the system: - Interrupt_List : aliased Interrupt_Types.Interrupt_Id_List := [ -{% for interrupt in interrupt_list %} - -- {{ interrupt.component_name }}.{{ interrupt.name }}: - {{ loop.index0 }} => {{ interrupt.id }}{{ "," if not loop.last }} -{% endfor %} - ]; - - -- Remove some reference style checking to deal with incorrect capitalization in system packages. - pragma Style_Checks ("+rn"); - -{% else %} - -- List of all interrupts used in the system: - Interrupt_List : aliased Interrupt_Types.Interrupt_Id_List := [1 .. 0 => 0]; -- empty - -{% endif %} -{% if component_kind_dict["queued"] %} - -- List of all components with positive queue sizes in the system: - Queued_Component_List : aliased Component.Component_List := [ -{% for component in component_kind_dict["queued"] %} - {{ loop.index0 }} => {{ component.instance_name }}'Access{{ "," if not loop.last }} -{% endfor %} - ]; - -{% else %} - -- List of all components with positive queue sizes in the system: - Queued_Component_List : aliased Component.Component_List := [1 .. 0 => null]; -- empty - {% endif %} end {{ name }}; diff --git a/gen/templates/assembly/name_components.ads b/gen/templates/assembly/name_components.ads new file mode 100644 index 00000000..473b65e2 --- /dev/null +++ b/gen/templates/assembly/name_components.ads @@ -0,0 +1,132 @@ +-------------------------------------------------------------------------------- +-- {{ formatType(model_name) }} {{ formatType(model_type) }} Components Spec +-- +-- Generated from {{ filename }} on {{ time }}. +-------------------------------------------------------------------------------- + +{% if components_ads_includes %} +-- Includes: +{% for include in components_ads_includes %} +with {{ include }}; +{% endfor %} +{% for include in includes %} +{% if include not in components_ads_includes %} +pragma Warnings (Off, "unit ""{{ include }}"" is not referenced"); +with {{ include }}; +pragma Warnings (On, "unit ""{{ include }}"" is not referenced"); +{% endif %} +{% endfor %} + +{% endif %} +{% if prepreamble %} +-- Pre-Preamble code: +{{ printMultiLine(prepreamble, '', 10000) }} +{% endif %} +{% if description %} +{{ printMultiLine(description, '-- ') }} +{% endif %} +package {{ name }}_Components is +{% if preamble %} + + -- Preamble code: +{{ printMultiLine(preamble, ' ', 10000) }} +{% endif %} +{% if components %} + + ----------------------------------- + -- Component Instances: + ----------------------------------- + -- Remove some reference style checking to deal with incorrect capitalization in system packages. + pragma Style_Checks ("-rn"); + +{% for component in components.values() %} +{% if component.instance_description %} +{{ printMultiLine(component.instance_description, ' -- ') }} +{% endif %} +{% macro capfirst(text) %}{{ text[0]|upper}}{{text[1:] }}{% endmacro %} +{% if component.generic %} + package {{ capfirst(component.instance_name) }}_Base_Package is new Component.{{ component.name }} ({{ component.generic.resolved_formal_parameter_call_string() }}); + package {{ capfirst(component.instance_name) }}_Package is new {{ capfirst(component.instance_name) }}_Base_Package.Implementation; +{% endif %} + {{ component.instance_name }} : aliased {% if component.generic %}{{ capfirst(component.instance_name) }}_Package{% else %}Component.{{ component.name }}.Implementation{% endif %}.Instance{% if component.discriminant.parameters %} ({{ component.discriminant.parameter_call_string() }}){% endif %}; +{% endfor %} + +{% endif %} + -- Remove some reference style checking to deal with incorrect capitalization in system packages. + pragma Style_Checks ("+rn"); + +{% if task_list %} + ----------------------------------- + -- Task Creation: + ----------------------------------- +{% for task in task_list %} + -- Instantiation of the {{ task.component_name }} component: + {{ task.component_name }}_{{ task.name }}_Task_Info : aliased Task_Types.Task_Info := ( + Number => {{ task.number }}, + Id => Ada.Task_Identification.Null_Task_Id, + -- The following is initialized by the component itself. + Priority => 0, + Stack_Address => System.Null_Address, + Stack_Size => 0, + Secondary_Stack_Address => System.Null_Address, + Secondary_Stack_Size => 0, + Secondary_Stack_Max_Usage => 0 + ); + {{ task.component_name }}_{{ task.name }}_Task_Signal : aliased Ada.Synchronous_Task_Control.Suspension_Object; + {{ task.component_name }}_{{ task.name }}_Task : Component.{% if task.name != "Active" %}{{ task.component_type }}.{% endif %}{{ task.name }}_Task ( + Task_Data => {{ task.component_name }}_{{ task.name }}_Task_Info'Access, + Class_Self => {{ task.component_name }}'Access, + Signal => {{ task.component_name }}_{{ task.name }}_Task_Signal'Access, + Pri => {{ task.priority }}, + Stack_Size => {{ task.stack_size }}, + Secondary_Stack_Size => {{ task.secondary_stack_size }} + ); + +{% endfor %} + -- List of task infos for all tasks: + Task_List : aliased Task_Types.Task_Info_List := [ +{% for task in task_list %} + -- {{ task.component_name }}.{{ task.name }}: + {{ task.number }} => {{ task.component_name }}_{{ task.name }}_Task_Info'Access{{ "," if not loop.last }} +{% endfor %} + ]; + +{% else %} + -- List of task infos for all tasks: + Task_List : aliased Task_Types.Task_Info_List := [1 .. 0 => null]; -- empty + +{% endif %} +{% if interrupt_list %} + -- Remove some reference style checking to deal with incorrect capitalization in system packages. + pragma Style_Checks ("-rn"); + + -- List of all interrupts used in the system: + Interrupt_List : aliased Interrupt_Types.Interrupt_Id_List := [ +{% for interrupt in interrupt_list %} + -- {{ interrupt.component_name }}.{{ interrupt.name }}: + {{ loop.index0 }} => {{ interrupt.id }}{{ "," if not loop.last }} +{% endfor %} + ]; + + -- Remove some reference style checking to deal with incorrect capitalization in system packages. + pragma Style_Checks ("+rn"); + +{% else %} + -- List of all interrupts used in the system: + Interrupt_List : aliased Interrupt_Types.Interrupt_Id_List := [1 .. 0 => 0]; -- empty + +{% endif %} +{% if component_kind_dict["queued"] %} + -- List of all components with positive queue sizes in the system: + Queued_Component_List : aliased Component.Component_List := [ +{% for component in component_kind_dict["queued"] %} + {{ loop.index0 }} => {{ component.instance_name }}'Access{{ "," if not loop.last }} +{% endfor %} + ]; + +{% else %} + -- List of all components with positive queue sizes in the system: + Queued_Component_List : aliased Component.Component_List := [1 .. 0 => null]; -- empty + +{% endif %} +end {{ name }}_Components; From a420b1d392bc2f668f039040309805eee4f104c5 Mon Sep 17 00:00:00 2001 From: Kevin Dinkel <1225857+dinkelk@users.noreply.github.com> Date: Tue, 19 Nov 2024 13:28:36 -0700 Subject: [PATCH 3/3] Add adb-specific `with` suport in assembly model --- gen/models/assembly.py | 2 ++ gen/schemas/assembly.yaml | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/gen/models/assembly.py b/gen/models/assembly.py index de55b0ac..553b4fcb 100644 --- a/gen/models/assembly.py +++ b/gen/models/assembly.py @@ -388,6 +388,8 @@ def load(self): # file: if "with" in self.data and self.data["with"]: self.includes = list(self.data["with"]) + if "with_adb" in self.data and self.data["with_adb"]: + self.adb_includes = list(self.data["with_adb"]) for include in self.includes: include = ada.formatType(include) if "preamble" in self.data: diff --git a/gen/schemas/assembly.yaml b/gen/schemas/assembly.yaml index b040551c..42021246 100644 --- a/gen/schemas/assembly.yaml +++ b/gen/schemas/assembly.yaml @@ -13,6 +13,11 @@ mapping: seq: - type: str required: False + # Manual "with" statements that should only appear in the .adb generation + with_adb: + seq: + - type: str + required: False # Any useful handcode to include in the .ads file can be included here. # You can think of this as inline Ada, which might be useful for declaring # custom enum types and the like. The code here is copied immediately