Ada-如何显式打包位字段记录类型?

Wos*_*ame 3 record ada stream bit-fields

请考虑以下实验性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;
Run Code Online (Sandbox Code Playgroud)

我在以下位置使用了以下信息: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              ............
Run Code Online (Sandbox Code Playgroud)

题:

如何在观察所有位域位置的情况下将此32位记录作为32位写入或读取流?想象一下,我正在与RS-232端口上的微控制器进行通信,要求每个位都在正确的时间正确地放置在正确的位置。该语法for RAM_Register use record...似乎对如何'Write安排其输出没有影响。

如果我提供我自己'Read'Write实现,不会是直接违背了“为RAM_Register使用记录...`代码?

Dee*_*Dee 6

You probably will have to convert the instance to an unsigned integer (via an unchecked conversion) and then write the unsigned integer to the stream. The default implementation of Write ignores the representation clause (see also RM 13 9/3):

For composite types, the Write or Read attribute for each component is called in canonical order, [...]

So, add

with Interfaces; use Interfaces;
with Ada.Unchecked_Conversion;
Run Code Online (Sandbox Code Playgroud)

and define RAM_Register as

   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;

Run Code Online (Sandbox Code Playgroud)

This yields

$ xxd -g1 test.dat
00000000: 01 03 8e 8f                                      ....
Run Code Online (Sandbox Code Playgroud)

Note: the bitorder may have been reversed as I had to comment the aspect specification for RAM_Register'Bit_Order use System.High_Order_First;