【问题标题】:Ada - how to explicitly pack a bit-field record type?Ada - 如何显式打包位字段记录类型?
【发布时间】:2019-10-21 19:49:58
【问题描述】:

请考虑以下实验性 Ada 程序,它尝试创建具有明确定义的位域的 32 位记录,创建一个并将其输出到文件流...

with System;
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Streams.Stream_Io; use Ada.Streams.Stream_Io;

procedure Main is

   type Bit is mod    (2 ** 1);

   type Opcode_Number is mod (2 ** 4);
   type Condition_Number is mod (2 ** 4);
   type Operand is mod (2 ** 9);

   type RAM_Register is
      record
         Opcode : Opcode_Number;
         Z      : Bit;
         C      : Bit;
         R      : Bit;
         I      : Bit;
         Cond   : Condition_Number;
         Rsvd_1 : Bit;
         Rsvd_2 : Bit;
         Dest   : Operand;
         Src    : Operand;
      end record;

   for RAM_Register use
      record
         Opcode at 0 range 28 .. 31;
         Z      at 0 range 27 .. 27;
         C      at 0 range 26 .. 26;
         R      at 0 range 25 .. 25;
         I      at 0 range 24 .. 24;
         Cond   at 0 range 20 .. 23;
         Rsvd_1 at 0 range 19 .. 19;
         Rsvd_2 at 0 range 18 .. 18;
         Dest   at 0 range  9 .. 17;
         Src    at 0 range  0 ..  8;
      end record;
   for RAM_Register'Size use 32;
   for RAM_Register'Bit_Order use System.High_Order_First;

   --  ADA 2012 language reference 'full_type_declaration'
   --  (page 758, margin number 8/3) for RAM_Register
   pragma Atomic (RAM_Register);


   --   3         2         1         0
   --  10987654321098765432109876543210
   --  OOOOzcriCONDrrDDDDDDDDDsssssssss

   X : RAM_Register := (2#1000#,
                           2#1#,
                           2#1#,
                           2#1#,
                           2#1#,
                        2#1000#,
                           2#1#,
                           2#1#,
                   2#100000001#,
                   2#100000001#);

   The_File : Ada.Streams.Stream_IO.File_Type;
   The_Stream : Ada.Streams.Stream_IO.Stream_Access;

begin
   begin
      Open (The_File, Out_File, "test.dat");
   exception
      when others =>
         Create (The_File, Out_File, "test.dat");
   end;

   The_Stream := Stream (The_File);
   RAM_Register'Write (The_Stream, X);
   Close (The_File);
end Main;

我使用这里的信息:https://rosettacode.org/wiki/Object_serialization#Ada 和这里:https://en.wikibooks.org/wiki/Ada_Programming/Attributes/%27Bit_Order(最后一个示例)来创建上述内容。

运行代码并使用 xxd -g1 test.dat 检查输出会得到以下 12 个字节的输出...

00000000: 08 01 01 01 01 08 01 01 01 01 01 01              ............

问题:

如何在观察所有位域位置的情况下将这个 32 位记录以 32 位的形式写入或读取流?想象一下,我正在与 RS-232 端口上的微控制器通信,每个位都需要在正确的时间准确地出现在正确的位置。语法for RAM_Register use record... 似乎对'Write 的输出排列方式没有影响。

如果我确实提供了自己的 'Read'Write 实现,那是否直接与“for RAM_Register 使用记录...”代码相矛盾?

【问题讨论】:

  • 您可以合法地制作自己的流属性,这些属性可以在线上转换为 XML 或从 XML 转换。 rep 子句定义了寄存器/存储中的布局,如果您想通过网络发送它,您应该这样做(在较低级别进行未经检查的转换)。 Ada 流是一个更高级别的结构。

标签: stream record ada bit-fields


【解决方案1】:

您可能必须将实例转换为无符号整数(通过未经检查的转换),然后将无符号整数写入流。 Write 的默认实现忽略了表示子句(另见RM 13 9/3):

对于复合类型,每个组件的写入或读取属性按规范顺序调用,[...]

所以,添加

with Interfaces; use Interfaces;
with Ada.Unchecked_Conversion;

并将RAM_Register定义为

   type RAM_Register is
      record
         Opcode : Opcode_Number;
         Z      : Bit;
         C      : Bit;
         R      : Bit;
         I      : Bit;
         Cond   : Condition_Number;
         Rsvd_1 : Bit;
         Rsvd_2 : Bit;
         Dest   : Operand;
         Src    : Operand;
      end record with Atomic;  

   procedure Write
     (Stream : not null access Ada.Streams.Root_Stream_Type'Class;
      Item   : RAM_Register);

   for RAM_Register'Write use Write;

   for RAM_Register use
      record         
         Opcode at 0 range 28 .. 31;
         Z      at 0 range 27 .. 27;
         C      at 0 range 26 .. 26;
         R      at 0 range 25 .. 25;
         I      at 0 range 24 .. 24;
         Cond   at 0 range 20 .. 23;
         Rsvd_1 at 0 range 19 .. 19;
         Rsvd_2 at 0 range 18 .. 18;
         Dest   at 0 range  9 .. 17;
         Src    at 0 range  0 ..  8;
      end record;   

   for RAM_Register'Size use 32;
   for RAM_Register'Bit_Order use System.High_Order_First; 

   -----------
   -- Write --
   -----------

   procedure Write
     (Stream : not null access Ada.Streams.Root_Stream_Type'Class;
      Item   : RAM_Register)
   is

      function To_Unsigned_32 is
        new Ada.Unchecked_Conversion (RAM_Register, Unsigned_32); 

      U32 : Unsigned_32 := To_Unsigned_32 (Item);

   begin   
      Unsigned_32'Write (Stream, U32);        
   end Write;

这会产生

$ xxd -g1 test.dat
00000000: 01 03 8e 8f                                      ....

注意:由于我不得不评论方面规范for RAM_Register'Bit_Order use System.High_Order_First;

,因此位序可能已经颠倒了

【讨论】:

  • 您的xxd 输出与我的笔和纸工作相匹配,但字节交换除外!我可以弥补这一点。我没想到会为了这样的事情诉诸“不受约束的”恶作剧。在这方面,官方文档很难遵循和理解。谢谢。
  • 我已经遇到了字节序问题,你应该在这个问题中找到提示stackoverflow.com/questions/56656184/… 但是,你会看到我为此使用了 Gnat only 属性。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-02-17
  • 1970-01-01
相关资源
最近更新 更多