6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sun Nov 24, 2024 11:02 pm

All times are UTC




Post new topic Reply to topic  [ 31 posts ]  Go to page 1, 2, 3  Next
Author Message
PostPosted: Wed Jun 24, 2009 12:31 am 
Offline

Joined: Wed Jun 24, 2009 12:25 am
Posts: 29
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! (:


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Wed Jun 24, 2009 6:56 am 
Offline

Joined: Sat Jan 04, 2003 10:03 pm
Posts: 1706
If the Z bit is 0, branch.


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Wed Jun 24, 2009 7:39 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8546
Location: Southern California
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 .


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Wed Jun 24, 2009 2:25 pm 
Offline

Joined: Fri Jun 27, 2003 8:12 am
Posts: 618
Location: Meadowbrook
and for a simulator source, the MAME source code has a 6502 emulator in there....

_________________
"My biggest dream in life? Building black plywood Habitrails"


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Wed Jun 24, 2009 5:26 pm 
Offline

Joined: Wed Jun 24, 2009 12:25 am
Posts: 29
ok, thanks everybody! i hope this could help ;D


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Wed Jun 24, 2009 5:48 pm 
Offline

Joined: Wed Jun 24, 2009 12:25 am
Posts: 29
well, this is the code i wrote to emulate the BNE instruction:

Code:
pc +=2;
if(zflag == 0)
{
     memory[pc-1] > 0x7f ? pc -= ((~memory[pc-1]) + 1) : pc += (memory[pc-1]);
}


...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


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Wed Jun 24, 2009 5:55 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10986
Location: England
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?


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Wed Jun 24, 2009 6:31 pm 
Offline

Joined: Wed Jun 24, 2009 12:25 am
Posts: 29
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?


on the line "memory[pc-1] > 0x7f" what i'm doing is to check if the byte is signed or not, but as i read in all the 6502's docs, the pc should be pointing to the next instruction after the branch before the branch is taken, that's why i prevoisly made "pc += 2".

...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 :'(


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Wed Jun 24, 2009 6:43 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10986
Location: England
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.


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Wed Jun 24, 2009 6:51 pm 
Offline

Joined: Wed Jun 24, 2009 12:25 am
Posts: 29
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.


i defined my memory array as an "unsigned char *". should i made it like a single char pointer? obviusly, it HAS to be char type, so i can acces the memory 1 byte at a time...


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Wed Jun 24, 2009 6:59 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10986
Location: England
Hmm, I can't offer any more than the suggestion to see what your code actually does. If you're in a linux/gcc/binutils system, you should have gdb available. You should certainly have some debugger available, and it would be worthwhile to become expert at using it.


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Thu Jun 25, 2009 9:15 pm 
Offline

Joined: Wed Jun 24, 2009 12:25 am
Posts: 29
yeeeppp! i finally could make it! here's the code i get so far:

Code:
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;


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! (:


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Thu Jun 25, 2009 9:24 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10986
Location: England
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


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Fri Jun 26, 2009 2:34 am 
Offline

Joined: Wed Jun 24, 2009 12:25 am
Posts: 29
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

"pc" must be an unsigned int because there's no negative values for the memory directions.
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!


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Fri Jun 26, 2009 2:41 am 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10986
Location: England
(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:
Code:
  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);

with results
Code:
100 + 0xf0  pc: 84
100 + 0x0a  pc: 110

(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:
Code:
unsigned short int ea;
if (cond)  {
  ea= memory[PC++];
  if (ea & 0x80) ea -= 0x100;
  PC += ea;
}  else  {
  PC++;
}

(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.


Last edited by BigEd on Thu Dec 17, 2009 1:52 pm, edited 1 time in total.

Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 31 posts ]  Go to page 1, 2, 3  Next

All times are UTC


Who is online

Users browsing this forum: No registered users and 24 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: