I have made VGA emulation with registers and memory in my emulator. But for some reason the writes to the union array with CPU data (register 0-8 of the VGA's Graphics Controller Registers, referenced with <GRAPHREGS>.DATA[index]) don't reflect on the union's data.
typedefunion __attribute__((packed))
{
byte DATA[9]; //9 registers present!
struct //Contains the registers itself!
{
//Set/Reset Register (index 00h)
union
{
struct
{
byte SetReset : 4; //Set/reset!
byte notused1 : 4; //Not used
};
byte SetResetFull; //Full Set/Reset register!
} SETRESETREGISTER;
//Enable Set/Reset register (index 01h)
union
{
struct
{
byte EnableSetReset : 4; //Set/reset!
byte notused2 : 4; //Not used
};
byte EnableSetResetFull; //Full Set/Reset register!
} ENABLESETRESETREGISTER;
//Color Compare register (index 02h)
union
{
struct
{
byte ColorCompare : 4; //Set/reset!
byte notused3 : 4; //Not used
};
byte ColorCompareFull; //Full Set/Reset register!
} COLORCOMPAREREGISTER;
//Data Rotate Register register (index 03h)
union
{
struct
{
byte RotateCount : 3; //Rotate count!
byte LogicalOperation : 2; //Logical operation!
byte notused4 : 3; //Not used
};
byte DataRotateFull; //Full Set/Reset register!
} DATAROTATEREGISTER;
//Read Map Select Register (index 04h)
union
{
struct
{
byte ReadMapSelect : 2; //Active memory plane for CPU (at location for VRAM)!
byte notused5 : 6;
};
byte ReadMapSelectRegisterFull; //Full register!
} READMAPSELECTREGISTER;
//Graphics Mode Register (Index 05h)
union
{
struct
{
byte WriteMode : 2;
byte notusedgraphics2 : 1;
byte ReadMode : 1;
byte Host_OE : 1;
union
{
struct
{
byte ShiftRegisterInterleaveMode : 1; //Shift Register interleave mode (4 colors), else 4-bits (16 colors).
byte Color256ShiftMode : 1; //1=support for 256-color, 0=Use Above bit.
}; //What sequencer mode?
byte ShiftRegister : 2; //What shift mode?
};
byte notusedgraphics7 : 1;
};
byte GraphicsModeRegisterFull; //Full register!
} GRAPHICSMODEREGISTER;
union
{
struct
{
byte AlphaNumericModeDisable : 1; //1 for graphics, 0 for text-mode.
byte EnableOddEvenMode : 1; //1 for enabled, 0 for disabled.
byte MemoryMapSelect : 2; //Where display memory resides in MMU:
/*
00b = A0000-BFFFFh (128k region)
01b = A0000-AFFFFh (64k region)
02b = B0000-B7FFFh (32k region)
03b = B8000-BFFFFh (32k region)
*/
byte notusedmisc : 4; //Unused!
};
byte MiscellaneousGraphicsRegister;
} MISCGRAPHICSREGISTER;
union
{
struct
{
byte ColorDontCare0 : 1; //Plane 0: We care about this color?
byte ColorDontCare1 : 1; //Plane 1: We care about this color?
byte ColorDontCare2 : 1; //Plane 2: We care about this color?
byte ColorDontCare3 : 1; //Plane 3: We care about this color?
byte notused7 : 4;
};
byte ColorCare; //We care about these colors?
} COLORDONTCAREREGISTER;
byte BITMASKREGISTER; //Bit Mask Register (index 08h)
} REGISTERS; //The registers itself!
} GRAPHREGS; //Graphics registers!
Anyone knows what's going wrong? Have I made an error in the registers? (In this case I write to register <GRAPHREGS>.DATA[8] (which should be the <GRAPHREGS>.REGISTERS.BITMASKREGISTER)), but the BITMASKREGISTER stays 0, while DATA[8] gets the correct value.
But shouldn't .DATA[8] correspond to .REGISTERS.BITMASKREGISTER? They're both the 9th byte in memory, with the union specifying they start at the same memory address? (.REGISTERS and .DATA should share 9 bytes of memory, or not?), so if I would take .REGISTERS as a seperate typedef pointing to &.DATA[0] it should have the same effect as this union? Or should the data within .REGISTERS be reversed?
But shouldn't .DATA[8] correspond to .REGISTERS.BITMASKREGISTER?
You might think so, and in practice that's how it probably would be implemented but as ne55 said: According to the C++ standard, you are invoking undefined behavior in doing so.
Many compilers (gcc for example), extend the language by defining the behavior in this case. I think the problem here is that you expect the union inside graphics mode register to somehow occupy 2 bits. Only bit fields can be less than a byte, not stricts or unions