简体   繁体   中英

Casting a Variable to the same type as another variable in Ada

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?

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;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM