Super Mario Brother Infinite Loop at: LDA $2000, BPL ....

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
Super Mario Brother Infinite Loop at: LDA $2000, BPL ....
by on (#43674)
Hi I'm trying to write a nes emulator. ( big news :roll: )
Well I'm using the Super Mario Brother to make tests with my emulator.

1º I already load the rom (mappers don't has support yet);
Image
2º The pattern table seems to be right;
Image
3º My debugger shows when it cames to infite loop;
Image
3º The ppu state has affected by this;
Image

Image


Anytime of PPu execution it change the flag Sign?
What's wrong...?[/img]

If I try to execute ppu (on real hardware I guess cpu and ppu runs togheter at same time) I will not have the data to plot something on screen then the classic:
1. Name table byte
2. Attribute table byte
3. Pattern table bitmap #0
4. Pattern table bitmap #1
Will not print nothing...

by on (#43676)
The game is waiting for the PPU to enter in VBLANK state.
your code emulate this correctly?

Code:
   if(scanline==240)
   {
      // start vblank simulation
      VBLANK_REG(1);
      SPRITE0_REG(0);

      // check non-emulated events
      sdl_poll_events();
      queue_check_cmd();

      // generate interrupts on vblank, if enabled
      if(VBLANK_ON_NMI)
         cpu_interrupt(INT_NMI);
   }

by on (#43687)
Thanks polaco I'll try to "simulate" in this way!

by on (#43688)
I guess the game wait that the value of $2000 update the sign/negative flag; but when I made a check (I mean write 1 to vblank at $2000) the number is 128, I have to check this number as unsigned byte ?

Always I have to change a flag must I to check the number as unsigned?

Code:
        cpu.setupFlagSign(cpu.accumulator);
        cpu.setupFlagZero(cpu.accumulator);


    public void setupFlagSign(short value) {
        flagSign = (byte) (((byte)value < 0) ? 1 : 0);
    }

    public void setupFlagZero(short value) {
        flagZero = (byte) (((byte)value == 0) ? 1 : 0);
    }
Code:

by on (#43689)
BPL means branch on result plus (not negative), it will test the accumulator and set the N flag according.

looking at the code, I see that is reads PPU status from $2002, and not from $2000.

Code:
8002: LDA #$10    ; read immediate value to set PPU control registers
8004: STA $2000   ; store value
8007: LDX #$FF    ; load immediate value into X register
8009: TXS         ; store X register into stack
800a: LDA $2002   ; read PPU flags into accumulator (set N flag based on bit 7)
800d: BPL         ; test N flag, branch to 800a if not positive, (N is set)


Code:
PPUSTATUS ($2002)
PPU status (read)

76543210
||||||||
|||+++++- Unimplemented
||+------ Sprite overflow. The PPU can handle only eight sprites on one
||        scanline and sets this bit if it starts dropping sprites.
||        Normally, this triggers when there are 9 sprites on a scanline,
||        but the actual behavior is significantly more complicated.
|+------- Sprite 0 Hit.  Set when a nonzero pixel of sprite 0 'hits'
|         a nonzero background pixel.  Used for raster timing.
+-------- Vertical blank has started (0: not in VBLANK; 1: in VBLANK)


This is the PPU status registers, and the last bit is the VBLANK state. I think you have confused it with the ppu control ($2000)

Code:
[edit] PPUCTRL ($2000)
Various flags controlling PPU operation (write)

76543210
||||||||
||||||++- Base nametable address
||||||    (0 = $2000; 1 = $2400; 2 = $2800; 3 = $2C00)
|||||+--- VRAM address increment per CPU read/write of PPUDATA
|||||     (0: increment by 1, going across; 1: increment by 32, going down)
||||+---- Sprite pattern table address for 8x8 sprites (0: $0000; 1: $1000)
|||+----- Background pattern table address (0: $0000; 1: $1000)
||+------ Sprite size (0: 8x8; 1: 8x16)
|+------- PPU master/slave select (has no effect on the NES)
+-------- Generate an NMI at the start of the
          vertical blanking interval (0: off; 1: on)


When bit 7 of control register is set, it instructs PPU to generate a NMI on VBLANK.

Also, take care when dealing with signed values, as it will fail the test if you try to put a negative value into an unsigned variable.

by on (#43703)
polaco wrote:
BPL means branch on result plus (not negative), it will test the accumulator and set the N flag according.
looking at the code, I see that is reads PPU status from $2002, and not from $2000.

Code:
8002: LDA #$10    ; read immediate value to set PPU control registers
8004: STA $2000   ; store value
8007: LDX #$FF    ; load immediate value into X register
8009: TXS         ; store X register into stack
800a: LDA $2002   ; read PPU flags into accumulator (set N flag based on bit 7)
800d: BPL         ; test N flag, branch to 800a if not positive, (N is set)


BPL change the flag N ?
In this case if N == 0 jump to 800A... then it waits for flag N to be marked, when I'm in Vblank I should mark the VBLANK started on $2002?

If I set it the value will be 10000000 (128) and this result on LDA set the N flag to 0 or 1? ( 0 if we suposse that the number is unsigned or 1 if we suposse that the numer is signed)

polaco wrote:
Code:
PPUSTATUS ($2002)
PPU status (read)

76543210
||||||||
|||+++++- Unimplemented
||+------ Sprite overflow. The PPU can handle only eight sprites on one
||        scanline and sets this bit if it starts dropping sprites.
||        Normally, this triggers when there are 9 sprites on a scanline,
||        but the actual behavior is significantly more complicated.
|+------- Sprite 0 Hit.  Set when a nonzero pixel of sprite 0 'hits'
|         a nonzero background pixel.  Used for raster timing.
+-------- Vertical blank has started (0: not in VBLANK; 1: in VBLANK)


This is the PPU status registers, and the last bit is the VBLANK state. I think you have confused it with the ppu control ($2000)

Code:
[edit] PPUCTRL ($2000)
Various flags controlling PPU operation (write)

76543210
||||||||
||||||++- Base nametable address
||||||    (0 = $2000; 1 = $2400; 2 = $2800; 3 = $2C00)
|||||+--- VRAM address increment per CPU read/write of PPUDATA
|||||     (0: increment by 1, going across; 1: increment by 32, going down)
||||+---- Sprite pattern table address for 8x8 sprites (0: $0000; 1: $1000)
|||+----- Background pattern table address (0: $0000; 1: $1000)
||+------ Sprite size (0: 8x8; 1: 8x16)
|+------- PPU master/slave select (has no effect on the NES)
+-------- Generate an NMI at the start of the
          vertical blanking interval (0: off; 1: on)


When bit 7 of control register is set, it instructs PPU to generate a NMI on VBLANK.
Also, take care when dealing with signed values, as it will fail the test if you try to put a negative value into an unsigned variable.

Thanks so much...

by on (#43704)
Code:
800a: LDA $2002   ; read PPU flags into accumulator (set N flag based on bit 7)
800d: BPL         ; test N flag, branch to 800a if not positive, (N is set)

The case is when the N flag is setted on VBlank?
When I came to VBlank period I set the 7th bit of $2002 to 1 this mades the value become 10000000 (128) if we see is as unsigned then it can't change the N flag...

However I guess this (128) is a negative number for the flag reasons... am I rigth?

by on (#43706)
dreampeppers99 wrote:
Code:
800a: LDA $2002   ; read PPU flags into accumulator (set N flag based on bit 7)
800d: BPL         ; test N flag, branch to 800a if not positive, (N is set)

The case is when the N flag is setted on VBlank?
When I came to VBlank period I set the 7th bit of $2002 to 1 this mades the value become 10000000 (128) if we see is as unsigned then it can't change the N flag...

However I guess this is a negative number for (128) the flag reasons... am I rigth?


Sorry, there is a typo in my post! BPL does no set the N flag, it tests it. Correcting my post:

Code:
800a: LDA $2002   ; read PPU flags into accumulator (set N flag based on bit 7)
800d: BPL         ; test N flag, branch to 800a if not positive, (if N is not set, jump)


a signed char in 8bit goes from -128 to 128, and the unsigned goes from 0 to 255. Warping occurs if you increment the value.

by on (#43707)
It's worth nothing that for all practical purposes in your emulator, you can treat everything as unsigned. The only thing that must be signed is the relative address for branching.

The 'N' flag just means 'high bit set'. Therefore values $80-$FF will set N, and values $00-7F will clear N.

by on (#43711)
polaco wrote:
a signed char in 8bit goes from -128 to 128

The range is actually -128 to 127. Just thought I'd point that out.

by on (#43712)
tokumaru wrote:
polaco wrote:
a signed char in 8bit goes from -128 to 128

The range is actually -128 to 127. Just thought I'd point that out.


He wasn't the only one to slip... ^_^;;

by on (#43716)
Fx3 wrote:
tokumaru wrote:
polaco wrote:
a signed char in 8bit goes from -128 to 128

The range is actually -128 to 127. Just thought I'd point that out.


He wasn't the only one to slip... ^_^;;


Wooops, thanks for pointing that! :D :D

by on (#43717)
polaco wrote:
Sorry, there is a typo in my post! BPL does no set the N flag, it tests it. Correcting my post:

Code:
800a: LDA $2002   ; read PPU flags into accumulator (set N flag based on bit 7)
800d: BPL         ; test N flag, branch to 800a if not positive, (if N is not set, jump)

This should read "branch to 800a if positive", or "branch to 800a if not negative" (the former is less confusing; prefer fewer negations).

Quote:
a signed char in 8bit goes from -128 to 128, and the unsigned goes from 0 to 255. Warping occurs if you increment the value.

Fencepost errors are common; always be on the watch for them. In this case, the range -128 to +128 indeed has 256 intervals, but this requires 257 boundary points, since a single interval requres two. Or perhaps you simply added the 128 negative and 128 non-zero positive values and came up with 256, forgetting zero in the middle. :)

by on (#43718)
Disch wrote:
The 'N' flag just means 'high bit set'. Therefore values $80-$FF will set N, and values $00-7F will clear N.

Thanks ! I'll think in this way!

by on (#43719)
tokumaru wrote:
polaco wrote:
a signed char in 8bit goes from -128 to 128

The range is actually -128 to 127. Just thought I'd point that out.

:o

by on (#43720)
Now I'm going deeper thanks you all !
Soon I'll be back here to post MANY others questions!
For those that wanna see the project is on http://code.google.com/p/jnesbr/ .

by on (#43774)
ASM Super Mario Brothers 1
Code:
0x8000:   SEI   ;
0x8001:   CLD   ;
0x8002:   LDA #$10   ;
0x8004:   STA $2000   ;
0x8007:   LDX #$FF   ;
0x8009:   TXS   ;
0x800A:   LDA $2002   ;
0x800D:   BPL   ;
0x800A:   LDA $2002   ;
0x800D:   BPL   ;
0x800A:   LDA $2002   ;
0x800D:   BPL   ;
0x800A:   LDA $2002   ;
0x800D:   BPL   ;
0x800F:   LDA $2002   ;
0x8012:   BPL   ;
0x8014:   LDY #$FE   ;
0x8016:   LDX #$5   ;
0x8018:   LDA $07D7 ,X    ;
0x801B:   CMP #$0A   ;
0x801D:   BCS   ;
0x802B:   JSR $90CC   ;
0x90CC:   LDX #$7   ;
0x90CE:   LDA #$0   ;
0x90D0:   STA $06   ;
0x90D2:   STX $07   ;
0x90D4:   CPX #$01   ;
0x90D6:   BNE   ;


Now my code seems to works better...
My question now is in most of CMP (comparison ... x , y ...)
I'm setting my flags in this way...

Code:
cpu.setupFlagSign(cpu.accumulator - getOperand());
        cpu.setupFlagZero(cpu.accumulator - getOperand()));
        cpu.flagCarry =(cpu.accumulator - getOperand() < 0x100) ? 1 : 0);


I'm doing it correct?
I can care about carry flag always like that?

The game seems to be in another loop but this time I can't see why it don't go out the loop... I believe that this part is waiting to decay the Y register one by one until zero...

Code:
0x802B:   JSR $90CC   ;
0x90CC:   LDX #$7   ;
0x90CE:   LDA #$0   ;
0x90D0:   STA $06   ;
0x90D2:   STX $07   ;
0x90D4:   CPX #$01   ;
0x90D6:   BNE   ;
0x90DC:   STA ($45),Y   ;
0x90DE:   DEY   ;
0x90DF:   CPY #$FF   ;
0x90E1:   BNE   ;
0x90D4:   CPX #$01   ;
0x90D6:   BNE   ;
0x90DC:   STA ($9D),Y   ;
0x90DE:   DEY   ;
0x90DF:   CPY #$FF   ;
0x90E1:   BNE   ;
0x90D4:   CPX #$01   ;
0x90D6:   BNE   ;
0x90DC:   STA ($6),Y   ;
0x90DE:   DEY   ;
0x90DF:   CPY #$FF   ;
0x90E1:   BNE   ;
0x90D4:   CPX #$01   ;
0x90D6:   BNE   ;
0x90DC:   STA ($B1),Y   ;
0x90DE:   DEY   ;
0x90DF:   CPY #$FF   ;
0x90E1:   BNE   ;
0x90D4:   CPX #$01   ;
0x90D6:   BNE   ;
0x90DC:   STA ($C8),Y   ;
0x90DE:   DEY   ;
0x90DF:   CPY #$FF   ;
0x90E1:   BNE   ;
0x90D4:   CPX #$01   ;
0x90D6:   BNE   ;
0x90DC:   STA ($3),Y   ;
0x90DE:   DEY   ;
0x90DF:   CPY #$FF   ;
0x90E1:   BNE   ;
0x90D4:   CPX #$01   ;
0x90D6:   BNE   ;
0x90DC:   STA ($44),Y   ;
0x90DE:   DEY   ;
0x90DF:   CPY #$FF   ;
0x90E1:   BNE   ;
0x90D4:   CPX #$01   ;
0x90D6:   BNE   ;
0x90DC:   STA ($9D),Y   ;
0x90DE:   DEY   ;
0x90DF:   CPY #$FF   ;
0x90E1:   BNE   ;
0x90D4:   CPX #$01   ;
0x90D6:   BNE   ;
0x90DC:   STA ($6),Y   ;
0x90DE:   DEY   ;
0x90DF:   CPY #$FF   ;
0x90E1:   BNE   ;
0x90D4:   CPX #$01   ;
0x90D6:   BNE   ;
0x90DC:   STA ($B1),Y   ;
0x90DE:   DEY   ;
0x90DF:   CPY #$FF   ;
0x90E1:   BNE   ;
0x90D4:   CPX #$01   ;
0x90D6:   BNE   ;
0x90DC:   STA ($0),Y   ;
0x90DE:   DEY   ;
0x90DF:   CPY #$FF   ;
0x90E1:   BNE   ;
0x90D4:   CPX #$01   ;
0x90D6:   BNE   ;
0x90DC:   STA ($A6),Y   ;
0x90DE:   DEY   ;
0x90DF:   CPY #$FF   ;
0x90E1:   BNE   ;
0x90D4:   CPX #$01   ;
0x90D6:   BNE   ;
0x90DC:   STA ($A8),Y   ;
0x90DE:   DEY   ;
0x90DF:   CPY #$FF   ;
0x90E1:   BNE   ;
0x90D4:   CPX #$01   ;
0x90D6:   BNE   ;
0x90DC:   STA ($2),Y   ;
0x90DE:   DEY   ;
0x90DF:   CPY #$FF   ;
0x90E1:   BNE   ;
0x90D4:   CPX #$01   ;
0x90D6:   BNE   ;
0x90DC:   STA ($65),Y   ;
0x90DE:   DEY   ;
0x90DF:   CPY #$FF   ;
0x90E1:   BNE   ;
0x90D4:   CPX #$01   ;
0x90D6:   BNE   ;
0x90DC:   STA ($A),Y   ;
0x90DE:   DEY   ;
0x90DF:   CPY #$FF   ;
0x90E1:   BNE   ;
0x90D4:   CPX #$01   ;
0x90D6:   BNE   ;
0x90DC:   STA ($1),Y   ;
0x90DE:   DEY   ;
0x90DF:   CPY #$FF   ;
0x90E1:   BNE   ;
0x90D4:   CPX #$01   ;
...

by on (#43778)
Why does the operand byte differ every time this instruction is executed?
Code:
0x90DC:   STA ($45),Y
0x90DC:   STA ($9D),Y
0x90DC:   STA ($6),Y
0x90DC:   STA ($B1),Y
0x90DC:   STA ($C8),Y
0x90DC:   STA ($3),Y
0x90DC:   STA ($44),Y
0x90DC:   STA ($9D),Y
0x90DC:   STA ($6),Y
0x90DC:   STA ($B1),Y
0x90DC:   STA ($0),Y

Perhaps you just need to ram your head into the wall until the purpose of this loop becomes clear. (You'll understand what that means later, once you've figured out why the operand dffers.)

by on (#43780)
If you're planning on using that as a recompilable disassembly, you have a major problem. I was recently working on a sort of homemade disassembler for myself (which maybe I'll release, but it might be worthless to others), and I used an offered "hex()" function which of course, displayed a value in hex. However, if the number was less than $10, it would display as $F, and not $0F. It didn't seem like it mattered at first, but it could prove to be a horrible disaster. In my disassembly, if there was ever an LDA $Absolute statement where the 16-bit address was say $0023, it would show up as LDA $23, which if you re-assembled it would prove to be interpreted as LDA $ZeroPage. And then the code would shifted back one byte because LDA ZP takes 2 bytes when LDA Absolute takes 3. Just thought I'd mention it.

So just make sure you're forcing your hex numbers to display at a constant width. Either 2 or 4 hex digits, depending on if it's ZP or Absolute.

by on (#43781)
Celius, I don't think this matters to him. He seems to be trying an emulator development strategy where he uses a single game (in this case, SMB1) and tries to fix whatever is wrong until the game runs. Those are just logs from his emulator, that he uses to detect strange behavior.

by on (#43797)
tepples wrote:
Why does the operand byte differ every time this instruction is executed?
Code:
0x90DC:   STA ($45),Y
0x90DC:   STA ($9D),Y
0x90DC:   STA ($6),Y
0x90DC:   STA ($B1),Y
0x90DC:   STA ($C8),Y
0x90DC:   STA ($3),Y
0x90DC:   STA ($44),Y
0x90DC:   STA ($9D),Y
0x90DC:   STA ($6),Y
0x90DC:   STA ($B1),Y
0x90DC:   STA ($0),Y

Perhaps you just need to ram your head into the wall until the purpose of this loop becomes clear. (You'll understand what that means later, once you've figured out why the operand dffers.)


Thanks Man I'll remember you... :)

by on (#43798)
tokumaru wrote:
Celius, I don't think this matters to him. He seems to be trying an emulator development strategy where he uses a single game (in this case, SMB1) and tries to fix whatever is wrong until the game runs. Those are just logs from his emulator, that he uses to detect strange behavior.

You are COMPLETLY rigth!
My aproach is that one.... however I change my game , now I'm trying to use PONG because I've got the asms files too then is easier and I don't need to bother you guys.
:) thanks soon more questions.

ps: about the aproach I guess it is the better one because I can see what I'm doing ... little tests, show something on the screen > this definitivilty helps keep the wish to dev the emu... at least to me.

by on (#43799)
Celius wrote:
If you're planning on using that as a recompilable disassembly, you have a major problem. I was recently working on a sort of homemade disassembler for myself (which maybe I'll release, but it might be worthless to others), and I used an offered "hex()" function which of course, displayed a value in hex. However, if the number was less than $10, it would display as $F, and not $0F. It didn't seem like it mattered at first, but it could prove to be a horrible disaster. In my disassembly, if there was ever an LDA $Absolute statement where the 16-bit address was say $0023, it would show up as LDA $23, which if you re-assembled it would prove to be interpreted as LDA $ZeroPage. And then the code would shifted back one byte because LDA ZP takes 2 bytes when LDA Absolute takes 3. Just thought I'd mention it.

So just make sure you're forcing your hex numbers to display at a constant width. Either 2 or 4 hex digits, depending on if it's ZP or Absolute.


Thanks I forgot about that... I just made a method
fillIfNeedsWith(2, "0", operandInHexa);
format with 2 "00" the number :)

by on (#43973)
tepples wrote:
Why does the operand byte differ every time this instruction is executed?

It was a bug I fix that ! :)
tepples wrote:
Perhaps you just need to ram your head into the wall until the purpose of this loop becomes clear. (You'll understand what that means later, once you've figured out why the operand dffers.)

Exactly as you said... when I figured out why operand differs...
:roll: Now I know thanks for open my eyes, I guess it is Clearing the RAM and another pieces of memory, Am I rigth?
Why the homebrew PONG.NES clean memory setting 20 ? (ps: Super Mario 1 cleans normaly decreasing the X from 6 to 0 and Y every time from FF to 0.

I needed to create a way on my debugger to jump N steps of execution... (later I'll try to build something more professional).

Image

by on (#43980)
The homebrew PONG.nes doesn't works... :lol: rsrsr I've tried it on real and good emulators and nothing happening...
Did you have one game like pong (without mapper) and source?
[because use super mario is good but the game is "big" to debug]

by on (#43989)
You could always try Tetramino.

by on (#43997)
tepples wrote:
You could always try Tetramino.

Thanks so much, I'll use that! which document you could indicate me to PPU ('til now I just mock the PPU behavior) ? (can be a set of best oneS)

And by the way: I have this sequence on memory:
20 CC 90 8D

It means: JSR 90CC;
..
..
..
RTS; after execute subrotine...
Now I should execute the 8D (STA $xxxx)?

by on (#44003)
dreampeppers99 wrote:
Now I should execute the 8D (STA $xxxx)?

In this case, yes, the $8D will probably be executed after the RTS, but you shouldn't count on it. Typically, a program will call subroutines (JSR) and return from them (RTS), but assembly is a very free language, and somewhere between the execution of those instruction the stack could be manipulated, in which case the RTS would jump to somewhere else, away from that $8D.

Just simulate the instructions based on what they actually do. JSR stores the return address to the stack and jumps to the specified location. RTS retrieves an address from the stack and jumps to it. If you simulate it that way, you don't have to worry about nasty stack manipulation tricks, because your emulator will be doing exactly what the 6502 does.

by on (#44053)
I made JSR like that:

Code:
    public void interpret() {
        cpu.push(cpu.programCounter + 2 >> 8) & 0xFF);
        cpu.push(cpu.programCounter + 2 & 0xFF);
        cpu.programCounter = getAbsoluteAddress();
    }


And RTS like that:
Code:
    public void interpret() {
        cpu.programCounter = cpu.pull();
        cpu.programCounter += (cpu.pull() << 8);
        cpu.programCounter++;
        cpu.programCounter &= 0xFFFF;
    }

by on (#44054)
Your Java code can't be right. I'm staring at it and see two errors right off the bat (well, one error for sure, the other depends on what your program is really doing with cpu.programCounter).

I can assure you that cpu.programCounter + 2 >> 8 is flat out wrong. Did anyone teach you order of operation?

I don't think anyone on this forum is going to sit here and write your entire program for you. Most people here won't sift through lines of actual code, but WILL sift through questions about the 6502 arch, as well as sift through emulator problems that you can describe generally.

Meaning: no one has any idea what your variables and structs actually do or what's in them when the code is run, so debugging that piece is entirely your responsibility. :-)

EDIT: I think you could clear up most of your architecture misconceptions if you took some time to read this, though be sure to note it's for the 65C02, so there are some opcodes which the NES does not have (6502 != 65C02). This might also help you (be sure to read RTS as well). If none of those make any sense, try this.

by on (#44055)
koitsu wrote:
I can assure you that cpu.programCounter + 2 >> 8 is flat out wrong. Did anyone teach you order of operation?


I wasn't sure about this myself... so I looked it up on MSDN and apparently the precedence is right (addition operator + has higher precedence than right-shift operator >>) -- in C++ anyway. I don't know whether or not it's the same in Java.

Though I do see other errors -- like mismatching parenthesis.

by on (#44057)
koitsu wrote:
Your Java code can't be right. I'm staring at it and see two errors right off the bat (well, one error for sure, the other depends on what your program is really doing with cpu.programCounter).

I can assure you that cpu.programCounter + 2 >> 8 is flat out wrong. Did anyone teach you order of operation?

I don't think anyone on this forum is going to sit here and write your entire program for you. Most people here won't sift through lines of actual code, but WILL sift through questions about the 6502 arch, as well as sift through emulator problems that you can describe generally.

Meaning: no one has any idea what your variables and structs actually do or what's in them when the code is run, so debugging that piece is entirely your responsibility. :-)

EDIT: I think you could clear up most of your architecture misconceptions if you took some time to read this, though be sure to note it's for the 65C02, so there are some opcodes which the NES does not have (6502 != 65C02). This might also help you (be sure to read RTS as well). If none of those make any sense, try this.


"Did anyone teach you order of operation?
I don't think anyone on this forum is going to sit here and write your entire program for you."

Me too (I'd never tell this) !
The pleasure to make it is MAKE IT.
And about of order of operation... that's sure I know, you could imagine: "A guy trying to write an emulator... humm that doesn't know this... " :S
What you think?

PRECEDENCE IN JAVA
http://java.sun.com/docs/books/tutorial ... ators.html

Thanks for links. (I realy want help not that someone sit and write the entyre emulator)

by on (#44058)
Disch wrote:
koitsu wrote:
I can assure you that cpu.programCounter + 2 >> 8 is flat out wrong. Did anyone teach you order of operation?


I wasn't sure about this myself... so I looked it up on MSDN and apparently the precedence is right (addition operator + has higher precedence than right-shift operator >>) -- in C++ anyway. I don't know whether or not it's the same in Java.

Though I do see other errors -- like mismatching parenthesis.


You're rigth in Java Too
http://java.sun.com/docs/books/tutorial ... ators.html

:roll: and about the errors [ (()) ] ! Thanks l'll try to correct them!
All are silly errors.

by on (#44059)
http://java.sun.com/docs/books/tutorial ... ators.html

Precedence:
+ -
>> <<

by on (#44060)
Wow, I could've sworn shifting had a significantly higher priority than addition, but Disch has corrected me, as have you with your Java reference, finally to boot Wikipedia.

I was completely and totally wrong, and I apologise for my criticism on that part.

by on (#44061)
koitsu wrote:
Wow, I could've sworn shifting had a significantly higher priority than addition, but Disch has corrected me, as have you with your Java reference, finally to boot Wikipedia.

I was completely and totally wrong, and I apologise for my criticism on that part.

No man, you don't need to apologise!
all the criticisme and errors! (they make me better)
Thanks

by on (#44077)
The moral about this story (operator precedence) is that you should not rely on them and put parenthesis to clarify what you want to do.

Those are the kind of mistake you can search for a while because at first sight the code seems right but doesn't do what you expect.

by on (#44079)
Banshaku wrote:
The moral about this story (operator precedence) is that you should not rely on them and put parenthesis to clarify what you want to do.

The one downside: Standard 6502 asm syntax uses () both for expression grouping and for indirect addressing modes. If you overparenthesize an expression, something that evaluates to lda $45,y becomes lda ($45),y.

by on (#44081)
tepples wrote:
The one downside: Standard 6502 asm syntax uses () both for expression grouping and for indirect addressing modes. If you overparenthesize an expression, something that evaluates to lda $45,y becomes lda ($45),y.


I kind of knew you were going to comment on this :) Of course, you must apply your judgment on a case by case basic. My comment was mostly for high level languages like C/C++/Java/c#/vb/vba etc. and especially when you have to supervise a group of junior in your company :wink:.