problem emulating BNE instruction in C++
- BigDumbDinosaur
- Posts: 9428
- Joined: 28 May 2009
- Location: Midwestern USA (JB Pritzker’s dystopia)
- Contact:
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...
BigEd wrote:
Code: Select all
unsigned short int ea;
ea= memory[PC++];
if (ea & 0x80) ea -= 0x100;
if (cond) {
PC += ea;
} else {
PC++;
}
-
teamtempest
- Posts: 443
- Joined: 08 Nov 2009
- Location: Minnesota
- Contact:
ehguacho wrote:
yeeeppp! i finally could make it! here's the code i get so far:
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;
Code: Select all
bne there:
there: lda #$80
Code: Select all
D0 00
A9 80
Unless I'm missing something, I do not think this is correct. Perhaps there is another increment somewhere else in the loop?
ehguacho wrote:
BigEd wrote:
Code: Select all
unsigned short int ea;
ea= memory[PC++];
if (ea & 0x80) ea -= 0x100;
if (cond) {
PC += ea;
} else {
PC++;
}
Code: Select all
unsigned short int ea;
ea = memory[PC++];
if (ea & 0x80) ea -= 0x100;
if (cond) PC += ea;
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.
-
leeeeee
- In Memoriam
- Posts: 347
- Joined: 30 Aug 2002
- Location: UK
- Contact:
Code: Select all
unsigned short int ea;
ea = memory[PC++];
if (cond) {
ea += 0xFF80;
ea ^= 0xFF80;
PC += ea;
}kc5tja wrote:
BigEd wrote:
Code: Select all
unsigned short int ea;
ea= memory[PC++];
if (ea & 0x80) ea -= 0x100;
if (cond) {
PC += ea;
} else {
PC++;
}
Code: Select all
unsigned short int ea;
if (cond) {
ea= memory[PC++];
if (ea & 0x80) ea -= 0x100;
PC += ea;
} else {
PC++;
}
Whats wrong with
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
Code: Select all
if (cond) {
PC += (char) memory[++PC];
} else {
PC++;
}
* I say this with 99.99% probability
EDIT: Changed PC++ to ++PC to reflect original ordering
-
teamtempest
- Posts: 443
- Joined: 08 Nov 2009
- Location: Minnesota
- Contact:
Here's one way:
And another:
And one more:
I think I like that last one best, even though it does an "unnecessary read".
Code: Select all
unsigned short int ea;
ea = cond ? memory[PC++] : 1;
PC += ea - ((ea & 0x80) << 1);
Code: Select all
unsigned short int ea;
if ( cond ) {
ea = memory[ PC++ ];
PC += ea - ((ea & 0x80) << 1);
}
else
PC++;
Code: Select all
unsigned short int ea;
ea = memory[ PC++ ];
if ( cond )
PC += ea - ((ea & 0x80) << 1);
leeeeee wrote:
Code: Select all
unsigned short int ea;
ea = memory[PC++];
if (cond) {
ea += 0xFF80;
ea ^= 0xFF80;
PC += ea;
}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.
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:
Where S is the size (b byte, w word, l long, q quad) - thats AT&T syntax, so % designates a register
Code: Select all
movszS displacement(%base, %index, multiple), %destreg
well this is the code i wrote and it works nice!
Code: Select all
case 0xd0: // BNE Relative
pc += 2;
branch = mem[pc-1];
if(z_flag == 0) pc += ((signed char)branch);
break;-
heronfisher
- Posts: 2
- Joined: 12 Mar 2010
- Location: london
sorry for revive old posts, but let me just paste my final code:
(C# Language)
tested in almost 5 NES roms and works nice.
(C# Language)
Code: Select all
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;
}