problem emulating BNE instruction in C++
problem emulating BNE instruction in C++
hi! i'm writing a 6502 emulator in C++ and i'm having problems while emulating the BNE instruction. can anybody tell me how EXACTLY the instruction works, please? and if you can, please write a C++ code wich emulates the instruction.
thanks! (:
thanks! (:
- GARTHWILSON
- Forum Moderator
- Posts: 8775
- Joined: 30 Aug 2002
- Location: Southern California
- Contact:
And like the other conditional branches, it takes 2 clocks if it does not branch, usually 3 if it does, and 4 only if the branch crosses a page boundary (which most don't). The byte following the $D0 BNE op code is a signed number of bytes relative to the address of the first byte after that operand; so D0 00 does nothing except delay 2 or 3 clocks depending on the Z flag, and D0 FE repeats itself endlessly if Z=0.
If you're writing a simulator, you really need to download WDC's excellent programming manual at http://www.westerndesigncenter.com/wdc/ ... manual.pdf .
If you're writing a simulator, you really need to download WDC's excellent programming manual at http://www.westerndesigncenter.com/wdc/ ... manual.pdf .
-
Nightmaretony
- In Memoriam
- Posts: 618
- Joined: 27 Jun 2003
- Location: Meadowbrook
- Contact:
well, this is the code i wrote to emulate the BNE instruction:
...but it doesn't works correctly 
i do pc +=2 so pc is pointing to the next instruction after the branch before the branch is taken.
if Z is 0, then if the byte after BNE is > than 7F (which means that the higher bit is 1) then it's a negative branch, so i substract the 2's compliment of that byte to the pc. if the byte is <= than 7F (so the higher bit is 0) then it's a positve branch as long as the byte itself, so i directly added the byte to the pc.
can anybody figure out why it's not working? ._.
PD: sorry about my english, i'm from argentina
Code: Select all
pc +=2;
if(zflag == 0)
{
memory[pc-1] > 0x7f ? pc -= ((~memory[pc-1]) + 1) : pc += (memory[pc-1]);
}
i do pc +=2 so pc is pointing to the next instruction after the branch before the branch is taken.
if Z is 0, then if the byte after BNE is > than 7F (which means that the higher bit is 1) then it's a negative branch, so i substract the 2's compliment of that byte to the pc. if the byte is <= than 7F (so the higher bit is 0) then it's a positve branch as long as the byte itself, so i directly added the byte to the pc.
can anybody figure out why it's not working? ._.
PD: sorry about my english, i'm from argentina
adding the offset looks OK, but your subtraction looks confused - you need first to consider whether memory[] is signed or not, and then consider what you're doing: are you subtracting an unsigned offset or should you be adding a signed offset?
by negating the value and then subtracting it you're probably going wrong.
how about you see where you go if the offset byte is FE?
by negating the value and then subtracting it you're probably going wrong.
how about you see where you go if the offset byte is FE?
BigEd wrote:
adding the offset looks OK, but your subtraction looks confused - you need first to consider whether memory[] is signed or not, and then consider what you're doing: are you subtracting an unsigned offset or should you be adding a signed offset?
by negating the value and then subtracting it you're probably going wrong.
how about you see where you go if the offset byte is FE?
by negating the value and then subtracting it you're probably going wrong.
how about you see where you go if the offset byte is FE?
...and i don't know why you say i'm negating the value, probably you gone wrong with the "~" character. what ~ does is to swap the bits in a binary number. in eg.: if you've got 10110, then ~10110 is 01001
i've found another way to emulate the instruction in case is a negative branch, but it doesn't works too
in case of "pc -= ((~memory[pc-1]) + 1)" if tried to do "pc -= (memory[pc-1] & 0x7f)" so the higher bit is set to 0, but no way....
please help me :'(
I can't give you an answer, but I'm sure your problem is confusion about signed arithmetic: C++ is capable of it, and the 6502 is capable of it, and you need to stay in control of both.
Look at how you defined your memory[] object. That's important.
Then print out the results of your one-line computation for various values of the inputs. You know what values you want to see, and your code isn't producing them.
Look at how you defined your memory[] object. That's important.
Then print out the results of your one-line computation for various values of the inputs. You know what values you want to see, and your code isn't producing them.
BigEd wrote:
I can't give you an answer, but I'm sure your problem is confusion about signed arithmetic: C++ is capable of it, and the 6502 is capable of it, and you need to stay in control of both.
Look at how you defined your memory[] object. That's important.
Then print out the results of your one-line computation for various values of the inputs. You know what values you want to see, and your code isn't producing them.
Look at how you defined your memory[] object. That's important.
Then print out the results of your one-line computation for various values of the inputs. You know what values you want to see, and your code isn't producing them.
yeeeppp! i finally could make it! here's the code i get so far:
it perfectly works ;D
anyway there's a lot of "why???'s" out there for me, so i'll be soon coming back for more help (hoping not to disturb)...
thnx all you guys for helping me! (:
Code: Select all
case 0xD0: // BNE Relative
printf("%X. BNE Relative zflag = %i\n",pc,zflag);
pc += 2;
if(zflag == 0)
{
pc--;
if(memory[pc] > 0x7f) pc -= (~memory[pc] & 0x00ff);
else pc += (memory[pc] & 0x00ff);
}
break;
anyway there's a lot of "why???'s" out there for me, so i'll be soon coming back for more help (hoping not to disturb)...
thnx all you guys for helping me! (:
BigEd wrote:
glad you got it! I don't quite understand it myself. Is pc a signed type? I think you have to work through the implicit conversions from one type to another. An explicit cast might be the answer, but it's best to know exactly why it is needed before adding a cast.
Cheers
Ed
Cheers
Ed
i'll explain it step by step:
1. pc += 2;
we increment in 2 bytes de pc, so it points to the next instruction after the BNE before the branch is added
2. if(zflag == 0)
if Z flag is not set then...
3. pc--;
since we'll have to branch we need to decrement the pc, because the byte after the BNE instruction (wich is the signed byte that gives the displacement) is relative to this byte
4. if(memory[pc] > 0x7f) pc -= (~memory[pc] & 0x00ff);
if the byte that gives the displacement is major than $7F then the higher bit is 1, so it's a negative branch. to calculate the displacement, what we do is to calculate the 1's compliment of the value given by the byte. after this last operation, our C++ will give as result a 2 bytes integer. since we need to discard the higher byte of that number, we apply yo it a logical AND using $00FF, so after this operation the higher byte of the integer is 0. and then we finally substract that value to the pc.
in e.g.: supose we have the value F5, which is a 1 byte integer. after apply the ~ operation, C++ will return FF0A, wich is a 2 bytes integer. note that 0A is the 1's compliment of F5, and that's the value we need to substract from the pc. then we use the logical AND with 00FF, and afther that FF0A turns to 0A, and there you go ;D
5. else pc += (memory[pc] & 0x00ff);
if it's a positive branch we simply add the byte next to BNE to the pc. the operation " & 0x00ff" it's not needed, but i just recently figured out that XD
is it clear now?? any doubts feel free to ask!
(oops, we collided there - I was composing and sent before I noticed your post. It's all fine though - I understand the correctness of your code, but it seems more complex than necessary. So:)
I did a quick test, and asking the C compiler to treat the offset as a signed quantity causes negative branches to go in the right direction without manual intervention:
with results
(I'm not worrying about the constant offset here, just the treatment of a signed quantity)
Having said that, I notice that Ian Piumarta's lib6502 proceeds a bit more like your original approach, and he's an expert:
(reformatted from original) (edit: removed extra code for clock tick counting) (edit 2009-12-17: corrected my gross 'formatting' error by making the ea calculations, with sideeffects, conditional)
Notice that his operand is a short, not a char.
I did a quick test, and asking the C compiler to treat the offset as a signed quantity causes negative branches to go in the right direction without manual intervention:
Code: Select all
unsigned short pc;
unsigned char operand;
pc=100;
operand=0xf0;
pc += (signed char)operand;
printf("100 + 0xf0 pc: %d\n", pc);
pc=100;
operand=0x0a;
pc += (signed char)operand;
printf("100 + 0x0a pc: %d\n", pc);
Code: Select all
100 + 0xf0 pc: 84
100 + 0x0a pc: 110
Having said that, I notice that Ian Piumarta's lib6502 proceeds a bit more like your original approach, and he's an expert:
Code: Select all
unsigned short int ea;
if (cond) {
ea= memory[PC++];
if (ea & 0x80) ea -= 0x100;
PC += ea;
} else {
PC++;
}
Notice that his operand is a short, not a char.
Last edited by BigEd on Thu Dec 17, 2009 1:52 pm, edited 1 time in total.