I'm having difficultly understanding Ada's type system. Coming from C/C++ it's I have a hard time grasping it type syntax and its polymorphism. I would like to create an abstract register class which can have 2 to 8 bytes of data storage:
package CPU is
pragma Preelaborate;
type Registers is array(0..4) of Register;
type DeviceId is range 0..6;
-- a register can be anywhere from 2 to 8 bytes
type Byte_Array is array (1 .. 8) of Byte;
type Register is record
Data: Byte_Array;
end record;
type IORegiser is new Register(1..2) with record
Address : Byte;
Busy : Boolean;
Error : Boolean;
Id : DeviceId;
end record;
for IORegiser use record
Address at 0 range 0..7;
Busy at 1 range 0..1;
Error at 1 range 2..2;
Id at 1 range 3..8;
end record;
end CPU;
Based on this abstraction, I want to create a standard register class where its data has no format and another register class where its data is formatted into fields:
A : Register := 16; -- put the number 16 in the register.
IOReg : IORegister (Address => #16#0011#, Busy => true, Error => false, Id => #16#0011#);
B : LongRegister; -- an 8 byte register
CPURegs : Registers := (A, IOReg, B); -- Array of registers
Also, standard Registers classes store data in several different fixed sizes. In C++, I would use a union, but it's unclear how to implement it in Ada.
Edits: Removing the use of tagged types.
Unformatted records of various sizes can be implemented as modular types such as
type U8 is mod 2**8;
type U16 is mod 2**16;
type U32 is mod 2**32;
type U64 is mod 2**64;
A register type for a 16 bit unformatted record is therefore
type Unformatted_16 is record with
Data : U16 := 0;
end record;
The beauty of using a modular type for the unformatted 16-bit register is the fact that the value assigned to the register can never overflow the register. The same modular arithmetic behavior is found in all Ada modular types.
Similarly your IORegister type could be the following on a machine with a 16 bit word size:
type IORegister is record with record
Address : U8;
Busy : Boolean;
Error : Boolean;
Id : DeviceId;
end record;
for IORegister use record
Address at 0 range 0..7;
Busy at 0 range 8..9;
Error at 0 range 10..10;
Id at 0 range 11..15;
end record;
An array four bytes is not the same as a 32-bit integer. Ada representation clauses deal with the word number and the bit offset from the start of the word. In the example above with a 16 bit word all offsets are from word 0.