Skip to content

Commit

Permalink
Split components declaration into its own package
Browse files Browse the repository at this point in the history
This provides a dedicated package to store assembly component
declaration, which also includes tasks and interrupt declaration. The
name of this file is <assembly>_components.ads.

By removing these from the overall autocoded <assembly>.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 <assembly>_components.ads file, removing
its dependency on the entire assembly .ads, and thus removing the
circular dependency.
  • Loading branch information
dinkelk committed Nov 19, 2024
1 parent 88e847d commit a7ee9d1
Show file tree
Hide file tree
Showing 5 changed files with 159 additions and 122 deletions.
1 change: 1 addition & 0 deletions gen/generators/assembly.py
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
23 changes: 16 additions & 7 deletions gen/models/assembly.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 = (
Expand Down Expand Up @@ -908,7 +909,15 @@ 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"]
)
)
)
self.adb_includes = list(OrderedDict.fromkeys(self.adb_includes))
self.components_ads_includes.extend(
list(
OrderedDict.fromkeys(
["Task_Types", "Interrupt_Types"]
Expand All @@ -929,17 +938,17 @@ def load_subassembly(name):
]
)
+ (self.generic_type_includes)
+ (self.includes)
)
)
)
self.ads_includes = list(OrderedDict.fromkeys(self.ads_includes))
self.components_ads_includes = list(OrderedDict.fromkeys(self.components_ads_includes))
self.includes = list(OrderedDict.fromkeys(self.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.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))

# Now generate all entity ids each component:
if not self.shallow_load:
Expand Down
9 changes: 9 additions & 0 deletions gen/templates/assembly/name.adb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
116 changes: 1 addition & 115 deletions gen/templates/assembly/name.ads
Original file line number Diff line number Diff line change
Expand Up @@ -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:
-----------------------------------
Expand Down Expand Up @@ -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 }};
132 changes: 132 additions & 0 deletions gen/templates/assembly/name_components.ads
Original file line number Diff line number Diff line change
@@ -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;

0 comments on commit a7ee9d1

Please sign in to comment.