Reputation: 456
I have a codebase which is being built for several different targets, each with its own set of register definitions. For a given target, there is a register definition file which will define register contents like this:
type Register1 is record
field1 : U7;
field2 : U8;
end record;
The types U7
and U8
are just Unsigned types defined like this:
type U7 is mod 2 ** 7 with Size => 7;
type U8 is mod 2 ** 8 with Size => 8;
...
In my driver, I have a Register_Write function which takes a Register1 as an argument. I've tried calling it like this:
field1_val: U32:= 1;
field2_val: U32:= 2;
...
Register_Write( Register1'(field1 => field1_val, field2 => field2_val ));
But this does not work and I get the error expected type "U7", found type "U32"
. The issue is that I cannot just make field1_val a U7, because the type of this field is different for different targets. For example, on some targets it may be U7, on some it may be U6, etc.
Is there a way of saying "Cast field1_val to the type of field1" when I create a Register1 record?
Upvotes: 0
Views: 329
Reputation: 2142
I will show you two ways, one that I recommend and one that I do not recommend. I will use the Ada terms "component" instead of "field", and "convert" instead of "cast".
The method that I do not recommend, but that is a more direct answer to your question, is to use the 'Pos attribute to convert the value to a universal-integer, which is then compatible with whatever type the record component has, assuming it is an integer type. In your example:
Register_Write( Register1'(
field1 => U32'Pos(field1_val),
field2 => U32'Pos(field2_val)));
I do not recommend that method for two reasons: firstly, because it circumvents strong typing, and secondly because it only works if the component type is an integer. I find that my HW register components often have enumerated types, and then the method does not work.
The method I recommend is to declare names for the component types in the same place (same package) where you declare the record types for the registers -- presumably a package with target-specific variants. This follows the Ada philosophy of using meaningful type names to model application semantics, instead of using a general type like U7 for a 7-bit component whatever the meaning of that component. For example (the type names here are of course not very meaningful as I don't know what the register or its components really mean):
type Reg1_Command is mod 2**7 with Size => 7;
type Reg1_Parameter is mod 2**8 with Size => 8;
type Register1 is record
Command : Reg1_Command;
Parameter : Reg1_Parameter;
end record;
Then you can use these component type-names for the values, and you will not need any type conversions:
Command_Val : Reg1_Command := 1;
Parameter_Val : Reg1_Parameter := 2;
Register_Write(Register1'(
Command => Command_Val,
Parameter => Parameter_Val));
If you like, you can shorten some component-type declarations by deriving from a general type:
type Reg1_Command is new U7;
Upvotes: 3