My bitfield below represents the 7 status flags for the 6502 CPU. I am trying to emulate the instruction php, which pushes a copy of the status flags onto the stack.
struct Flags {
uint8_t C: 1;
uint8_t Z: 1;
uint8_t I: 1;
uint8_t D: 1;
uint8_t V: 1;
uint8_t N: 1;
uint8_t B: 2;
};
I need a way to pack each field into a single-byte datatype like uint8_t so that I can push it to the stack. However, the code below gives this error: operand of type 'struct Flags' where arithmetic or pointer type is required. How do I resolve this problem?
int main() {
struct Flags f = {0, 0, 0, 0, 1, 0, 0};
uint8_t f_as_byte = (uint8_t) f;
}
The problem with bitfields is that it is implementation-defined in what order the bits are laid out. This could be rather unacceptable for a 6502 emulator. The PHP command must push the status word in the exact desired format, i.e. something like
uint8_t as_state = f.N << 7 | f.V << 6 | f.B << 4 | f.D << 3 | f.I << 2 | f.Z << 1 | f.C;
Your layout is wrong, the B member is in wrong position. All in all considering the complex code like one above, maybe it would be easier to just consider the flags as a single uint8_t and have access macros for it, something like
#define FLAG_N 0x80U
...
#define FLAG_C 0x1U
#define SET_FLAG(flag_var, flag) ((flag_var) |= (flag))
#define CLR_FLAG(flag_var, flag) ((flag_var) &= ~(flag))
#define GET_FLAG(flag_var, flag) ((_Bool)((flag_var) & (flag)))
uint8_t flags = 0;
SET_FLAG(flags, FLAG_C);
if (GET_FLAG(flags, FLAG_N)) { ... }
That way the PHP instruction can be coded to just push flags as is...
Except that the B flag that is pushed is not a flag from the status register...
You can do it with a union:
typedef unsigned char uint8_t;
struct Flags {
uint8_t C:1;
uint8_t Z:1;
uint8_t I:1;
uint8_t D:1;
uint8_t V:1;
uint8_t N:1;
uint8_t B:2;
};
union uFlags {
uint8_t B;
struct Flags F;
};
int
main()
{
struct Flags f = { 0, 0, 0, 0, 1, 0, 0 };
union uFlags u;
u.F = f;
uint8_t f_as_byte = u.B;
}
With a designated initializer, you may be able to initialize the union directly without a separate f:
typedef unsigned char uint8_t;
struct Flags {
uint8_t C:1;
uint8_t Z:1;
uint8_t I:1;
uint8_t D:1;
uint8_t V:1;
uint8_t N:1;
uint8_t B:2;
};
union uFlags {
uint8_t B;
struct Flags F;
};
int
main()
{
union uFlags u = {
.F = { .V = 1 }
};
uint8_t f_as_byte = u.B;
}
Instead of casting the structure as a (uint8_t), you should take its address and cast that as a (uint8_t *):
#include <stdio.h>
struct Flags {
uint8_t C: 1;
uint8_t Z: 1;
uint8_t I: 1;
uint8_t D: 1;
uint8_t V: 1;
uint8_t N: 1;
uint8_t B: 2;
};
int main() {
struct Flags f = {0, 0, 0, 0, 1, 0, 0};
uint8_t f_as_byte = *(uint8_t *)&f;
printf("flags: %.2X\n", f_as_byte);
return 0;
}
Note however that the actual bit values used to represent the bit-field members are implementation defined. The C Standard does not even guarantee that the Flags structure fit in a single byte. This make bit-fields a risky choice to represent hardware registers or instruction opcodes as a would make the emulator non-portable. Little-endian and big-endian systems typically use a different layout for bit-fields members.
Related
I know this question is asked tons of times, but I cannot seem to link it to my problem.
My problem is something to do with filling out a web of structs
Here is my buggy code
src\fpu.c:17:7: error: dereferencing pointer to incomplete type
cpu->instr.fpu.control = 0x37F;
^
This is the buggy code in a function
void fpuInit(struct emu_cpu *cpu) {
cpu->instr.fpu.control = 0x37F;
cpu->instr.fpu.status = 0;
cpu->instr.fpu.tag = 0xFFFF;
cpu->instr.fpu.lastDataPointer = 0;
cpu->instr.fpu.lastDataSeg = 0;
cpu->instr.fpu.lastIP = 0;
cpu->instr.fpu.lastIPseg = 0;
cpu->instr.fpu.opcode = 0;
}
Here is how the struct web looks like
cpu
struct emu_cpu
{
struct emu *emu;
struct emu_memory *mem;
uint32_t debugflags;
uint32_t eip;
uint32_t eflags;
uint32_t reg[8];
uint16_t *reg16[8];
uint8_t *reg8[8];
struct emu_instruction instr;
struct emu_cpu_instruction_info *cpu_instr_info;
uint32_t last_fpu_instr[2];
char *instr_string;
bool repeat_current_instr;
struct emu_track_and_source *tracking;
};
instruction
struct emu_instruction
{
uint16_t prefixes;
uint8_t opcode;
uint8_t is_fpu : 1;
union
{
struct emu_cpu_instruction cpu;
struct emu_fpu_instruction fpu;
};
struct
{
struct emu_tracking_info init;
struct emu_tracking_info need;
} track;
struct
{
uint8_t has_cond_pos : 1;
uint32_t norm_pos;
uint32_t cond_pos;
} source;
};
fpu struct
union FpuMmxRegister {
long double fp;
unsigned char b[10]; //only use 8 of these for mmx
unsigned short s[4];
unsigned int i[2];
unsigned long long ll;
};
struct emu_fpu_instruction
{
uint16_t prefixes;
uint8_t fpu_opcode;
//uint8_t fpu_modrm;
struct /* mod r/m data */
{
union
{
uint8_t mod : 2;
uint8_t x : 2;
};
union
{
uint8_t reg1 : 3;
uint8_t opcode : 3;
uint8_t sreg3 : 3;
uint8_t y : 3;
};
union
{
uint8_t reg : 3;
uint8_t reg2 : 3;
uint8_t rm : 3;
uint8_t z : 3;
};
struct
{
uint8_t scale : 2;
uint8_t index : 3;
uint8_t base : 3;
} sib;
union
{
uint8_t s8;
uint16_t s16;
uint32_t s32;
} disp;
uint32_t ea;
} fpu_modrm;
//uint32_t ea;
uint16_t control;
uint16_t status;
uint16_t tag;
uint32_t lastIP;
uint32_t lastIPseg;
uint32_t lastDataPointer;
uint32_t lastDataSeg;
uint16_t opcode;
uint32_t last_instr;
union FpuMmxRegister r[8];
};
Tell me what I am doing wrong thank you
Just so you know they are all wrong in that starting function
src\fpu.c:17:7: error: dereferencing pointer to incomplete type
cpu->instr.fpu.control = 0x37F;
^
src\fpu.c:18:7: error: dereferencing pointer to incomplete type
cpu->instr.fpu.status = 0;
^
src\fpu.c:19:7: error: dereferencing pointer to incomplete type
cpu->instr.fpu.tag = 0xFFFF;
^
src\fpu.c:20:7: error: dereferencing pointer to incomplete type
cpu->instr.fpu.lastDataPointer = 0;
^
src\fpu.c:21:7: error: dereferencing pointer to incomplete type
cpu->instr.fpu.lastDataSeg = 0;
^
src\fpu.c:22:7: error: dereferencing pointer to incomplete type
cpu->instr.fpu.lastIP = 0;
^
src\fpu.c:23:7: error: dereferencing pointer to incomplete type
cpu->instr.fpu.lastIPseg = 0;
^
src\fpu.c:24:7: error: dereferencing pointer to incomplete type
cpu->instr.fpu.opcode = 0;
^
Your definition of struct emu_cpu is not visible at the point of definition of function fpuInit. For this reason all references to struct emu_cpu in fpuInit definition are seen as forward declarations of a new, incomplete type.
If your struct emu_cpu is defined in a header file, make sure it is included into the file that defines fpuInit.
Anonymous unions are only allowed at the end of a structure tree:
In
a->b.c.d =
d can be an anonymous ( without name ) struct or union,
b and c can't, and need to have names.
Reference: **Are "anonymous structs" standard? And, really, what *are* they? **
I have some mpeg ts bitfields, for example transport stream package:
struct ts_package_header_s {
unsigned int continuity_counter :4;
unsigned int adaptation_field_control :2;
unsigned int transport_scrambling_control :2;
unsigned int PID :13;
unsigned int transport_priority :1;
unsigned int payload_unit_start_indicator :1;
unsigned int transport_error_indicator :1;
unsigned int sync_byte :8;
};
struct ts_package_s {
struct ts_package_header_s ts_header;
unsigned char ts_body[TS_BODY];
};
union ts_package_u {
struct ts_package_s ts_package;
unsigned char bytes[TS_PACKAGE];
};
In my source code I initialize header struct:
pat_package_header.sync_byte = 0x47;
pat_package_header.transport_error_indicator = 0;
pat_package_header.payload_unit_start_indicator = 1;
pat_package_header.transport_priority = 0;
pat_package_header.PID = PAT_PID;
pat_package_header.transport_scrambling_control = 0;
pat_package_header.adaptation_field_control = 1;
pat_package_header.continuity_counter = 0;
And than I make ts_packag union
union ts_package_u package;
package.ts_package.ts_header = pat_package_header;
Than I fill ts_body array.
When I write this package to file. I get backwards array:
10 00 40 47 XX XX XX.. instead of 47 40 10 00 XX XX XX..
I tried to cast my struct to char* instead of using union, but got same result.
Where is fault? Thanks.
It's dangerous to use try and serialise structs like this directly to disk where the format must be known across different architectures, or use different compilers.
Compilers differ in how they store bitfields and the underlying endianess of your architecture also changes how the data is stored
For example, it could be that a compiler chooses to align bitfields on byte, word or some other boundary. It's a compiler decision. It may also choose to save the bits in any order, which usually depends on the endianess of your machine.
In order to safely write this header to disk, you need to serialise the data yourself. The header is 32-bit and Big Endian according to Wikipedia.
So for example:
#include <stdio.h>
#define TS_BODY 1024
#define PAT_PID 0x40
struct ts_package_header_s {
unsigned int continuity_counter :4;
unsigned int adaptation_field_control :2;
unsigned int transport_scrambling_control :2;
unsigned int PID :13;
unsigned int transport_priority :1;
unsigned int payload_unit_start_indicator :1;
unsigned int transport_error_indicator :1;
unsigned int sync_byte :8;
};
struct ts_package_s {
struct ts_package_header_s ts_header;
unsigned char ts_body[TS_BODY];
};
static void write_ts( struct ts_package_s pat_package )
{
FILE* f = fopen( "test.ts", "wb+" );
unsigned int header = 0;
if( f == NULL )
return;
header = pat_package.ts_header.sync_byte << 24;
header |= ( pat_package.ts_header.transport_error_indicator << 23 );
header |= ( pat_package.ts_header.payload_unit_start_indicator << 22 );
header |= ( pat_package.ts_header.transport_priority << 21 );
header |= ( pat_package.ts_header.PID << 8 );
header |= ( pat_package.ts_header.transport_scrambling_control << 6 );
header |= ( pat_package.ts_header.adaptation_field_control << 4 );
header |= ( pat_package.ts_header.continuity_counter );
/* Write the 32-bit header as big-endian */
unsigned char byte = header >> 24;
fwrite( &byte, 1, 1, f );
byte = ( header >> 16 ) & 0xFF;
fwrite( &byte, 1, 1, f );
byte = ( header >> 8 ) & 0xFF;
fwrite( &byte, 1, 1, f );
byte = header & 0xFF;
fwrite( &byte, 1, 1, f );
fclose( f );
}
int main( int argc, char* argv[] )
{
struct ts_package_s pat_package;
pat_package.ts_header.sync_byte = 0x47;
pat_package.ts_header.transport_error_indicator = 0;
pat_package.ts_header.payload_unit_start_indicator = 1;
pat_package.ts_header.transport_priority = 0;
pat_package.ts_header.PID = PAT_PID;
pat_package.ts_header.transport_scrambling_control = 0;
pat_package.ts_header.adaptation_field_control = 1;
pat_package.ts_header.continuity_counter = 0;
write_ts( pat_package );
return 0;
}
Writes a file with the following header:
0x47 0x40 0x01 0x10
which appears to be correct according to the values you're using.
I am trying to create .bmp file (filled with one colour for testing purposes).
Here is code that I'm using:
#include <stdio.h>
#define BI_RGB 0
typedef unsigned int UINT;
typedef unsigned long DWORD;
typedef long int LONG;
typedef unsigned short WORD;
typedef unsigned char BYTE;
typedef struct tagBITMAPFILEHEADER {
UINT bfType;
DWORD bfSize;
UINT bfReserved1;
UINT bfReserved2;
DWORD bfOffBits;
} BITMAPFILEHEADER;
typedef struct tagBITMAPINFOHEADER {
DWORD biSize;
LONG biWidth;
LONG biHeight;
WORD biPlanes;
WORD biBitCount;
DWORD biCompression;
DWORD biSizeImage;
LONG biXPelsPerMeter;
LONG biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;
} BITMAPINFOHEADER;
typedef struct COLORREF_RGB
{
BYTE cRed;
BYTE cGreen;
BYTE cBlue;
}COLORREF_RGB;
int main(int argc, char const *argv[])
{
BITMAPINFOHEADER bih;
bih.biSize = sizeof(BITMAPINFOHEADER);
bih.biWidth = 600;
bih.biHeight = 600;
bih.biSizeImage = bih.biWidth * bih.biHeight * 3;
bih.biPlanes = 1;
bih.biBitCount = 24;
bih.biCompression = BI_RGB;
bih.biXPelsPerMeter = 2835;
bih.biYPelsPerMeter = 2835;
bih.biClrUsed = 0;
bih.biClrImportant = 0;
COLORREF_RGB rgb;
rgb.cRed = 0;
rgb.cGreen = 0;
rgb.cBlue = 0;
BITMAPFILEHEADER bfh;
bfh.bfType = 0x424D;
bfh.bfReserved1 = 0;
bfh.bfReserved2 = 0;
bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + bih.biSize;
bfh.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) +
bih.biWidth * bih.biHeight * 4;
FILE *f;
f = fopen("test.bmp","wb");
fwrite(&bfh, sizeof(BITMAPFILEHEADER), 1, f);
fwrite(&bih, sizeof(BITMAPINFOHEADER), 1, f);
int i,j;
for(i = 0; i < bih.biHeight; i++)
{
for(j = 0; j < bih.biWidth; j++)
{
fwrite(&rgb,sizeof(COLORREF_RGB),1,f);
}
}
fclose(f);
return 0;
}
and jet every time I compile and run it I get error saying that its not valid BMP image. I double checked all values in multiple references and still can't find error here.
Did I misunderstood something and what am I doing wrong here?
Also not sure if important but I am using Ubuntu 14.04 to compile this.
EDIT
Found one more issue :
bfh.bfType = 0x424D;
should be
bfh.bfType = 0x4D42;
But still can't see image.
First of all, you set:
bfSize Specifies the size of the file, in bytes.
to invalid value, your code resulted into 1440112 while size of file is actually 1080112
bfh.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) +
bih.biWidth * bih.biHeight * sizeof(COLORREF_RGB);
Because sizeof(COLORREF_RGB) is actually 4 not 3.
Another mistake is that size of your structs and types:
expected size actual size*
typedef unsigned int UINT; // 2 4
typedef unsigned long DWORD; // 4 8
typedef long int LONG; // 4 8
typedef unsigned short WORD; // 2 2
typedef unsigned char BYTE; // 1 1
* I'm using gcc on x86_64 architecture
Your offsets just don't match with offsets on wikipedia, reference you are using was probably written for 16 bit compiler on 16 bit OS (as pointed out by cup in a comment) so it assumes int to be 2B type.
Using values from stdint.h worked for me (guide on stdint.h for Visual Studio here):
#include <stdint.h>
typedef uint16_t UINT;
typedef uint32_t DWORD;
typedef int32_t LONG;
typedef uint16_t WORD;
typedef uint8_t BYTE;
And last but not least you have to turn off memory alignment as suggested by Weather Vane.
I believe your field sizes to be incorrect, try this
#pragma pack(push, 1)
typedef struct tagBITMAPFILEHEADER {
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
} BITMAPFILEHEADER;
#pragma pack(pop)
You are trying to map a C structure to some externally-defined binary format There are a number of problems with this:
Size
typedef unsigned int UINT;
typedef unsigned long DWORD;
typedef long int LONG;
typedef unsigned short WORD;
typedef unsigned char BYTE;
The C language only specify the minimum sizes of these types. Their actual sizes can and do vary between different compilers and operating systems. The sizes and offset of the members in your structures may not be what you expect. The only size that you can rely on (on almost any system that you are likely to encounter these days) is char being 8 bits.
Padding
typedef struct tagBITMAPFILEHEADER {
UINT bfType;
DWORD bfSize;
UINT bfReserved1;
UINT bfReserved2;
DWORD bfOffBits;
} BITMAPFILEHEADER;
It is common for DWORD to be twice as large as a UINT, and in fact your program depends on it. This usually means that the compiler will introduce padding between bfType and bfSize to give the latter appropriate alignment for its type. The .bmp format has no such padding.
Order
BITMAPFILEHEADER bfh;
bfh.bfType = 0x424D;
...
fwrite(&bfh, sizeof(BITMAPFILEHEADER), 1, f);
Another problem is that the C language does not specify the endianess of the types. The .bfType member may be stored as [42][4D] (Big-Endian) or [4D][42] (Little-Endian) in memory. The .bmp format specifically requires the values to be stored in Little-Endian order.
Solution
You might be able to solve some of these problems by using compiler-specific extensions (such as #pragma's or compiler switches), but probably not all of them.
The only way to properly write an externally-defined binary format, is to use an array of unsigned char and write the values a byte at a time. Personally, I would write a set of helper functions for specific types:
void w32BE (unsigned char *p, unsigned long ul)
{
p[0] = (ul >> 24) & 0xff;
p[1] = (ul >> 16) & 0xff;
p[2] = (ul >> 8) & 0xff;
p[3] = (ul ) & 0xff;
}
void w32LE (unsigned char *p, unsigned long ul)
{
p[0] = (ul ) & 0xff;
p[1] = (ul >> 8) & 0xff;
p[2] = (ul >> 16) & 0xff;
p[3] = (ul >> 24) & 0xff;
}
/* And so on */
and some functions for writing the entire .bmp file or sections of it:
int function write_header (FILE *f, BITMAPFILEHEADER bfh)
{
unsigned char buf[14];
w16LE (buf , bfh.bfType);
w32LE (buf+ 2, bfh.bfSize);
w16LE (buf+ 6, bfh.bfReserved1);
w16LE (buf+ 8, bfh.bfReserved2);
w32LE (buf+10, bfh.bfOffBits);
return fwrite (buf, sizeof buf, 1, f);
}
So i have 2 structs:
struct cmd {
uint8_t a;
uint8_t b;
uint8_t c;
};
typedef struct someName{
uint8_t size;
struct cmd cmdID;
} someName_t;
And i got a char res[0] containing the string "0xabc".
This 0xabc need to be put inside the cmd struct.
But the problem is 0xabc is 12 bit (1010 1011 1100) so if i put this into the struct with only uint8_t a and uint8_t b it will work because it will "fit" into 16 bits. But i got uint8_t a, uint8_t b and uint8_t c so 24 bits and that is my problem..
I tried:
someName_t msg;
sscanf(res[0], "0x%x", &(msg.cmdID));
But this does not work. This does work however if i remove the uint8_t c variable from the struct because it then fits inside the remaining 16 bits..
So how can i get the value "0xabc" into this (24bit) struct without adjusting the struct.
If you have control of your input format, i.e. you can guarantee it will always be something like 0xabc, then you can try:
const char input[] = "0xabc";
uint32_t tmp;
sscanf(input, "0x%x", &tmp);
struct cmd cmdid;
cmdid.a = (tmp & 0xFF0000U) >> 16;
cmdid.b = (tmp & 0xFF00U) >> 8;
cmdid.c = (tmp & 0xFFU);
You could try changing struct cmd to:
struct cmd {
unsigned int c:4;
unsigned int b:4;
unsigned int a:4;
};
But YMMV depending on compiler. Works OK on MSVC++ 2010.
I have this structure representing a generic message
typedef struct {
uint16_t length;
uint8_t type1;
uint8_t type2;
uint8_t *data;
} generic_msg_t;
After reading type1 and type 2 I can know to which specific message it corresponds, for example this one:
typedef struct {
uint16_t length;
uint8_t type1;
uint8_t type2;
uint16_t a;
uint8_t b;
uint8_t c;
double d;
double e;
double f;
double g;
double h;
uint8_t i;
} specific_msg_t;
Supposing msg contains verified data, I would like to understand why if I do this I can not access to d, e, f, g, h data (but well a, b, c)
specific_msg_t * specific_msg = (specific_msg_t *) msg;
uint16_t a = specific_msg->a; //OK
double d = specific_msg->d; //NOK`
I have to do instead:
unsigned char * buffer = (unsigned char *) msg;
double d = buffer[15] + (buffer[14] << 8) + (buffer[13] << 16) + (buffer[12] << 24) + (buffer[11] << 32) + (buffer[10] << 40) + (buffer[9] << 48) + (buffer[8] << 56);`
specific_msg_t has potentially different alignment requirements than generic_msg_t so on some architectures, that code could result in a crash - the compiler has no particular requirement to align a generic_msg_t object on a boundary suitable for accessing a double.
It would help to know exactly what error you're getting though.
As long as the sender and receiver use the same headers (uint16_t is the same for both of them) and both of them use the same architecture (e.g. x86 or whatever) there shouldn't be too many problems.
I would also define a union with all the specific message types that you need, in order to avoid those nasty calculations and most of the casts.
Something similar to this:
typedef struct {
uint16_t length;
uint8_t type1;
uint8_t type2;
// whatever you need here...
double a;
float b;
// etc.
} specific_msg_t1;
typedef struct {
uint16_t length;
uint8_t type1;
uint8_t type2;
uint16_t a;
uint8_t b;
uint8_t c;
double d;
double e;
double f;
double g;
double h;
uint8_t i;
} specific_msg_t2;
typedef struct
{
uint16_t length;
uint8_t type1;
uint8_t type2;
} selector_msg_t;
typedef union
{
selector_msg_t selector;
specific_msg_t1 msgtype1;
specific_msg_t2 msgtype2;
} message_type_t;
With this setup you could be sending messages of type "message_type_t". Use the member "selector" to decide which specific type of message you received and then use the appropriate specific type to read the different data members.
If the size difference is considerable between the specific types, then it is a bad idea, but if you're not limited by bandwidth then it's at least readable and not that error prone.