6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Tue Jul 02, 2024 1:36 pm

All times are UTC




Post new topic Reply to topic  [ 31 posts ]  Go to page Previous  1, 2, 3  Next
Author Message
 Post subject:
PostPosted: Fri Jun 26, 2009 3:32 am 
Offline

Joined: Wed Jun 24, 2009 12:25 am
Posts: 29
nice code too ;D
as we may see there's a lot of ways to emulate the BNE instruction, but just a few of them are really efficient. my code looks quite confusing or complex right now, but i'll optimize it later, when the emulator has been done. thanks again dude! you really helped me out (:


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

Joined: Thu May 28, 2009 9:46 pm
Posts: 8237
Location: Midwestern USA
GARTHWILSON wrote:
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...

To be pedantic about it, the offset is a signed twos complement value.


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

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

To be pedantic about it, the offset is a signed twos complement value.

you're totally right my friend, but beleave it or not i found some errors while using 2's compliment. but everything went right with 1's complement. so strange :\


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Tue Dec 15, 2009 3:10 am 
Offline

Joined: Wed Jun 24, 2009 12:25 am
Posts: 29
BigEd wrote:
Code:
  unsigned short int ea;
  ea= memory[PC++];
  if (ea & 0x80) ea -= 0x100;
  if (cond)  {
      PC += ea;
    }  else  {
      PC++;
    }


the most effective way ever seen ;)


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Thu Dec 17, 2009 1:40 am 
Offline

Joined: Sun Nov 08, 2009 1:56 am
Posts: 390
Location: Minnesota
ehguacho wrote:
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;



I'm a little puzzled by this code. Does it work if the operand at "memory[pc]" has the value zero? As in:

Code:

         bne there:
there:   lda #$80



Which is legal (though useful perhaps only for playing with timing) and when assembled produces:

Code:

        D0 00
        A9 80



In the emulator code above, if "zflag" is not zero, "pc" gets incremented by two (past the zero operand value). If "zflag" is zero, "pc" gets incremented by only one (and still points at the zero operand value). Fetching that zero operand as the next instruction would trigger a BRK.

Unless I'm missing something, I do not think this is correct. Perhaps there is another increment somewhere else in the loop?


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Thu Dec 17, 2009 6:14 am 
Offline

Joined: Sat Jan 04, 2003 10:03 pm
Posts: 1706
ehguacho wrote:
BigEd wrote:
Code:
  unsigned short int ea;
  ea= memory[PC++];
  if (ea & 0x80) ea -= 0x100;
  if (cond)  {
      PC += ea;
    }  else  {
      PC++;
    }


the most effective way ever seen ;)


This absolutely will crash. Get rid of the second PC++.

Code:
  unsigned short int ea;
  ea = memory[PC++];
  if (ea & 0x80) ea -= 0x100;
  if (cond) PC += ea;


Remember that the effective address is relative to the PC after the CPU's already read the effective address byte. That is, it's relative to the next instruction.

Since you already post-increment PC when fetching the effective address, PC already points to the next instruction. No need to increment it again if the condition is false.


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Thu Dec 17, 2009 1:21 pm 
Offline

Joined: Fri Aug 30, 2002 2:05 pm
Posts: 347
Location: UK
Code:
  unsigned short int ea;
  ea = memory[PC++];
  if (cond) {
      ea += 0xFF80;
      ea ^= 0xFF80;
      PC += ea;
      }

Lee.


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Thu Dec 17, 2009 1:49 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10838
Location: England
kc5tja wrote:
BigEd wrote:
Code:
  unsigned short int ea;
  ea= memory[PC++];
  if (ea & 0x80) ea -= 0x100;
  if (cond)  {
      PC += ea;
    }  else  {
      PC++;
    }


This absolutely will crash.


The error is of course mine: run6502 works, after all. The source is macro-heavy and I flattened it incorrectly. I'll try again:
Code:
unsigned short int ea;
if (cond)  {
   ea= memory[PC++];
   if (ea & 0x80) ea -= 0x100;
   PC += ea;
}  else  {
   PC++;
}

You'll notice it doesn't even read the offset if the condition is false - it's a very efficient emulator.


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Thu Dec 17, 2009 9:16 pm 
Offline

Joined: Thu Jul 26, 2007 4:46 pm
Posts: 105
Whats wrong with

Code:
if (cond)  {
   PC += (char) memory[++PC];
}  else  {
   PC++;
}


The 6502 is twos complement. Your machine is twos complement*. Why not use it's ability to handle it natively? It will be much faster than messing around with it yourself and branching

* I say this with 99.99% probability

EDIT: Changed PC++ to ++PC to reflect original ordering


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Fri Dec 18, 2009 2:23 am 
Offline

Joined: Sun Nov 08, 2009 1:56 am
Posts: 390
Location: Minnesota
Here's one way:

Code:
  unsigned short int ea;

  ea = cond ? memory[PC++] : 1;
  PC += ea - ((ea & 0x80) << 1);



And another:

Code:
  unsigned short int ea;

  if ( cond ) {
    ea = memory[ PC++ ];
    PC += ea - ((ea & 0x80) << 1);
 }
 else
    PC++;



And one more:

Code:
  unsigned short int ea;

  ea = memory[ PC++ ];
  if ( cond )
    PC += ea - ((ea & 0x80) << 1);



I think I like that last one best, even though it does an "unnecessary read".


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Fri Dec 18, 2009 10:04 am 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10838
Location: England
leeeeee wrote:
Code:
  unsigned short int ea;
  ea = memory[PC++];
  if (cond) {
      ea += 0xFF80;
      ea ^= 0xFF80;
      PC += ea;
      }


Nice! Avoiding an extra branch feels like a good thing, although it's never wise to second-guess micro-optimisations. My ultimate preference would be for code which is "obviously" right, and efficient. Although I like this one, I had to think a bit.

Maybe I like OwenS' code best: inform the compiler of signedness, and have it generate the best machine code for sign-extension. It's short and simple, but you can only write it if you already understand very well what you need to do and how your language works.

I don't think I've yet seen code which would be ideal as a teaching example. Maybe you have to write your own, and struggle.

It's interesting that you can get a long way - even in C - without deeply understanding type conversions and machine operations. It's a good thing that so many people like to write an emulator - the value isn't in having one, but in creating one.


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Fri Dec 18, 2009 12:13 pm 
Offline

Joined: Thu Jul 26, 2007 4:46 pm
Posts: 105
Particularly on x86, where branches can become hideously expensive (Though unlikely in this case, since it's a very short stream of instructions), avoiding them is good. Might as well use the sign extended load instruction:
Code:
movszS displacement(%base, %index, multiple), %destreg


Where S is the size (b byte, w word, l long, q quad) - thats AT&T syntax, so % designates a register


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Sat Dec 19, 2009 10:26 pm 
Offline

Joined: Wed Jun 24, 2009 12:25 am
Posts: 29
well this is the code i wrote and it works nice!

Code:
case 0xd0: // BNE Relative
     pc += 2;
     branch = mem[pc-1];
     if(z_flag == 0) pc += ((signed char)branch);
     break;


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Tue Mar 16, 2010 10:35 am 
Offline

Joined: Fri Mar 12, 2010 12:56 pm
Posts: 2
Location: london
This 6502 Cpu emulator was coded in Visual Basic by Don Jarrett. It will prove to be the main CPU emulator used in VB5 Emulators (It's been used in PCSloMo). This is the final release version. Compile it using Visual Basic 5.0.


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Mon Aug 16, 2010 6:22 pm 
Offline

Joined: Wed Jun 24, 2009 12:25 am
Posts: 29
sorry for revive old posts, but let me just paste my final code:

(C# Language)
Code:
private void Branch(bool Flag, bool Condition)
{
     PC += 2; // PC points to the next instruction after the branch before the branch is taken
     if (Flag == Condition)
     {
          PC--;
          UInt16 Displacement = Memory[PC++]; // Post-increment the PC
          if (Convert.ToBoolean(Displacement & 0x80)) Displacement -= 0x100;
          PC += Displacement;
     }
           
     return;
}


tested in almost 5 NES roms and works nice.

_________________
sorry about my english, i'm from Argentina :S

http://felliniycia.comule.com/


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

All times are UTC


Who is online

Users browsing this forum: No registered users and 2 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: