Changes in union typedef aren't mirrored?

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.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
typedef union __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.
http://stackoverflow.com/questions/1812348/a-question-about-union-in-c
reading from a member of the union other than the one recently written to leads to undefined behaviour
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?

1
2
3
GRAPHREGS test;
test.DATA[8] = 0xFF;
print("%02X",test.REGISTERS.BITMASKREGISTER); //Still 0x00 instead of 0xFF 
Last edited on
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
Topic archived. No new replies allowed.