On another note: have you considered the field and record alignment options that the compiler offers ? (I would like to test myself but unfortunately my agenda is a bit crowded atm). (*)
fwiw I especially like the anonymous embedding as that is really a lacking feature.
(*) By that initially I meant the actual layout in memory. The language construct themselves can be added if not (properly) supported right now.
On a technical level this just adds a (hidden if unnamed) field to the record of that type you composite. So if you compsite another record the record field will be aligned as per alignment rules of the parent record ($PACKRECORDS, packed or bitpacked), while the elements of the child record are internally aligned according to the internal record packing:
{$PACKRECORDS C}
TTest = record // Packed according to PACKRECORDS C
...
using packed record // non aligned because of the "packed" keyword
...
end;
...
end;
So from that perspective it does not change anything about the packing rules, it's just syntactic sugar that rather than writing x.child.foo you can just write x.foo.
You make your case very well. But strictly as a matter or curiosity, when you do LD A -> (BC), does A go into B, or C, or perhaps both, or perhaps one or the other depending on whether the "BigEndian" switch is on or off? And if A goes into B, is C left alone, or set to zero?
The programmer knows the answers having the manual ready to hand and probably memorized after long hours of work. But the reader might not. And that makes me wonder if there isn't a better way to represent the case (in general, not just in this one example)?
Don't get me started on endianess for the emulator, in the Gameboy Manual it is very confusing on this, and without code examples I probably wouldn't have figured out myself.
But basically yes, this is just some syntactic sugar around variant records, so endianess and all that other stuff effects the definition of the types. You probably need something like this:
TAFRecord = record
case Boolean of
True: (AF: Word);
{$IfDef LittleEndian}
False: (A, F: Byte);
{$Else}
False: (F, A: Byte);
{$EndIf}
end;
...
TCPURegs = record
uses TAFRecord;
uses TBCRecord;
...
end;
But this is the sort of stuff that you get always in contact with when doing low level programming. I think there isn't a good solution for that problem, basically you will always have to write things twice if you are going to handle different endianess. Personally, as I usually only write software for modern x86_64 CPUs, I just don't care and always assume little endian. When I'm feeling extra secure I may add something like:
{$IfNDef LittleEndial}
{$Error Currently only works on Little Endian architectures}
{$EndIf}