Modularity/File Size vs. Efficiency

Discuss technical or other issues relating to programming the Nintendo Entertainment System, Famicom, or compatible systems.

Moderator: Moderators

User avatar
67726e
Posts: 129
Joined: Sat Apr 03, 2010 5:45 pm
Location: South Carolina
Contact:

Modularity/File Size vs. Efficiency

Post by 67726e »

I'm just wondering what you would consider more important in making a game: Reducing file size or more efficiency.
tepples
Posts: 22345
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples »

Really, do whatever you need to fit the size and frame rate targets that you have set. If your game is 132 KiB, and your publisher wants you to get it down to 128 KiB so that it will fit in the smaller ROM chip, you might need to cut out some lookup tables. If you want to have a lot of big levels, space efficiency of the map encoding is important. If a lot of critters in one area are causing the CPU to take longer than 29,000 cycles to make a frame, you'll need to find some tradeoffs to get more speed.

Not everybody's targets are the same. Micronics games, for instance, appear to trade off frame rate for development time.
User avatar
67726e
Posts: 129
Joined: Sat Apr 03, 2010 5:45 pm
Location: South Carolina
Contact:

Post by 67726e »

tepples wrote:your publisher .
Publisher? lolwut?

So basically it really doesn't matter as long as you get it done and it works? I guess I like that way of looking at it since I'm still working on my first game.
User avatar
blargg
Posts: 3717
Joined: Mon Sep 27, 2004 8:33 am
Location: Central Texas, USA
Contact:

Post by blargg »

Most important: it's fun. Depending on what approach you take, you may need to work on reducing data size (if it's a game with large maps), improving efficient (if it involves lots of objects on screen and fast action), or something else entirely (perhaps coming up with a design that can handle the complexity of a turn-based game).
User avatar
Bregalad
Posts: 8036
Joined: Fri Nov 12, 2004 2:49 pm
Location: Caen, France

Post by Bregalad »

Publisher? lolwut?
tepples is always faking that we're commercial developers. He probably took that habit from GBAdev.
Not that at some point we're all doing this - tepples just say it loud.

Personally I hate frame rate drops so i'd rather have a "bigger" file (anyways even if you make a VERY large 512k game it's really small by todays standards).
Useless, lumbering half-wits don't scare us.
tepples
Posts: 22345
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples »

Bregalad wrote:tepples is always faking that we're commercial developers. He probably took that habit from GBAdev.
Not that at some point we're all doing this - tepples just say it loud.
I wouldn't be saying it out loud if it weren't for Sivak and bunnyboy. (No, not that bunnyboy.) Then again, I meant "publisher" in a fairly broad sense. For example, if you are entering a 16K competition, the compo sponsor is your publisher, and you'll need to fit everything into 16384 bytes.
User avatar
Kasumi
Posts: 1293
Joined: Wed Apr 02, 2008 2:09 pm

Post by Kasumi »

For me right now efficiency is the most important. My game does complicated things, and it needs to take a lot of space to do what it does at all. It sometimes needs to take even more to do it fast. The routine that runs the main character is 3.75 kilobytes or something like that.

However I code for space on the side, since I also want more levels. So I take a page from the atari programmer's book, and turn jmps into branches whenever possible. (Which saves a byte. Saved bytes add up though. I've saved enough already for at least a medium sized level)

Sometimes it's easy like this:

Code: Select all

  bne label
  jmp label2
becomes

Code: Select all

  bne label
  beq label2
Sometimes it's trickier like realizing no instructions change the carry flag in between a cmp, sec, sbc etc and a jmp. Then changing the jmp to a branch that brances on the condition that the carry flag with definitely be.

I do some other probably crazy things to save space. But mostly I'm about speed.

If I was doing something else I'd work on saving space, since I think it's kind of fun, actually. So yeah, depends on the game.
User avatar
67726e
Posts: 129
Joined: Sat Apr 03, 2010 5:45 pm
Location: South Carolina
Contact:

Post by 67726e »

Kasumi, I swear everytime you respond to one of my threads I learn something new about efficiency. Using a BEQ in place of JMP is so blatantly obvious that I just completely don't see it. Truth be told that just gave me several ideas on ways I could make my code just a little better.
User avatar
koitsu
Posts: 4203
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Post by koitsu »

blargg wrote:Most important: it's fun.
Ding ding, blargg wins the prize. (I have no idea what the prize is, but he wins it)
User avatar
tokumaru
Posts: 12106
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru »

I usually optimize for speed, but I can't completely forget about the size. Even though mappers allow you to have a lot of PRG-ROM, the addressing space of the 6502 is still pretty small, and only 32KB of PRG can be mapped at any given time, which means that the way your code and data are organized will haven an impact on the efficiency of the program as well.

I often use branches instead of jumps when a flag (N, C, Z or V) is guaranteed to always have the same value at that point, even if I have to shuffle some instructions around to make sure that value is constant.

Another thing that helps, one byte at a time, is not doing CLC or SEC before additions and subtractions if the value of the carry is known, even if that means compensating the added/subtracted value. For example, if I want to add $20 to a variable but the carry is always set, I add $1F instead.

That's the kind of optimization I do when a block of code is already working without any "tricks" though, because sometimes if you do them while still prototyping the logic you might end up changing the way a flag behaves and screw up the rest of the logic, and that kind of bug can be hard to find.
User avatar
Dwedit
Posts: 4470
Joined: Fri Nov 19, 2004 7:35 pm
Contact:

Post by Dwedit »

Not setting or clearing the carry flag is very dangerous. I thought I was doing some clever optimizations, and they backfired for that reason.
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!
User avatar
tokumaru
Posts: 12106
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru »

That's why I only do that as the last step before considering a piece of code final, so that no changes could by accident modify the carry.
User avatar
blargg
Posts: 3717
Joined: Mon Sep 27, 2004 8:33 am
Location: Central Texas, USA
Contact:

Post by blargg »

Optimizations like doing BEQ BNE instead of BEQ JMP are pretty silly, unless it's in a macro that's used hundreds of times. Focus your efforts on things that yield hundreds of bytes of savings. Things like this are fragile (change the BEQ to something else and it breaks if you aren't watching). Others, like avoiding a CLC or SEC, are useful only in critical loops where a few cycles saved is significant. Everywhere else they just make the code more brittle. Given that assembly code is some of the hardest to debug, you don't need techniques like this making it even harder. I think most cases of this have ill effects, especially when people here use them in introductory NES code of all places.

tokumaru has it exactly right: If you're going to do things like this, do them last, and only when you can see that they will make a noticeable difference in speed or code size. Otherwise, you're de-optimizing clarity. Always remember that downside.
User avatar
Kasumi
Posts: 1293
Joined: Wed Apr 02, 2008 2:09 pm

Post by Kasumi »

My current savings by using branches instead of jmps is 143ish bytes. Nothing to sneeze at. Space is space. That's a lot of animations or a level to three. (In my formats)

Another thing I neglected to mention is to tag your branches that used to be jmps with a comment. This is so if more added code brings the label the branch points to out of range, you just turn it into a jmp, rather than the first instinct of creating an extended branch which takes up both more cycles AND bytes. (But of course this is avoided entirely if you convert jmps to branches last.)

I do agree it sometimes makes code less readable in the less obvious cases, and you should only do it when you're sure the logic in place is set in stone.

As for avoiding clc and sec, it can indeed save you a lot of cycles in loops. clc/sec before a loop instead of during every iteration is simple enough. My first 8-bit division routine took 214 cycles (Max). After optimization, it takes 133 (Max). (I used to divide a lot, so this was VERY important. I might be able to do it even faster if I bring the tile type back that used division)

Other than during loops, I'll get rid of them if I see it, but I don't actively look for instances where I can avoid them. They're used so seldom the byte (and cycle savings) don't often make it worth it.

I'm not advocating being careless. Be REALLY sure before you make a change like any of these. I have stuff like this comment in my code:

Code: Select all

velmask.highmid.pos:
	bne velmask.highmidstart2
	plp
	jmp velmask.end;bcc would probably work, but I'm scared to try it
I'm pretty sure all paths that lead to that label push a clear carry byte to the stack, but I'm not sure. If I REALLY need that byte later, I can always come back :) Never make a change you're not sure of for one byte. I'm not saying that.
Last edited by Kasumi on Mon Jul 05, 2010 6:11 pm, edited 1 time in total.
tepples
Posts: 22345
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples »

Kasumi wrote:My current savings by using branches instead of jmps is 143ish bytes. Nothing to sneeze at. Space is space. That's a lot of animations or a level to three.
It's nine tiles.
Never make a change you're not sure of for one byte.
You're right. This is the NES, not the Atari 2600.
Post Reply