Copyright (C) А.Гавва V-0.4w май 2004

17. Низкоуровневые средства для системного программирования

Кроме богатого набора традиционных средств абстракции данных, Ада, в отличие от многих современных языков программирования, предоставляет ряд низкоуровневых средств, которые могут быть удобны при организации взаимодействия с используемым оборудованием или внешним программным обеспечением. Например, с помощью таких средств можно управлять требуемым двоичным представлением данных или размещением объектов в фиксированных адресах физической памяти.

Описанию средств системного программирования Ады посвящено приложение C (Annex C) стандарта Ada95. Кроме того, различные реализации компиляторов могут предусматривать дополнительные атрибуты типов и/или директивы компилятора которые управляют внутренним представлением объектов и поведением окружения времени выполнения.

Следует заметить, что многие зависящие от реализации системы константы располагаются в стандартном пакете System. Например, число битов в элементе памяти, число доступных элементов памяти, наибольшее и наименьшее доступное целое число, имя операционной системы и т.д.

17.1 Спецификация внутреннего представления данных

С помощью спецификации представления, для идентификаторов любого перечислимого типа можно указать специфические значения для внутреннего представления значений перечислимого типа. Предположим, что у нас есть перечислимый тип, который описывает страны:

    
    
    type  Country is (USA, Russia, France, UK, Australia);
    

Мы можем, используя спецификацию представления, указать для каждого идентификатора этого перечислимого типа значение телефонного кода соответствующей страны следующим образом:

    
    
    type  Country is (USA, Russia, France, UK, Australia);
    for Country use (USA => 1, Russia => 7, France => 33, UK => 44, Australia => 61);
    

Таким образом, внутреннее значение используемое, например, для представления идентификатора France будет 33.

При спецификации внутреннего представления перечислимого типа, значения для внутреннего представления должны указываться в порядке увеличения значений и быть уникальны. Следует также обратить внимание на то, что атрибуты перечислимого типа будут возвращать значения которые не учитывают спецификацию внутреннего представления, например:

Для того, чтобы получить доступ к значениям внутреннего представления перечислимого типа необходимо воспользоваться стандартным настраиваемым модулем Ada.Unchecked_Convertion, который позволяет получить внутреннее представление объекта как значение другого типа, не выполняя при этом никаких промежуточных преобразований.

Следует заметить, что использование модуля настраиваемой функции Ada.Unchecked_Convertion обладает одним ограничением: объект-источник и объект-приемник должны иметь одинаковый битовый размер. Поэтому, чтобы гарантировать соответствие размеров объектов источника и приемника, необходимо указать компилятору размер внутреннего представления перечислимого типа Country. Например, можно указать, что размер внутреннего представления типа Country должен быть равен размеру типа Integer. Это можно выполнить следующим образом:

    
    
    type  Country is (USA, Russia, France, UK, Australia);
    for Country'Size use Integer'Size;
    for Country use (USA => 1, Russia => 7, France => 33, UK => 44, Australia => 61);
    

Напомним, что атрибут T'Size возвращает размер экземпляра объекта типа T в битах.

Следующий пример простой программы, которая выводит телефонный код Франции, демонстрирует использование рассмотренных средств спецификации внутреннего представления:

    
    
    with  Ada.Unchecked_Conversion;
    with  Ada.Text_IO;              use   Ada.Text_IO;
    
    procedure Main  is
    
        type  Country is (USA, Russia, France, UK, Australia);
        for Country'Size use Integer'Size;
        for Country use (USA       => 1,
                                       Russia    => 7,
                                       France    => 33,
                                       UK        => 44,
                                       Australia => 61);
    
        function International_Dialing_Code is
                new Ada.Unchecked_Conversion (Country, Integer);
    
    begin
        Put ("International Dialing Code for France is ");
        Put ( Integer'Image(International_Dialing_Code (France)) );
        New_Line;
    end Main;
    

17.2 Привязка объекта к фиксированному адресу памяти

В некоторых случаях может потребоваться выполнение чтения или записи по фиксированному абсолютному адресу памяти. Простым примером подобной ситуации может быть то, что операционная система MS-DOS хранит значение времени в фиксированных адресах памяти 46E и 46C (шестнадцатеричные значения). Более точная спецификация этих значений следующая:

Таким образом, для получения текущего времени необходимо осуществить привязку объекта к фиксированному адресу памяти. Для осуществления этого, можно привязать переменную Time_Hight типа Integer к фиксированному адресу 16#046E# следующим образом:

    
    
    Time_Hight_Address  : constant  Address := To_Address (16#046E#);
    
    type  Time  is range 0 .. 65365;
    for Time'Size use 16;
    
    Time_Hight  : Time;
    for Time_Hight'Address use Time_Hight_Address;
    

Следует заметить, что здесь, тип Time является беззнаковым 16-битным целым. Величина адреса 16#046E# должна иметь тип Address, который описывается в пакете System. Стандартная функция To_Address, которая выполняет преобразование целочисленного значения в значение адреса, описывается в пакете System.Storage_Elements.

17.3 Организация доступа к индивидуальным битам

Организацию доступа к индивидуальным битам можно рассмотреть на примере операционной системы MS-DOS, в которой фиксированный адрес памяти 16#0417# содержит состояние установок клавиатуры. Вид физического представления этого байта следующий:

7 6 5 4 3 2 1 0
Insert Caps
Lock
Num
Lock
Scroll
Lock
       

Пример следующей простой программы демонстрирует организацию доступа к индивидуальным битам, характеризующим состояние клавиатуры:

    
    
    with  Ada.Text_IO;              use   Ada.Text_IO;
    with  System.Storage_Elements;  use   System.Storage_Elements;
    
    procedure Keyboard_Status_Demo is
    
        Keyboard_Address  : constant Address := To_Address (16#0417#);
    
        type  Status  is  (Not_Active, Active);
        for   Status  use (Not_Active => 0, Active => 1);
        for   Status'Size  use 1;
    
        type  Keyboard_Status is
            record
                Scroll_Lock : Status;   -- состояние Scroll Lock
                Num_Lock    : Status;   -- состояние Num Lock
                Caps_Lock   : Status;   -- состояние Caps Lock
                Insert      : Status;   -- состояние Insert
            end record;
        for Keyboard_Status use
            record
                Scroll_Lock at 0 range 4..4;  -- бит 4
                Num_Lock    at 0 range 5..5;  -- бит 5
                Caps_Lock   at 0 range 6..6;  -- бит 6
                Insert      at 0 range 7..7;  -- бит 7
            end record;
    
        Keyboard_Status_Byte  : Keyboard_Status;
        for Keyboard_Status_Byte'Address use Keyboard_Address;
    
    begin
    
        if  Keyboard_Status_Byte.Insert = Active  then
            Put_Line("Insert mode ON");
        else
            Put_Line("Insert mode OFF");
        end if;
    
        if  Keyboard_Status_Byte.Caps_Lock = Active  then
            Put_Line("Caps Lock mode ON");
        else
            Put_Line("Caps Lock mode OFF");
        end if;
    
        if  Keyboard_Status_Byte.Num_Lock = Active  then
            Put_Line("Num Lock mode ON");
        else
            Put_Line("Num Lock mode OFF");
        end if;
    
        if  Keyboard_Status_Byte.Scroll_Lock = Active  then
            Put_Line("Scroll Lock mode ON");
        else
            Put_Line("Scroll Lock mode OFF");
        end if;
    
    end Keyboard_Status_Demo;
    

В данном примере, тип Status описан так, чтобы значения этого типа занимали ровно один бит. Далее, с используя тип Status, описывается тип записи Keyboard_Status, внутреннее представление которой соответствует физической структуре байта состояния клавиатуры.

Следует заметить, что спецификатор "Scroll_Lock at 0 range 4 .. 4" указывает, что объект Scroll_Lock должен быть размещен по нулевому смещению в четвертой битовой позиции записи Keyboard_Status (отсчет ведется в битах от начала записи).


Copyright (C) А.Гавва V-0.4w май 2004