用动态选择记录聚合

时间:2016-03-21 22:44:16

标签: ada

我需要在硬件寄存器中写一个由除0位之外的所有Bit组成的值,其中寄存器有点像

type Bit_Number is range 0 .. 31;
type Bits_1 is array (Bit_Number) of Boolean
with
  Component_Size => 1,
  Size => 32;

Register_1 : Bits_1
  with
    Volatile,
    Address => System'To_Address (16#1234_5678#);

Register_1(Atmel的典型寄存器ATSAM3X8E,如Arduino Due中所定义的)被定义为只写,并且如果您阅读它,它未指定您得到的内容,以及未指明哪些访问宽度合法;我们被告知的是,当我们写入寄存器时,只有1位有效。 (顺便说一句,这意味着GNAT特定方面Volatile_Full_AccessAI12-0128中提出的更改不会有帮助。)

在GPIO外设中使能引脚需要在几个寄存器中设置其Bit。由于我无法改变的原因(AdaCore's SVD2Ada),每个寄存器都有自己的上述Bits_1数组类型。

我想写

procedure Set_Bit (Bit : Bit_Number) is
begin
   Register_1 := (Bit => True, others => False);
   Register_2 := (Bit => True, others => False);
   ...
end Set_Bit;

但是编译器说

19.    procedure Set_Bit (Bit : Bit_Number) is
20.    begin
21.       Register_1 := (Bit => True, others => False);
                         |
    >>> dynamic or empty choice in aggregate must be the only choice

是对ARM 4.3.3(17)的引用,

  

array_component_association的discrete_choice_list允许具有discrete_choice,这是一个非静态choice_expression,或者是一个subtype_indication或定义非静态或null范围的范围,只有当它是其discrete_choice_list的单个discrete_choice时才有,并且只有一个array_aggregate中的array_component_association。

我可以解决这个问题,

procedure Set_Bit (Bit : Bit_Number) is
begin
   declare
      B : Bits_1 := (others => False);
   begin
      B (Bit) := True;
      Register_1 := B;
   end;
   ... ad nauseam
end Set_Bit;

但这看起来很笨拙!还有其他建议吗?

4 个答案:

答案 0 :(得分:4)

它必须是一个数组吗? 另一种选择可能是:

with Interfaces;
procedure Set_Bit is
   Register : Interfaces.Unsigned_32;
begin
   for J in 0..31 loop
      Register := 2**J;
   end loop;
end Set_Bit;

答案 1 :(得分:4)

我认为这可能有点麻烦,但是如果你需要一个数组,你可以使用连续的切片聚合将它作为一个整体初始化:

    for J in 0 .. 31 loop
       Register := Bits'(others => False)(0..J-1) &
                   True & Bits'(others => False)(J+1..31);
    end loop;

答案 2 :(得分:1)

它看起来像是函数的候选者:

function Single_Bit (Set : in Bit_Number) return Bits_1 is
begin
   return Result : Bits_1 := (others => False) do
      Result (Set) := True;
   end return;
end Single_Bit;

然后:

Register_1 := Single_Bit (Set => Some_Bit);
Register_2 := Single_Bit (Set => Another_Bit);

答案 3 :(得分:0)

Example 1

这使用Shift_Left操作。

with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Unchecked_Conversion;
with Interfaces; use Interfaces;

procedure Main_Test is
   function One_Bit (Index : Natural) return Unsigned_32 is (Shift_Left (1, Index));

   type Bit_Array_32_Index is range 0 .. 31;
   type Bit_Array_17_Index is range 0 .. 16;
   type Bit_Array_32 is array (Bit_Array_32_Index) of Boolean with Component_Size => 1, Size => 32;
   type Bit_Array_17 is array (Bit_Array_17_Index) of Boolean with Component_Size => 1, Size => 17;

   -- For every new array type instantiate a convert function.
   function Convert is new Ada.Unchecked_Conversion (Unsigned_32, Bit_Array_32);
   function Convert is new Ada.Unchecked_Conversion (Unsigned_32, Bit_Array_17);
   B32 : Bit_Array_32 with Volatile;
   B17 : Bit_Array_17 with Volatile;
begin
   B17 := Convert (One_Bit (2)) or Convert (One_Bit (5));
   B32 := Convert (One_Bit (2) or One_Bit (5));
   for E of B17 loop
      Put (Boolean'Pos (E), 1);
   end loop;
   New_Line;
   for E of B32 loop
      Put (Boolean'Pos (E), 1);
   end loop;
end;

结果

00100100000000000
00100100000000000000000000000000

警告

main.adb:21:04: warning: types for unchecked conversion have different sizes
main.adb:21:04: warning: size of "Unsigned_32" is 32, size of "Bit_Array_17" is 17
main.adb:21:04: warning: 15 high order bits of source will be ignored

Example generics

这使用Shift_Left操作,但使用泛型。

with Ada.Text_IO; use Ada.Text_IO;
with Ada.Unchecked_Conversion;
with Interfaces; use Interfaces;

procedure Main is
   package Unsigned_32_IO is new Ada.Text_IO.Modular_IO (Unsigned_32);

   type Bit_Array_32_Index is range 0 .. 31;
   type Bit_Array_17_Index is range 0 .. 16;
   type Bit_Array_32 is array (Bit_Array_32_Index) of Boolean with Component_Size => 1, Size => 32;
   type Bit_Array_17 is array (Bit_Array_17_Index) of Boolean with Component_Size => 1, Size => 32;

   generic
      type I is (<>);
      type T is array (I) of Boolean;
   procedure Generic_Put (Item : T; Width : Field; Base : Number_Base);
   procedure Generic_Put (Item : T; Width : Field; Base : Number_Base) is
      function Convert_To_Unsigned_32 is new Ada.Unchecked_Conversion (T, Unsigned_32);
   begin
      Unsigned_32_IO.Put (Convert_To_Unsigned_32 (Item), Width, Base);
   end;

   generic
      type I is (<>);
      type T is array (I) of Boolean;
   function Generic_Shift_Left (Value : Unsigned_32; Amount : Natural) return T;
   function Generic_Shift_Left (Value : Unsigned_32; Amount : Natural) return T is
      function Convert_To_Bit_Array_32 is new Ada.Unchecked_Conversion (Unsigned_32, T);
   begin
      return Convert_To_Bit_Array_32 (Interfaces.Shift_Left (Value, Amount));
   end;

   function Shift_Left is new Generic_Shift_Left (Bit_Array_32_Index, Bit_Array_32);
   function Shift_Left is new Generic_Shift_Left (Bit_Array_17_Index, Bit_Array_17);
   procedure Put is new Generic_Put (Bit_Array_32_Index, Bit_Array_32);
   procedure Put is new Generic_Put (Bit_Array_17_Index, Bit_Array_17);

   B32 : Bit_Array_32 with Volatile;
   B17 : Bit_Array_17 with Volatile;
begin
   B32 := Shift_Left (1, 2) or Shift_Left (1, 5);
   B17 := Shift_Left (1, 2) or Shift_Left (1, 5);
   Put (B17, 0, 2);
   New_Line;
   Put (B32, 0, 2);
end;

结果

2#100100#
2#100100#

gprbuild -v

GPRBUILD GPL 2015 (20150428) (i686-pc-mingw32)

问题

它适用于大端机吗? 我没有经过测试。见does bit-shift depend on endianness?