It is currently Sat Mar 25, 2017 6:41 pm

All times are UTC - 7 hours





Post new topic Reply to topic  [ 36 posts ]  Go to page 1, 2, 3  Next
Author Message
PostPosted: Tue Mar 20, 2012 8:46 am 
Offline
User avatar

Joined: Fri Oct 14, 2011 1:09 am
Posts: 248
There is a test called cpu_dummy_reads written by Blargg.

I created a logical counterpart called cpu_dummy_writes.

As I understand it, read-modify-write instructions, such as INC, issue two writes: Once for the unmodified value, and then for the modified value.

I tried my hand at making one (sans timings), and it is here, with source code: http://bisqwit.iki.fi/src/nes_tests/cpu ... writes.zip

It includes two versions. One depends on OAM reading being reliable, and the other depends on proper implementation of the PPU's open bus.

Test results for OAM version:

-- FCEUX, oldppu: OAM reading not supported (867 errors); fails test #3 (fail #2 given)
-- FCEUX, newppu: All opcodes pass, but 5 errors in OAM read test (fail #6)
-- BNES (BSNES 087): All official instructions pass, but emulator errors out at the first unofficial instruction (technically fail #9, but error message never gets displayed)
-- Nesemu1 (my emulator): All tests pass
-- Nintendulator 0.970: All opcodes pass, but 3 errors in OAM read test (fail #6)
-- Nestopia 1.40: All tests pass
-- NES: Random failures, more often than not. This suggests that OAM reading is reliable only on emulators. Though this test can help catch buggy CPU emulators, it does not suggest overall accuracy as it is now.

Test results for the PPU memory version:

-- FCEUX, oldppu: All tests pass
-- FCEUX, newppu: 150 open bus errors, opcodes worked fine (fail #10)
-- BNES (BSNES 087): 750 open bus errors, crash at unofficial instructions (technically fail #9, but error message never gets displayed), all official instructions report failure (but this is because open bus is not implemented properly).
-- Nesemu1 (my emulator): All tests pass
-- Nintendulator 0.970: All tests pass (nags about unofficial instructions)
-- Nestopia 1.40: 15 open bus errors, opcodes worked fine (fail #10)
-- NES: All tests pass


Last edited by Bisqwit on Sun Mar 25, 2012 2:43 pm, edited 14 times in total.

Top
 Profile  
 
 Post subject:
PostPosted: Tue Mar 20, 2012 9:14 am 
Offline
Formerly Fx3
User avatar

Joined: Fri Nov 12, 2004 4:59 pm
Posts: 2962
Location: Brazil
*ahem* RockNES 5.07 gives error #10, "INC abs should do double-write".

Code:
#define INC(v) \
   z_readvalue(); \
   v += 1; \
   SET_SZ_FLAGS(v)

CPUOP(INC1)
  value = readvalue(offset);
  INC(value);
  writevalue(offset, value);
OPEND


Also... the timing diagram source.
Code:
Read-Modify-Write instructions (ASL, LSR, ROL, ROR, INC, DEC,
                                     SLO, SRE, RLA, RRA, ISB, DCP)

        #  address R/W description
       --- ------- --- ------------------------------------------
        1    PC     R  fetch opcode, increment PC
        2    PC     R  fetch low byte of address, increment PC
        3    PC     R  fetch high byte of address, increment PC
        4  address  R  read from effective address
        5  address  W  write the value back to effective address,
                       and do the operation on it
        6  address  W  write the new value to effective address


Looks like the document is OK. I can't believe I bypassed it! :(

_________________
Zepper
RockNES developer


Top
 Profile  
 
 Post subject:
PostPosted: Tue Mar 20, 2012 9:28 am 
Offline

Joined: Sat May 08, 2010 9:31 am
Posts: 225
All test passed with puNES :)


Top
 Profile  
 
 Post subject:
PostPosted: Tue Mar 20, 2012 10:24 am 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 17977
Location: NE Indiana, USA (NTSC)
Might one be able to exploit open bus to get the right value into INC $2005?
Code:
 ldx #$1F
  inc $1FF5,x
  ; read #$FE = INC a,x
  ; read #$F5
  ; read #$1F
  ; read $1F05 = $0705
  ; read $2005 (open bus; hopefully returns value left there by reading $1F05)
  ; write back old value to $2005
  ; write back new value to $2005

$2006 (VRAM address) and $2007 (VRAM data) also have semantics for multiple reads and writes, and they may ignore writes too.

I'd make this, but my PowerPak's open bus behavior can't be trusted.


Top
 Profile  
 
PostPosted: Tue Mar 20, 2012 11:33 am 
Offline
User avatar

Joined: Mon Jan 03, 2005 10:36 am
Posts: 2778
Location: Tampere, Finland
Bisqwit wrote:
-- NES, PowerPak: According to Kiddcade at #nesdev, the OAM write/read tests fail randomly; and when they succeed, the instruction tests fail randomly. However, as of this writing, he has not tried the newest version.

This is expected, see this thread.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Mar 20, 2012 4:10 pm 
Offline
Formerly Fx3
User avatar

Joined: Fri Nov 12, 2004 4:59 pm
Posts: 2962
Location: Brazil
Well, I did the necessary changes, but there's a problem. The APU test ROM (4017_timing.nes) fails regarding "delay after effective $4017 write: 0". Here's my new code anyways...

Code:
#define INC(v) \
   v += 1; \
   SET_SZ_FLAGS(v)

CPUOP(INC1)
  value = readvalue(offset);
  writevalue(offset, value);
  INC(value);
  writevalue(offset, value);
OPEND


EDIT: I had to modify ASL, ROL, LSR and ROR w/ implicit addressing mode to take 2 cycles again. Everything's fine.

_________________
Zepper
RockNES developer


Last edited by Zepper on Wed Mar 21, 2012 9:48 am, edited 1 time in total.

Top
 Profile  
 
PostPosted: Wed Mar 21, 2012 6:40 am 
Offline

Joined: Mon Mar 27, 2006 5:23 pm
Posts: 1262
Bisqwit wrote:
-- BNES (BSNES 087): All official instructions pass, but emulator errors out at the first unofficial instruction (technically fail #50, but error message never gets displayed)


The documentation on unofficial opcodes is piss-poor, and wildly inconsistent. Every unofficial opcode also has 5+ mnemonics, which doesn't help matters any.

I'd appreciate if there were a document that explains 100% of all behaviors (especially the ones that have "undefined behavior", which is coded speak for "I don't understand the actual interactions with past CPU actions/states"), and gives exactly one community-preferred name for each mnemonic.


Top
 Profile  
 
 Post subject: Re: unofficial opcodes
PostPosted: Wed Mar 21, 2012 7:32 am 
Offline
User avatar

Joined: Fri Oct 14, 2011 1:09 am
Posts: 248
SLO (ASL+ORA), RLA (ROL+AND), SRE (LSR+EOR), RRA (ROR+ADC), DCP (DEC+CMP), ISB (INC+SBC).

These six are very consistent and regular. They are (nearly) perfect synthesis of their component opcodes.
I am currently rewriting my CPU core, and from the rewritten core the combined synthesis of these opcodes becomes also rather obvious.
--------
Take opcode $17 (SLO zx) for example. It is a perfect synthesis of $16 (ASL zx) and 15 (ORA zx).
ASL zx:
Code:
      //    address    write        recipient      code
      Array('PC.raw',false,        'data',        '++PC.raw; ADDR.raw=data'),
      Array('ADDR.raw',false,      'data',        'ADDR.lo+=X'),
      Array('ADDR.raw',false,      'data',        't&=data; data=t'),
      Array('ADDR.raw',true,       'data',        'sb=0; reg.P_C = t&0x80; t<<=1$ t|=sb; data=t'),
      Array('ADDR.raw',true,       'data'), // Write new value
      Array('PC.raw',false,        'OPCODE',      '++PC.raw; reg.P_N=t&0x80; reg.P_Z=!u8(t)'),

ORA zx:
Code:
      Array('PC.raw',false,        'data',        '++PC.raw; ADDR.raw=data'),
      Array('ADDR.raw',false,      'data',        'ADDR.lo+=X'),
      Array('ADDR.raw',false,      'data',        't&=data; t2&=A'),
      Array('PC.raw',false,        'OPCODE',      '++PC.raw; t|=t2; A=t; reg.P_N=t&0x80; reg.P_Z=!u8(t)'),

SLO zx:
Code:
      Array('PC.raw',false,        'data',        '++PC.raw; ADDR.raw=data'),     IDENTICAL
      Array('ADDR.raw',false,      'data',        'ADDR.lo+=X'),                  IDENTICAL
      Array('ADDR.raw',false,      'data',        't&=data; t2&=A; data=t'),      INCLUDES EVERYTHING FROM BOTH COMPONENTS
      Array('ADDR.raw',true,       'data',        'sb=0; reg.P_C = t&0x80; t<<=1$ t|=sb; data=t'), THIS COMES FROM ASL
      Array('ADDR.raw',true,       'data'), // Write new value                    THIS FROM ASL
      Array('PC.raw',false,        'OPCODE',      '++PC.raw; t|=t2; A=t; reg.P_N=t&0x80; reg.P_Z=!u8(t)'), INCLUDES EVERYTHING FROM BOTH COMPONENTS

--------
Similarly, opcode 8D, STA abs:
Code:
      Array('PC.raw',false,        'data',        '++PC.raw; ADDR.lo=data'),
      Array('PC.raw',false,        'data',        '++PC.raw; ADDR.hi=data; t&=A; data=t'),
      Array('ADDR.raw',true,       'data'),
      Array('PC.raw',false,        'OPCODE',      '++PC.raw'),

Opcode 8E, STX abs:
Code:
      Array('PC.raw',false,        'data',        '++PC.raw; ADDR.lo=data'),
      Array('PC.raw',false,        'data',        '++PC.raw; ADDR.hi=data; t&=X; data=t'),
      Array('ADDR.raw',true,       'data'),
      Array('PC.raw',false,        'OPCODE',      '++PC.raw'),

Opcode 8F, SAX abs:
Code:
      Array('PC.raw',false,        'data',        '++PC.raw; ADDR.lo=data'),          IDENTICAL
      Array('PC.raw',false,        'data',        '++PC.raw; ADDR.hi=data; t&=A; t&=X; data=t'), EVERYTHING FROM BOTH
      Array('ADDR.raw',true,       'data'),                                           IDENTICAL
      Array('PC.raw',false,        'OPCODE',      '++PC.raw'),                        IDENTICAL

--------
For a more complicated (and at first glance, irregular) example, consider the differences between these two official opcodes:
Opcode 95, STA zx (official):
Code:
      Array('PC.raw',false,        'data',        '++PC.raw; ADDR.raw=data'),
      Array('ADDR.raw',false,      'data',        'ADDR.lo+=X; t&=A; data=t'), // dummy read while the CPU is preparing data
      Array('ADDR.raw',true,       'data'),
      Array('PC.raw',false,        'OPCODE',      '++PC.raw'),

Opcode 96, STX zy (official):
Code:
      Array('PC.raw',false,        'data',        '++PC.raw; ADDR.raw=data'),
      Array('ADDR.raw',false,      'data',        'ADDR.lo+=Y; t&=X; data=t'),
      Array('ADDR.raw',true,       'data'),
      Array('PC.raw',false,        'OPCODE',      '++PC.raw'),

However, with absolute indexing, there is an extra cycle dedicated for fixing up the 16-bit address, and this conflicts with the indexing logic (the high-part of the address is loaded at the same time (I guess, in the same bus) as the target register, which is an index register), making 9E (STX absy) broken and therefore not part of the official set of instructions.

Opcode 9D, STA absx (official):
Code:
      Array('PC.raw',false,        'data',        '++PC.raw; ADDR.lo=data'),
      Array('PC.raw',false,        'data',        '++PC.raw; ADDR.hi=data; ADDR.lo+=X; overflow=ADDR.lo<X'),
      Array('ADDR.raw',false,      'data',        'ADDR.hi += overflow; t&=A; data=t'),
      Array('ADDR.raw',true,       'data'),
      Array('PC.raw',false,        'OPCODE',      '++PC.raw'),

Opcode 9E, STX absy (unofficial, alternative names: SHX/SXA/XAS)
Code:
      Array('PC.raw',false,        'data',        '++PC.raw; ADDR.lo=data'),
      Array('PC.raw',false,        'data',        '++PC.raw; ADDR.hi=data; ADDR.lo+=Y; overflow=ADDR.lo<Y'),
      Array('ADDR.raw',false,      'data',        't&=(ADDR.hi + overflow); t&=X; data=t'),
      Array('ADDR.raw',true,       'data'),
      Array('PC.raw',false,        'OPCODE',      '++PC.raw'),

Then the perfect synthesis opcode of these two becomes:
Opcode 9F, SAX absx (unofficial, alternative names: SHA/AHA/AHX)
Code:
      Array('PC.raw',false,        'data',        '++PC.raw; ADDR.lo=data'),
      Array('PC.raw',false,        'data',        '++PC.raw; ADDR.hi=data; ADDR.lo+=X; overflow=ADDR.lo<X'),
      Array('ADDR.raw',false,      'data',        't&=(ADDR.hi+overflow); t&=A; t&=X; data=t'),
      Array('ADDR.raw',true,       'data'),
      Array('PC.raw',false,        'OPCODE',      '++PC.raw'),

--------
At this cycle-level opcode analysis, the even the erradic behavior of the unofficial opcodes starts looking surprisingly regular.
True, there are some that are unpredictable, such as 8B (ANE #imm), which is a synthesis of 89 STA #imm + 82 STX #imm, both functionally NOPs, but combined does weird things.
--------
To answer your concern, what matters is not what people call these opcodes. What matters is what they do.


Last edited by Bisqwit on Wed Mar 21, 2012 2:17 pm, edited 6 times in total.

Top
 Profile  
 
PostPosted: Wed Mar 21, 2012 7:46 am 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 17977
Location: NE Indiana, USA (NTSC)
byuu wrote:
I'd appreciate if there were a document that explains 100% of all behaviors (especially the ones that have "undefined behavior", which is coded speak for "I don't understand the actual interactions with past CPU actions/states")

The behaviors behind instructions involving $11 or $EE is actually analog, as a page on visual6502 explains. The CPU is trying to read and write the special bus at the same time, where some of it is direct and the other goes through ADC's decimal mode circuitry. The timing on this differs from one lot of 6502s to another and possibly even by temperature and RFI. It also involves the RDY input, meaning the behavior might change around a DMC DMA request (which pulls RDY low for a few cycles).

Quote:
and gives exactly one community-preferred name for each mnemonic.

For the stable opcodes, I'd pick whatever mnemonic ca65's 6502X mode uses. My article about practical uses of unofficial opcodes had mostly followed ca65's mnemonics, and today I changed SBX to AXS to conform fully.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Mar 22, 2012 7:28 am 
Offline
Formerly Fx3
User avatar

Joined: Fri Nov 12, 2004 4:59 pm
Posts: 2962
Location: Brazil
Is there something else for CPU emulation that could be tested? Such test was important here.

_________________
Zepper
RockNES developer


Top
 Profile  
 
 Post subject:
PostPosted: Thu Mar 22, 2012 9:12 am 
Offline

Joined: Thu Feb 09, 2012 3:54 am
Posts: 24
Nice to see someone other than blargg creating some tests!

My emu (jaNES) passed both official and unnofficial tests :)


Top
 Profile  
 
 Post subject:
PostPosted: Sat Mar 24, 2012 4:56 pm 
Offline
User avatar

Joined: Fri Oct 14, 2011 1:09 am
Posts: 248
I created another version of this test, now using PPU memory for the double write testing. It also verifies whether the emulator emulates PPU's open bus features properly. I also updated the OAM version to do more exhaustive testing on the OAM.

I have updated the first post of the thread with test results.

The test(s) can be downloaded here: http://bisqwit.iki.fi/kala/cpu_dummy_writes.zip

I would appreciate it if someone could run this test on the real NES a few times and report carefully the results, preferably before people start using this test and before it becomes difficult to release updates to it.

Screenshots from Nestopia (1.40), BSNES (v087), Nintendulator (0.970), FCEUX (2.1.4a), RockNES (5.07), puNES (0.56), nesemu1, iNES 3.6, Famtasia, Nesticle ;-)
Image Image Image Image Image Image Image Image Image Image

Video capture from my emulator:
http://bisqwit.iki.fi/kala/snap/nesemu1 ... te_oam.avi , http://bisqwit.iki.fi/kala/snap/nesemu1 ... ppumem.avi


Last edited by Bisqwit on Sat Mar 24, 2012 7:32 pm, edited 4 times in total.

Top
 Profile  
 
 Post subject:
PostPosted: Sat Mar 24, 2012 6:51 pm 
Offline
Formerly Fx3
User avatar

Joined: Fri Nov 12, 2004 4:59 pm
Posts: 2962
Location: Brazil
It's time for implementing such unofficial opcodes. In fact, they are/were used to identify bad dumps and/or bugs in the emulation.

_________________
Zepper
RockNES developer


Top
 Profile  
 
 Post subject:
PostPosted: Sat Mar 24, 2012 7:24 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 17977
Location: NE Indiana, USA (NTSC)
I ran the OAM test with my PowerPak in NovaYoshi's NES. Most of the time I got this:
"n FAILED READS; SPRDATA does not appear to be reliable RAM at all"
The most common values of n were 126 and 895, depending on PPU-CPU alignment at reset, but 6, 134, and 902 were seen more than once.

Occasionally I got this:
"INC abs should do double-write"

So I long-reset and did the PPU tests. Each line of open bus behavior was "0- 0- 00 0- 0- 0- 0- 00". Then it got glitchy as heck for a couple seconds. And then randomly depending on PPU-CPU alignment at reset, it would either pass or display a blank box below the "1B3B5B7BDBFB". Once I got it to say "Pas " with four spaces after "Pas". On the most part the result of a passed run looked like Nintendulator, except for orange horizontal lines running through most blank areas, and random characters scattered about the screen.

I don't have my video recording equipment with me at the moment. In a couple days, should I make videos covering about a dozen resets of each test?


Top
 Profile  
 
 Post subject:
PostPosted: Sat Mar 24, 2012 7:34 pm 
Offline
User avatar

Joined: Fri Oct 14, 2011 1:09 am
Posts: 248
tepples wrote:
I don't have my video recording equipment with me at the moment. In a couple days, should I make videos covering about a dozen resets of each test?

Thank you, but no, I think that description was verbose enough. Weird!
The jumpy image was to be expected, it does that on emulators too. (Though on emulators, it jumps during the open bus testing, not during the opcode testing.)
I tried to minimize the times the screen is blanked, just in case an emulator crashes in the middle of the test and leaves nothing to be seen on the screen, but I may have cut it too close at times. I did include a vblank wait at relevant times, or so I think. I'll see if I can fix it more.
I'm not sure what to make of the "blank box". There was a blank box on the next screen in some earlier version, but the scrolling position is set with a vblank wait before the pass texts are output.

I will leave the OAM test like that though; I don't think I can improve it in any way except by adding more opcodes into the test or by making the opcode tests not depend on earlier tests, as is in the PPU memory version.

Good to know that the assumptions I made in making the open bus test were right.


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

All times are UTC - 7 hours


Who is online

Users browsing this forum: No registered users and 4 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:  
Powered by phpBB® Forum Software © phpBB Group