Forums

Sega Master System / Mark III / Game Gear
SG-1000 / SC-3000 / SF-7000 / OMV
Home - Forums - Games - Scans - Maps - Cheats - Credits
Music - Videos - Development - Hacks - Translations - Homebrew

View topic - Great way to simulate bits in C

Reply to topic
Author Message
Chris
  • Guest
Reply with quote
Great way to simulate bits in C
Post Posted: Wed Jul 14, 1999 7:35 am
Now, I don't know if this is the best way but I really think this is an easy and un-complicated way to
simulate bits in C. Eric Quinn showed me a technique of nesting structures inside of unions to easily
manipulate internal structural data with an external variable while at the same time being able
to manipulate internal data without re-writing everything else. Here's the code he tought me to
simulate a Z80 register pair, such as AF or BC:

typedef union {
typedef struct {
byte low;
byte high;
} REG8;
word REG16;
} REGPAIR;

Now, say you declared the Z80 register pair HL. Register L would be represented as low and register
H would be represented as high. Everyone knows that unions re-write over everything else because
that's their purpose. But from what Marat's sources have and what Eric explained everything ties
together perfectly. You can change registers H or L without them writing over each other and the
values of low and high are always linked together inside REG16, which would be like saying HL.
Ok. Now that things have been clarifyed (*gulp* I hope), I was flipping though my C book and a
found a technique that will let you simulate bits. You definine integral variables that represent
bits inside of a structure. Here's an example:

struct {
int bit1: 1;
int bit2: 1;
int bit3: 1;
int bit4: 1;
int bit5: 1;
int bit6: 1;
int bit7: 1;
int bit8: 1;
} byte;

Oh, I forgot to mention that the : 1 is used to define how many bits large the variable will be. Since were
simulating individual bits I declared all bit varaibles 1 bit size. So, if you want to change the status of
bit position 4, you would simply type:

byte.bit4 = 0;

Damn, one more thing. If you need to set the bit you make it equal 1. If you need to reset it's value
give it 0. If you want to solve confusion problems later on down the line, either in your header or
main code, create two constants:

#define SET 1
#define RESET 0

So if you needed to set a bit to 0 give it RESET's value and if you need to set a bit to 1 give it SET's
value.

Now, the reason why this sucks right now is because you can only access one bit at a time. So you can't
send data back and forth unless the information was in bit. Then I got the most kick ass idea, "Why
don't I unite the bits!!" And that's exactly what I did. I used Marat's and Eric's idea of nesting structures
inside of unions!!! Look:

typedef union {
typedef struct {
int bit1: 1;
int bit2: 1;
int bit3: 1;
int bit4: 1;
int bit5: 1;
int bit6: 1;
int bit7: 1;
int bit8: 1;
} bits;
byte allbits;
} newbyte;

See? So if I need to manipulate an individual bit I just type:

newbyte.bits.bit(1-8)

and if I need to deal with all of the bits I use allbits:

newbyte.allbits = 0xFF;

With that code all of the bits will be set to 0!!! It's so great! Or, if I send a value to allbits like this:

newbyte.allbits = 0x04;

and I write this:

newbyte.bits.bit3 = RESET /*or 0*/

newbyte.allbits will now equal 0. Why? You gotta understand hex and binary (I don't feel like
explaining that one :o)). This same piece of code could be used with just about anything!! To
simulate the Flags registers in most CPUs, to simulate dipswitches in arcade machines. Aww man,
the endless possiblities!

Oh, and for the experts out there. Even though I declared all those intergers the whole union
is still only one byte. If you don't believe me, copy all of this code and then type:

printf("%d",sizeof(newbyte));

and it should return 1. It did for me.

Like I said before, this may not be the most perfect way, and I'm sure there's some out there
who would love to show me up but I think it's excellent and I'm going to use it in all my emu cores.

Chris :o)
 
Chris
  • Guest
Reply with quote
Woah, major boo boo!!
Post Posted: Wed Jul 14, 1999 7:41 am
Quote
> newbyte.allbits = 0xFF;

> With that code all of the bits will be set to 0!!! It's so great! Or, if I send a value to allbits like this:

I don't believe I did that. I guess I was too excited at the time. Assigning 0xFF or allbits will set all
the internal bits to 1, not 0. If you don't understand, read the previous message and you will see.

Chris :o)
 
  • Joined: 24 Jun 1999
  • Posts: 1732
  • Location: Paris, France
Reply with quote
Post Posted: Wed Jul 14, 1999 9:59 am
Quote
> Now, I don't know if this is the best way but I really think this is an easy and un-complicated way to
> simulate bits in C. Eric Quinn showed me a technique of nesting structures inside of unions to easily
[..]
Quote
> Like I said before, this may not be the most perfect way, and I'm sure there's some out there
> who would love to show me up but I think it's excellent and I'm going to use it in all my emu cores.
[..]

This is far from excellent. Why are you bothering "accessing" bits the way you do ?
You ot a value, let's say, a byte, then just use the | & ^ ! operator to manipulate them.

| is OR.
0 or 0 = 0, 1 or 0 = 1, 0 or 1 = 1, 1 or 1 = 1
& is AND.
0 and 0 = 0, 1 and 0 = 0, 0 and 1 = 0, 1 and 1 = 1
^ is XOR (exclusive OR)
0 xor 0 = 0, 1 xor 0 = 1, 0 xor 1 = 1, 1 xor 1 = 0
! is NOT (inverse), unary operator
not 0 = 1, not 1 = 0

You can do just about everything with them.
  View user's profile Send private message Visit poster's website
Chris
  • Guest
Reply with quote
That's the thing...
Post Posted: Wed Jul 14, 1999 3:50 pm
Quote
> | is OR.
> 0 or 0 = 0, 1 or 0 = 1, 0 or 1 = 1, 1 or 1 = 1
> & is AND.
> 0 and 0 = 0, 1 and 0 = 0, 0 and 1 = 0, 1 and 1 = 1
> ^ is XOR (exclusive OR)
> 0 xor 0 = 0, 1 xor 0 = 1, 0 xor 1 = 1, 1 xor 1 = 0
> ! is NOT (inverse), unary operator
> not 0 = 1, not 1 = 0

> You can do just about everything with them.

I figured it would be a nice easy way to turn bits on and off and it's structured. I think it's very easy
to debug too. Say you do a structure like this:

union {
struct{
int carry: 1;
int bit2: 1;
int bit3: 1;
int ovfl: 1;
...
... and so on

So instead of writiing some

(flags &| 0xF9) whatever, I feel all that hex and binary is too cryptic, especially for me because I know
I will forget in a couple of months. If you want the carry flag on, just say

F.flags.carry = RESET /*Or set if you need to*/
F.flags.ovfl = SET /*Or reset if you need to*/

Meanwhile, you can still access flags as a byte by using the united byte outside of the structure.

Chris :o)
 
  • Joined: 24 Jun 1999
  • Posts: 1732
  • Location: Paris, France
Reply with quote
Re: That's the thing...
Post Posted: Wed Jul 14, 1999 4:28 pm
Quote
> (flags &| 0xF9) whatever, I feel all that hex and binary is too cryptic, especially for me because I know
> I will forget in a couple of months.

So you don't want to learn, or what ?

Quote
> If you want the carry flag on, just say
> F.flags.carry = RESET /*Or set if you need to*/
> F.flags.ovfl = SET /*Or reset if you need to*/
> Meanwhile, you can still access flags as a byte by using the united byte outside of the structure.

Yes but it is much slower.
  View user's profile Send private message Visit poster's website
Eric
  • Guest
Reply with quote
Re: That's the thing...
Post Posted: Wed Jul 14, 1999 4:49 pm

Chris,

If you read my original e-mail message about using unions this way you should see that there is a small caveat with using unions in this way: C does NOT guarantee that fields of a union will occupy contiguous addresses.

This means that in the following declarataion:

ypedef union {
typedef struct {
byte low;
byte high;
} REG8;
word REG16;
} REGPAIR;

The bytes "low" and high" may NOT be next to each other in memory, making the this kind of declaration useless for it's intended purpose. For example, your C compiler could do this for it's addresses:

xx00: low
xx04: high
xx00: REG16

This would not be uncommon on a 32-bit system. where it's desirable to have variables aligned on 32-bit word boundaries in memory. Strictly speaking, this is still a union since "low" and "REG16" share the same address. Note, however, that "high" is no longer next to "low", and your program will not operate as you expect.

However, most compilers WILL place "low" and "high" in contiguous memory addresses (as you found out with your printf("%d",sizeof(newbyte)) experiment"). So, for the most part, your program should work. There's no problem if you will always be using the same version of the same compiler (that you know will do what you want). However, you mentioned using this technique in all your emu cores, and there's a chance that in future your compiler could change (or even the compiler your using now could change) and NOT support this technique. Please be careful. In my z80 emulator (which uses this technique) I do a little test at the beginning of the program, just to make sure the union trick works. If it doesn't my program exits with an error message. This way I know I can change/upgrade compiler, and my program will automatically inform me if there's a problem (with the way the new compiler handles unions.)

Also, the structured approach you have taken is certainly desirable from a high-level language stand-point. However, you are writing a high-performance emulator. All of this structure may cause a performance hit due to a lot of unnecessary address calculations, (generally speaking accessing fields in a structure requires a bit of indirect addressing, your compiler may or may not be able to optimize this out, since field offsets are constant and are known at compile time. Any experts out there know for sure?) My suggestion is to take Zoop's advice, just to be sure you're not unnecessarily clogging your emulator.

You make the point that it is easier to implement flags using there names rather than "all that hex and binary," but why can't you name the FLAG bits just like you did RESET and SET? For example:


#define Z80_C_FLAG (0x01)
#define Z80_S_FLAG (0x80)

etc..

Then, simply define the z80 flags like this:


BYTE Z80_FLAGS;

and manipulate them like this:


Z80_FLAGS |= Z80_C_FLAG; /* This SETs C flag */
Z80_FLAGS &= ~(C_FLAG); /* this RESETS C flag */


You can even make macros to do this for you:


#define SET_Z80_FLAG(flag) {Z80_FLAGS |= flag;}
#define RESET_Z80_FLAG(flag) {Z80_FLAGS &= ~(flag);}


To manipulate flags:


SET_Z80_FLAG(Z80_C_FLAG); /* SET Carry flag */
RESET_Z80_FLAG(Z80_C_FLAG); /* RESET Carry flag */


You can even manipulate more than one flag at once by combining them using the | operator:


SET_Z80_FLAG(Z80_C_FLAG|Z80_S_FLAG); /* SET both Sign and Carry flags */
RESET_Z80_FLAG(Z80_C_FLAG|Z80_S_FLAG); /* RESET both Sign and Carry flags*/


(ORing the flags together to combine them still works in the RESET_Z80_FLAG case based on how the macro is defined, it ANDS with the INVERSE of the flag mask provided. Feel free to prove this to yourself by hand.)

So, you see, things can still be made easily readable using direct bit manipulation instead of a highly-structured address mechanism, and your won't take a performance hit.

These are just my suggestsions, take them or leave them as you wish.

Good luck.

Eric
 
Eric
  • Guest
Reply with quote
Clarification
Post Posted: Wed Jul 14, 1999 4:56 pm
Let me clarify one thing:

I think using the "union technique" is perfect for implementing the Z80 registers.

However, for bit manipulation, I believe you are better of using C's bit manipulation operators rather than a union/structure of bits.

You'll also note that your method reduces to Zoops method (using C's bit manipulation operators) if more than one bit has to be accessed anyway. So, why not use Zoops method for ALL bit manipulation?

Eric
 
Chris
  • Guest
Reply with quote
Slower?
Post Posted: Wed Jul 14, 1999 7:33 pm
Slower? How do you know it's slower?

And I'm game. I'm willing to learn anything new, you know that. I just wanted some opinions on
my union/structure idea. I still think it's excellent but if it will hinder my speed in the end then this
is what I don't want. My whole purpose in writing this emulator was to have it fast and accurate.
But speed comes first. This is starting to piss me off now because it's been 4 days and I'm still
bullshitting around with pointers and setting/resetting flags. I should be already be 1/3 done
with the first 256 set of op codes.

Chris :o)
 
Chris
  • Guest
Reply with quote
Preprocessor
Post Posted: Wed Jul 14, 1999 7:44 pm

I never knew that you could create little functions with the preprocessor! Does it make the function faster or something since the compiler deals with it ahead of time? Now I understand what Marat was doing. In his m6502 processor core he defined a bunch or macros that performed all of the 6502's different was of accessing memory, like indirect, direct, direct addressing, etc.


Sorry. Just testing my HTML.

Chris :o)
 
Chris
  • Guest
Reply with quote
Invalid Message *do not read*
Post Posted: Wed Jul 14, 1999 7:54 pm
I thought I told YOU not to read this?
I'm just fiddling around with HTML, that's all. You can leave this message now.


#define
void main()
{
printf("This kicks ass!" }


Bye bye!
 
  • Joined: 24 Jun 1999
  • Posts: 1732
  • Location: Paris, France
Reply with quote
Re: Slower?
Post Posted: Wed Jul 14, 1999 8:20 pm
Quote
> Slower? How do you know it's slower?

Because you cannot access a value bit per bit, so the whole byte will be acceeded to modify a single bit.
So when you will have to set, let's say four bits, it'll be four times slower (I think)

Quote
> And I'm game. I'm willing to learn anything new, you know that. I just wanted some opinions on
> my union/structure idea. I still think it's excellent but if it will hinder my speed in the end then this
> is what I don't want. My whole purpose in writing this emulator was to have it fast and accurate.
> But speed comes first. This is starting to piss me off now because it's been 4 days and I'm still
> bullshitting around with pointers and setting/resetting flags.
> I should be already be 1/3 done with the first 256 set of op codes.

Emulating the first 256 set of Z80 opcodes represent 5 or 10 percents of the total work, I would say.
  View user's profile Send private message Visit poster's website
Eric
  • Guest
Reply with quote
Re: Preprocessor
Post Posted: Wed Jul 14, 1999 8:27 pm
They are faster in the sense that function calls/returns are eliminated. However, they can dramatically increase program size since the preprocessor actually pastes your code in wherever the macro is invoked. Typically they are best used when a simple code section (just a few lines) is repeated often throughout your program (as in the case of modifying Z80 flags in a Z80 emulator).

Eric
 
Richard Bannister
  • Guest
Reply with quote
Post Posted: Fri Jul 23, 1999 6:51 am
Quote
> typedef union {
> typedef struct {
> byte low;
> byte high;
> } REG8;
> word REG16;
> } REGPAIR;

Be careful here - if you want to write portable code, it should be:

typedef union {
typedef struct {
#ifdef LSB_FIRST
byte low;
byte high;
#else
byte high;
byte low;
#endif
} REG8;
word REG16;
} REGPAIR;

Quote
> typedef union {
> typedef struct {
> int bit1: 1;
> int bit2: 1;
> int bit3: 1;
> int bit4: 1;
> int bit5: 1;
> int bit6: 1;
> int bit7: 1;
> int bit8: 1;
> } bits;
> byte allbits;
> } newbyte;

That may make your life easier as a programmer, but it generates the most atrocious code possible with many compilers, for example every bit change affects allbits immediately, even though the allbits value may not be read until several more bits have been changed. Extra code is needed to make sure that the values remain in sync - and while the compiler does this for you, it's unlikely to do it in an efficient way.

$0.02 ;)

Regards,
Richard

 
Reply to topic



Back to the top of this page

Back to SMS Power!