I'm attempting to write a Gameboy emulator in C, and am currently in the process of deciding how to implement the following behavior:
For example, registers A and F, which are 8-bit registers, can be used jointly as the 16-bit register AF. However when the contents of registers A and F change, these changes should be reflected in subsequent referrals to register AF.
If I implement register AF as a uint16_t*
, can I store the contents of registers A and F as uint8_t*
's pointing to the first and second byte of register AF respectively? If not, any other suggestions would be appreciated :)
EDIT: Just to clarify, this is a very similar architecture to the Z80
Use a union.
union b
{
uint8_t a[2];
uint16_t b;
};
The members a and b share the bytes. When a value is written in member a
and then read using member b
the value is reinterpreted in this type. This could be a trap representation, which would cause undefined behavior, but types uint8_t and uint16_t don't have them.
Another issue is endianness, writing into the first element of member a
will always change the first byte of member b
, but depending on endianness that byte might represent most or least significant bits of b
, so the resulting value will differ over architectures.
To avoid trap representations and endianness, rather only use the type uint16_t
and write into it using bitwise operations. For example, to write into the most significant 8 bits:
uint16_t a = 0;
uint8_t b = 200;
a = ( uint16_t )( ( ( unsigned int )a & 0xFF ) | ( ( unsigned int )b << 8 ) ) ;
and similarly for the least significant 8 bits:
a = ( uint16_t )( ( ( unsigned int )a & 0xFF00 ) | ( unsigned int )b );
These operations should be put into a function.
The casts to ( unsigned int )
are there to avoid integer promotions. If INT_MAX
equals 2^15-1, and there are trap representations for signed integers, then the operation: b << 8
could technically cause undefined behavior.