Question

So I'm new to Ada, and I'm attempting to write a kernel in it, but I cannot seem to find any good information on how to do this properly. In C, I would write:

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

to access the video ram directly and write 'a' to it. I've heard I need to use an Ada array and other pragma's to do this in a typesafe manner in Ada. Is there any good resources on this kind of Ada programming?

Was it helpful?

Solution

You can use the 'Address attribute:

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

If you don't want to use String and Characters, you can define your own data types.. like:

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;

Btw, you even get range checking for the index, so you can't write outside of the Videoram range.

OTHER TIPS

If you use an address attribute (i.e. for Object'Address use ... ), you should use the To_Address() function found in System.Storage_Elements because the Address type doesn't have to be an integer. The Ada Reference Manual only states:

"Address is a definite, nonlimited type with preelaborable initialization"

Whereas for the Integer_Address type in System.Storage_Elements it states:

"Integer_Address is a (signed or modular) integer subtype. To_Address and To_Integer convert back and forth between this type and Address."

So, you should really use:

for Object'Address use To_Address( 16#B8000# );

One last thing to point out from T.E.D's answer is that if you are concerned about object initialization using this method, simply add a pragma Import( Ada, your_object ) after the declaration so that default initialization is suppressed.

There are actually two ways.

One is to set a pointer to the address you want to use, and access the object via the pointer.

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#);

The other is to overlay your data right on top of the location.

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

Generally, I prefer using the former. Among other issues, the latter counts as a declaration, which means that any fields in My_Video_RAM_Struct that have initialization code will get reinitialized every time you declare your overlay. Additionally, it is tempting to folks to overuse (abuse) that feature to alias objects all over the place, which is both hard on the optimizer and hard on the maintanence programmer.

The pointer method just tells the compiler to assume the given address holds the structure you told it, which IMHO is exactly what you want to happen.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top