Как получить доступ к адресам памяти непосредственно в Аде?

Итак, я новичок в Аде и пытаюсь написать на ней ядро, но не могу найти никакой хорошей информации о том, как это сделать правильно. В C я бы написал:

unsigned char* videoram = (char*) 0xB8000;
videoram[0] = 65;

для прямого доступа к видеопамяти и записи в нее «a». Я слышал, что мне нужно использовать массив Ada и другие прагмы, чтобы сделать это безопасным способом в Ada. Есть ли хорошие ресурсы по такому программированию на Аде?


person MarkHammons    schedule 30.05.2012    source источник
comment
Еще одна мысль об ответе oenones (и моем вкладе) - если вы выполняете только обработку текста и знаете свои границы экрана, вы можете определить свой массив как двумерный массив и иметь возможность прямого доступа к позициям строк и столбцов без расчета смещения памяти каждый время. (просто будьте осторожны в отношении основных проблем со строками или столбцами (что на первом месте и как это соотносится с вашим сегментом памяти))   -  person NWS    schedule 30.05.2012


Ответы (3)


Вы можете использовать атрибут 'Address:

Videoram : String (1 .. Videoram_Size);
for Videoram'Address use 16#B8000#;
-- ...
Videoram (1) := 'a';

Если вы не хотите использовать строки и символы, вы можете определить свои собственные типы данных, например:

type Byte is mod 2**8; -- unsigned char
type Byte_Array is array (Natural range <>) of Byte;
Videoram : Byte_Array (0 .. Videoram_Size - 1);
for Videoram'Address use 16#B8000#;
-- ...
Videoram (0) := 65;

Кстати, вы даже получаете проверку диапазона для индекса, поэтому вы не можете писать за пределами диапазона Videoram.

person Rommudoh    schedule 30.05.2012
comment
Есть ли безопасный способ определить 2-байтовый тип, где первый байт является символом, а второй - цветным байтом? Потому что это фактический формат видеопамяти для каждого символа. - person MarkHammons; 30.05.2012
comment
@MarkHammons Я немного сбит с толку. Вы имели в виду, что видеопамять занимает пару символов? (Последний раз, когда я проверял, байт был размером с символ!) - person NWS; 30.05.2012
comment
@NWS да, на символ видеорамка занимает пару байтов. Первый байт — это фактический символ, а второй байт определяет цвет фона и переднего плана. Например, 0x00 — это черный на черном. В C videoram[0] = 65; видеорам[1] = 0x00; видеорам[2] = 66; видеорам[3] = 0x00; печатает ab черным цветом на черном фоне. - person MarkHammons; 30.05.2012
comment
вы можете использовать для этого запись и указать макет записи с помощью пункта представления записи, описанного в RM 13.5.1, и, возможно, определить «размер до 2 * 2 ** 8». - person Rommudoh; 30.05.2012
comment
Большое спасибо, это очень интересно. - person MarkHammons; 30.05.2012
comment
@MarkHammons: (с 16-битными символами все в порядке!) oenone верен, массив записей с использованием предложения представления - это путь. См. это для примера того, как делать предложения представления. Таким образом, вы можете определить тип записи с элементами для символа, цвета переднего плана и цвета фона, указав битовые позиции для каждого из них, определить их массив и установить начало массива, как предложено. - person NWS; 30.05.2012

Если вы используете атрибут адреса (т. е. для Object'Address используйте ...), вы должны использовать функцию To_Address(), найденную в System.Storage_Elements, потому что тип Address не обязательно должен быть целым числом. В Справочном руководстве Ады говорится только:

"Адрес - это определенный, неограниченный тип с предустановленной инициализацией"

Принимая во внимание, что для типа Integer_Address в System.Storage_Elements указано:

«Integer_Address — целочисленный подтип (подписанный или модульный). To_Address и To_Integer выполняют преобразование между этим типом и адресом».

Итак, вы действительно должны использовать:

для адреса объекта используйте To_Address (16#B8000#);

И последнее, на что следует обратить внимание в ответе T.E.D: если вас беспокоит инициализация объекта с помощью этого метода, просто добавьте прагму Import(Ada, your_object) после объявления, чтобы инициализация по умолчанию подавлялась.

person Micronian Coder    schedule 31.05.2012
comment
Вероятно, это можно было бы сделать в качестве комментариев к двум другим ответам. Однако вы новичок и можете использовать репутацию, так что +1 вам. :-) - person T.E.D.; 01.06.2012

На самом деле есть два пути.

Один из них — установить указатель на адрес, который вы хотите использовать, и получить доступ к объекту через указатель.

type Video_RAM_Pointer is access all My_Video_Ram_Struct;
package Convert is new System.Address_To_Access_Conversions (Video_RAM_Pointer);
Video_RAM : constant Video_RAM_Pointer := Convert.To_Access (16#B8000#);

Другой — наложить ваши данные прямо поверх местоположения.

Video_RAM : My_Video_RAM_Struct;
for Video_RAM'address use at 16#B8000#;

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

Метод указателя просто говорит компилятору предположить, что данный адрес содержит структуру, которую вы ему сказали, что, ИМХО, именно то, что вы хотите.

person T.E.D.    schedule 30.05.2012
comment
Это должен быть Convert.To_Pointer, а параметр, передаваемый в initialiseSystem.Address_To_Access_Conversions, должен быть базовым типом, а не типом доступа. Кроме того, я почти уверен, что это должно быть Video_RAM : constant Convert.Object_Pointer... Это единственный способ заставить этот код компилироваться с использованием GNAT и ориентироваться на ada2012. - person ajxs; 22.04.2019