Reputation: 456
I have a source file in my project which comes from an external team, and I cannot modify it. It contains a record which defines the contents of a register:
type R_Field is (R_FALSE, R_TRUE) with Size => 1;
for R_Field use (R_FALSE => 16#0#, R_TRUE => 16#1#);
type W_Field is (W_FALSE, W_TRUE) with Size => 1;
for W_Field use (W_FALSE => 16#0#, W_TRUE => 16#1#);
type U_Field is (U_FALSE, U_TRUE) with Size => 1;
for U_Field use (U_FALSE => 16#0#, U_TRUE => 16#1#);
type My_Register is record
R : R_Field;
W : W_Field;
U : U_Field;
end record with Size => 32, Object_Size => 32;
for My_Register use record
R at 0 range 0 .. 0;
W at 0 range 1 .. 1;
U at 0 range 5 .. 5;
end record;
I am writing a driver which will be built against many different targets, each with it's own register file. For some variants of the register file, the My_Register record will not have the U field.
I am trying to initialize a My_Register record in my code in such a way that will set all the fields to 0. I want my code to work in both the case when U is defined and in the case when it is not.
I cannot do reg : My_Register := (R => R_FALSE, W => W_FALSE, U => U_FALSE)
because this does not compile in the case when U and U_FALSE are not defined in the register file.
Is there a way to zero-init the entire record, the same way that = {0}
would do in C?
Upvotes: 1
Views: 604
Reputation: 3358
The (others => Value)
aggregate only works when all the fields have the same type; (others => <>)
gives you the default values, which for this definition gives random values.
What you need is an abstract register type that your program may deal with regardless of the actual register type:
package Registers is
type Abstract_Register is record
R : Boolean := False;
W : Boolean := False;
U : Boolean := False;
end record;
procedure Op (Register : in Abstract_Register);
-- Do something with a register
end Registers;
Then you have a different pkg body for each actual register type. If the actual doesn't have the U component, your operations simply ignore the U component of Abstract_Register. For your example:
package body Registers is
type R_Field is (R_FALSE, R_TRUE) with Size => 1;
for R_Field use (R_FALSE => 16#0#, R_TRUE => 16#1#);
type W_Field is (W_FALSE, W_TRUE) with Size => 1;
for W_Field use (W_FALSE => 16#0#, W_TRUE => 16#1#);
type U_Field is (U_FALSE, U_TRUE) with Size => 1;
for U_Field use (U_FALSE => 16#0#, U_TRUE => 16#1#);
type My_Register is record
R : R_Field;
W : W_Field;
U : U_Field;
end record with Size => 32, Object_Size => 32;
for My_Register use record
R at 0 range 0 .. 0;
W at 0 range 1 .. 1;
U at 0 range 5 .. 5;
end record;
function To_Concrete (Register : in Abstract_Register) return My_Register is
(R => R_Field'Val (Boolean'Pos (Register.R) ),
W => W_Field'Val (Boolean'Pos (Register.W) ),
U => U_Field'Val (Boolean'Pos (Register.R) ) );
-- Alternatively, R => (if Register.R then R_True else R_False),
function To_Abstract ...
procedure Op (Register : in Abstract_Register) is
Concrete : My_Register := To_Concrete (Register);
...
end Registers;
Upvotes: 0
Reputation: 2142
So you have some code (a record type definition) that is different for different targets. Therefore your build system has some way to select the source files to be used for a chosen target. I advise you to make your record-initialization source code also different for different targets, making the build system select the proper source file for each target in the same way as it selects the proper source file containing the record-type declaration for that target. And the same applies to any code that has to access the U component if it is present.
The answer to your question if (others => <>) guarantees zero initialization is "no". It asks for default initialization of all components, so to get "zero" initialization the type for each component should have a default value of "zero" (or "R_FALSE", etc.), which would require adding a default-value aspect to the type declarations from the external team, something it seems you are not allowed to do.
If you don't want to use the target-specific source-file method, but you are sure that the size of the record is 32 bits for all targets, you can instantiate an Unchecked_Conversion function from "mod 2**32" to the record type, and apply that conversion to a zero value to get a record value with 32 zero bits. But of course Unchecked_Conversion is a hack that can lead to problems later on.
Upvotes: 5