It is currently Mon Oct 23, 2017 3:38 pm

All times are UTC - 7 hours





Post new topic Reply to topic  [ 96 posts ]  Go to page 1, 2, 3, 4, 5 ... 7  Next
Author Message
 Post subject: DMC IRQs
PostPosted: Tue Jun 22, 2010 10:09 am 
Offline
User avatar

Joined: Wed Sep 07, 2005 9:55 am
Posts: 300
Location: Phoenix, AZ
So I'm playing around with splitting the screen twice without a mapper. The first split will use sprite0 and be around scanline 32. The second split will be around scanline 208. I'm trying to use the dmc irq to approximate it since it doesn't have to be exact (I'm extending vblank for chr-ram writes).


The main loop (without all the init code):

Code:
   ; ...

   ldx #$40           ;
   stx PORT2          ;
   ldx #0             ;
   stx SND_CLOCK      ;    
   ; ...

   cli
_loop:
   jmp _loop



This is the code called during the nmi handler. The sample is located at $C000 and is $401 bytes of $00.

Code:
   lda sndChannelEnable      ; disable dmc channel
   and #$0F                  ;
   sta SND_CLOCK             ;

   lda #%10001111            ; set sample ctrl
   sta SND_DMC_CTRL          ;
   lda #$00                  ; set dac
   sta SND_DMC_DA            ;
   lda #$00                  ; set sample addr
   sta SND_DMC_ADDR          ;
   lda #$40                  ; set sample length
   sta SND_DMC_DL            ;

   lda sndChannelEnable      ; enable dmc channel
   ora #$10                  ;
   sta sndChannelEnable      ;
   sta SND_CLOCK             ;



The IRQ handler is empty for now:

Code:
IRQBRK:
   sei
   rti



I've been able to split the screen with mapper IRQs, but I'm not sure if I'm initializing the APU correctly. Any thoughts?


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jun 22, 2010 11:14 am 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19122
Location: NE Indiana, USA (NTSC)
A while back, I made a demo that does two splits, and does it to within a granularity less than one scanline. I plan to post it tonight to see what someone else can do with it.


Top
 Profile  
 
 Post subject: Re: DMC IRQs
PostPosted: Tue Jun 22, 2010 11:55 am 
Offline
User avatar

Joined: Wed Nov 10, 2004 6:47 pm
Posts: 1845
never-obsolete wrote:
Code:
IRQBRK:
   sei
   rti



That will deadlock your program.

1) I is already set by the IRQ. The SEI does nothing.
2) RTI will pull status from the stack, resulting in I being cleared again
3) Because RTI will clear I, another IRQ will occur immediately, causing a deadlock in the IRQ handler.

You need to acknowledge the IRQ. I forget how this is done on the DMC. I think you just read $4015, but you'll have to double-check.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jun 22, 2010 12:08 pm 
Offline
User avatar

Joined: Fri Nov 12, 2004 2:49 pm
Posts: 7235
Location: Chexbres, VD, Switzerland
For the first part of your code, I'm not familiar with those weird labels so I can't help you.

Like Dish says, you MUST acknownledge an IRQ before doing cli or rti or any instruction that will return else it will be an endless loop of IRQs (the only exeption is an IRQ triggered by a brk instruction but here it's clearly not the case).

In the case of DMC IRQs, you should read $4015 before returning. If DMC is your only source of IRQ, you can just discard the result and assume the source of the IRQ was the DMC, else you'd have to acknownledge all possible source of IRQs, and check if their bit was set, and act accordingly,

I recommend to do something like this in your IRQ handler :
Code:
IRQ
    bit $4015
    bvs _noDMC    ;This line can be deleted if DMC is the only possible IRQ source
    lda GrayScale_toggle
    eor #$01
    sta GrayScale_toggle
    ora #$1e
    sta $2001
_noDMC
   rti


This will toggle grayscale mode each IRQ. If you have correctly 2 splitpoint, the middle of your screen between both splitpoints should be gray.

_________________
Life is complex: it has both real and imaginary components.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jun 22, 2010 12:54 pm 
Offline
User avatar

Joined: Wed Sep 07, 2005 9:55 am
Posts: 300
Location: Phoenix, AZ
D'oh, I forgot about acknowledging the irq. Thanks for the heads up.

@Tepples: I'll wait to see your example. I have a feeling I'm not setting up the DMC registers correctly.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jun 22, 2010 3:16 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19122
Location: NE Indiana, USA (NTSC)
It turned out that I had lost half the source code for this effect when my laptop died a few months ago. But I still had the working ROM on my PowerPak, and I managed to teach myself enough about da65 to recreate working source code.

DPCM Split
Mapper 0, runs on PowerPak. README file inside archive explains how it works. It still has glitches that someone like blargg might be able to help find and fix.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jun 24, 2010 1:56 am 
Offline
User avatar

Joined: Fri Nov 12, 2004 2:49 pm
Posts: 7235
Location: Chexbres, VD, Switzerland
Your technique is interesting. If I understand well, you play a 1-byte sample, and count the cycles before the first IRQ, to compensate for the jittering.

The problem is that you have to wait a dozen of IRQs for a dozen of scanline, so if this technique were to be used for a longer time between both split, this constant stream of useless IRQs would waste very significant CPU time for nothing (and half-killing the purpose of interrupts, although it's still better than waste ALL the CPU time).
Would this technique work as well if you play a 1-byte sample, count the # of cycles before the interrupt, then play a 17 or 33 byte sample to have only 2 IRQs in total ?

Another thing is that you use sprite-0 hit (with 7-cycle jitter I guess) for the first split, and start your IRQ technique from there. If you'd instead reverse the thing, and use IRQ for the first split and sprite 0 for the second, you could do that technique with 3 cycle jitter instead, and it could perform better. Altough of course this will waste 100% of CPU time between the 1st and 2nd split instead of between the top and the 1st split, so it all depends of what you'd want to achieve.

EDIT : Yet another thing is that you could, in the first loop, wait for $4015.7 to rise, while having the I flag set. This would prevent the IRQ, and possibly (possybly not ?) increase accuracy of the code and simplify the code inside the IRQ (that would only execute once per frame).


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jun 24, 2010 4:44 am 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19122
Location: NE Indiana, USA (NTSC)
Bregalad wrote:
The problem is that you have to wait a dozen of IRQs for a dozen of scanline, so if this technique were to be used for a longer time between both split, this constant stream of useless IRQs would waste very significant CPU time for nothing

It's significant, but the 37 cycles out of 432 still fall within my 10% of CPU time budget.
Code:
irq_handler:
  bit $4015  ; acknowledge dpcm irq
  inc irqs

  ; schedule another IRQ
  pha
  lda enable_timer
  sta $4015
  pla 
  rti

And it's not entirely useless to know how much time I have left before the IRQ fires.

Quote:
Would this technique work as well if you play a 1-byte sample, count the # of cycles before the interrupt, then play a 17 or 33 byte sample to have only 2 IRQs in total ?

Playing a 17-byte sample would allow skipping the first IRQs if the splits are far enough apart ((17+1)*8*54 = 7776 CPU cycles or 69 scanlines). But the demo's splits are only about 10 bytes apart, and it would be two more instructions in the IRQ to handle switching to 1-byte samples after the initial 17- or 33-byte sample. I'll consider it in the second.

Quote:
Altough of course this will waste 100% of CPU time between the 1st and 2nd split instead of between the top and the 1st split, so it all depends of what you'd want to achieve.

What motivated my development of this technique was trying to display a background picture that needs more than 4 KiB of CHR while decompressing a page of text to put into the next picture. Here, sprite 0 would be in a fixed place (doesn't matter where as long as it's present), and the code would wait for the end of vblank by waiting for sprite 0 flag to turn off.

Quote:
EDIT : Yet another thing is that you could, in the first loop, wait for $4015.7 to rise, while having the I flag set.

The number of cycles in the loop that measures the IRQ jitter has to match the number of cycles in the loop that compensates, and it takes more time to read $4015 than the zero-page variable that the IRQ handler updates.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jun 24, 2010 5:27 am 
Offline
User avatar

Joined: Fri Nov 12, 2004 2:49 pm
Posts: 7235
Location: Chexbres, VD, Switzerland
Quote:
What motivated my development of this technique was trying to display a background picture that needs more than 4 KiB of CHR while decompressing a page of text to put into the next picture. Here, sprite 0 would be in a fixed place (doesn't matter where as long as it's present), and the code would wait for the end of vblank by waiting for sprite 0 flag to turn off.

That's right, and no offense tepples, but the way you're using IRQ with this "inc variable" method you're polling completley kills the purpose of an IRQ, which is to free the main CPU to do another task.
Doing it is completely dumb - you'd as well have the main code doing a loop timed between the split and the result would be the same.

Yet I understand that this is a proof of concept, but you should have the main code doing something else than polling available in order to have this any useful.
So the IRQ handler will need not only to acknownledge, but also to handle the split and the loop that comensate the jitering. That's why I suggest you wait a fake IRQ just by polling $4015 after the first split (in our case) - this should simplify code and avoid an if/else statement in your IRQ routine.

_________________
Life is complex: it has both real and imaginary components.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jun 24, 2010 6:14 am 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19122
Location: NE Indiana, USA (NTSC)
Bregalad wrote:
Quote:
What motivated my development of this technique was trying to display a background picture that needs more than 4 KiB of CHR while decompressing a page of text to put into the next picture.

That's right, and no offense tepples, but the way you're using IRQ with this "inc variable" method you're polling completley kills the purpose of an IRQ, which is to free the main CPU to do another task.

I understand that, but finalizing the code for this other task may take weeks. I have a day job, my workouts, and sometimes younger cousins who visit over summer break.

Quote:
So the IRQ handler will need not only to acknownledge, but also to handle the split and the loop that comensate the jitering.

It doesn't wait for IRQ ten times; it waits for the number of elapsed IRQs to reach 10. So even if I do something that takes the time of eight IRQs to complete before I jump into that loop, I can still get into the loop in time. But now I bet tokumaru is itching to remind me that "something" may occasionally exceed this time, causing an occasional glitch. So my ultimate plan is to move more of the scroll split processing into the IRQ handler, which should add two cycles to the "just count" case.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Aug 12, 2010 9:57 am 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19122
Location: NE Indiana, USA (NTSC)
As the Tourette's Guy channeling the late Robert Stack would put it, "UPDATE!"

I got the whole effect to run in the NMI and IRQ handlers. This version is a rock-solid letterbox generator for NTSC NES.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Aug 12, 2010 11:22 am 
Online
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10068
Location: Rio de Janeiro - Brazil
Are you saying that with your method it is possible to use DMC IRQ's for effects that were only possible with special mappers? That's awesome!

Is it precise enough to allow you to change the scroll mid-frame without artifacts? If yes, I'd say you just did a great thing for the NESDEV community. I always wanted a method to do raster effects without having to use mappers or 100% of the CPU time.

And if you keep sample playback disabled during VBlank and a while after that I guess you can read the controller then, without having to worry about corruption, right?

EDIT: I imagine it would be hard to make this effect dynamic, right? I mean, if you need the split to move up and down as opposed to keeping it steady.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Aug 12, 2010 12:01 pm 
Offline
User avatar

Joined: Fri Nov 12, 2004 2:49 pm
Posts: 7235
Location: Chexbres, VD, Switzerland
Congratluation tepples, this is really great.
Quote:

Are you saying that with your method it is possible to use DMC IRQ's for effects that were only possible with special mappers? That's awesome!

Yeah he's saying this. I think it only works if there is a sprite zero hit first tough. Also I'm not sure if it's possible to get 3 or more splitpoints that way, but anyways 2 is still much better than just 1 without any mapper.

Quote:
And if you keep sample playback disabled during VBlank and a while after that I guess you can read the controller then, without having to worry about corruption, right?

You can read the controller multiple times anyway so I don't think this is a problem unless you're like REALLY tight on timing.

_________________
Life is complex: it has both real and imaginary components.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Aug 12, 2010 12:10 pm 
Online
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10068
Location: Rio de Janeiro - Brazil
Bregalad wrote:
I think it only works if there is a sprite zero hit first tough.

He said that the purpose of the sprite hit was to time the first IRQ, and that you don't need it if your NMI handler is constant-timed (like mine is).

Quote:
You can read the controller multiple times anyway

Well, you can, but why would you? I'd rather have my NMI handler read the controllers before doing any DMC IRQ stuff and use that one read for the rest of the frame.

Quote:
so I don't think this is a problem unless you're like REALLY tight on timing.

I don't like the idea of indefinitely reading the controllers until 2 consecutive read match, so I'd rather just read it when it's safe to do so.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Aug 12, 2010 12:39 pm 
Offline
User avatar

Joined: Fri Nov 19, 2004 7:35 pm
Posts: 3944
Could the DMC technique be used for screen masking for vertical mirroring?

_________________
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 96 posts ]  Go to page 1, 2, 3, 4, 5 ... 7  Next

All times are UTC - 7 hours


Who is online

Users browsing this forum: Bing [Bot] and 9 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