Ада - как явно упаковать тип записи битового поля? - PullRequest
3 голосов
/ 21 октября 2019

Пожалуйста, рассмотрите следующую экспериментальную программу 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, разве это не напрямую противоречит 'для записи об использовании RAM_Register ... `код?

1 Ответ

6 голосов
/ 21 октября 2019

Вам, вероятно, придется преобразовать экземпляр в целое число без знака (с помощью непроверенного преобразования), а затем записать целое число без знака в поток. Реализация по умолчанию Write игнорирует условие представления (см. Также RM 13 9/3 ):

Для составных типов вызывается атрибут Write или Read для каждого компонентав каноническом порядке [...]

Итак, добавьте

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                                      ....

Примечание: bitorder, возможно, был полностью изменен, поскольку я должен был прокомментировать спецификацию аспекта for RAM_Register'Bit_Order use System.High_Order_First;

...