OAM/DMC DMA tests

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
OAM/DMC DMA tests
by on (#169070)
cpow ran some tests with visual2a03 to delve further into DMA behavior. Though his notes were a bit scattered for my tastes, and left me with a few unanswered questions.

So using his notes as a base, I ran my own tests on visual2a03 to verify them, and to fill in a few of the gaps.

Here are my findings:


Code:
==========================================
==========================================
==========================================
General
==========================================


DMA unit alternates between 'get' cycles and 'put' cycles.  Values are read on 'get' cycles and written on 'put' cycles.  'get' cycles can never write -- 'put' cycles can read, but discard any value read.  DMA unit seems to alternate between get/put even when DMA is not active -- effectively meaning that even cycles are 'get' cycles, and odd cycles are 'put' cycles.

"Dummy reads" ALWAYS seem to be performed from whatever address the CPU will want to read from next -- that is, whatever address will be read from once the DMA is complete.


When the DMA unit needs to cut into the CPU, it begins a 'halt' process.  The process appears to be as follows:

    1)  The 'halt attempt' cycle -- Let the CPU start its next cycle. 
        a)  If this cycle is a write, perform it normally.  Repeat step 1
        b)  If this cycle is a read, hijack the read, discard the value, and prevent all other actions that occur on this cycle (PC not incremented, etc).
                Presumably, side-effects from performing the read still occur.  Proceed to step 2
               
    2)  For DMC DMA ONLY -- do another dummy read, discarding the result.
   
    3)  If the DMA unit is currently on a 'put' cycle, do another dummy read  ('alignment' cycle)
   
    4)  Actually perform the DMA
        a)  For DMC, this performs a single read cycle, then returns control to main CPU logic
        b)  For OAM, this performs 256 alternating reads/writes as you'd expect
       
       
Note that the DMA is effectively delayed as it waits for all CPU write cycles to complete.  Though this is just a delay, and does not actually alter the length of the DMA

What DOES alter the length of the DMA is the optional alignment cycle.



==========================================
==========================================
==========================================
DMC
==========================================

DMC DMAs appear to try to halt during the 'put' phase -- meaning they will take 4 cycles normally:
    1) 'put' - halt
    2) 'get' - extra DMC dummy read
    3) 'put' - dummy cycle for alignment
    4) 'get' - DMA
   
When DMC halt happens "on a write cycle", this makes it take 3 cycles because alignment can be skipped:
    *) 'put' - initial halt attempt -- but if a write cycle, it's delayed
    1) 'get' - attempt to halt again -- successful this time because it's a read cycle
    2) 'put' - extra DMC dummy read
            alignment not needed
    3) 'get' - DMA
   
    (note the '*' write cycle is performed normally, and therefore does not count as a stolen cycle, hence DMC only steals 3 cycles here)
   
   
However the DMC will steal 4 cycles if it attempts to halt during the first write of a RMW instruction (INC/DEC/etc)
    *) 'put' - halt attempt - fails because CPU is writing (first RMW write)
    *) 'get' - halt attempt - fails because CPU is writing (second RMW write)
    1) 'put' - halt attempt - successful
    2) 'get' - extra DMC dummy read
    3) 'put' - alignment
    4) 'get' - DMA

The above logic matches for 3 consecutive writes (interrupts/BRK).  If the halt is during the 1st or 3rd write, it'll steal 3 cycles... but if it's during the 2nd write, it'll steal 4.

==========================================
==========================================
==========================================
OAM / 4014
==========================================
   
OAM DMA behaves similarly, but skips the DMC-only dummy read.  Meaning OAM will take 513 / 514 cycles depending on whether or not
the alignment cycle is needed

Assuming the write is performed with a STA/STX/STY:
    *)  $4014 write cycle triggering OAM DMA
    1)  halt attempt - successful (next cycle is a read for the next opcode, or is an interrupt)
    ?)  possible alignment
    2)  'get' - read 1st byte
    3)  'put' - write 1st byte
        ...
       
       
Writing to 4014 twice consecutively (INC/DEC/etc) holds expected logic.  Both writes will perform, followed by the halt cycle,
possible alignment, then 512 cycles of DMA.



==========================================
==========================================
==========================================
Both at the same time
==========================================

Things to note:
- DMC DMA trumps OAM DMA
- A DMC halt is considered successful if it happens on an OAM DMA cycle
- under no circumstances can a DMC DMA cycle immediately follow a successful DMC halt cycle.  There must be at least 1 dummy cycle, alignment cycle, or OAM DMA cycle between the halt and the DMA.


Examples:
    Cycles marked with '+' are "DMC stolen"
    p = must be a 'put' cycle (remember DMC always halts on a put cycle)
    g = must be a 'get' cycle
    * = normal, unaffected CPU cycle

DMC halts on the $4014 write cycle:
    p *)    $4014 write - unsuccessful DMC halt
    g 1)    DMC & OAM halt -- successful
    p 2)    DMC dummy / alignment      not a DMC stolen cycle, since this would have to be alignment regardless
    g+3)    DMC DMA
    p+4)    re-alignment
    g 5)    OAM DMA read 1
    p 6)    OAM DMA write 1
            ...
       
DMC halts 1 cycle after $4014 write:
    g *)    $4014 write
    p 1)    DMC & OAM halt - successful
    g 2)    OAM read 1      (DMC dummy)
    p 3)    OAM write 1     (DMC alignment)
    g+4)    DMC
    p+5)    re-alignment
    g 6)    OAM read 2
    p 7)    OAM write 2
    ...
   
   
This logic follows for 2 consecutive writes to $4014.




==========================================
==========================================
==========================================
What I was not able to test
==========================================


Visual2a03 gave EXTREMELY weird behavior for OAM DMA.  I suspect it needs more warmup time.  OAM DMA was fetching from the wrong address, and the address being read from was being mangled by DMC DMAs, which was resulting in 700+ stolen cycles... and would also result in extremely corrupted sprites on a real system.  Because of this I was unable to test the following:

1)  What happens on edge case when DMC DMA occurs at the very end of OAM DMA?
2)  If you INC $4014, does it DMA from the pre-incremented value or post-incremented?



I also uploaded the unpolished / scattered notes which has the results of my tests as well as links to the test programs I ran:

https://www.dropbox.com/s/afvbxers66v9994/dma.txt?dl=0
Re: OAM/DMC DMA tests
by on (#169105)
I just want to point out that what you describe as "halt attempt" is describing what the 6502 RDY pin does.
Re: OAM/DMC DMA tests
by on (#169114)
Quote:
If you INC $4014, does it DMA from the pre-incremented value or post-incremented?

Both. It'll perform a read from $4014 (dummy, should return $40), then write it to $4014 (DMA-ing). The value $40 becomes $41 and another DMA is performed. Now waiting for someone to correct me. :mrgreen: :roll:

Well, that's the expected operation considerating the INC timing diagram. What happens during the 1st or 2nd sprite DMA is another subject. :)
Re: OAM/DMC DMA tests
by on (#169116)
DMA can't start until R/W goes high, because that's how the 6502 RDY signal works.
It definitely only does one of the two DMAs, but I don't remember which.
Re: OAM/DMC DMA tests
by on (#169117)
lidnariq wrote:
DMA can't start until R/W goes high, because that's how the 6502 RDY signal works.
It definitely only does one of the two DMAs, but I don't remember which.


So... an INC $4014 wouldn't be correctly performed in the current emulators. Why would it fail in the first write to $4014? A read from $4014 returns $40; then a write should occur. Where is my mistake?
Re: OAM/DMC DMA tests
by on (#169119)
Zepper wrote:
So... an INC $4014 wouldn't be correctly performed in the current emulators. Why would it fail in the first write to $4014? A read from $4014 returns $40; then a write should occur. Where is my mistake?


You can think of it this way:

A $4014 write does not immediately perform a DMA. Instead, it sets a flag to indicate that a DMA should start on the next CPU read cycle.

If two $4014 writes happen back-to-back (as with INC), they both set the flag, but no DMA has been performed yet because there hasn't been a read cycle.


lidnariq wrote:
I just want to point out that what you describe as "halt attempt" is describing what the 6502 RDY pin does.


Yeah I'm pretty sure a lot of this info was known already. I know cpow posted several posts where he tested a lot of this and came up with similar results. I just wanted to test it myself because the information was scattered and often unclear.

I get feedback sometimes that people like when I make these kinds of summaries because I guess the way I explain it is helpful? *shrug* So I figured I'd post it. =P

If nothing else, doing these tests has certainly helped ME understand it.
Re: OAM/DMC DMA tests
by on (#169122)
Disch wrote:
A $4014 write does not immediately perform a DMA. Instead, it sets a flag to indicate that a DMA should start on the next CPU read cycle.

If two $4014 writes happen back-to-back (as with INC), they both set the flag, but no DMA has been performed yet because there hasn't been a read cycle.

Wait. Lemme think...
1. read instruction opcode ($EE)
2. read low byte of address ($14)
3. read high byte of address ($40)
4. read from effective address ($4014 should return $40)
5. write the value back to effective address (should set the SPRDMA flag?)
6. do the operation (INC) and write the new value ($41) to the effective address (SPRDMA flag already set)
*7. read the next instruction opcode (trigger SPRDMA?)
Disch wrote:
I get feedback sometimes that people like when I make these kinds of summaries because I guess the way I explain it is helpful? *shrug* So I figured I'd post it. =P

Always welcome. ^_^;;

EDIT: *I mean... if the SPRDMA flag is waiting for a CPU read to trigger, it should do on the first cycle of the next instruction... no??
Re: OAM/DMC DMA tests
by on (#169128)
Your summary looks correct.


- write: 1st $4014 write (original value)
- write: 2nd $4014 write (new value)
- read: next opcode -- but DMA halts here, so this read is thrown away
> optional read: next opcode again & thrown away. This only done if this is an odd cycle (DMA unit has to align so reads are on even cycles)
- read: $xx00
- write: $2004
- read: $xx01
- write: $2004
...
- read: $xxFF
- write: $2004
- read: next opcode
Re: OAM/DMC DMA tests
by on (#169139)
Disch wrote:
I get feedback sometimes that people like when I make these kinds of summaries because I guess the way I explain it is helpful? *shrug* So I figured I'd post it. =P

If nothing else, doing these tests has certainly helped ME understand it.


I've been wanting to make the DMC reads in my NSF player accurate for some time now (not that it actually matters for an NSF player), and this is the first time anyone has described it in terms I can understand. Thank you muchly.

One quick question: is the DMA put/get cycle in any way related to the APU clock? Are they aligned in a specific way, or can the alignment change between resets?
Re: OAM/DMC DMA tests
by on (#169143)
Glad it's useful! :mrgreen:

Regarding your questions: I have no idea. This is something I wouldn't want to test on visual2a03 -- but would want to do on a real cart... and making an actual test ROM for it would be a lot of work =x
Re: OAM/DMC DMA tests
by on (#169147)
I was hoping someone might have traced the circuit to see if they were driven by the same divider. Never mind.

The reason I asked is that if the APU (and therefore DMC output unit) always clocks on a "get" cycle, that might explain why the DMC DMA always starts on a "put" cycle.
Re: OAM/DMC DMA tests
by on (#169149)
They're the same divider. In Visual2A03 they're called apu_clk1 and apu_clk2e and control the OAM DMA cadence. Tracing down the exact even/odd clock used by the DPCM DMA is more of a pain, but I see apu_/clk2 poking around it.
Re: OAM/DMC DMA tests
by on (#169153)
Chip internals are way beyond me, so thanks for looking into it.

I implemented the above logic for DMC DMA in my NSF player, and got... no observable result, as expected. :P It still passes all the same tests as it did before, but I don't have anything picky enough to spot the difference.
Re: OAM/DMC DMA tests
by on (#169221)
Quote:
2) If you INC $4014, does it DMA from the pre-incremented value or post-incremented?

Visual2A03 seems to be able to DMA only from zero page, even though I can see enough memory for two pages. Hmm...


Btw, can someone clarify for me what the wiki means here regarding DMAs? "1 dummy read cycle while waiting for writes to complete, +1 if on an odd CPU cycle, then 256 alternating read/write cycles."
Does the "while waiting for writes to complete" refer to what happens if you R&W(2 write cycles) to 0x4014? Isn't it easier to say that a DMA (and only one DMA) starts after an instruction finishes? Did I miss something here or is it referring to something else?
Re: OAM/DMC DMA tests
by on (#169231)
fred wrote:
Isn't it easier to say that a DMA (and only one DMA) starts after an instruction finishes? Did I miss something here or is it referring to something else?

The DMA starts after the writes finish. The DMA unit has no knowledge of where instructions start and end. It can only watch the bus to see if the CPU is writing or reading, and it can only pause the CPU after a read, so it always waits for a single read to complete before it starts. The result of that read is then discarded, turning it into a dummy read.
Re: OAM/DMC DMA tests
by on (#169234)
Rahsennor wrote:
fred wrote:
Isn't it easier to say that a DMA (and only one DMA) starts after an instruction finishes? Did I miss something here or is it referring to something else?

The DMA starts after the writes finish. The DMA unit has no knowledge of where instructions start and end. It can only watch the bus to see if the CPU is writing or reading, and it can only pause the CPU after a read, so it always waits for a single read to complete before it starts. The result of that read is then discarded, turning it into a dummy read.


Almost. From previous posts, the DMA won't start before the next CPU read. As I said, it doesn't trigger in the 1st write because the following cycle is the operation + another write to $4014. So, the opcode fetch (instruction read) triggers the DMA.
Re: OAM/DMC DMA tests
by on (#169235)
That's what I just said. One read, then the DMA.
Re: OAM/DMC DMA tests
by on (#169244)
Here is the ambiguous part:
Quote:
The DMA starts after the writes finish.

It's after the second write and on the next CPU read. Just to be crystal clear, sorry.
Re: OAM/DMC DMA tests
by on (#169245)
I like examples!

Code:
        This code:
INC $4014
NOP

        Yields these cycles
       
read:   'INC' opcode
read:   #$14
read:   #$40
read:   $4014
write:  $4014           <- trigger
write:  $4014           <- DMA attempts to halt, can't because it's a write
read:   'NOP' opcode    <- DMA attempts to halt, success!  This becomes a dummy read
  -rd:  'NOP' opcode    <- 'alignment' dummy read **ONLY IF** DMA unit is on a 'put' cycle
read:   $xx00           <- DMA starts here .. this is a DMA read
write:  $2004           <- DMA write
...
Re: OAM/DMC DMA tests
by on (#169246)
Zepper wrote:
Here is the ambiguous part:

fred asked if the DMA occured after the instruction finishes. That's true, but misleading; it's the write cycles the DMA is actually waiting on. That's what the statement you just quoted was addressing.

The rest of my post explained exactly the same thing you just felt the need to correct, twice, although my choice of words was admittedly very poor. I do that a lot, and from what I gather English isn't your first language, so the miscommunication is understandable. I'll shut up now.

This is why I don't help people. :roll:
Re: OAM/DMC DMA tests
by on (#169247)
Ah.

In that case, it's worth nothing that on BRK/interrupt, the writes are NOT the end of the instruction. That is why the distinction is important. While a $4014 write can't happen during an interrupt, a DMC fetch certainly can.

More examples!

Code:
        This code:
BRK

        Can yield these cycles, assuming DMC wants to fetch on the indicated cycle:
       
read:   'BRK' opcode
read:   byte following opcode
write:  $01xx push PCH      <- DMC DMA tries to halt here, fails
write:  $01xx push PCL      <- tries to halt here, fails
write:  $01xx push status   <- tries to halt here, fails
read:   $FFFE               <- tries to halt here, success -- this is a dummy read
read:   $FFFE               <- another dummy read for DMC
--rd:   $FFFE               <- 'alignment' dummy read only if DMA unit is on a put cycle
read:   $xxxx               <- DMC DMA fetch
read:   $FFFE               <- normal BRK read
read:   $FFFF
Re: OAM/DMC DMA tests
by on (#169261)
Is it only the halting read cycle that shows up outside the 6502? Do the DMA's dummy reads not cause actual pin activity?
Re: OAM/DMC DMA tests
by on (#169263)
There shouldn't be any functional difference between dummy reads and normal reads.
Re: OAM/DMC DMA tests
by on (#169268)
Quote:
That's true, but misleading; it's the write cycles the DMA is actually waiting on.

Oh, I see! I just assumed it worked similarly to interrupts. Thanks for explaining it.
Re: OAM/DMC DMA tests
by on (#169305)
If the CPU is interrupted during a $4016 read, it was only a single bit deletion. Is that information incorrect or is there another explanation for it? Would this also mean that an interrupted $2007 read triggers up to three extra PPU address increments?
Re: OAM/DMC DMA tests
by on (#169309)
the wiki wrote:
For the controller registers, this can cause an extra rising clock edge to occur, and thus shift an extra bit out. For the others, the PPU will see multiple reads, which will cause extra increments of the address latches, or clear the vblank flag.


Sounds like controller ports only process 1 extra read, but the PPU processes all of them. That suggests multiple reads do in fact take place, but 4016/7 process them in a way where some of them get ignored. Maybe they ignore successive reads similar to how MMC1 ignores successive writes?
Re: OAM/DMC DMA tests
by on (#169310)
Disch wrote:
Sounds like controller ports only process 1 extra read, but the PPU processes all of them. That suggests multiple reads do in fact take place, but 4016/7 process them in a way where some of them get ignored. Maybe they ignore successive reads similar to how MMC1 ignores successive writes?
$4016 and $4017 have no special logic to that effect. If you're seeing different behavior between $2007 and $4016, there's got to be something else going on.
Re: OAM/DMC DMA tests
by on (#169315)
Knowing the logic involved in generating the CLK pulse sent to the controller ports would help. /OE1 and /OE2 might be involved, though it's hard to imagine that the DMA disconnects those (seemingly unrelated) signals as well. The wiki could also be wrong, and we might be misremembering the effects of the conflict.
Re: OAM/DMC DMA tests
by on (#169316)
The clock pulse is exactly

NOT(A15…A0 = h'4016' AND M2 = 1 AND R/W = 1)

You can trace it in visual2a03, it's called "r4016"
Re: OAM/DMC DMA tests
by on (#169342)
If a $4016 read is triggered on r4016 going low, then it would ignore successive reads because r4016 stays low for the entire duration (it does not toggle with phi2):


http://www.qmtpro.com/~nes/chipimages/v ... 4010fe30fe
Code:

cyc      ab  db rw               pc   a  x  y  s    p          r4016
=======================================================================
1398    0084 ad 1 LDA&nbsp;Abs  0084 00 a2 00 bd Nv&#8209BdIzc   1      <- LDA $4016
1399    0084 ad 1 LDA&nbsp;Abs  0084 00 a2 00 bd Nv&#8209BdIzc   1
1399    0085 16 1               0085 00 a2 00 bd Nv&#8209BdIzc   1
1400    0085 16 1               0085 00 a2 00 bd Nv&#8209BdIzc   1
1400    0086 40 1               0086 00 a2 00 bd Nv&#8209BdIzc   1
1401    0086 40 1               0086 00 a2 00 bd Nv&#8209BdIzc   1
1401    4016 00 1               0087 00 a2 00 bd Nv&#8209BdIzc   0      <- DMA halt
1402    4016 00 1               0087 00 a2 00 bd Nv&#8209BdIzc   0
1402    4016 00 1               0087 00 a2 00 bd nv&#8209BdIZc   0
1403    4016 00 1               0087 00 a2 00 bd nv&#8209BdIZc   0
1403    4016 00 1               0087 00 a2 00 bd nv&#8209BdIZc   0
1404    4016 00 1               0087 00 a2 00 bd nv&#8209BdIZc   0
1404    c001 00 1               0087 00 a2 00 bd nv&#8209BdIZc   1      <- actual DMA read
1405    c001 00 1               0087 00 a2 00 bd nv&#8209BdIZc   1
1405    4016 00 1               0087 00 a2 00 bd nv&#8209BdIZc   0      <- proper 4016 read
1406    4016 00 1               0087 00 a2 00 bd nv&#8209BdIZc   0
1406    0087 10 1 BPL&nbsp;     0087 00 a2 00 bd nv&#8209BdIZc   1      <- next instruction
Re: OAM/DMC DMA tests
by on (#169353)
I see! I thought the CPU's clock signal was also used for the logic, but considering rams and roms aren't synchronous, they don't need to know the CPU's clock, and same with the controller ports. It makes sense now, thanks!
Re: OAM/DMC DMA tests
by on (#169367)
I didn't think about the fact that INC 4014 also reads from 4014, hah. What's the expected return value? Visual2A03 returns whatever was written there last, but is this an "open bus" case?
Re: OAM/DMC DMA tests
by on (#169371)
I tested DEC -- and posted about it long ago. Not INC, but similar behavior.

viewtopic.php?f=3&t=9033&hilit=+Visual2A03

The RDY is triggered by the first write but the address given to the DMA engine is based on the second write -- which in INC and DEC case happens to be the "result write". The "dummy write" is the first one because the CPU needs a cycle to do the increment/decrement of A.

However, having said all of that, I just went back through my programs and adjusted the URL to accomodate the new location of the simulator.

Something's changed/BROKEN? The program I used in the above post provides DIFFERENT RESULTS than what I reported back then??

This is the program.

The difference? The original post shows the sprite DMA occurring from the DEC result address ($FF00...). But the new simulator shows the sprite DMA occurring from the DEC dummy address ($0000...).

What? The earlier result didn't confuse me because it made sense. This one confuses me because it doesn't!
Re: OAM/DMC DMA tests
by on (#169373)
cpow wrote:
The difference? The original post shows the sprite DMA occurring from the DEC result address ($FF00...). But the new simulator shows the sprite DMA occurring from the DEC dummy address ($0000...).

I think there's a bug that it's forcing the OAM source address to $00. Probably just coincidental that it happens to be the DEC dummy address, would be better to DEC a non-zero value. (I'm not sure if Visual 2A03 is mapping readable RAM under the $4014 address, might be hard to change the value if not.)
Re: OAM/DMC DMA tests
by on (#169376)
thefox wrote:
I think there's a bug that it's forcing the OAM source address to $00. Probably just coincidental that it happens to be the DEC dummy address, would be better to DEC a non-zero value. (I'm not sure if Visual 2A03 is mapping readable RAM under the $4014 address, might be hard to change the value if not.)

Confirmed with this program that attempts to DEC sprite DMA with A set to $02. Instead of DMAing from $01xx... the simulator DMAs from $00xx...

This is a new bug because clearly the DMAing previously worked as I described in the simulator. With $00 in A the DMAing occurred from $FF..
Re: OAM/DMC DMA tests
by on (#169379)
There's other bugs with the OAM DMA, too. If the DMC cuts in during the OAM DMA, it mangles the OAM source address, possibly adding or removing reads. I had one OAM DMA run over 700 cycles because the DMC would interrupt and move the OAM source back like $40 places
Re: OAM/DMC DMA tests
by on (#169380)
Disch wrote:
There's other bugs with the OAM DMA, too. If the DMC cuts in during the OAM DMA, it mangles the OAM source address, possibly adding or removing reads. I had one OAM DMA run over 700 cycles because the DMC would interrupt and move the OAM source back like $40 places


I've confirmed there are indeed "other bugs" but they are "new bugs" not "always there bugs.

RE my DMC DMA during Sprite DMA testing, discussed here, the DMC DMA occurs on cycles 40 and 822. In the latest simulator the same program has a DMC DMA at cycle 38, 1404, 1836, and 2268. So it seems the engine skips a couple of cycles but then "rights itself"?!?

Additionally, I noticed that previously the DMA cycles were two half-cycles of the same "clock cycle". In other words, the DMA occurs on both half-cycles of CPU cycle 40. In the new simulation it's like this:

Code:
39   0017   8d   1   STA&nbsp;Abs   0018   01   c0   00   bd   nv&#8209Bdizc   1
39   c000   00   1   BRK   0018   01   c0   00   bd   nv&#8209Bdizc   0
38   c000   00   1   BRK   0018   01   c0   00   bd   nv&#8209Bdizc   0
38   0017   8d   1   STA&nbsp;Abs   0018   01   c0   00   bd   nv&#8209Bdizc   0


The DMC DMA occurs on one half-cycle of CPU cycle 38 and one half-cycle of CPU cycle 39. I'm not sure which way is properly representative of what actually happens, but something VERY strange in that it's now *different*.

Here's what it looked like originally:

Code:
39   0018   14   1      0019   01   c0   00   bd   nv-Bdizc   0
39   0018   14   1      0019   01   c0   00   bd   nv-Bdizc   0
40   c000   00   1      0019   01   c0   00   bd   nv-Bdizc   0
40   c000   00   1      0019   01   c0   00   bd   nv-Bdizc   0
41   0018   14   1      0019   01   c0   00   bd   nv-Bdizc   1
41   0018   14   1      0019   01   c0   00   bd   nv-Bdizc   1


RE the simulator crashing, have you hidden the chip display? It runs much faster when not bothering with that, but still slows down once I get to ~800 cycles. But no crash.
Re: OAM/DMC DMA tests
by on (#169381)
I got the crashing problem sorted a while ago.

Also it looks like Visual2a03 has had this OAM problem since at least November, as in the thread you linked, thefox mentions he's having the same problem when he tried to reproduce your tests.

Anyway, cpow, were you ever able to test what happens when DMC DMA occurs on the last few cycles of OAM? That's really the last piece of the puzzle as far as I can tell.
Re: OAM/DMC DMA tests
by on (#169384)
Disch wrote:
Anyway, cpow, were you ever able to test what happens when DMC DMA occurs on the last few cycles of OAM? That's really the last piece of the puzzle as far as I can tell.

I'm not confident in the simulator given the recent observations. I'll wait until it's "fixed". If ever. Too bad.
Re: OAM/DMC DMA tests
by on (#174426)
Hi,

I am working on DMC DMA currently and found this thread immensely helpful, thanks for all the wealth of knowledge.

I do have a question though about something Disch wrote in his dropbox notes in the opening post of this thread:
Quote:
; LDX starts at cycle 8 (after reset)
; $4015 write happens on cycle 23
; first DMA takes 3 cycles @ 26, 27, 28 (ignoring this because
; APU hasn't fully primed yet apparently)


I found this interesting, so I did a test on Visual 2A03. Instead of performing STA $4015 early on, I performed it on cycle 1400 (where the second DMC DMA usually occurs in Disch's code. )

The result is also 3 DMA cycles instead of the normal 4:

Code:
cycle   ab   db   rw   Fetch   pc   a   x   y   s   p   c_rdy
1406   0089   ea   1   NOP   0089   1f   a2   00   bd   nv&#8209BdIzc   1
1406   0089   ea   1      0089   1f   a2   00   bd   nv&#8209BdIzc   1
1405   0089   ea   1      0089   1f   a2   00   bd   nv&#8209BdIzc   1
1405   0088   ea   1   NOP   0088   1f   a2   00   bd   nv&#8209BdIzc   1
1404   0088   ea   1   NOP   0088   1f   a2   00   bd   nv&#8209BdIzc   1
1404   0088   ea   1      0088   1f   a2   00   bd   nv&#8209BdIzc   1
1403   0088   ea   1      0088   1f   a2   00   bd   nv&#8209BdIzc   1
1403   c000   00   1      0088   1f   a2   00   bd   nv&#8209BdIzc   0 
1402   c000   00   1      0088   1f   a2   00   bd   nv&#8209BdIzc   0  vvvvv three dead cycles instead of usual 4
1402   0088   ea   1      0088   1f   a2   00   bd   nv&#8209BdIzc   0
1401   0088   ea   1      0088   1f   a2   00   bd   nv&#8209BdIzc   0
1401   0088   ea   1      0088   1f   a2   00   bd   nv&#8209BdIzc   0
1400   0088   ea   1      0088   1f   a2   00   bd   nv&#8209BdIzc   1
1400   0087   ea   1   NOP   0087   1f   a2   00   bd   nv&#8209BdIzc   1  ^^^^ Dummy read
1399   0087   ea   1   NOP   0087   1f   a2   00   bd   nv&#8209BdIzc   1
1399   0087   ea   1      0087   1f   a2   00   bd   nv&#8209BdIzc   1
1398   0087   ea   1      0087   1f   a2   00   bd   nv&#8209BdIzc   1
1398   0086   ea   1   NOP   0086   1f   a2   00   bd   nv&#8209BdIzc   1
1397   0086   ea   1   NOP   0086   1f   a2   00   bd   nv&#8209BdIzc   1
1397   4015   1f   0      0086   1f   a2   00   bd   nv&#8209BdIzc   1
1396   4015   40   0      0086   1f   a2   00   bd   nv&#8209BdIzc   1
1396   0085   40   1      0085   1f   a2   00   bd   nv&#8209BdIzc   1
1395   0085   40   1      0085   1f   a2   00   bd   nv&#8209BdIzc   1
1395   0084   15   1      0084   1f   a2   00   bd   nv&#8209BdIzc   1
1394   0084   15   1      0084   1f   a2   00   bd   nv&#8209BdIzc   1
1394   0083   8d   1   STA&nbsp;Abs   0083   1f   a2   00   bd   nv&#8209BdIzc   1
1393   0083   8d   1   STA&nbsp;Abs   0083   1f   a2   00   bd   nv&#8209BdIzc   1
1393   0083   8d   1      0083   1f   a2   00   bd   nv&#8209BdIzc   1


Could it be that DMC DMA's are seperately triggered by writes to $4015 and the DMC bits remaining counter reaching zero? The latter seems to take 4 cycles, but does the former take 3?

I also noticed a few cycles between when the write occurs and when the DMA starts, a few NOPs worth actually.

So is this behaviour correct? I am trying to get sprdma_and_dmc_dma test to pass but I cannot for the life of me make it work. I always end up with exactly 1 more cycle happening for each step then I should. I think this is the reason but am not sure how to implement it.

Any more experienced people have any ideas?

Thanks!

EDIT: I implemented this behaviour and now pass sprdma_and_dmc_dma perfectly. I a pretty confident it is correct.