From 0bc780f8a2fcebc543c527a8db09571a538d4def Mon Sep 17 00:00:00 2001 From: gusthoff Date: Mon, 6 Jan 2025 10:27:43 +0100 Subject: [PATCH 01/26] Editorial change: remove todo item --- .../parts/data_types/shared_variable_control.rst | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst b/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst index 9938fdb46..e79694f1d 100644 --- a/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst +++ b/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst @@ -469,21 +469,6 @@ these array declarations are equivalent: end Shared_Var_Types; -.. - TO BE DONE: - - :ada:`Full_Access_Only` - ----------------------- - - .. admonition:: Relevant topics - - - :arm22:`The Package System.Atomic_Operations ` - - .. todo:: - - - **Briefly** discuss :ada:`Full_Access_Only` - - Add to previous section! - .. TO BE DONE: From a61eecabe85639d90875a7bc9750678e8c748396 Mon Sep 17 00:00:00 2001 From: gusthoff Date: Mon, 6 Jan 2025 10:30:15 +0100 Subject: [PATCH 02/26] Editorial change: adding anchor --- .../advanced-ada/parts/data_types/shared_variable_control.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst b/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst index e79694f1d..ecae03dac 100644 --- a/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst +++ b/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst @@ -11,6 +11,8 @@ start by discussing volatile objects. - :arm22:`C.6 Shared Variable Control ` +.. _Adv_Ada_Shared_Variable_Control_Volatile: + Volatile -------- @@ -127,6 +129,8 @@ makes sense in the context, of course. In the example above, even though array , it's automatically set as well. +.. _Adv_Ada_Shared_Variable_Control_Independent: + Independent ----------- From 81c774fbf82c2f6fbe5def073ee373d475fc03a8 Mon Sep 17 00:00:00 2001 From: gusthoff Date: Sun, 24 Nov 2024 22:52:43 +0100 Subject: [PATCH 03/26] Editorial change: adding anchor --- content/courses/advanced-ada/parts/data_types/aggregates.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/content/courses/advanced-ada/parts/data_types/aggregates.rst b/content/courses/advanced-ada/parts/data_types/aggregates.rst index e3be74b58..cfd42ba7a 100644 --- a/content/courses/advanced-ada/parts/data_types/aggregates.rst +++ b/content/courses/advanced-ada/parts/data_types/aggregates.rst @@ -1956,6 +1956,8 @@ appropriate view, we're able to initialize an object of ascending type descendent type (:ada:`Point_3D`), which contains more components. +.. _Adv_Ada_Delta_Aggregates: + Delta Aggregates ---------------- From 865e629791332a9bd999d5992864ce67d67856da Mon Sep 17 00:00:00 2001 From: gusthoff Date: Mon, 6 Jan 2025 10:34:15 +0100 Subject: [PATCH 04/26] Adding subsection on Full_Access_Only aspect --- .../data_types/shared_variable_control.rst | 240 ++++++++++++++++++ 1 file changed, 240 insertions(+) diff --git a/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst b/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst index ecae03dac..93954c3fe 100644 --- a/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst +++ b/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst @@ -473,6 +473,246 @@ these array declarations are equivalent: end Shared_Var_Types; +.. _Adv_Ada_Shared_Variable_Control_Full_Access_Only: + +Full access only +---------------- + +.. note:: + + This feature was introduced in Ada 2022. + +A full access object is an object that requires that read or write operations +on this object are performed by reading or writing all bits of the object (i.e. +the *full object*) at once. Accordingly, a full access type is a type whose +objects follow this requirement. Note that a full access type must be +simultaneously a +:ref:`volatile type ` or an +:ref:`atomic type `. (In other words, +if a type isn't volatile or atomic, it cannot be a full access type.) + +Let's see some examples: + +.. code:: ada compile_button project=Courses.Advanced_Ada.Data_Types.Type_Representation.Shared_Variable_Control.Full_Access_Only_Types + + pragma Ada_2022; + + package Show_Full_Access_Only_Types is + + type Nonatomic_Full_Access_Type is + new Long_Float + with Volatile, Full_Access_Only; + + type Atomic_Full_Access_Type is + new Long_Float + with Atomic, Full_Access_Only; + + end Show_Full_Access_Only_Types; + +Likewise, we can define nonatomic and atomic full-access objects: + +.. code:: ada compile_button project=Courses.Advanced_Ada.Data_Types.Type_Representation.Shared_Variable_Control.Full_Access_Only_Objects + + pragma Ada_2022; + + package Show_Full_Access_Only_Objects is + + Nonatomic_Full_Access_Obj : Long_Float + with Volatile, Full_Access_Only; + + Atomic_Full_Access_Obj : Long_Float + with Atomic, Full_Access_Only; + + end Show_Full_Access_Only_Objects; + + +.. admonition:: Relevant topics + + - :arm22:`9.10 Shared Variables <9-10>` + - :arm22:`C.6 Shared Variable Control ` + + +Nonatomic full-access +~~~~~~~~~~~~~~~~~~~~~ + +As we already know, the value of a volatile object may be constantly changing, +so the compiler generates code in such a way that the process must read the +value of the volatile object from memory for each access. (In other words, the +value cannot be stored in a register for further processing.) + +In the case of nonatomic full-access objects, the value of the object must not +only be read from memory or updated to memory every time, but those operations +must also be performed for the complete object at once. + +For example: + +.. code:: ada run_button project=Courses.Advanced_Ada.Data_Types.Type_Representation.Shared_Variable_Control.Alarms_Nonatomic_Full_Access + + pragma Ada_2022; + + package Alarms is + + type Day is (Mon, Tue, Wed, + Thu, Fri, + Sat, Sun); + + type Enabled is new Boolean + with Size => 1; + + type Hours is range 0 .. 23 + with Size => 5; + + type Minutes is range 0 .. 59 + with Size => 6; + + type Day_Enabled is + array (Day) of Enabled + with Pack; + + type Alarm is record + Days : Day_Enabled; + Hour : Hours; + Minute : Minutes; + end record + with + Volatile, + Size => 24; + + for Alarm use record + Days at 0 range 0 .. 6; + Hour at 0 range 8 .. 12; + Minute at 0 range 16 .. 21; + end record; + + end Alarms; + + pragma Ada_2022; + + with Alarms; use Alarms; + + procedure Show_Alarm is + + A : Alarm; + + begin + -- Initializing the alarm + A := (Days => (others => False), + Hour => 8, + Minute => 0); + + -- Activating alarm on + -- Monday and Wednesday + A.Days (Mon) := True; + A.Days (Wed) := True; + end Show_Alarm; + +In this example, we have a very simple alarm system specified in the +:ada:`Alarms` package. We can set the alarm to ring at the same time on +specific days. In the :ada:`Show_Alarm` procedure, we set the alarm to just +ring on Mondays and Wednesdays. + +The compiler may generate multiple operations for the update of the +:ada:`A.Days (Mon)` and :ada:`A.Days (Wed)` components. If we use +:ada:`Full_Access_Only` aspect, we may combine those updates in a single +operation |mdash| in addition, we have to use a +:ref:`delta aggregate `. + +Note that we haven't discussed the topic of delta aggregates yet: we'll do that +:ref:`later on in this course `. However, in simple +terms, we can use them to modify specific components of a record without +changing the remaining components of the record. + +Let's update the previous example: + +.. code:: ada run_button project=Courses.Advanced_Ada.Data_Types.Type_Representation.Shared_Variable_Control.Alarms_Nonatomic_Full_Access + + + pragma Ada_2022; + + with Alarms; use Alarms; + + procedure Show_Alarm is + + A : Alarm + with Full_Access_Only; + + begin + -- Initializing the alarm + A := (Days => (others => False), + Hour => 8, + Minute => 0); + + -- Activating alarm on + -- Monday and Wednesday + A.Days := (A.Days + with delta Mon | + Wed => True); + end Show_Alarm; + +Now, by assigning the delta aggregate to a full-access object, we ensure that +the complete :ada:`A` object is updated at once. + + +Atomic full-access +~~~~~~~~~~~~~~~~~~ + +As we already know, +:ref:`atomic objects ` only accept +atomic reads and updates, which |mdash| as a whole |mdash| are indivisible, +i.e. they must be done in a single instruction, so that no other instruction +could execute on that same object before the read or update completes. + +In the case of atomic full-access objects, the complete object must be read and +updated at once. Ideally, this operation corresponds to a single atomic +operation on the target machine, but it can also translate to multiple atomic +operations. + +Let's see a simplified version of the previous example to illustrate this: + +.. code:: ada run_button project=Courses.Advanced_Ada.Data_Types.Type_Representation.Shared_Variable_Control.Alarms_Atomic_Full_Access + + pragma Ada_2022; + + package Alarms is + + type Day is (Mon, Tue, Wed, + Thu, Fri, + Sat, Sun); + + type Enabled is new Boolean + with Size => 1; + + type Day_Enabled is + array (Day) of Enabled + with Pack; + + end Alarms; + + pragma Ada_2022; + + with Alarms; use Alarms; + + procedure Show_Alarm is + + D : Day_Enabled + with Atomic, Full_Access_Only; + + begin + -- Initializing the alarm + D := (others => False); + + -- Activating alarm on + -- Monday and Wednesday + D := (D with delta Mon | Wed => True); + end Show_Alarm; + +In the :ada:`Show_Alarm` procedure, we again activate the alarm to ring on +Mondays and Wednesdays by assigning a delta aggregate to :ada:`D`. This +assignment is performed at once because :ada:`D` is an atomic full-access +object. Note, however, that if multiple atomic operations are needed, those +will be sequential for this object. + + .. TO BE DONE: From f9318e4910bc7b82b325f5184660c83ed510a661 Mon Sep 17 00:00:00 2001 From: gusthoff Date: Sat, 11 Jan 2025 03:25:47 +0100 Subject: [PATCH 05/26] Minor corrections and improvements --- .../parts/data_types/shared_variable_control.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst b/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst index 93954c3fe..362776957 100644 --- a/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst +++ b/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst @@ -489,7 +489,7 @@ objects follow this requirement. Note that a full access type must be simultaneously a :ref:`volatile type ` or an :ref:`atomic type `. (In other words, -if a type isn't volatile or atomic, it cannot be a full access type.) +if a type is neither volatile nor atomic, it cannot be a full access type.) Let's see some examples: @@ -542,7 +542,8 @@ value cannot be stored in a register for further processing.) In the case of nonatomic full-access objects, the value of the object must not only be read from memory or updated to memory every time, but those operations -must also be performed for the complete object at once. +must also be performed for the complete record object |mdash| not just parts of +it. For example: From e746a79f64a2c78e47d94c97f8c1ebcd9c7c805a Mon Sep 17 00:00:00 2001 From: gusthoff Date: Sat, 11 Jan 2025 03:25:59 +0100 Subject: [PATCH 06/26] Editorial change: adding anchor --- .../advanced-ada/parts/data_types/shared_variable_control.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst b/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst index 362776957..7baf2ba0c 100644 --- a/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst +++ b/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst @@ -532,6 +532,8 @@ Likewise, we can define nonatomic and atomic full-access objects: - :arm22:`C.6 Shared Variable Control ` +.. _Adv_Ada_Shared_Variable_Control_Non_Atomic_Full_Access: + Nonatomic full-access ~~~~~~~~~~~~~~~~~~~~~ From bef0c1c062e9efcf82f0ce4680aecaedf8bb0c97 Mon Sep 17 00:00:00 2001 From: gusthoff Date: Sat, 11 Jan 2025 03:41:01 +0100 Subject: [PATCH 07/26] Replacing code examples Parts of the code examples are inspired by the Ada Drivers Library (https://github.com/AdaCore Ada_Drivers_Library). --- .../data_types/shared_variable_control.rst | 267 ++++++++++++------ 1 file changed, 184 insertions(+), 83 deletions(-) diff --git a/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst b/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst index 7baf2ba0c..b21715d9c 100644 --- a/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst +++ b/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst @@ -549,65 +549,116 @@ it. For example: -.. code:: ada run_button project=Courses.Advanced_Ada.Data_Types.Type_Representation.Shared_Variable_Control.Alarms_Nonatomic_Full_Access +.. code:: ada compile_button project=Courses.Advanced_Ada.Data_Types.Type_Representation.Shared_Variable_Control.Nonatomic_Full_Access_Register pragma Ada_2022; - package Alarms is + with System; + + package Registers is - type Day is (Mon, Tue, Wed, - Thu, Fri, - Sat, Sun); + type Boolean_Bit is new Boolean + with Size => 1; - type Enabled is new Boolean + type UInt1 is mod 2**1 with Size => 1; - type Hours is range 0 .. 23 - with Size => 5; + type UInt2 is mod 2**2 + with Size => 2; + + type UInt14 is mod 2**14 + with Size => 14; - type Minutes is range 0 .. 59 - with Size => 6; + type Window_Register is record + -- horizontal line count + Horizontal_Cnt : UInt14 := 16#0#; - type Day_Enabled is - array (Day) of Enabled - with Pack; + -- unspecified + Reserved_14_15 : UInt2 := 16#0#; - type Alarm is record - Days : Day_Enabled; - Hour : Hours; - Minute : Minutes; + -- vertical line count + Vertical_Cnt : UInt14 := 16#0#; + + -- refresh signalling + Refresh_Needed : Boolean_Bit := False; + + -- unspecified + Reserved_30 : UInt1 := 16#0#; end record - with - Volatile, - Size => 24; - - for Alarm use record - Days at 0 range 0 .. 6; - Hour at 0 range 8 .. 12; - Minute at 0 range 16 .. 21; - end record; + with Size => 32, + Bit_Order => System.Low_Order_First, + Volatile, + Full_Access_Only; + + for Window_Register use record + Horizontal_Cnt at 0 range 0 .. 13; + Reserved_14_15 at 0 range 14 .. 15; + Vertical_Cnt at 0 range 16 .. 29; + Refresh_Needed at 0 range 30 .. 30; + Reserved_30 at 0 range 31 .. 31; + end record; + + procedure Show (WR : Window_Register); + + end Registers; + + with Ada.Text_IO; use Ada.Text_IO; - end Alarms; + package body Registers is + + procedure Show (WR : Window_Register) is + begin + Put_Line ("WR = (Horizontal_Cnt => " + & WR.Horizontal_Cnt'Image + & ","); + Put_Line (" Vertical_Cnt => " + & WR.Vertical_Cnt'Image + & ","); + Put_Line (" Refresh_Needed => " + & WR.Refresh_Needed'Image + & ")"); + end Show; + + end Registers; + + +.. code:: ada run_button project=Courses.Advanced_Ada.Data_Types.Type_Representation.Shared_Variable_Control.Nonatomic_Full_Access_Register pragma Ada_2022; - with Alarms; use Alarms; + with Registers; use Registers; + + procedure Show_Register is + WR : Window_Register; + begin + -- Nonatomic full-access assignments + WR.Horizontal_Cnt := 800; + WR.Vertical_Cnt := 600; + WR.Refresh_Needed := True; + + Show (WR); + end Show_Register; + + - procedure Show_Alarm is +.. code:: ada run_button project=Courses.Advanced_Ada.Data_Types.Type_Representation.Shared_Variable_Control.Nonatomic_Full_Access_Register - A : Alarm; + with Ada.Text_IO; use Ada.Text_IO; + + with Registers; use Registers; + procedure Show_Register is + WR : Window_Register; begin - -- Initializing the alarm - A := (Days => (others => False), - Hour => 8, - Minute => 0); + -- Nonatomic full-access assignment + -- using an aggregate: + WR := (Horizontal_Cnt => 800, + Vertical_Cnt => 600, + Refresh_Needed => True, + others => <>); - -- Activating alarm on - -- Monday and Wednesday - A.Days (Mon) := True; - A.Days (Wed) := True; - end Show_Alarm; + Show (WR); + end Show_Register; In this example, we have a very simple alarm system specified in the :ada:`Alarms` package. We can set the alarm to ring at the same time on @@ -625,32 +676,25 @@ Note that we haven't discussed the topic of delta aggregates yet: we'll do that terms, we can use them to modify specific components of a record without changing the remaining components of the record. -Let's update the previous example: - -.. code:: ada run_button project=Courses.Advanced_Ada.Data_Types.Type_Representation.Shared_Variable_Control.Alarms_Nonatomic_Full_Access +.. code:: ada run_button project=Courses.Advanced_Ada.Data_Types.Type_Representation.Shared_Variable_Control.Nonatomic_Full_Access_Register + with Ada.Text_IO; use Ada.Text_IO; - pragma Ada_2022; - - with Alarms; use Alarms; - - procedure Show_Alarm is - - A : Alarm - with Full_Access_Only; + with Registers; use Registers; + procedure Show_Registers is + WR : Window_Register := + (Horizontal_Cnt => 800, + Vertical_Cnt => 600, + others => <>); begin - -- Initializing the alarm - A := (Days => (others => False), - Hour => 8, - Minute => 0); - - -- Activating alarm on - -- Monday and Wednesday - A.Days := (A.Days - with delta Mon | - Wed => True); - end Show_Alarm; + -- Delta assignment + WR := (WR with delta + Vertical_Cnt => 800, + Refresh_Needed => True); + + Show (WR); + end Show_Registers; Now, by assigning the delta aggregate to a full-access object, we ensure that the complete :ada:`A` object is updated at once. @@ -672,42 +716,99 @@ operations. Let's see a simplified version of the previous example to illustrate this: -.. code:: ada run_button project=Courses.Advanced_Ada.Data_Types.Type_Representation.Shared_Variable_Control.Alarms_Atomic_Full_Access +.. code:: ada compile_button project=Courses.Advanced_Ada.Data_Types.Type_Representation.Shared_Variable_Control.Atomic_Full_Access_Register pragma Ada_2022; - package Alarms is + with System; - type Day is (Mon, Tue, Wed, - Thu, Fri, - Sat, Sun); + package Registers is - type Enabled is new Boolean + type Boolean_Bit is new Boolean with Size => 1; - type Day_Enabled is - array (Day) of Enabled - with Pack; + type UInt1 is mod 2**1 + with Size => 1; - end Alarms; + type UInt2 is mod 2**2 + with Size => 2; - pragma Ada_2022; + type UInt14 is mod 2**14 + with Size => 14; - with Alarms; use Alarms; + type Window_Register is record + -- horizontal line count + Horizontal_Cnt : UInt14 := 16#0#; - procedure Show_Alarm is + -- unspecified + Reserved_14_15 : UInt2 := 16#0#; - D : Day_Enabled - with Atomic, Full_Access_Only; + -- vertical line count + Vertical_Cnt : UInt14 := 16#0#; - begin - -- Initializing the alarm - D := (others => False); + -- refresh signalling + Refresh_Needed : Boolean_Bit := False; + + -- unspecified + Reserved_30 : UInt1 := 16#0#; + end record + with Size => 32, + Bit_Order => System.Low_Order_First, + Volatile, + Full_Access_Only; - -- Activating alarm on - -- Monday and Wednesday - D := (D with delta Mon | Wed => True); - end Show_Alarm; + for Window_Register use record + Horizontal_Cnt at 0 range 0 .. 13; + Reserved_14_15 at 0 range 14 .. 15; + Vertical_Cnt at 0 range 16 .. 29; + Refresh_Needed at 0 range 30 .. 30; + Reserved_30 at 0 range 31 .. 31; + end record; + + procedure Show (WR : Window_Register); + + end Registers; + + with Ada.Text_IO; use Ada.Text_IO; + + package body Registers is + + procedure Show (WR : Window_Register) is + begin + Put_Line ("WR = (Horizontal_Cnt => " + & WR.Horizontal_Cnt'Image + & ","); + Put_Line (" Vertical_Cnt => " + & WR.Vertical_Cnt'Image + & ","); + Put_Line (" Refresh_Needed => " + & WR.Refresh_Needed'Image + & ")"); + end Show; + + end Registers; + +We then use the package in our test application: + +.. code:: ada run_button project=Courses.Advanced_Ada.Data_Types.Type_Representation.Shared_Variable_Control.Atomic_Full_Access_Register + + with Registers; use Registers; + + procedure Show_Register is + WR : Window_Register := + (Horizontal_Cnt => 800, + Vertical_Cnt => 600, + Refresh_Needed => True, + others => <>); + begin + WR := (Horizontal_Cnt => + WR.Horizontal_Cnt * 2, + Vertical_Cnt => + Wr.Vertical_Cnt * 2, + others => <>); + + Show (WR); + end Show_Register; In the :ada:`Show_Alarm` procedure, we again activate the alarm to ring on Mondays and Wednesdays by assigning a delta aggregate to :ada:`D`. This From 8a62997fd15f7969ff36ad6e8a5b5e7861ba460b Mon Sep 17 00:00:00 2001 From: gusthoff Date: Sat, 11 Jan 2025 03:50:54 +0100 Subject: [PATCH 08/26] Adapting description of code example --- .../data_types/shared_variable_control.rst | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst b/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst index b21715d9c..b0b54ad65 100644 --- a/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst +++ b/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst @@ -660,15 +660,7 @@ For example: Show (WR); end Show_Register; -In this example, we have a very simple alarm system specified in the -:ada:`Alarms` package. We can set the alarm to ring at the same time on -specific days. In the :ada:`Show_Alarm` procedure, we set the alarm to just -ring on Mondays and Wednesdays. - -The compiler may generate multiple operations for the update of the -:ada:`A.Days (Mon)` and :ada:`A.Days (Wed)` components. If we use -:ada:`Full_Access_Only` aspect, we may combine those updates in a single -operation |mdash| in addition, we have to use a +In addition, we have to use a :ref:`delta aggregate `. Note that we haven't discussed the topic of delta aggregates yet: we'll do that @@ -810,11 +802,10 @@ We then use the package in our test application: Show (WR); end Show_Register; -In the :ada:`Show_Alarm` procedure, we again activate the alarm to ring on -Mondays and Wednesdays by assigning a delta aggregate to :ada:`D`. This -assignment is performed at once because :ada:`D` is an atomic full-access -object. Note, however, that if multiple atomic operations are needed, those -will be sequential for this object. +In this example, we first have an atomic initialization of :ada:`WR` using an +aggregate. Then, we have an atomic assignment to the atomic full-access object +:ada:`WR`. Because its type is an atomic full-access type, the operations are +atomic operations that always access the full object from and to memory. .. From 9047c648ef6fee14b00642326e641b7f64949c74 Mon Sep 17 00:00:00 2001 From: gusthoff Date: Sat, 11 Jan 2025 03:58:36 +0100 Subject: [PATCH 09/26] Minor change: adapting explanation --- .../advanced-ada/parts/data_types/shared_variable_control.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst b/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst index b0b54ad65..d9fa20725 100644 --- a/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst +++ b/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst @@ -660,7 +660,8 @@ For example: Show (WR); end Show_Register; -In addition, we have to use a +If we want to just change two components, but leave the information of other +components untouched, we can use a :ref:`delta aggregate `. Note that we haven't discussed the topic of delta aggregates yet: we'll do that From c70f4f521c49e626cbfaa464f9e88854bb5e5434 Mon Sep 17 00:00:00 2001 From: gusthoff Date: Sat, 11 Jan 2025 03:59:28 +0100 Subject: [PATCH 10/26] Minor editorial change --- .../parts/data_types/shared_variable_control.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst b/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst index d9fa20725..6ab8a32ec 100644 --- a/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst +++ b/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst @@ -663,11 +663,11 @@ For example: If we want to just change two components, but leave the information of other components untouched, we can use a :ref:`delta aggregate `. +(Note that we haven't discussed the topic of delta aggregates yet: we'll do +that :ref:`later on in this course `. However, in +simple terms, we can use them to modify specific components of a record without +changing the remaining components of the record.) -Note that we haven't discussed the topic of delta aggregates yet: we'll do that -:ref:`later on in this course `. However, in simple -terms, we can use them to modify specific components of a record without -changing the remaining components of the record. .. code:: ada run_button project=Courses.Advanced_Ada.Data_Types.Type_Representation.Shared_Variable_Control.Nonatomic_Full_Access_Register From 10a332f171c8a9af53e22a2cb348922bf5cbcadf Mon Sep 17 00:00:00 2001 From: gusthoff Date: Sat, 11 Jan 2025 04:00:06 +0100 Subject: [PATCH 11/26] Minor suggested change --- .../advanced-ada/parts/data_types/shared_variable_control.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst b/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst index 6ab8a32ec..b10ee96f2 100644 --- a/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst +++ b/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst @@ -703,7 +703,7 @@ i.e. they must be done in a single instruction, so that no other instruction could execute on that same object before the read or update completes. In the case of atomic full-access objects, the complete object must be read and -updated at once. Ideally, this operation corresponds to a single atomic +updated. Ideally, this operation corresponds to a single atomic operation on the target machine, but it can also translate to multiple atomic operations. From bda8dabe01c4dffeac97f7bf1ebcc448db47b124 Mon Sep 17 00:00:00 2001 From: gusthoff Date: Sat, 11 Jan 2025 04:02:58 +0100 Subject: [PATCH 12/26] Adding and adapting explanations about new code examples --- .../data_types/shared_variable_control.rst | 30 +++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst b/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst index b10ee96f2..83282b6d4 100644 --- a/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst +++ b/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst @@ -621,6 +621,8 @@ For example: end Registers; +Let's use the :ada:`Window_Register` type from the :ada:`Registers` package in +a test application: .. code:: ada run_button project=Courses.Advanced_Ada.Data_Types.Type_Representation.Shared_Variable_Control.Nonatomic_Full_Access_Register @@ -639,7 +641,20 @@ For example: Show (WR); end Show_Register; +The example contains assignments such as :ada:`WR.Horizontal_Cnt := 800` and +:ada:`WR.Vertical_Cnt:= 600`. Because :ada:`Window_Register` is a full-access +type, these assignments are performed for the complete 32-bit register, even +though we're updating just a single component of the record object. (Note that +if :ada:`Window_Register` wasn't a *full-access* object, an assignment such as +:ada:`WR.Horizontal_Cnt := 800` could be performed with a 16-bit operation.) +Whenever possible, this *full-access* assignment is performed in a single +machine operation. However, if it's not possible to generate a single machine +operation on the target machine, the compiler may generate multiple operations +for the update of the record components. + +Note that we could combine these two assignments into a single one using an +aggregate: .. code:: ada run_button project=Courses.Advanced_Ada.Data_Types.Type_Representation.Shared_Variable_Control.Nonatomic_Full_Access_Register @@ -660,6 +675,10 @@ For example: Show (WR); end Show_Register; +Again, this assignment is performed for the complete 32-bit register |mdash| +ideally, using a single 32-bit machine operation |mdash| by reading the value +from the memory. + If we want to just change two components, but leave the information of other components untouched, we can use a :ref:`delta aggregate `. @@ -668,6 +687,8 @@ that :ref:`later on in this course `. However, in simple terms, we can use them to modify specific components of a record without changing the remaining components of the record.) +For example, we might want to update just the vertical count and indicate that +update via the :ada:`Refresh_Needed` flag, but keep the same horizontal count: .. code:: ada run_button project=Courses.Advanced_Ada.Data_Types.Type_Representation.Shared_Variable_Control.Nonatomic_Full_Access_Register @@ -689,8 +710,13 @@ changing the remaining components of the record.) Show (WR); end Show_Registers; -Now, by assigning the delta aggregate to a full-access object, we ensure that -the complete :ada:`A` object is updated at once. +A delta assignment using an aggregate such as :ada:`(WR with delta ...)` +includes reading the value of complete 32-bit :ada:`WR` object from memory, +changing the components specified after :ada:`with delta`, and writing the +complete 32-bit :ada:`WR` object back to memory. The reason is that we need to +retrieve the information that is supposed to remain intact |mdash| the +:ada:`Horizontal_Cnt` and the reserved components |mdash| in order to write +them back as a *full-access* operation. Atomic full-access From cc285c7447dab6a31c9ebce5b427273b01cbd93c Mon Sep 17 00:00:00 2001 From: gusthoff Date: Sat, 11 Jan 2025 04:03:27 +0100 Subject: [PATCH 13/26] Adding Graphviz diagram --- .../parts/data_types/shared_variable_control.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst b/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst index 83282b6d4..c5904eca6 100644 --- a/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst +++ b/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst @@ -621,6 +621,18 @@ For example: end Registers; +In this example, we have a 32-bit register (of :ada:`Window_Register` type) +that contains window information for a display: + +.. graphviz:: + + digraph foo { + "Record_R" [ + label = "{ position | bits | component } | { 0 | { { #0 .. 13 | Horizontal_Cnt } | { #14 .. #15 | Reserved_14_15 } | { #16 .. #29 | Vertical_Cnt } | { #30 .. #31 | Reserved_30_31 } } }" + shape = "record" + ]; + } + Let's use the :ada:`Window_Register` type from the :ada:`Registers` package in a test application: From a5d5aae4c881c2de9f86f5629fa5336d90f79974 Mon Sep 17 00:00:00 2001 From: gusthoff Date: Sat, 11 Jan 2025 04:03:41 +0100 Subject: [PATCH 14/26] Adding code example --- .../data_types/shared_variable_control.rst | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst b/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst index c5904eca6..d8fc8dc44 100644 --- a/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst +++ b/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst @@ -691,6 +691,35 @@ Again, this assignment is performed for the complete 32-bit register |mdash| ideally, using a single 32-bit machine operation |mdash| by reading the value from the memory. +Let's add another statement to the code example: + +.. code:: ada run_button project=Courses.Advanced_Ada.Data_Types.Type_Representation.Shared_Variable_Control.Nonatomic_Full_Access_Register + + pragma Ada_2022; + + with Registers; use Registers; + + procedure Show_Register is + WR : Window_Register := + (Horizontal_Cnt => 800, + Vertical_Cnt => 600, + Refresh_Needed => True, + others => <>); + begin + WR := (Horizontal_Cnt => + WR.Horizontal_Cnt * 2, + Vertical_Cnt => + Wr.Vertical_Cnt * 2, + others => <>); + + Show (WR); + end Show_Register; + +In this example, we have an initialization using the same aggregate as in the +previous code example. We also have an assignment, in which we read the value +of :ada:`WR` and use it in the calculation. + + If we want to just change two components, but leave the information of other components untouched, we can use a :ref:`delta aggregate `. From 231254da6af4359ad24edacc17474c2973e9ebda Mon Sep 17 00:00:00 2001 From: gusthoff Date: Sat, 11 Jan 2025 04:04:04 +0100 Subject: [PATCH 15/26] Minor editorial changes --- .../parts/data_types/shared_variable_control.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst b/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst index d8fc8dc44..ce8ec4622 100644 --- a/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst +++ b/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst @@ -547,7 +547,7 @@ only be read from memory or updated to memory every time, but those operations must also be performed for the complete record object |mdash| not just parts of it. -For example: +Consider the following example: .. code:: ada compile_button project=Courses.Advanced_Ada.Data_Types.Type_Representation.Shared_Variable_Control.Nonatomic_Full_Access_Register @@ -774,7 +774,8 @@ updated. Ideally, this operation corresponds to a single atomic operation on the target machine, but it can also translate to multiple atomic operations. -Let's see a simplified version of the previous example to illustrate this: +Let's adapt the previous example to illustrate this. First, we adapt the type +in the package: .. code:: ada compile_button project=Courses.Advanced_Ada.Data_Types.Type_Representation.Shared_Variable_Control.Atomic_Full_Access_Register From 494d6d15cc1d513eb4849a599d7ec246a3b9cb3a Mon Sep 17 00:00:00 2001 From: gusthoff Date: Sat, 11 Jan 2025 04:04:27 +0100 Subject: [PATCH 16/26] Editorial change: adding subsection for delta aggregates --- .../parts/data_types/shared_variable_control.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst b/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst index ce8ec4622..bdff69996 100644 --- a/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst +++ b/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst @@ -720,6 +720,11 @@ previous code example. We also have an assignment, in which we read the value of :ada:`WR` and use it in the calculation. +.. _Adv_Ada_Shared_Variable_Control_Non_Atomic_Full_Access_Delta_Aggregates: + +Delta aggregates +^^^^^^^^^^^^^^^^ + If we want to just change two components, but leave the information of other components untouched, we can use a :ref:`delta aggregate `. From 0f264b891f62c46e7df2dd6e77e0548c021d4aef Mon Sep 17 00:00:00 2001 From: gusthoff Date: Sat, 11 Jan 2025 04:05:20 +0100 Subject: [PATCH 17/26] Adding subsection on comparison between full-access and non-full-access types --- .../data_types/shared_variable_control.rst | 390 ++++++++++++++++++ 1 file changed, 390 insertions(+) diff --git a/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst b/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst index bdff69996..b793f5454 100644 --- a/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst +++ b/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst @@ -882,6 +882,396 @@ aggregate. Then, we have an atomic assignment to the atomic full-access object atomic operations that always access the full object from and to memory. +Comparison: full-access and non-full-access types +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +An interesting exercise for the reader is to compare the Assembly code +generated for the code example above with a version of this code where the +:ada:`Window_Register` is not a full-access type. + +.. admonition:: Relevant topics + + On a Linux platform, you can use `objdump` to retrieve the Assembly code + and `diff` to see the difference between both versions of the type. + For example: + + .. code-block:: bash + + objdump --target=elf64-x86-64 -d -S ./show_register > full_access.txt + + # [...] + + diff --width=80 -t -y full_access.txt no_full_access.txt + +By doing this kind of comparisons, you might gain more insights on the impact +of the :ada:`Full_Access_Only` aspect. + +.. admonition:: For further reading... + + By running on an PC, we can compare the + :wikipedia:`Intel Assembly ` code for various + versions of the code. Let's start with the version using a nonatomic + full-access version of :ada:`Window_Register` vs. the nonatomic + (non-full-access) version of :ada:`Window_Register`: + + .. code-block:: ada + + type Window_Register is record + -- [...] + end record + with Size => 32, + Bit_Order => System.Low_Order_First, + Volatile, + Full_Access_Only; + + type Window_Register is record + -- [...] + end record + with Size => 32, + Bit_Order => System.Low_Order_First, + Volatile; + + These are the manually-adapted differences between both versions: + + .. code-block:: none + + -- Volatile, Full_Access_Only | -- Volatile + + procedure Show_Register is procedure Show_Register is + push %rbp push %rbp + mov %rsp,%rbp mov %rsp,%rbp + sub $0x20,%rsp | sub $0x10,%rsp + WR : Window_Register := WR : Window_Register := + (Horizontal_Cnt => 800, (Horizontal_Cnt => 800, + mov -0x4(%rbp),%eax mov -0x4(%rbp),%eax + and $0xffffc000,%eax and $0xffffc000,%eax + or $0x320,%eax or $0x320,%eax + mov %eax,-0x4(%rbp) mov %eax,-0x4(%rbp) + mov -0x4(%rbp),%eax mov -0x4(%rbp),%eax + and $0x3f,%ah and $0x3f,%ah + mov %eax,-0x4(%rbp) mov %eax,-0x4(%rbp) + mov -0x4(%rbp),%eax mov -0x4(%rbp),%eax + and $0xc000ffff,%eax and $0xc000ffff,%eax + or $0x2580000,%eax or $0x2580000,%eax + mov %eax,-0x4(%rbp) mov %eax,-0x4(%rbp) + mov -0x4(%rbp),%eax mov -0x4(%rbp),%eax + or $0x40000000,%eax or $0x40000000,%eax + mov %eax,-0x4(%rbp) mov %eax,-0x4(%rbp) + mov -0x4(%rbp),%eax mov -0x4(%rbp),%eax + and $0x7fffffff,%eax and $0x7fffffff,%eax + mov %eax,-0x4(%rbp) mov %eax,-0x4(%rbp) + mov -0x4(%rbp),%eax < + mov %eax,-0x14(%rbp) < + mov -0x14(%rbp),%eax < + mov %eax,-0x8(%rbp) < + Vertical_Cnt => 600, Vertical_Cnt => 600, + Refresh_Needed => True, Refresh_Needed => True, + others => <>); others => <>); + begin begin + WR := (Horizontal_Cnt => WR := (Horizontal_Cnt => + WR.Horizontal_Cnt * 2, WR.Horizontal_Cnt * 2, + mov -0x8(%rbp),%eax | mov -0x4(%rbp),%eax + mov %eax,%ecx < + and $0x3fff,%cx | and $0x3fff,%ax + > add %eax,%eax + WR := (Horizontal_Cnt => < + mov -0xc(%rbp),%eax < + mov %eax,%edx < + WR.Horizontal_Cnt * 2, < + lea (%rcx,%rcx,1),%eax < + and $0x3fff,%ax and $0x3fff,%ax + WR := (Horizontal_Cnt => WR := (Horizontal_Cnt => + movzwl %ax,%eax movzwl %ax,%eax + and $0x3fff,%eax and $0x3fff,%eax + and $0xffffc000,%edx < + or %edx,%eax < + mov %eax,%edx mov %eax,%edx + mov %edx,%eax | mov -0x8(%rbp),%eax + mov %eax,-0xc(%rbp) | and $0xffffc000,%eax + mov -0xc(%rbp),%eax | or %edx,%eax + > mov %eax,-0x8(%rbp) + > mov -0x8(%rbp),%eax + and $0x3f,%ah and $0x3f,%ah + mov %eax,-0xc(%rbp) | mov %eax,-0x8(%rbp) + Vertical_Cnt => Vertical_Cnt => + Wr.Vertical_Cnt * 2, Wr.Vertical_Cnt * 2, + mov -0x8(%rbp),%eax | mov -0x4(%rbp),%eax + shr $0x10,%eax shr $0x10,%eax + mov %eax,%ecx | and $0x3fff,%ax + and $0x3fff,%cx | add %eax,%eax + WR := (Horizontal_Cnt => < + mov -0xc(%rbp),%eax < + mov %eax,%edx < + Wr.Vertical_Cnt * 2, < + lea (%rcx,%rcx,1),%eax < + and $0x3fff,%ax and $0x3fff,%ax + WR := (Horizontal_Cnt => WR := (Horizontal_Cnt => + movzwl %ax,%eax movzwl %ax,%eax + and $0x3fff,%eax and $0x3fff,%eax + shl $0x10,%eax shl $0x10,%eax + and $0xc000ffff,%edx < + or %edx,%eax < + mov %eax,%edx mov %eax,%edx + mov %edx,%eax | mov -0x8(%rbp),%eax + mov %eax,-0xc(%rbp) | and $0xc000ffff,%eax + mov -0xc(%rbp),%eax | or %edx,%eax + > mov %eax,-0x8(%rbp) + > mov -0x8(%rbp),%eax + and $0xbfffffff,%eax and $0xbfffffff,%eax + mov %eax,-0xc(%rbp) | mov %eax,-0x8(%rbp) + mov -0xc(%rbp),%eax | mov -0x8(%rbp),%eax + and $0x7fffffff,%eax and $0x7fffffff,%eax + mov %eax,-0xc(%rbp) < + mov -0xc(%rbp),%eax < + mov %eax,-0x8(%rbp) mov %eax,-0x8(%rbp) + > mov -0x8(%rbp),%eax + > mov %eax,-0x4(%rbp) + others => <>); others => <>); + + As we can see, although parts of the Assembly code are the same or look + very similar, there are some differences between both versions. These + differences are mostly related to the fact that we have to operate on the + full object when reading it from memory. + + Likewise, we can compare the Assembly code for the atomic full-access + version of :ada:`Window_Register` vs. the atomic (non-full-access) version + of :ada:`Window_Register`: + + .. code-block:: ada + + type Window_Register is record + -- [...] + end record + with Size => 32, + Bit_Order => System.Low_Order_First, + Atomic, + Full_Access_Only; + + type Window_Register is record + -- [...] + end record + with Size => 32, + Bit_Order => System.Low_Order_First, + Atomic; + + These are the manually-adapted differences between both versions: + + .. code-block:: none + + -- Atomic, Full_Access_Only | -- Atomic + + procedure Show_Register is procedure Show_Register is + push %rbp push %rbp + mov %rsp,%rbp mov %rsp,%rbp + sub $0x20,%rsp | sub $0x10,%rsp + WR : Window_Register := WR : Window_Register := + (Horizontal_Cnt => 800, (Horizontal_Cnt => 800, + mov -0x4(%rbp),%eax mov -0x4(%rbp),%eax + and $0xffffc000,%eax and $0xffffc000,%eax + or $0x320,%eax or $0x320,%eax + mov %eax,-0x4(%rbp) mov %eax,-0x4(%rbp) + mov -0x4(%rbp),%eax mov -0x4(%rbp),%eax + and $0x3f,%ah and $0x3f,%ah + mov %eax,-0x4(%rbp) mov %eax,-0x4(%rbp) + mov -0x4(%rbp),%eax mov -0x4(%rbp),%eax + and $0xc000ffff,%eax and $0xc000ffff,%eax + or $0x2580000,%eax or $0x2580000,%eax + mov %eax,-0x4(%rbp) mov %eax,-0x4(%rbp) + mov -0x4(%rbp),%eax mov -0x4(%rbp),%eax + or $0x40000000,%eax or $0x40000000,%eax + mov %eax,-0x4(%rbp) mov %eax,-0x4(%rbp) + mov -0x4(%rbp),%eax mov -0x4(%rbp),%eax + and $0x7fffffff,%eax and $0x7fffffff,%eax + mov %eax,-0x4(%rbp) mov %eax,-0x4(%rbp) + WR : Window_Register := WR : Window_Register := + mov -0x4(%rbp),%eax mov -0x4(%rbp),%eax + mov %eax,-0x14(%rbp) < + mov -0x14(%rbp),%eax < + mov %eax,-0x8(%rbp) mov %eax,-0x8(%rbp) + Vertical_Cnt => 600, Vertical_Cnt => 600, + Refresh_Needed => True, Refresh_Needed => True, + others => <>); others => <>); + begin begin + WR := (Horizontal_Cnt => WR := (Horizontal_Cnt => + WR.Horizontal_Cnt * 2, WR.Horizontal_Cnt * 2, + mov -0x8(%rbp),%eax mov -0x8(%rbp),%eax + mov %eax,%ecx < + and $0x3fff,%cx | and $0x3fff,%ax + | add %eax,%eax + WR := (Horizontal_Cnt => < + mov -0xc(%rbp),%eax < + mov %eax,%edx < + WR.Horizontal_Cnt * 2, < + lea (%rcx,%rcx,1),%eax < + and $0x3fff,%ax and $0x3fff,%ax + WR := (Horizontal_Cnt => WR := (Horizontal_Cnt => + movzwl %ax,%eax movzwl %ax,%eax + and $0x3fff,%eax and $0x3fff,%eax + > mov %eax,%edx + > mov -0xc(%rbp),%eax + and $0xffffc000,%edx | and $0xffffc000,%eax + or %edx,%eax or %edx,%eax + mov %eax,%edx < + mov %edx,%eax < + mov %eax,-0xc(%rbp) mov %eax,-0xc(%rbp) + mov -0xc(%rbp),%eax mov -0xc(%rbp),%eax + and $0x3f,%ah and $0x3f,%ah + mov %eax,-0xc(%rbp) mov %eax,-0xc(%rbp) + Vertical_Cnt => Vertical_Cnt => + Wr.Vertical_Cnt * 2, Wr.Vertical_Cnt * 2, + mov -0x8(%rbp),%eax mov -0x8(%rbp),%eax + shr $0x10,%eax shr $0x10,%eax + mov %eax,%ecx < + and $0x3fff,%cx | and $0x3fff,%ax + > add %eax,%eax + WR := (Horizontal_Cnt => < + mov -0xc(%rbp),%eax < + mov %eax,%edx < + Wr.Vertical_Cnt * 2, < + lea (%rcx,%rcx,1),%eax < + and $0x3fff,%ax and $0x3fff,%ax + WR := (Horizontal_Cnt => WR := (Horizontal_Cnt => + movzwl %ax,%eax movzwl %ax,%eax + and $0x3fff,%eax and $0x3fff,%eax + shl $0x10,%eax shl $0x10,%eax + > mov %eax,%edx + > mov -0xc(%rbp),%eax + and $0xc000ffff,%edx | and $0xc000ffff,%eax + or %edx,%eax or %edx,%eax + mov %eax,%edx < + mov %edx,%eax < + mov %eax,-0xc(%rbp) mov %eax,-0xc(%rbp) + mov -0xc(%rbp),%eax mov -0xc(%rbp),%eax + and $0xbfffffff,%eax and $0xbfffffff,%eax + mov %eax,-0xc(%rbp) mov %eax,-0xc(%rbp) + mov -0xc(%rbp),%eax mov -0xc(%rbp),%eax + and $0x7fffffff,%eax and $0x7fffffff,%eax + mov %eax,-0xc(%rbp) mov %eax,-0xc(%rbp) + mov -0xc(%rbp),%eax mov -0xc(%rbp),%eax + xchg %eax,-0x8(%rbp) xchg %eax,-0x8(%rbp) + others => <>); others => <>); + + Again, there are some differences between both versions, even though some + parts of the Assembly code are the same or look very similar. + + Finally, we might want to compare the nonatomic full-access version + vs. the atomic full-access version of the :ada:`Window_Register` type: + + .. code-block:: ada + + type Window_Register is record + -- [...] + end record + with Size => 32, + Bit_Order => System.Low_Order_First, + Volatile, + Full_Access_Only; + + type Window_Register is record + -- [...] + end record + with Size => 32, + Bit_Order => System.Low_Order_First, + Atomic, + Full_Access_Only; + + These are the differences between both versions: + + .. code-block:: none + + -- Volatile, Full_Access_Only | -- Atomic, Full_Access_Only + + procedure Show_Register is procedure Show_Register is + push %rbp push %rbp + mov %rsp,%rbp mov %rsp,%rbp + sub $0x20,%rsp sub $0x20,%rsp + WR : Window_Register := WR : Window_Register := + (Horizontal_Cnt => 800, (Horizontal_Cnt => 800, + mov -0x4(%rbp),%eax mov -0x4(%rbp),%eax + and $0xffffc000,%eax and $0xffffc000,%eax + or $0x320,%eax or $0x320,%eax + mov %eax,-0x4(%rbp) mov %eax,-0x4(%rbp) + mov -0x4(%rbp),%eax mov -0x4(%rbp),%eax + and $0x3f,%ah and $0x3f,%ah + mov %eax,-0x4(%rbp) mov %eax,-0x4(%rbp) + mov -0x4(%rbp),%eax mov -0x4(%rbp),%eax + and $0xc000ffff,%eax and $0xc000ffff,%eax + or $0x2580000,%eax or $0x2580000,%eax + mov %eax,-0x4(%rbp) mov %eax,-0x4(%rbp) + mov -0x4(%rbp),%eax mov -0x4(%rbp),%eax + or $0x40000000,%eax or $0x40000000,%eax + mov %eax,-0x4(%rbp) mov %eax,-0x4(%rbp) + mov -0x4(%rbp),%eax mov -0x4(%rbp),%eax + and $0x7fffffff,%eax and $0x7fffffff,%eax + mov %eax,-0x4(%rbp) mov %eax,-0x4(%rbp) + WR : Window_Register := WR : Window_Register := + mov -0x4(%rbp),%eax mov -0x4(%rbp),%eax + mov %eax,-0x14(%rbp) mov %eax,-0x14(%rbp) + mov -0x14(%rbp),%eax mov -0x14(%rbp),%eax + mov %eax,-0x8(%rbp) mov %eax,-0x8(%rbp) + Vertical_Cnt => 600, Vertical_Cnt => 600, + Refresh_Needed => True, Refresh_Needed => True, + others => <>); others => <>); + begin begin + WR := (Horizontal_Cnt => WR := (Horizontal_Cnt => + WR.Horizontal_Cnt * 2, WR.Horizontal_Cnt * 2, + mov -0x8(%rbp),%eax mov -0x8(%rbp),%eax + mov %eax,%ecx mov %eax,%ecx + and $0x3fff,%cx and $0x3fff,%cx + WR := (Horizontal_Cnt => WR := (Horizontal_Cnt => + mov -0xc(%rbp),%eax mov -0xc(%rbp),%eax + mov %eax,%edx mov %eax,%edx + WR.Horizontal_Cnt * 2, WR.Horizontal_Cnt * 2, + lea (%rcx,%rcx,1),%eax lea (%rcx,%rcx,1),%eax + and $0x3fff,%ax and $0x3fff,%ax + WR := (Horizontal_Cnt => WR := (Horizontal_Cnt => + movzwl %ax,%eax movzwl %ax,%eax + and $0x3fff,%eax and $0x3fff,%eax + and $0xffffc000,%edx and $0xffffc000,%edx + or %edx,%eax or %edx,%eax + mov %eax,%edx mov %eax,%edx + mov %edx,%eax mov %edx,%eax + mov %eax,-0xc(%rbp) mov %eax,-0xc(%rbp) + mov -0xc(%rbp),%eax mov -0xc(%rbp),%eax + and $0x3f,%ah and $0x3f,%ah + mov %eax,-0xc(%rbp) mov %eax,-0xc(%rbp) + Vertical_Cnt => Vertical_Cnt => + Wr.Vertical_Cnt * 2, Wr.Vertical_Cnt * 2, + mov -0x8(%rbp),%eax mov -0x8(%rbp),%eax + shr $0x10,%eax shr $0x10,%eax + mov %eax,%ecx mov %eax,%ecx + and $0x3fff,%cx and $0x3fff,%cx + WR := (Horizontal_Cnt => WR := (Horizontal_Cnt => + mov -0xc(%rbp),%eax mov -0xc(%rbp),%eax + mov %eax,%edx mov %eax,%edx + Wr.Vertical_Cnt * 2, Wr.Vertical_Cnt * 2, + lea (%rcx,%rcx,1),%eax lea (%rcx,%rcx,1),%eax + and $0x3fff,%ax and $0x3fff,%ax + WR := (Horizontal_Cnt => WR := (Horizontal_Cnt => + movzwl %ax,%eax movzwl %ax,%eax + and $0x3fff,%eax and $0x3fff,%eax + shl $0x10,%eax shl $0x10,%eax + and $0xc000ffff,%edx and $0xc000ffff,%edx + or %edx,%eax or %edx,%eax + mov %eax,%edx mov %eax,%edx + mov %edx,%eax mov %edx,%eax + mov %eax,-0xc(%rbp) mov %eax,-0xc(%rbp) + mov -0xc(%rbp),%eax mov -0xc(%rbp),%eax + and $0xbfffffff,%eax and $0xbfffffff,%eax + mov %eax,-0xc(%rbp) mov %eax,-0xc(%rbp) + mov -0xc(%rbp),%eax mov -0xc(%rbp),%eax + and $0x7fffffff,%eax and $0x7fffffff,%eax + mov %eax,-0xc(%rbp) mov %eax,-0xc(%rbp) + mov -0xc(%rbp),%eax mov -0xc(%rbp),%eax + mov %eax,-0x8(%rbp) | xchg %eax,-0x8(%rbp) + others => <>); others => <>); + + As we can see, the code is basically the same |mdash| except for the last + Assembly instruction, which is a `mov` instruction in the volatile version + and an `xchg` instruction in the atomic version |mdash| which is an atomic + instruction on this platform. + + .. TO BE DONE: From 0d937ec7da1a42993edf977614a85cedc228819a Mon Sep 17 00:00:00 2001 From: gusthoff Date: Sat, 11 Jan 2025 04:19:45 +0100 Subject: [PATCH 18/26] Minor correction to code example --- .../advanced-ada/parts/data_types/shared_variable_control.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst b/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst index b793f5454..b45fa3382 100644 --- a/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst +++ b/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst @@ -820,7 +820,7 @@ in the package: end record with Size => 32, Bit_Order => System.Low_Order_First, - Volatile, + Atomic, Full_Access_Only; for Window_Register use record From 14fa74a8c38550519c364149fce7ea2bbd103c23 Mon Sep 17 00:00:00 2001 From: gusthoff Date: Sat, 11 Jan 2025 04:20:16 +0100 Subject: [PATCH 19/26] Editorial change: removing button We need the `-gnat2022` switch to run this example. --- .../advanced-ada/parts/data_types/shared_variable_control.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst b/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst index b45fa3382..75eb25406 100644 --- a/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst +++ b/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst @@ -782,7 +782,7 @@ operations. Let's adapt the previous example to illustrate this. First, we adapt the type in the package: -.. code:: ada compile_button project=Courses.Advanced_Ada.Data_Types.Type_Representation.Shared_Variable_Control.Atomic_Full_Access_Register +.. code:: ada no_button project=Courses.Advanced_Ada.Data_Types.Type_Representation.Shared_Variable_Control.Atomic_Full_Access_Register pragma Ada_2022; @@ -856,7 +856,7 @@ in the package: We then use the package in our test application: -.. code:: ada run_button project=Courses.Advanced_Ada.Data_Types.Type_Representation.Shared_Variable_Control.Atomic_Full_Access_Register +.. code:: ada no_button project=Courses.Advanced_Ada.Data_Types.Type_Representation.Shared_Variable_Control.Atomic_Full_Access_Register with Registers; use Registers; From 8a53adfb2e608806676510a4905b21245bc545c1 Mon Sep 17 00:00:00 2001 From: gusthoff Date: Sun, 12 Jan 2025 17:02:50 +0100 Subject: [PATCH 20/26] Minor corrections to code example --- .../parts/data_types/shared_variable_control.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst b/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst index 75eb25406..095287210 100644 --- a/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst +++ b/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst @@ -596,7 +596,7 @@ Consider the following example: Vertical_Cnt at 0 range 16 .. 29; Refresh_Needed at 0 range 30 .. 30; Reserved_30 at 0 range 31 .. 31; - end record; + end record; procedure Show (WR : Window_Register); @@ -738,6 +738,8 @@ update via the :ada:`Refresh_Needed` flag, but keep the same horizontal count: .. code:: ada run_button project=Courses.Advanced_Ada.Data_Types.Type_Representation.Shared_Variable_Control.Nonatomic_Full_Access_Register + pragma Ada_2022; + with Ada.Text_IO; use Ada.Text_IO; with Registers; use Registers; @@ -829,7 +831,7 @@ in the package: Vertical_Cnt at 0 range 16 .. 29; Refresh_Needed at 0 range 30 .. 30; Reserved_30 at 0 range 31 .. 31; - end record; + end record; procedure Show (WR : Window_Register); From 8bf36eb38736839b12121cac598792c7bba7e8ef Mon Sep 17 00:00:00 2001 From: gusthoff Date: Fri, 7 Feb 2025 19:54:28 +0100 Subject: [PATCH 21/26] Correction: "objects" => "types" --- .../advanced-ada/parts/data_types/shared_variable_control.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst b/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst index 095287210..bccd73862 100644 --- a/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst +++ b/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst @@ -397,7 +397,7 @@ Later on, we talk again about the :ref:`System'To_Address attribute `. In addition to atomic objects, we can declare atomic types |mdash| similar to -what we've seen before for volatile objects. For example: +what we've seen before for volatile types. For example: .. code:: ada compile_button project=Courses.Advanced_Ada.Data_Types.Shared_Variable_Control.Atomic.Types From 17dfef406d83b5c23875df16ffd58cb5c63030d1 Mon Sep 17 00:00:00 2001 From: gusthoff Date: Fri, 7 Feb 2025 19:55:00 +0100 Subject: [PATCH 22/26] Adding admonition about atomic and volatile --- .../parts/data_types/shared_variable_control.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst b/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst index bccd73862..2f0d0671e 100644 --- a/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst +++ b/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst @@ -491,6 +491,12 @@ simultaneously a :ref:`atomic type `. (In other words, if a type is neither volatile nor atomic, it cannot be a full access type.) +.. admonition:: Important + + Just as a reminder, any atomic type is automatically also + :ref:`volatile ` and + :ref:`independent `. + Let's see some examples: .. code:: ada compile_button project=Courses.Advanced_Ada.Data_Types.Type_Representation.Shared_Variable_Control.Full_Access_Only_Types From c140663695b5628a7a789d8424a49e042278f1c3 Mon Sep 17 00:00:00 2001 From: gusthoff Date: Fri, 7 Feb 2025 19:55:39 +0100 Subject: [PATCH 23/26] Minor editorial corrections --- .../advanced-ada/parts/data_types/shared_variable_control.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst b/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst index 2f0d0671e..f46fc2bfd 100644 --- a/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst +++ b/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst @@ -765,7 +765,7 @@ update via the :ada:`Refresh_Needed` flag, but keep the same horizontal count: end Show_Registers; A delta assignment using an aggregate such as :ada:`(WR with delta ...)` -includes reading the value of complete 32-bit :ada:`WR` object from memory, +includes reading the value of the complete 32-bit :ada:`WR` object from memory, changing the components specified after :ada:`with delta`, and writing the complete 32-bit :ada:`WR` object back to memory. The reason is that we need to retrieve the information that is supposed to remain intact |mdash| the @@ -916,7 +916,7 @@ of the :ada:`Full_Access_Only` aspect. .. admonition:: For further reading... - By running on an PC, we can compare the + By running on a PC, we can compare the :wikipedia:`Intel Assembly ` code for various versions of the code. Let's start with the version using a nonatomic full-access version of :ada:`Window_Register` vs. the nonatomic From caae7f359da188ff959228c066c2a272b11edd2b Mon Sep 17 00:00:00 2001 From: gusthoff Date: Fri, 7 Feb 2025 19:56:05 +0100 Subject: [PATCH 24/26] Editorial change: simplifying phrase --- .../advanced-ada/parts/data_types/shared_variable_control.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst b/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst index f46fc2bfd..ecc9d3b16 100644 --- a/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst +++ b/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst @@ -544,7 +544,7 @@ Nonatomic full-access ~~~~~~~~~~~~~~~~~~~~~ As we already know, the value of a volatile object may be constantly changing, -so the compiler generates code in such a way that the process must read the +so the compiler generates code to read the value of the volatile object from memory for each access. (In other words, the value cannot be stored in a register for further processing.) From a2544e0e3ac2d726669bb6ce070a0f2143c121ae Mon Sep 17 00:00:00 2001 From: gusthoff Date: Fri, 7 Feb 2025 19:56:34 +0100 Subject: [PATCH 25/26] Minor addition: mentioning "atomic" and "volatile" --- .../advanced-ada/parts/data_types/shared_variable_control.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst b/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst index ecc9d3b16..7897fe6da 100644 --- a/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst +++ b/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst @@ -780,7 +780,8 @@ As we already know, :ref:`atomic objects ` only accept atomic reads and updates, which |mdash| as a whole |mdash| are indivisible, i.e. they must be done in a single instruction, so that no other instruction -could execute on that same object before the read or update completes. +could execute on that same object before the read or update completes. (Again, +if an object is atomic, this implies it is also volatile.) In the case of atomic full-access objects, the complete object must be read and updated. Ideally, this operation corresponds to a single atomic From a0b575e0b9375e8bb9bb4f7be1aac7490a227293 Mon Sep 17 00:00:00 2001 From: gusthoff Date: Fri, 7 Feb 2025 19:56:57 +0100 Subject: [PATCH 26/26] Elaborating on compiler optimizations and full-access objects --- .../parts/data_types/shared_variable_control.rst | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst b/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst index 7897fe6da..658ad69d4 100644 --- a/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst +++ b/content/courses/advanced-ada/parts/data_types/shared_variable_control.rst @@ -662,9 +662,14 @@ a test application: The example contains assignments such as :ada:`WR.Horizontal_Cnt := 800` and :ada:`WR.Vertical_Cnt:= 600`. Because :ada:`Window_Register` is a full-access type, these assignments are performed for the complete 32-bit register, even -though we're updating just a single component of the record object. (Note that -if :ada:`Window_Register` wasn't a *full-access* object, an assignment such as -:ada:`WR.Horizontal_Cnt := 800` could be performed with a 16-bit operation.) +though we're updating just a single component of the record object. + +Note that if :ada:`Window_Register` wasn't a *full-access* object, an +assignment such as :ada:`WR.Horizontal_Cnt := 800` could be performed with a +16-bit operation. In fact, this is what a compiler would most probably select +for this assignment, because that is more efficient than manipulating the +entire object. Therefore, using a *full-access* object prevents the compiler +from generating operations that could lead to unexpected results. Whenever possible, this *full-access* assignment is performed in a single machine operation. However, if it's not possible to generate a single machine