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 - Bit of Nostalgic humor

Reply to topic
Author Message
Consolemu
  • Guest
Reply with quote
Bit of Nostalgic humor
Post Posted: Sat Apr 29, 2000 6:54 pm
I was on my old computer, listening to some of my older Midis and playing games I used to play (back when that sorry piece of crap was my primary PC), and then I decided to browse through some of my old games and emulation stuff and boy, was I stupid! I don't believe some of the really stupid things I used to code and the stupid codes I used to use. For example, does anybody remember my project called, SG1K, a Sega Game 1000 emulator for DOS? I was flipping through the codes that I used and I couldn't believe some of the codes I used. What really made it obvious was the source code that Eric Quinn returned back to me (I sent it to him first) with his suggestions. In the headers I was doing stuff like this...

typedef unsigned char BYTE;
typedef unsigned short WORD;

typedef union {
...struct {
......BYTE low;
......BYTE high;
...}
}

What I was trying to do was create a way for me to access both the low and high portions of a 16-bit variable. The major problem was that I could only access either low or high, not both (for 16-bit addressing); which was one of the major things that the Z80 needs with 16-bit registers and memory. Eric politely noted that but I know he could've gone all out on me :o)

I needed to add a 16-bit variable that would be shared with the low and high bytes. I need to add...

WORD WHOLE;

or something similar inside of the union. But that's not all...

Later on in the program I was having problems with bits. I remember talking to either Eric or Nyef about it and they suggested the bitwise operators. For some reason, I just couldn't grasp the concept. So I got the hairbrain idea of using unions and structures and...remember this one???

typedef union {
...struct {
......BYTE bit1;
......BYTE bit2;
......BYTE bit3;
......BYTE bit4;
......BYTE bit5;
......BYTE bit6;
......BYTE bit7;
......BYTE bit8;
...}
...BYTE 8bit;
}

Back then I was thinking I could use TRUE and FALSE on the BYTE bits but today I see a complete waste in memory and a horrible way to do it. Shit, I damn there created a 72-bit union! Now, imagine using that with A, F, B, C, D, E, H, and L. That's a big ass waste of memory. I did a lot more dumb things that I don't really wish to share but all I can say about the whole thing is...I really didn't know what I was doing. I thought I did but I didn't. Even today I don't want to admit that I know everything. I don't think I'll ever be able to admit that I knew everything because you can never know everything. It's impossible.

(sorry this wasn't an important message)

Chris :o)
 
ATani
  • Guest
Reply with quote
Post Posted: Sat Apr 29, 2000 8:25 pm
Quote
>
> typedef union {
> ...struct {
> ......BYTE bit1;
> ......BYTE bit2;
> ......BYTE bit3;
> ......BYTE bit4;
> ......BYTE bit5;
> ......BYTE bit6;
> ......BYTE bit7;
> ......BYTE bit8;
> ...}
> ...BYTE 8bit;
> }
>


I dont believe that the above structure would even work for accessing the bits of the 8bit variable. I believe it would have to be done like this:


typedef union {
...struct {
......BYTE bit1 : 1 ;
......BYTE bit2 : 1 ;
......BYTE bit3 : 1 ;
......BYTE bit4 : 1 ;
......BYTE bit5 : 1 ;
......BYTE bit6 : 1 ;
......BYTE bit7 : 1 ;
......BYTE bit8 : 1 ;
...}
...BYTE 8bit;
}


Just adding the ' : 1 ' makes the variable only take up 1 bit of memory, and the entire union will still only be 1 byte of memory.

ATani
 
Consolemu
  • Guest
Reply with quote
Post Posted: Sat Apr 29, 2000 9:08 pm
Well, now that I know and understand the bitwise operators and shifting I'd rather do it that way. This will also help me improve my hex reading skills. It will probably save me cycles too. If I want to set a bit on, I use OR. If I want to switch it off I use XOR. If I need to test a bit, I use AND.

To switch 1 on...

B |= 0x01;

To switch 1 off...
B ^= 0x01;

To test 1...

result = B & 0x01;
if(result != 0x01){printf("Bit 1 is off
");}
if(result == 0x01){printf("Bit 1 is on
");}

Or, if I really wanted to encapsulate things I could say...

if((A & 0x01) != 0x01){blah blah...}
...

and so on.

All I have to do is alter the hex value and that will be the factor in which bit(s) will be altered.

Chris :o)
 
  • Joined: 24 Jun 1999
  • Posts: 1732
  • Location: Paris, France
Reply with quote
Post Posted: Sun Apr 30, 2000 12:58 am
Quote
> To switch 1 off...
> B ^= 0x01;

Actually this will invert the bit, not switch it off in all cases.
Switching it off would be B &= ~0x01

Quote
> To test 1...
>
> result = B & 0x01;
> if(result != 0x01){printf("Bit 1 is off
");}
> if(result == 0x01){printf("Bit 1 is on
");}
>

Bit 0 is off/on, not bit 1 :)
  View user's profile Send private message Visit poster's website
Consolemu
  • Guest
Reply with quote
Wait, what's that?
Post Posted: Sun Apr 30, 2000 1:31 am
What does ~ do then? I've seen that kind of statement before, like in C++. Used with constructors and deconstructors in the C++ class interface (structure). And why did you use AND with it? Why not XOR or OR?

Chris :o)
 
Consolemu
  • Guest
Reply with quote
Mabye that's why...
Post Posted: Sun Apr 30, 2000 1:45 am
I think that's the reason why my Bits have had problems. I was debugging and it's amazing how one bug can have a major effect on your overall program. In my original code, I had a function that would set bits for Bytes (8-bit variables) like this...

SetBit8(BYTE destination, BYTE pos)
{
...destination |= pos;
}

It's obvious that now when I look at it that it makes sense because I'm not returning the modifyed value back to destination. At the time when I was making the function it seemed dandy because I was using global variables. But for some reason, whether the variable be global or local, the value must be directly returned or it won't work. So I changed it to this...

BYTE SetBit8(BYTE destination, BYTE pos)
{
...destination |= pos;
...return(destination);
}

With this way there's no doubt about as to whether the variable has been changed or not.

After that bug, I found another one in my reset bit function. The value would be altered sometimes but not all the time. Here's the function...

BYTE ResetBit8(BYTE destination, BYTE pos)
{
...destination ^= pos;
...return(destination);
}


Zoop was saying use ~ but I don't know how or what it's for. Anyway, the point to this message is just a reminder that a minor bug can be just as important as a major one. Especially in my case because one bug in any one of my routines ruins the whole emulation.

Chris :o)
 
ATani
  • Guest
Reply with quote
Re: Wait, what's that?
Post Posted: Sun Apr 30, 2000 2:03 am
Quote
> What does ~ do then? I've seen that kind of statement before, like in C++. Used with constructors and deconstructors in the C++ class interface (structure). And why did you use AND with it? Why not XOR or OR?


the '~' operator is the 'Negation' operator. It inverts the bits of the value to the right of it.

ATani
 
  • Site Admin
  • Joined: 25 Oct 1999
  • Posts: 2029
  • Location: Monterey, California
Reply with quote
Re: Wait, what's that?
Post Posted: Sun Apr 30, 2000 2:08 am
Quote
> What does ~ do then? I've seen that kind of statement before, like in C++. Used with constructors and deconstructors in the C++ class interface (structure). And why did you use AND with it? Why not XOR or OR?

(sigh)

The ~ (bitwise negation) operator inverts all the bits of the value that follows. 1's become zeros, zeros become ones.

So, ~1 (assuming 1 is a byte) is 254 (in hex, $FE. In Binary, %1111110). 5 (%00001001) inverted is (%11110110), which is 246.

Okay, let's say with have a variable 'x' which is an unsigned byte.

We'll start out setting it to 7.

x=7; //easy enough

Now, using your method, we clear bit 0.

x ^= 1; //x == 6! we did it.

But, what if we use that one a bit that is already clear? We'll do the above operation on x again:

x ^= 1; //x == 7 now. It should still be 6, dammit,

That's because bit zero of x is clear, and bit zero of 1 is, of course, set. The resulting bit will be set, since that's how bitwise XOR works.

Well, crud, what do we do? Let's try it with or.

x = 7; //back where we started.
x |= 1; //x == 7 still. Bit zero will be set, regardless of the original value

Definately not what we're looking for. How about AND?

x = 7; //ho hum
x &= 1; //x == 1. Whoops.
x = 6; //Just to demonstrate a point
x &= 1; //x == 0.

Well, shit, what and does is clear EVERY bit except the one we wanted to clear. The one we're targetting, bit zero, remains as it was. If it was set going in, it'll be set going out. If it was clear going in, it'll be clear going out.

Now, isn't this just the opposite of what we're trying to do? Insteads of clearing all the bits but bit zero, and leaving bit zero untouched, what we want to do is leave all other bits untouched, and clear bit zero. Is there a way to do it the opposite way?

Yes! Instead of ANDing with 1, we AND with the 'inverted' version of 1.

x = 7;
x &= ~1; //X is ANDED with 11111110.The result? 6! Just what we wanted.
//But will it work if bit zero is already clear?
x &= ~1; //x==6. We did it!


So, you may want to go back and review bitwise operations.
  View user's profile Send private message Visit poster's website
  • Site Admin
  • Joined: 25 Oct 1999
  • Posts: 2029
  • Location: Monterey, California
Reply with quote
Hit the books, kid.
Post Posted: Sun Apr 30, 2000 2:13 am


Quote
> Zoop was saying use ~ but I don't know how or what it's for. Anyway, the point to this message is just a reminder that a minor bug can be just as important as a major one. Especially in my case because one bug in any one of my routines ruins the whole emulation.

Whichever C book you were studying from, I'd say go out and get another.
I think the O'Reilly book on C is good, though I don't know personally.
  View user's profile Send private message Visit poster's website
  • Site Admin
  • Joined: 25 Oct 1999
  • Posts: 2029
  • Location: Monterey, California
Reply with quote
Hit the books, kid.
Post Posted: Sun Apr 30, 2000 2:13 am


Quote
> Zoop was saying use ~ but I don't know how or what it's for. Anyway, the point to this message is just a reminder that a minor bug can be just as important as a major one. Especially in my case because one bug in any one of my routines ruins the whole emulation.

Whichever C book you were studying from, I'd say go out and get another.
I think the O'Reilly book on C is good, though I don't know personally.
  View user's profile Send private message Visit poster's website
  • Joined: 24 Jun 1999
  • Posts: 1732
  • Location: Paris, France
Reply with quote
Re: Mabye that's why...
Post Posted: Sun Apr 30, 2000 10:05 am

Quote
> It's obvious that now when I look at it that it makes sense because I'm not returning the modifyed value back to destination. At the time when I was making the function it seemed dandy because I was using global variables. But for some reason, whether the variable be global or local, the value must be directly returned or it won't work. So I changed it to this...
>
> BYTE SetBit8(BYTE destination, BYTE pos)
> {
> ...destination |= pos;
> ...return(destination);
> }
>

> With this way there's no doubt about as to whether the variable has been changed or not.

Still it's wrong. It won't set bit "pos" of "destination" to 1.

#define SetBit(dest,pos) { dest |= 1<
Would be better
  View user's profile Send private message Visit poster's website
Thanks
  • Guest
Reply with quote
Re: Wait, what's that?
Post Posted: Sun Apr 30, 2000 3:15 pm
Now it makes sense. To tell the truth, I don't even think this C book talks about the ~ operator. 9 times out of 10 it's not needed in common tasks and programs (that's what these guys said) so they only had a couple paragraphs on it and no source code. Borland C++'s help file tells you what it is but not how to use it and Microsoft Visual C++ doesn't even have it in their help file. I should be fine now, now that I can invert bits, and do all that neat stuff I did in the Tetris and Wurm games. It's just a couple more assembly level things I gotta learn and then I should be fine. Thanks.

Chris :o)
 
  • Joined: 18 Sep 1999
  • Posts: 498
  • Location: Portland, Oregon USA
Reply with quote
Re: Mabye that's why...
Post Posted: Sun Apr 30, 2000 6:08 pm
Quote
>
> > It's obvious that now when I look at it that it makes sense because I'm not returning the modifyed value back to destination. At the time when I was making the function it seemed dandy because I was using global variables. But for some reason, whether the variable be global or local, the value must be directly returned or it won't work. So I changed it to this...
> >
> > BYTE SetBit8(BYTE destination, BYTE pos)
> > {
> > ...destination |= pos;
> > ...return(destination);
> > }
> >

> > With this way there's no doubt about as to whether the variable has been changed or not.

> Still it's wrong. It won't set bit "pos" of "destination" to 1.

> #define SetBit(dest,pos) { dest |= 1<
> Would be better

Yes. I agree with Zoop. You are better off using a macro. (Which is what the #define SetBit... statement creates).

The HTML in Zoop's message got messed up. So here it is again (hopefully):


#define SetBit(dest,pos) { dest |= 1 &lt&lt pos); }


The "&LT&LT" operator is a shift. The above macro shifts a "1" to the left "pos" number of times and then OR's dest with it.


Also, the "Truth Tables" for AND, OR and XOR may prove to be useful to help you decipher how to SET and RESET bits.


OR (the | symbol is used to denote bit-wise OR in C++)

X Y X|Y
----------
0 0 0
0 1 1
1 0 1
1 1 1


You can see from the above that the resulting BIT is "1" when either inputs are 1 (i.e., If either X or Y is 1, then the result is 1, hence the name OR).
As you know, ORing a bit-mask against a variable will always SET the bits in the variable that were SET in the bit-mask.




XOR (the ^ symbol is used to denote bit-wise XOR in C++)

X Y X^Y
----------
0 0 0
0 1 1
1 0 1
1 1 0


You can see from the above that the resulting BIT is "1" when either but not both of the inputs are 1 (i.e., If either X is 1, or Y is 1, but not both, then the result is 1. The "exclusive" comes from the fact that "boundary case" X=Y=1 does not result in a 1. You should note that the normal OR operations is sometimes called "Inclusive OR").


Imagine that X is a bit in your variable and Y is a bit in the bit-mask. You can see from the table above that if Y is 0 the result of XOR is just X. (X^0 = X, lines 1 and 3). However, if Y is 1 then the result is NOT X (opposite of X). (X^1 = ~X, lines 2 and 4). XOR is used to flip a bit's value. As Zoop pointed out, this is not acceptable for RESETing a bit unless you know that the bit is already SET. If try to RESET an already RESET bit, the bit will become SET if you use XOR. This is not what you want. Use AND to RESET bits (see below.)




AND (the & symbol is used to denote bit-wise AND in C++)

X Y X*Y
----------
0 0 0
0 1 0
1 0 0
1 1 1


You can see from the above that the resulting BIT is only "1" when BOTH inputs are 1 (i.e., X AND Y must be 1, hence the name AND).


Imagine that X is a bit in your variable and Y is a bit in the bit-mask. You can see from the table above that if Y is 0 the result is always 0. (X^0 = 0, lines 1 and 3). However, if Y is 1 then the result is simply X. (X&1 = X, lines 2 and 4). So, you can use AND to clear bits by providing 0's in the appropriate places in the bit-mask. The other bits should be 1's, which, when ANDed with the original value simply returns the original value.



The statement X |= 0x01 will SET bit 0.

The statement X &= 0x01 will RESET all bits except bit 0 which will retain it's original value.

The statement X &= ~(0x01) is equivalent to X &= 0xFE, which RESETs bit 0 and leaves the other's alone.



I hope this helps.

Eric Quinn
  View user's profile Send private message Visit poster's website
Consolemu
  • Guest
Reply with quote
It does help
Post Posted: Mon May 01, 2000 7:23 pm
I really apreciate everything but you lost me after a while. What makes the macro so much different from the function that I used? Is it faster or something? If I need to set a bit, I do this...

#define CARRY 0x01

BYTE SetBit8(BYTE dest, BYTE pos){
dest |= pos;
return(dest);
}

P = SetBit8(P,CARRY)

What is wrong with that code? I've checked every possibility and it's worked the hundreds of other times that I've used it. I did change my ResetBit function to zoop's because my technique didn't always work. I added the ~ operator to reset just the single bit I need to change. It works perfect now.

Chris :o)
 
  • Site Admin
  • Joined: 25 Oct 1999
  • Posts: 2029
  • Location: Monterey, California
Reply with quote
Re: It does help
Post Posted: Mon May 01, 2000 7:56 pm
Quote
> I really apreciate everything but you lost me after a while. What makes the macro so much different from the function that I used? Is it faster or something?

The reason you would want to implement this as a macro is that there is a certain amount of processor overhead required whenever you do a function call, necessary to adjust the stack frame, call the function, and return from it. The overhead isn't very large, however, when your function is so small and simple that it's actually smaller and faster than the function overhead, then yes, you'll shave some time off your routines by using macros to embed the routine into the cpu emulator itself.
These are the sorts of things that add up over the course of a frame.

Quote
>If I need to set a bit, I do this...
> #define CARRY 0x01

> BYTE SetBit8(BYTE dest, BYTE pos){
> dest |= pos;
> return(dest);
> }

Look at the wasteful nature of this function:
Your program needs to place dest and pos on the stack, possibly push some registers, adjust the stack frame, call your function, actually do the operation, fix the stack frame, and copy the return value into P.

The operation itself is so small, but all the bulk surround it is far greater.

Now, let's say you have a macro

#define SetBit(p, bit) (p |= bit)

And you use it in your emulator, it places:

p |= bit;

it your main code, which could translate into as little as a single cpu instruction. Rather than call all the disruptive bulk that goes with the function.
This is not intended to discourage you from using functions in general, but sometimes it's best to put small things into a macro.
Note also that the SetBit modifies P itself, without having to assign P back into itself. Your function could do that also, if you were to pass a pointer to the byte instead of the byte itself.

Another reason not to use a function in this case is that it may foul up your compilers register allocations and wreck several oppurtunities for optimizations. When your compiler sees that you will jump to a function, it will have to choose to save the values in its registers on the stack, or sacrifice the register values and reload them after the function call is done. If the compiler finds "p |= SOMENUMBER" instead of a function call, it might not have to save any registers at all. If at that point the compiler knows that 'p' will already be loaded into an available register (from a previous instruction) and will be used by the next instruction (for instance, if you are setting and clearing several bits in a row) it can condense the operation into a single opcode.

Exactly how the compiler will optimize (or even, if) is up to the compiler, but it's best to give it as many oppurtunities as possible.



Quote
> P = SetBit8(P,CARRY)
> What is wrong with that code? I've checked every possibility and it's worked the hundreds of other times that I've used it. I did change my ResetBit function to zoop's because my technique didn't always work. I added the ~ operator to reset just the single bit I need to change. It works perfect now.

> Chris :o)
  View user's profile Send private message Visit poster's website
  • Site Admin
  • Joined: 25 Oct 1999
  • Posts: 2029
  • Location: Monterey, California
Reply with quote
one more thing.
Post Posted: Mon May 01, 2000 8:08 pm
Quote
> #define CARRY 0x01

> BYTE SetBit8(BYTE dest, BYTE pos){
> dest |= pos;
> return(dest);
> }

> P = SetBit8(P,CARRY)
>
> What is wrong with that code? I've checked every possibility and it's worked the hundreds of other times that I've used it. I did change my ResetBit function to zoop's because my technique didn't always work. I added the ~ operator to reset just the single bit I need to change. It works perfect now.

The above code WILL work, -if- the CARRY bit in the 6502 status flags is bit zero, not bit one. What is important is that when you provide the function with a 'pos' value, that you don't pass the number of the bit you want to set ( like "P = SetBit8(P, 5)" will NOT set bit 5, it will set bits 0 and 2), but instead pass an appropriate bit mask, a number that has the same bits set in it that you want to be set in your value for 'p'.

For instance:

P = SetBit8(P, 7);

does not set bit 7, rather it sets bits 0, 1, and 2 (since 7 is %00000111 in binary, and that value is OR'd with P). If you wanted to set bit 7, you'd have to call:

P = SetBit8(P, 128);

Since 128 in binary is %10000000, which as you can see has its top bit set, and no other bit.

I suspect that's what you are trying to do, but if not, well keep slugging,
  View user's profile Send private message Visit poster's website
Consolemu
  • Guest
Reply with quote
Slow speed, wasted memory, it's been changed to macro(nt)
Post Posted: Tue May 02, 2000 6:28 pm

 
Consolemu
  • Guest
Reply with quote
Please read this last message carefully...
Post Posted: Tue May 02, 2000 6:36 pm
Quote
> The above code WILL work, -if- the CARRY bit in the 6502 status flags is bit zero, not bit one. What is important is that when you provide the function with a 'pos' value, that you don't pass the number of the bit you want to set ( like "P = SetBit8(P, 5)" will NOT set bit 5, it will set bits 0 and 2), but instead pass an appropriate bit mask, a number that has the same bits set in it that you want to be set in your value for 'p'.

Why do you think I said #define 0x01? I know what bits change what positions. If I say 0xFF, then it will change all bits on. But, that function wasn't designed for that purpose. It was built to change a bit at a time (yes, I could alter more if I needed to). Now, I can finally take a deap breath and say you are incorrect. Whether the carry flag is 0 or 1, it will be changed to one...

OR
1 | 1 = 1
1 | 0 = 1
0 | 1 = 1
0 | 0 = 0


I know that...and I know hex as well. When I'm using pos, I'm refering to hex values that modify certain bits. If you don't believe me check this out...

#define bit0 0x01
#define bit1 0x02
#define bit2 0x04
#define bit3 0x08
#define bit4 0x10
#define bit5 0x20
#define bit6 0x40
#define bit7 0x80


Well, I'm tired of slugging over the same bit stuff. I've learned it, it works, I know how it works, and that's all that's important. Sorry if I'm being rude but I'm tired as fuck from school and I'm really cranky today.

Chris :o|
 
  • Site Admin
  • Joined: 25 Oct 1999
  • Posts: 2029
  • Location: Monterey, California
Reply with quote
Re: Please read this last message carefully...(you do the same)
Post Posted: Tue May 02, 2000 6:59 pm
Quote
> > The above code WILL work, -if- the CARRY bit in the 6502 status flags is bit zero, not bit one. What is important is that when you provide the function with a 'pos' value, that you don't pass the number of the bit you want to set ( like "P = SetBit8(P, 5)" will NOT set bit 5, it will set bits 0 and 2), but instead pass an appropriate bit mask, a number that has the same bits set in it that you want to be set in your value for 'p'.

> Why do you think I said #define 0x01? I know what bits change what positions. If I say 0xFF, then it will change all bits on. But, that function wasn't designed for that purpose. It was built to change a bit at a time (yes, I could alter more if I needed to). Now, I can finally take a deap breath and say you are incorrect. Whether the carry flag is 0 or 1, it will be changed to one...

I am not incorrect. I didn't say that it will only set the carry if the carry is clear, I said it will only work if the carry flag is bit zero. That is, bit -position- zero. (I've been following the convention around here of naming bit positions by prefixing them with 'bit', and specifying the status of binary digits as 'set' and 'clear', or just using an unqualified zero or one). I said that because I don't know which bit is the carry flag is on a 6502.
I pointed it out because the bit of code looked suspiciously like one of those things that will seem to work in practice, but will fail you when you try it with different values. Since you call the function SetBit8 I suspected that you might have intended for it to set a particular bit by position number.

Since you weren't, like I said, keep slugging.

Quote
> I know that...and I know hex as well. When I'm using pos, I'm refering to hex values that modify certain bits. If you don't believe me check this out...


> Well, I'm tired of slugging over the same bit stuff. I've learned it, it works, I know how it works, and that's all that's important. Sorry if I'm being rude but I'm tired as fuck from school and I'm really cranky today.

you know more than you did. and you have more to learn.
we should be getting paid for this.
  View user's profile Send private message Visit poster's website
Reply to topic



Back to the top of this page

Back to SMS Power!