It is currently Thu Dec 14, 2017 3:53 pm

All times are UTC - 7 hours





Post new topic Reply to topic  [ 60 posts ]  Go to page Previous  1, 2, 3, 4  Next
Author Message
 Post subject:
PostPosted: Sun Nov 20, 2005 12:55 am 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10164
Location: Rio de Janeiro - Brazil
I don't mean to be an ass, sorry if it may seem so. And I do have faith in you. You learn very fast, you put a lot of dedication in your work and you will probably achieve great things in NES development. But my advice is only that you don't take steps larger then your legs, or you'll miss some important stuff in the way. But, in the end, it is your decision.

Sorry if it seemed like I was saying only bad things about you, it started directed to you but then it got more general, and I even thought about me a while ago, as I was writing my last post.

I know you learned a lot lately, and I believe when you say you don't copy/paste anymore. Your improvements are very clear.

It is just that sometimes the questions you ask tell us you are not ready for some things yet. You say you need detailed explanations and all, but why is that? It's not because you're dumb, 'cause you're not. It's because you don't yet know ANYTHING about what you're asking.

Unfortunatelly, not always we can turn a thread in a classroom and teach you everything from the ground. Sometimes we try, but usually it is just so much new stuff, that it seems impossible to explain it to you in enough detail.

Now you asked about screen splitting, but you didn't know anything about CPU and PPU cycles. You simply shouldn't be asking about screen splitting without knowing that. Then, we try to go through all the steps to get where you want, but sometimes there is so much stuff in between that there is no way to cover everything in a few posts and expect you to understand.

That's why there is an order for learning things. When you understand the basics of timing, then you experiment with screen splitting, that would be a reasonable order to do things.

I'm not trying to teach you a lesson or anything. I get nothing out of it. What you do in here does not bother me at all. When I say these things to you, It may seem I'm playing the role of the annoying dad, who says all that boring stuff but only wants good things for his child. And it may be exactly like this in the end.

We're all here for NES development. Because we love to see new, exciting stuff hapenning in the limited system that is the NES. All I want here is to see the great stuff you'll do for the NES someday, so I try to talk you into doing things in a more ordered way, so you'll actually release quality software in the future.

I too talk too much sometimes, and usually forget where I was going after a few paragraphs.

Well, I'm not trying to bug you. And will try not to say a thing about this subject anymore. Just wanted to explain to you why I do it, and why I insist on doing it. If it is such a bother I'll just shut up.


Top
 Profile  
 
 Post subject:
PostPosted: Sun Nov 20, 2005 11:27 am 
Offline
User avatar

Joined: Sun Jun 05, 2005 2:04 pm
Posts: 2143
Location: Minneapolis, Minnesota, United States
I didn't mean it like you're the bad guy here, I am very hot headed sometimes. I understand what you're saying, and I'll take it into account. And you don't really bother me, it's just that we talk about this in every forum. If we could just talk about it in one, it would be fine. But I understand your intentions are good, and you mean well. Thank you. And I was a bit of an ass back there. Sorry. Well, I need to learn a little more before I can say I know exactly what I'm doing. If I know I don't know something, I'll either go learn it from a document(probably best), or ask about it here. Like I should've asked about CPU cycles before partiall scrolling.

And I sadly... Need to know more about IRQs, all I know is it's excecuted on BRK. That's really all I know about IRQs. 100% of my knowledge about IRQs was put into that sentence. And I feel bad making these long ass forums, because I think that people don't really like answering 1000 times. That Level Designing forum and the Object Collision forum are unnecisarilly long! I felt bad. I didn't think people were too in to posting 20 times everyday there. I should ask about IRQs in the Newbie Help Center, because that is something you should understand before posting here. Maybe if you could lend me a little of your knowledge here, I wouldn't have to start one. Could you? If you want to, only. Thanks for everything! :)


Top
 Profile  
 
 Post subject:
PostPosted: Sun Nov 20, 2005 11:59 am 
Offline
User avatar

Joined: Wed Nov 10, 2004 6:47 pm
Posts: 1845
IRQs are almost the exact same thing as NMIs. They're both kinds of interrupts.

An interrupt is anything that will "interrupt" your code and force it to jump to another label (without you specifically telling it to in code.. like with a JMP or JSR command). In your programs so far... you have your 'NMI routine' which gets called when an NMI is tripped (every VBlank when enabled). The program jumps here because you give the address to your nmi routine in the vector table (at $FFFA)

IRQs are the same idea. But instead of tripping at the start of VBlank like NMIs do... they trip under different circumstances. The most common type of IRQ is some sort of scanline or cycle timer which a game uses to be interrupted when the rendering has gotten so far in the frame. So then in their IRQ routine, they could split the screen. Without having to constantly check for Sprite 0 hit or count CPU cycles.

For example... MMC3's IRQ counter counts every scanline that passes. So you could tell it to fire after 120 scanlines (if you want to split the screen in the middle) and when those 120 scanlines are up, it'll jump to your irq routine automatically.


The key differences between NMI and IRQ are:

1) They have different vectors. NMI vector is at $FFFA... IRQ vector is at $FFFE

2) IRQs can be completely disabled by setting the I CPU flag (SEI command), but can be re-enabled by clearing I (CLI command). The I flag has no effect at all on NMIs.

3) Only thing on the NES that will trip an NMI is the PPU on VBlank. But There are several things which can trip IRQs (APU frame sequencer, DMC, mapper, etc). If you only want to use one kind of IRQ you must be sure to disable all other kinds of IRQs.


Top
 Profile  
 
 Post subject:
PostPosted: Sun Nov 20, 2005 12:12 pm 
Offline
User avatar

Joined: Sun Jun 05, 2005 2:04 pm
Posts: 2143
Location: Minneapolis, Minnesota, United States
Oh, I get it! Thanks! But I'm a little confused about MMC3's scanline counter, like how do you set something like this up? Like, do you still have to count CPU cycles? Or what? I'm a little confused, but what you just said cleared a whole lot up for me, thank you! So just to get this right, an IRQ is just like the NMI, but it can be enabled/disabled via CLI and SEI, and you can use it for many things such as well, scanline counting, and DMC and stuff like that? :)


Top
 Profile  
 
 Post subject:
PostPosted: Sun Nov 20, 2005 12:54 pm 
Offline
User avatar

Joined: Wed Nov 10, 2004 6:47 pm
Posts: 1845
Celius wrote:
Oh, I get it! Thanks! But I'm a little confused about MMC3's scanline counter, like how do you set something like this up?


Well for starters, you have to be using MMC3 (mapper 4). Rather than get into the nitty-gritty details here, I'll link you to this doc:
http://www.tripoint.org/kevtris/mappers/mmc3/index.html

The basic idea is you set the number of scanlines to wait by writing to $C000, the you clear the IRQ counter so it can reload (by writing to $C001). Then you enable mapper IRQs by writing to $E001 (and of course CLI). You also have to be sure to disable APU frame IRQs (by writing $40 or $C0 to $4017), and you should also disable DMC IRQs (write $0x to $4010).

The counter will count down every scanline and when it reaches 0, it will trigger an IRQ. Like... basically you say "hey... let me know when 60 scanlines have passed" -- then the mapper butts in after 60 scanlines with an IRQ. You don't have to rely on sprite 0 or count cycles or anything (though there are some other weird rules you have to follow).


Top
 Profile  
 
 Post subject:
PostPosted: Sun Nov 20, 2005 12:57 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10164
Location: Rio de Janeiro - Brazil
I played with this MMC3 stuff a while back and this is how I did (figured out by watching how kirby did):

In your NMI, you store the number of the scanline you want the IRQ to fire, minus 1, in $C000. Then you write anything to $C001 (it will clear the counter or something), and then write anything to $E001 (will enable the counting I think). You can enable this before the NMI ends, 'cause it will only count when lines are actually rendered. You must now enable IRQ's (do a CLI) so the IRQ will actually fire when it is the time.

Now, in the IRQ section of your code (the code that will run when the counter reaches the scanline you wanted and the IRQ fires), you have to write anything to $E000 (will acknowledge the interrupt, I don't know why this is so important) and then do whatever you want. Change the scroll, turn the screen off, whatever. When you're done, return from the interrupt. If you want the IRQ to fire again in the same frame, you can set it inside the IRQ code as many times as you want, but you'll have to think of a way to diferentiate between the many IRQ's, probably by setting a variable and checking it at the beginning of the IRQ routine.

Oh, and remember to turn sound IRQ's off (you have to write something to $4017, I don't remember what) or it will fire all the f*cking time and make you crazy trying to figure out what's wrong, as happened to me.

I may not be 100% correct here, as I havent played with this stuff in a while, but the process is pretty much it.

You may not need to count cycles when using scanline counters, but I'm not sure at exactly what time the IRQ fires. If it fires at the beginning of the scanline, it is desireble for you to wait 'till hblank to write the value that will change the rendering, so you don't get any graphical glitches.

Do any of you more experienced people know where exactly does the IRQ fire? I see many games with small glitches where the game screen splits into the status bar. I find it a little annoying.

EDIT: to disable sound IRQ's:
Code:
LDA #$40
STA $4017


Top
 Profile  
 
 Post subject:
PostPosted: Sun Nov 20, 2005 1:06 pm 
Offline
User avatar

Joined: Wed Nov 10, 2004 6:47 pm
Posts: 1845
tokumaru wrote:
Do any of you more experienced people know where exactly does the IRQ fire?


Under normal circumstances... scanline cycle 260 (4 PPU cycles into HBlank) -- of course if you tack on the 7 eaten CPU cycles it takes for the interrupt to complete, you'll be at cycle 281 at the earliest -- so it might be a good idea to have the IRQ trip at least 1 scanline early, then wait for almost one full scanline in your IRQ routine.

And I agree... most MMC3 games were done sloppily/lazily and have that ugly visual distortion *cough*Megaman3*cough*

*shakes fingers with a tsk-tsk at those game programmers*


Top
 Profile  
 
 Post subject:
PostPosted: Sun Nov 20, 2005 2:49 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10164
Location: Rio de Janeiro - Brazil
Okay... so it is a good thing to have the IRQ fire earlier and wait with timed code for a better time (next hblank) to do the writes that will affect rendering.

Why do you say "under normal circumstances" when saying it happens at cycle 260? What are the exceptions?

A bit off-topic but... why exactly does it take 7 cycles to get into the IRQ routine? What happens in the process?


Top
 Profile  
 
 Post subject:
PostPosted: Sun Nov 20, 2005 3:22 pm 
Offline
User avatar

Joined: Wed Nov 10, 2004 6:47 pm
Posts: 1845
tokumaru wrote:
Why do you say "under normal circumstances" when saying it happens at cycle 260? What are the exceptions?


The MMC3 IRQ counter doesn't really count scanlines, it watches the rising edge of the ?PPU's? A12 line. "Normal circumstances" is when the BG uses the left pattern table (ppu $0xxx) and sprites use the right pattern table ($1xxx) -- in which case the rising edge will happen on the first sprite tile fetch (cycle 260). However if you put sprites on the left and BG on the right, it'll happen at cycle 6 (I think?). Or if you put both BG and sprites on the right pattern table, it may never happen at all. Additionally you can manually toggle the A12 line by alternating $0000 -> $1000 writes to $2006 to make the counter count anywhere.

So yeah... as long as you keep all BG tiles on the left pattern table and all sprites on the right pattern table.. you've got your normal circumstances, and the IRQ will count on 260.

Quote:
A bit off-topic but... why exactly does it take 7 cycles to get into the IRQ routine? What happens in the process?


1 cycle for each (they may not happen in this order):

1) PC high pushed to stack
2) PC low pushed to stack
3) Status pushed to stack
4) Read PC low from $FFFE
5) Read PC high from $FFFF

I don't know what the other two cycles are for... possibly dummy reads?


Top
 Profile  
 
 Post subject:
PostPosted: Sun Nov 20, 2005 3:43 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10164
Location: Rio de Janeiro - Brazil
Disch wrote:
"Normal circumstances" is when the BG uses the left pattern table (ppu $0xxx) and sprites use the right pattern table ($1xxx)

Yeah... I heard of these limitaions before... not such a big deal though, if you still can use 8x16 sprites. Can you?

Quote:
Additionally you can manually toggle the A12 line by alternating $0000 -> $1000 writes to $2006 to make the counter count anywhere.

But that is useless, right? What's the point of firing an IRQ manually? If you know when to do a certain thing just do it instead of using IRQ's... right?

Quote:
So yeah... as long as you keep all BG tiles on the left pattern table and all sprites on the right pattern table.. you've got your normal circumstances, and the IRQ will count on 260.

You mentioned that if you use the pattern tables the other way around, it would happen at cycle 6 (although you're not sure), now *that* may be usefull, as you'll have to wait less for the hblank, so you waste less time just "waiting".

Quote:
1 cycle for each (they may not happen in this order):

1) PC high pushed to stack
2) PC low pushed to stack
3) Status pushed to stack
4) Read PC low from $FFFE
5) Read PC high from $FFFF

I don't know what the other two cycles are for... possibly dummy reads?

I thought it seemed too much... but if these are the rules...!


Top
 Profile  
 
 Post subject:
PostPosted: Sun Nov 20, 2005 8:10 pm 
Offline
User avatar

Joined: Sun Jun 05, 2005 2:04 pm
Posts: 2143
Location: Minneapolis, Minnesota, United States
So you don't really have to do anything different for $8000 and $8001, because it's just specifying the bank # and data section(org, right?). And I was confused about what you have to do with $A000 and $A001, something to do with WRAM(...Okay, this is bad, but what does WRAM stand for?), and you write the counter to $C000, and just a value to $C001, and another value to $E001, am I missing anything? And you say you write to $C000, $C001, and $E001 in NMI? and do a CLI in the NMI? Well, I do a CLI, then store #$5D(120-1) in $C000, and I store random values in $E001, and $C001, and #$00 in $4010, and #$40 in $4017 every NMI. I increment a variable in my NMI that I store in $2005 in my IRQ routine. Am I missing something? because the screen just sits there. Anyone know what's wrong? Thanks!


Top
 Profile  
 
 Post subject:
PostPosted: Sun Nov 20, 2005 8:39 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10164
Location: Rio de Janeiro - Brazil
$8000 and $8001 are related to bankswitching and have nothing to do with the scanline counter. About the CLI, I did what kirby did: IRQ's stay off (SEI) until you set up the counter. Then, inside the IRQ routine it turns IRQ's off again. I guess this is not to risk getting an unwanted IRQ.

I think writing #$00 in $4010, and #$40 in $4017 can be done only once in the beginning of your program, if you're not using these registers. I don't think anything external changes their contents.

About writing random values to $E001 and $C001, just write the same thing you wrote to $C000, it's faster, since you don't have to load any new values. Also, try to keep the order: first write to $C001 and then to $E001.

Then it should work. The IRQ routine should do the following:
-acknowledge the interrupt by writing to $E000;
-write your variable to $2005 (as you're already doing);
-disable IRQ's (SEI), kirby did;
-return from the interrupt (RTI);

And remember to enable NMI's by setting bit 7 of $2000, or your NMI routine will never run.

I guess that's all there is to it...


Top
 Profile  
 
 Post subject:
PostPosted: Sun Nov 20, 2005 9:11 pm 
Offline
User avatar

Joined: Sun Jun 05, 2005 2:04 pm
Posts: 2143
Location: Minneapolis, Minnesota, United States
here is my code, I don't know what's wrong, I read kevin horton's MMC3 page several times, and I read your post several times as well, and I don't know what's wrong with my code. The screen won't scroll in Nintendulator, I open up the dissassembly thing in it, and click IRQ, and it scrolls halfway, and says "Bad opcode, CPU blocked." Then I open it in FCE UXD ultra, and it scrolls to that point and then stops. And I'm not even trying to scroll like that. I'm counting scanlines, and I want it to you know, do what MMC3 does, and it doesn't work. Would you please just look over my code, and see if you see anything wrong? I didn't want to have to do this, but I've been trying this for a while, and it's giving me a headache. Any ideas? thanks.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Nov 21, 2005 11:08 am 
Offline
User avatar

Joined: Sun Sep 19, 2004 10:59 pm
Posts: 1393
1. IRQ is an interrupt, so you need to perform an RTI instruction at the end, not RTS.
2. You do not need the "lda #$FF" before "sta $E000", since the value does not matter.
3. If you modify registers in your NMI/IRQ routines, you should save copies of them (and restore them at the end) so as to not disturb any other code that may have been interrupted. The standard way to do this is to start all interrupt routines with "PHA | TXA | PHA | TYA | PHA" and then end them with "PLA | TAY | PLA | TAX | PLA | RTI".

_________________
Quietust, QMT Productions
P.S. If you don't get this note, let me know and I'll write you another.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Nov 21, 2005 3:51 pm 
Offline
User avatar

Joined: Sun Jun 05, 2005 2:04 pm
Posts: 2143
Location: Minneapolis, Minnesota, United States
Yeah, the RTS definitly caused many problems. And I set my counter you know? Yeah, it does a regular scroll, but not in Nintendulator. My IRQ routine isn't even running in Nintendulator. And in FCEUXD ultra, it scrolls, and in NESticle(no one cares) it scrolls. But not in Nintendulator. Why? I think maybe my IRQs aren't initiated correctly. I'll look at it, but if you see why, please tell me! Thanks! You guys are so cool! :)


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

All times are UTC - 7 hours


Who is online

Users browsing this forum: No registered users and 5 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