It is currently Tue Feb 19, 2019 4:22 am

All times are UTC - 7 hours





Post new topic Reply to topic  [ 13 posts ] 
Author Message
 Post subject: Hello Everyone :)
PostPosted: Tue Jan 29, 2019 8:29 pm 
Offline
User avatar

Joined: Tue Jan 29, 2019 7:39 pm
Posts: 6
Location: Canada
Hello!

Since I was not sure in which topic to post just to say hello, here it is!

I have been learning Assembly for the NES for a moment now (2-3 weeks?), jumping from random piece of information and tutorial there and there, learning a little more everyday!

I will most likely have a millions of questions soon, since I am working on making a clone of the game Jumper, but for the NES (obviously!)

I have no idea if it is a realistic project to do for the limitation of the NES, but even if it is the case, I will learn a lot anyway, which is my main goal right now!

I will ask my questions later (I am stubborn, and I try really hard to find the solution of my problems without asking :P)

Here an image of the progress I have done so far! (Even if you cant see electricity animation, Player's Physic, etc!)
LEFT : NES Version
RIGHT : Original I try to clone
Attachment:
File comment: Sector3_1_Progress
WIP_S3_1.png
WIP_S3_1.png [ 61.11 KiB | Viewed 1605 times ]


Top
 Profile  
 
 Post subject: Re: Hello Everyone :)
PostPosted: Tue Jan 29, 2019 11:06 pm 
Offline
User avatar

Joined: Wed Jan 16, 2019 9:13 pm
Posts: 15
Location: Lower East Side
Welcome! I'm relatively new to the forum as well and learning 6502 for the first time. Folks here have been helpful to me. Good luck with the Jumper port!


Top
 Profile  
 
 Post subject: Re: Hello Everyone :)
PostPosted: Thu Jan 31, 2019 5:17 pm 
Offline
User avatar

Joined: Tue Jan 29, 2019 7:39 pm
Posts: 6
Location: Canada
ericandrewlewis wrote:
Welcome! I'm relatively new to the forum as well and learning 6502 for the first time. Folks here have been helpful to me. Good luck with the Jumper port!


Thanks for the welcome!

Alright, I guess it is time to ask some questions :P
Before someone ask, I am using NESASM3.

1. Is there a good way to manage branch that are out of range?
Does having multiple JMP just to reach a far away branch is bad/fine/good?
Should I use a JSR instead of 2/3/4... JMP?
Do I just need to get used to it and manage my code better?

2. Good way to "DISABLE" a sprite?
I have read somewhere that only 8 sprites per scanline is allowed, so does I just put all the non-used sprites on the same scanline?
I also red about sprite 0 being special if used in a certain way, should I avoid using it for now?

3. Good way to change a background tile?
I had some problems some days ago that changing the background was making my screen flicker, and not always the same tile was being changed.
One thing I found was"You have about 2270 cycles after the NMI happens to safely write things to $2007 (PPU_DATA)"
I changed when I change the tile at the start of NMI, and now it is good.
I also heard that if I want to modify a tons of tile at the same time, I should disable background and sprites rendering.
Is that correct?

4. Is there a reason that all of my sprites are rendered 1 pixel too high then the given position?
(Or maybe my background is offset by 1 somehow, but does not looks like it)

5. Is there a better way to simulate a "switch case" then that?
Code:
LDA vVariable
CMP #$00
BEQ GoHereIfValue0
CMP #$01
BEQ GoHereIfValue1
...
CMP #$0F
BEQ GoHereIfValue15


Maybe something like this (if it is possible)?
Code:
;Multiply by 3, total length of 3(If I am not wrong) JMP[1] + Label[2]
LDA vVariable
CLC
ADC vVariable
ADC vVariable

??? (Move current memory location by vVariable ammount)

JMP GoHereIfValue0 ;Here if vVariable is 0
JMP GoHereIfValue1 ;Here if vVariable is 1
...
JMP GoHereIfValue15 ;Here if vVariable is 15


Not sure if it would be better for a small amount of case, but I would like to know just for the knowledge of it :)

So, I do have more questions, but I think it is good enough for now :D


Top
 Profile  
 
 Post subject: Re: Hello Everyone :)
PostPosted: Thu Jan 31, 2019 7:20 pm 
Offline
Site Admin
User avatar

Joined: Mon Sep 20, 2004 6:04 am
Posts: 3649
Location: Indianapolis
Foulco wrote:
1. Is there a good way to manage branch that are out of range?
Does having multiple JMP just to reach a far away branch is bad/fine/good?
Should I use a JSR instead of 2/3/4... JMP?
Do I just need to get used to it and manage my code better?


That's fine, totally normal. If 'BNE True' is out of range, just do BEQ False / JMP True. With CA65 there are some built-in "longbranch" macros. Instead of BNE you do JNE, and it will change it to a jump whenever it becomes needed. I don't know if anyone has made a similar macro for NESASM.

Sometimes you can avoid out of range branches by putting the destination somewhere else, but I wouldn't do it unless it makes the code easier to read. One fairly common way this shows up, if you need to branch to an RTS instruction, you can move that RTS so it's before the start of the subroutine, instead of at the end. Or sometimes it's the RTS that's part of an already existing subroutine that's in memory below this one.

Quote:
2. Good way to "DISABLE" a sprite?
I have read somewhere that only 8 sprites per scanline is allowed, so does I just put all the non-used sprites on the same scanline?
I also red about sprite 0 being special if used in a certain way, should I avoid using it for now?


The best way is to set the Y coordinate to $EF or higher. If you put them at coordinate 0,0 they will probably be off screen on an NTSC TV, but maybe not on a PAL TV.
Yeah, best to avoid using sprite zero. If you'll be having more than 8 sprites per line in your game, you'll probably want to avoid tying game objects to specific sprite numbers.

Quote:
3. Good way to change a background tile?
I had some problems some days ago that changing the background was making my screen flicker, and not always the same tile was being changed.
One thing I found was"You have about 2270 cycles after the NMI happens to safely write things to $2007 (PPU_DATA)"
I changed when I change the tile at the start of NMI, and now it is good.
I also heard that if I want to modify a tons of tile at the same time, I should disable background and sprites rendering.
Is that correct?

That's correct sometimes, it depends. It might makes sense to turn off the screen when you're loading a large amount of data (like 8kB of pattern tables into CHR-RAM). But usually not for nametables, unless you're coming into it from a blank screen anyways (like title screen, or other transitions).

To update the background/nametables, usually the way to go is to create a buffer in RAM, so you can update that at any time. Then in the NMI routine, check if that buffer is ready, and write it to the PPU if it is.

Quote:
4. Is there a reason that all of my sprites are rendered 1 pixel too high then the given position?
(Or maybe my background is offset by 1 somehow, but does not looks like it)


Yeah, that's normal. Sprite rendering kinda lags behind. I guess it's because while a line is being rendered, the PPU is evaluating which sprites will be displayed on the next line.

Quote:
5. Is there a better way to simulate a "switch case" then that?

Some good examples are here: https://wiki.nesdev.com/w/index.php/Jump_table

edit: whoops, sorry if the post before this got screwed up. My reply accidentally turned into an edit of that post, I tried to restore it.


Top
 Profile  
 
 Post subject: Re: Hello Everyone :)
PostPosted: Thu Jan 31, 2019 7:26 pm 
Offline
User avatar

Joined: Wed Apr 02, 2008 2:09 pm
Posts: 1273
1. When branching, you want to go the label if the condition is true, and under the label when the condition is false.
Code:
lda check
bne checktrue
;will go here if equal

ldx whatever
;code here

checktrue:

If the branch is out of range, you still want the code to go to the same places in the same conditions.
Code:
lda check
beq checkfalse
jmp checktrue
checkfalse:

ldx whatever
;longer code here

checktrue:

Essentially, when a branch is out of range, reverse the condition and branch over a jmp. This will go to the same code for the same condition. The branch will never be too far since it is only branching over a jmp.

So you should never need more than one branch.

2. To disable a sprite, just put it offscreen. (Y position of 239 or greater. 239 works because sprites are drawn one pixel lower than the given coordinate, and 240 is below the screen.)

But that's not exactly related to 8 sprites per scanline. What most games do is write to the RAM page used as a sprite buffer in a way that ensures the same parts of the same objects aren't dropped from being drawn every frame.

Sprite 0 ($0200-$0203 if you're using RAM Page 2 for sprites) will always be drawn. Sprite 1 will always be drawn as well. Same for sprites 2-7 because they are the highest priority sprites. Sprite 8 will drawn so long as all of sprites 0-7 are not in the same row of pixels as sprite 8. etc.

So say player 1 is one sprite. Games will write player 1's tile/position/attributes to $0200-$0203 in frame 0, then $0204-$0207 the next frame (frame 1). Etc. It will cycle all the other objects in a similar way. This ensures a different set of sprites will be drawn whenever there are more than 8 sharing a horizontal line, rather than the same objects always getting dropped.

(There are better methods than offsetting it by one every time, but maybe that's for another post.)

There's no reason to avoid using Sprite 0 unless you're actually using sprite 0 for the special thing it can do.

3. Indeed, you don't have a lot of time to safely update tiles after an NMI hits. Four columns/their attributes is close to the practical limit, even with really fast code. If you want to do more than this in a single frame, you have to turn off background/sprite rendering, yes.

If you want to do writes that aren't in order (like tile columns are) the limit is lower. (Since you also have to update $2006 which takes more time than just a $2007 write.)

4. That's just how the NES is. A Y position of 0 will draw the sprite on pixel 1, and there's no way to draw a sprite on pixel 0.

_________________
https://kasumi.itch.io/indivisible


Top
 Profile  
 
 Post subject: Re: Hello Everyone :)
PostPosted: Thu Jan 31, 2019 7:52 pm 
Offline
User avatar

Joined: Sun Apr 08, 2018 11:45 pm
Posts: 41
Location: Southern California
Memblers wrote:
That's fine, totally normal. If 'BNE True' is out of range, just do BEQ False / JMP True. With CA65 there are some built-in "longbranch" macros. Instead of BNE you do JNE, and it will change it to a jump whenever it becomes needed. I don't know if anyone has made a similar macro for NESASM.


Oh that's cool, that will save me a lot of headaches! They have docs about the "longbranch" macros and other things in the ca65 user's guide.


Top
 Profile  
 
 Post subject: Re: Hello Everyone :)
PostPosted: Thu Jan 31, 2019 8:43 pm 
Offline
User avatar

Joined: Tue Jan 29, 2019 7:39 pm
Posts: 6
Location: Canada
Memblers wrote:
That's fine, totally normal. If 'BNE True' is out of range, just do BEQ False / JMP True. With CA65 there are some built-in "longbranch" macros. Instead of BNE you do JNE, and it will change it to a jump whenever it becomes needed. I don't know if anyone has made a similar macro for NESASM.

Sometimes you can avoid out of range branches by putting the destination somewhere else, but I wouldn't do it unless it makes the code easier to read. One fairly common way this shows up, if you need to branch to an RTS instruction, you can move that RTS so it's before the start of the subroutine, instead of at the end. Or sometimes it's the RTS that's part of an already existing subroutine that's in memory below this one.

Kasumi wrote:
1. When branching, you want to go the label if the condition is true, and under the label when the condition is false.

If the branch is out of range, you still want the code to go to the same places in the same conditions.

Essentially, when a branch is out of range, reverse the condition and branch over a jmp. This will go to the same code for the same condition. The branch will never be too far since it is only branching over a jmp.

So you should never need more than one branch.


Just flipping the condition around is sometime not enough, at least, not enough if I want to try and keep the code more readable
Good to know that it is an option to branch on code over instead of only below, the machine does not care if it memory goes forward or backward.

Memblers wrote:
The best way is to set the Y coordinate to $EF or higher. If you put them at coordinate 0,0 they will probably be off screen on an NTSC TV, but maybe not on a PAL TV.
Yeah, best to avoid using sprite zero. If you'll be having more than 8 sprites per line in your game, you'll probably want to avoid tying game objects to specific sprite numbers.

Kasumi wrote:
2. To disable a sprite, just put it offscreen. (Y position of 239 or greater. 239 works because sprites are drawn one pixel lower than the given coordinate, and 240 is below the screen.)

But that's not exactly related to 8 sprites per scanline. What most games do is write to the RAM page used as a sprite buffer in a way that ensures the same parts of the same objects aren't dropped from being drawn every frame.

Sprite 0 ($0200-$0203 if you're using RAM Page 2 for sprites) will always be drawn. Sprite 1 will always be drawn as well. Same for sprites 2-7 because they are the highest priority sprites. Sprite 8 will drawn so long as all of sprites 0-7 are not in the same row of pixels as sprite 8. etc.

So say player 1 is one sprite. Games will write player 1's tile/position/attributes to $0200-$0203 in frame 0, then $0204-$0207 the next frame (frame 1). Etc. It will cycle all the other objects in a similar way. This ensures a different set of sprites will be drawn whenever there are more than 8 sharing a horizontal line, rather than the same objects always getting dropped.

(There are better methods than offsetting it by one every time, but maybe that's for another post.)

There's no reason to avoid using Sprite 0 unless you're actually using sprite 0 for the special thing it can do.


Using sprite 0 should be fine overall, but just in case, I will avoid it for now.
I should not need a tons of sprites at the same time, if what I am thinking of is going to work.
Putting sprite offscreen is good enough for disabling them (and if possible #$EF or bigger)

Memblers wrote:
That's correct sometimes, it depends. It might makes sense to turn off the screen when you're loading a large amount of data (like 8kB of pattern tables into CHR-RAM). But usually not for nametables, unless you're coming into it from a blank screen anyways (like title screen, or other transitions).

To update the background/nametables, usually the way to go is to create a buffer in RAM, so you can update that at any time. Then in the NMI routine, check if that buffer is ready, and write it to the PPU if it is.

Kasumi wrote:
3. Indeed, you don't have a lot of time to safely update tiles after an NMI hits. Four columns/their attributes is close to the practical limit, even with really fast code. If you want to do more than this in a single frame, you have to turn off background/sprite rendering, yes.

If you want to do writes that aren't in order (like tile columns are) the limit is lower. (Since you also have to update $2006 which takes more time than just a $2007 write.)


Yes for turning of if need a lot of change
About 4 columns of sprite after NMI hit is at best what I can change in a frame, I doupt I will need this for this game, but good to know.
Write a buffer if needed.

Memblers wrote:
Yeah, that's normal. Sprite rendering kinda lags behind. I guess it's because while a line is being rendered, the PPU is evaluating which sprites will be displayed on the next line.

Kasumi wrote:
4. That's just how the NES is. A Y position of 0 will draw the sprite on pixel 1, and there's no way to draw a sprite on pixel 0.

Oki Doki Loki!
Memblers wrote:

I shall read it tomorrow, but parsing it quickly, it seems good!

samophlange wrote:
Oh that's cool, that will save me a lot of headaches! They have docs about the "longbranch" macros and other things in the ca65 user's guide.

It is another thing I need to read, since apparently "most" people here use ca65.
But I am happy with NESASM for the moment.

Thanks again for your answers!


Top
 Profile  
 
 Post subject: Re: Hello Everyone :)
PostPosted: Fri Feb 01, 2019 2:25 am 
Offline
User avatar

Joined: Wed Apr 02, 2008 2:09 pm
Posts: 1273
Quote:
Just flipping the condition around is sometime not enough, at least, not enough if I want to try and keep the code more readable

Once a branch goes out of range, you will need another instruction to get to the same label from that place. Making this instruction a jmp instead of another branch (branching to a lower branch) means you won't have to modify it again should the code in between the branch and label get even longer.

You can branch to a jmp without reversing the condition as well, but this bets on having someplace safe to place that jmp that won't execute on some other code path. Even then it may end up quite far from the initial branch which can also affect readability, where the condition flipped jmp will be in the same area.

If the condition flip is not enough, what alternative is? Something like JNE is more readable, but is also assembler specific.
Quote:
About 4 columns of sprite after NMI hit is at best what I can change in a frame, I doupt I will need this for this game, but good to know.

No, four columns of tiles.

Giving the sprite buffer in RAM to the PPU will basically always take 513 cycles. This also must be done in the 2270 window. So most games have about 1757 cycles for non sprite updates, since sprites are often a given.

(You can update the sprite buffer itself at any time during the frame, but the changes you make won't be seen by the PPU until $4014 is written to. The write to $4014 is what takes 513 cycles.)

Writing a single thing to the PPU at the start of the NMI takes 18 cycles at the fastest (assuming you want the thing written to go a specific address).

Code:
lda #$20;high byte of address;2 cycles
sta $2006;4 cycles

lda #$00;low byte of address;2 cycles
sta $2006;4 cycles

lda #$10;2 cycles
sta $2007;4 cycles

The reason why doing bytes that aren't in order slower is because of the cycles spent setting the address (the $2006 writes.) Once they're written it's 6 to 8 cycles per byte for fast methods. 1757 / 8 = 219, but other things the NMI needs to do (as well as the bytes to be updated usually needing more than one address set) makes the practical limit lower.

You can see how many cycles each instruction uses on this page: http://www.obelisk.me.uk/6502/reference.html

But you're unlikely to run into trouble unless you start doing very complicated background updates.

_________________
https://kasumi.itch.io/indivisible


Top
 Profile  
 
 Post subject: Re: Hello Everyone :)
PostPosted: Fri Feb 01, 2019 4:31 am 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 21101
Location: NE Indiana, USA (NTSC)
Memblers wrote:
you'll probably want to avoid tying game objects to specific sprite numbers.

Cf. an essay I recently wrote.


Top
 Profile  
 
 Post subject: Re: Hello Everyone :)
PostPosted: Fri Feb 01, 2019 8:40 pm 
Offline
User avatar

Joined: Tue Jan 29, 2019 7:39 pm
Posts: 6
Location: Canada
Kasumi wrote:
Once a branch goes out of range, you will need another instruction to get to the same label from that place. Making this instruction a jmp instead of another branch (branching to a lower branch) means you won't have to modify it again should the code in between the branch and label get even longer.

You can branch to a jmp without reversing the condition as well, but this bets on having someplace safe to place that jmp that won't execute on some other code path. Even then it may end up quite far from the initial branch which can also affect readability, where the condition flipped jmp will be in the same area.

If the condition flip is not enough, what alternative is? Something like JNE is more readable, but is also assembler specific.


So, I guess there is no miracle solution than, which is ok, just gonna need to get used to it.
It just "seems wrong" when it happen since out of range label is not a problem for modern language (at least, not a problem for us but for the compilator, so we are not affected)

Kasumi wrote:
No, four columns of tiles.

Giving the sprite buffer in RAM to the PPU will basically always take 513 cycles. This also must be done in the 2270 window. So most games have about 1757 cycles for non sprite updates, since sprites are often a given.

(You can update the sprite buffer itself at any time during the frame, but the changes you make won't be seen by the PPU until $4014 is written to. The write to $4014 is what takes 513 cycles.)

Writing a single thing to the PPU at the start of the NMI takes 18 cycles at the fastest (assuming you want the thing written to go a specific address).

Code:
lda #$20;high byte of address;2 cycles
sta $2006;4 cycles

lda #$00;low byte of address;2 cycles
sta $2006;4 cycles

lda #$10;2 cycles
sta $2007;4 cycles

The reason why doing bytes that aren't in order slower is because of the cycles spent setting the address (the $2006 writes.) Once they're written it's 6 to 8 cycles per byte for fast methods. 1757 / 8 = 219, but other things the NMI needs to do (as well as the bytes to be updated usually needing more than one address set) makes the practical limit lower.

You can see how many cycles each instruction uses on this page: http://www.obelisk.me.uk/6502/reference.html

But you're unlikely to run into trouble unless you start doing very complicated background updates.

Oops, I wanted to say "tile" but said "sprite".
But the extra information is very good to have.
I actually did not exactly know what writing to $4014 was doing before now. (I started out with the Nerdy Night tutorial, using it code as template, so I do not know for sure what everything is doing yet)

The site with the cycle amount for each instructions, thanks!
It will be good to optimize later on and just knowing in general what "cost" more.

tepples wrote:

From reading the essay,
I already do not hardcode the player's sprite to a specific one (well this is currently a lie, but I was planning to not do that, it is this way because learning and stuff)

Just in general, I try to not hardcode things that prevent me from potentially doing something more versatile. Just a general good thing to do in programing.
Even if I know for that game it would not be a problem, I try to build up some code I could use again for a future game.


Top
 Profile  
 
 Post subject: Re: Hello Everyone :)
PostPosted: Sat Feb 09, 2019 10:06 pm 
Offline
User avatar

Joined: Tue Jan 29, 2019 7:39 pm
Posts: 6
Location: Canada
I have not done as much "coding" progress as I would like since last week, but I at least did some decent "how does this thing work" progress, which I guess, it is progress anyway!

I did a very quick video of what I currently have if anyone is interested
https://www.youtube.com/watch?v=xT_7ajTXQ4w

I am also back to ask some questions! :)

1.
I do have question in general regarding how to properly manage CHR data, because right now, I am currently using 4 banks of CHR to be able to do some animation using bank switching.
It does work, but I am pretty sure there is a better way to do that than doing a full bank switching...
For exemple, when I use the PPU Viewer in FCEUX for the game StarTropics, when in a dungeon, depending if you are facing up, right, down or left, only the first 4 rows change of a pattern table.
I would guess it would be better if I could also do that as well, because having a full 2 banks for simple electricity animation seems overkill for how much memory it use for the NES, when each byte are important.

2.
Is there a good way to know if your code is "good enough" for making sure your game is not going to lag if it was played on an original NES?
Like, is there a specific number of cycles that you want to NOT reach per frames? And if there is, how can we count (If even possible) the number of cycles? (It is probably more complicate than just the number of cycles, but I do not know much about that yet)
Is there an emulator/tools that is really good to test that?

3.
I might try and go and test some sounds stuff next (which could still be in a while..., I do have stuffs that I want to fix first), I have look quickly the Nerdy Nights - Sound tutotial (as referenced here : http://nintendoage.com/forum/messagevie ... eadid=7155 ), it seems to be good, should I follow it or is there a "better" one around?


Top
 Profile  
 
 Post subject: Re: Hello Everyone :)
PostPosted: Mon Feb 11, 2019 4:13 am 
Offline
User avatar

Joined: Wed Apr 02, 2008 2:09 pm
Posts: 1273
1. The size of a "bank" depends on the mapper or cartridge.

CNROM must swap all 512 tiles at once, so two frames of electricity would cost 16KB.

MMC3 can swap as few as 64 tiles at once, so two frames of electricity could cost only 2KB. (Assuming there were less than 64 unique, animated electricity tiles.)

Games that use RAM (CHR RAM) for tiles instead of ROM can update exactly one tile for animation if they want, at the cost of vblank time to make the updates.

And some mappers even offer bank switched CHR RAM, which is a best of both worlds kind of thing. Here is one such homebrew mapper: https://wiki.nesdev.com/w/index.php/UNROM_512

Edit: If your game doesn't scroll and you only have two frames of background animation, you can just swap the nametables. (One nametable has the background for one frame, the other nametable has the background for the other frame. You can swap between them by writing a different nametable to the lowest bits of $2000 when you want to change frames.

2. It's good enough when you think it's good enough. Modern accurate emulators will lag in the same places as NES, usually, so that's how you can know if it will on an original NES.

There are 29780.5 cycles in an NTSC frame. It isn't more complicated than that, really.

Several emulators allows very easy counting of cycles.

My favorite is this ancient build of VirtuaNES, because it puts the count right on the window: http://forums.nesdev.com/viewtopic.php?p=47911#p47911

To use, write any value to $401E to start counting, and any value to $401F to stop counting.

Code:
sta $401E;Start counting
lda #$02;2 cycles always
sta $401F;stop counting

That would make 2 display on the window. How you'd count an entire frame depends on the structure of your program, but it's usually writing to $401E after you're done waiting for the frame to start, and writing to $401F just before the jmp to the frame wait loop.

Nintendulator DX works similar to the above, but offers more timers at once: http://forums.nesdev.com/viewtopic.php?t=6773

Mesen: https://www.mesen.ca/
Offers an extreme profiler (tools, debugger. Tools, Memory Tools. Profiler.)

3. I'm not aware of a better one, but I do know some links in that are dead. But also be aware you may not need to learn much audio coding at all. Audio is one problem that's solved by many people in free-to-use ways.
Check out FamiTone2: https://shiru.untergrund.net/code.shtml
GGSound: http://www.gradualgames.com/p/sound-engine.html
and Pently: https://github.com/pinobatch/pently

_________________
https://kasumi.itch.io/indivisible


Top
 Profile  
 
 Post subject: Re: Hello Everyone :)
PostPosted: Mon Feb 11, 2019 6:02 pm 
Offline
User avatar

Joined: Tue Jan 29, 2019 7:39 pm
Posts: 6
Location: Canada
Kasumi wrote:
1. The size of a "bank" depends on the mapper or cartridge.

CNROM must swap all 512 tiles at once, so two frames of electricity would cost 16KB.

MMC3 can swap as few as 64 tiles at once, so two frames of electricity could cost only 2KB. (Assuming there were less than 64 unique, animated electricity tiles.)

Games that use RAM (CHR RAM) for tiles instead of ROM can update exactly one tile for animation if they want, at the cost of vblank time to make the updates.

And some mappers even offer bank switched CHR RAM, which is a best of both worlds kind of thing. Here is one such homebrew mapper: https://wiki.nesdev.com/w/index.php/UNROM_512

Edit: If your game doesn't scroll and you only have two frames of background animation, you can just swap the nametables. (One nametable has the background for one frame, the other nametable has the background for the other frame. You can swap between them by writing a different nametable to the lowest bits of $2000 when you want to change frames.

Different mapper for different goal, that is definitively something I will need to learn more about.
I sort of thought that there was a way to do X or Y, but you only needed to knew how.
I am not sure if switching nametable would completly work for what I have, since I do change some specific background tile, since my background are most of my "objects/interactions", so it is not going to be a "static background"
There is also (Just because the creator was feeling fancy) 2 stage that scroll horizontaly, and 1 stage that scroll verticaly, so it would not work for those... but I could have write a special case for those I guess.
Kasumi wrote:
2. It's good enough when you think it's good enough. Modern accurate emulators will lag in the same places as NES, usually, so that's how you can know if it will on an original NES.

There are 29780.5 cycles in an NTSC frame. It isn't more complicated than that, really.

Several emulators allows very easy counting of cycles.

My favorite is this ancient build of VirtuaNES, because it puts the count right on the window: viewtopic.php?p=47911#p47911

To use, write any value to $401E to start counting, and any value to $401F to stop counting.

Code:
sta $401E;Start counting
lda #$02;2 cycles always
sta $401F;stop counting

That would make 2 display on the window. How you'd count an entire frame depends on the structure of your program, but it's usually writing to $401E after you're done waiting for the frame to start, and writing to $401F just before the jmp to the frame wait loop.

Nintendulator DX works similar to the above, but offers more timers at once: viewtopic.php?t=6773

Mesen: https://www.mesen.ca/
Offers an extreme profiler (tools, debugger. Tools, Memory Tools. Profiler.)

So, it is easy to test performance, neat!
I guess I was thinking too much about modern language and game were dynamic memory allocation and multi-threading and etc... make it harder to test specific things.

I tested out VirtualNES and it works well!
2.5k cycles with a max of 4k cycles, and that is with some (a lot) of spaghetti code!
Of course there is a lot of stuffs missing as well, but it is better then I thought. I thought that I was almost already at around 70% capacity... but I am around 10-20%

Kasumi wrote:
3. I'm not aware of a better one, but I do know some links in that are dead. But also be aware you may not need to learn much audio coding at all. Audio is one problem that's solved by many people in free-to-use ways.
Check out FamiTone2: https://shiru.untergrund.net/code.shtml
GGSound: http://www.gradualgames.com/p/sound-engine.html
and Pently: https://github.com/pinobatch/pently

I did check GGSound (Will check the others link probably later!), and the 9 minutes tutorial video explain it all.
It does looks very very easy to use.
BUT, as someone who like to understand what he is doing, I shall still read the Nerdy Nights tutorial, and probably make my own sound engine at a later point.


On a side note, I am suprise on the big amount of excellents answer people give here.
With a lof of informations and all.
(I also have not really been on a forum for probably 8? years, so it might just be that but, it is great to see!)


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 13 posts ] 

All times are UTC - 7 hours


Who is online

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