Jump to content

Managing ROM size with efficient code.


Recommended Posts

As the title says. I am looking for any tips on writing code that keeps the ROM size as small as possible.


Are there good and bad ways to write certain IntyBASIC code, that generates the same result, but adds less size?


For example, would better use of constants, functions or procedures, help? What about better placement of if, or nested if, statements? Better use of variables? I can go on, but I know you guys get it.


Sure you can play with the ORG statement, but more efficient code will help too.


I have another adjacent thread where I now have a ROM that is (in Windows NTSF) over 50kb. I have no music, sound effects, graphics screens yet, and this is concerning as I believe the max size would be about 84kb.


Any tips?



Link to comment
Share on other sites

There are a few principles to optimize IntyBASIC programs:


* If a routine is repeated several times in your program, it qualifies to become a subroutine, just check for the common parameter.

* If a semi-long expression is repeated several times in your program, consider replacing it with a subroutine or a DEF FN.

* If you have several IF doing comparison with constants, replace with ON GOTO or ON GOSUB

* if you have tons of PRINT with strings (for example a text adventure), start considering using DATA PACKED and a printing subroutine.


  • Like 1
Link to comment
Share on other sites

The IntyBASIC compiler output interlists your original code with the assembly code it generated.


It can be rather instructive to write code, compile it, and see what IntyBASIC produces.  IntyBASIC doesn't have a general register allocator, but it does try to reuse values it's already loaded in registers within an expression.  So, swapping the order of operands in an addition, or placing parentheses creatively can make a difference.



  • Like 2
Link to comment
Share on other sites

Hey guys, thanks.


The reason my code is so extensive is also that I may be a bit ambitious. I'm using options to choose a player of different abilities, different code for multiplayer also, animations going E/W and N/S and not moving, different game speeds, different enemy A/Is, etc. You can see how this branches out into many permutations and combinations. It's like a tree.


Also, it being a maze game adds some complicated collision detection.


At any rate, here's some sample code, which is quite frequent all over my program. It's simplistic and hypothetical. Not asking for any "perfect" answer, but, if there are ideas on how to save space on the following it would be nice.


if expr0 then if expr1 then if expr5 then statement01:statement02 else statement03
if expr0 then if expr2 then if expr6 then statement04:statement05 else statement06
if expr0 then if expr3 then if expr7 then statement07:statement08 else statement09
if expr0 then if expr4 then if expr8 then statement10:statement11 else statement12


I recently added some similar code to make one enemy's A/I a bit more sophisticated. It added over 5kb in ROM size - geez, it was only like 4 lines! ?







Link to comment
Share on other sites

I see.


You can optimize your code this way (notice the nesting):



if expr1 then if expr5 then statement01:statement02 else statement03
if expr2 then if expr6 then statement04:statement05 else statement06
if expr3 then if expr7 then statement07:statement08 else statement09
if expr4 then if expr8 then statement10:statement11 else statement12



I understand when you say more variations, it means you add a different speed like this (and replicate code):


IF speed = 0 THEN

    enemy_x = enemy_x + 1

    enemy_y = enemy_y + 1

ELSEIF speed = 1 THEN

    enemy_x = enemy_x + 2

    enemy_y = enemy_y + 2



This can be optimized this way:


enemy_x = enemy_x + speed_table(speed)

enemy_y = enemy_y + speed_table(speed)


'  In another part for data

speed_table: DATA 1,2



  • Like 5
Link to comment
Share on other sites

I've had many issues in the past with having bulky code and needing to shrink the footprint some.  


consider replacing routines like:

counter = counter + 1: if counter > 1 then counter = 0


counter = 1 - counter



counter = counter + 1: if counter > 7 then counter = 0


counter = (counter + 1) % 8


Those can free a small amount.  Everything adds up if you have many routines like that though.


Nanochess' example on using DATA routines for tables is incredibly useful.  I use tables for just about everything, including movement patterns for enemies, jumping animation, enemy attributes, as well as stage configuration.


If you using PRINT commands to place a few GRAMs or characters on screen, it can be leaner to use #BACKTAB instead.


DO/LOOP tends to be more wasteful than having a label and a IF THEN GOTO statement.


Having subroutines that check enemy backtab collision, updating enemy X or Y position, or changing enemy direction can be useful if you have many different enemy types.  Each enemy can call on the same subroutines rather than duplicating the same type of code for each enemy type.


I tend to use subroutines for lots of little things as well, like clearing sprites on screen, resetting enemy variables, or time delays (FOR I = 0 to DELAY_TIME: WAIT: NEXT).



  • Like 3
Link to comment
Share on other sites

Hey thanks! I am working on said suggestions right now. I will report back with questions and results.


My last contest entry, "Deadly Balls", although only one level was still less than 40kb, and it had sound effects, music, and full game play. I've worked on it since then, added two levels, some different enemies, some extra music, some background, and it's still only around 40kb.


My current attempting entry has no music, no sound effects, one level, and game play is still not complete and it's already well over 50kb. It astounds me what's going on this time around. Just thought I'd share that. Anyway, maybe if and when I post source someone can help if needed on that.


Thanks for now. ?

Link to comment
Share on other sites

One thing that helped me immensely was developing ways to compress levels down.  For Super Mario Bros, fitting 32 stages and all the various secret areas was not going to happen without some kind of compression.   The repeating backgrounds are drawn in 1x12 strips that are pulled from a table, and the level objects are drawn over the background as needed, but done with DATA PACKED tables that contain the following:

Object type (single backtab tile, tile strip, enemy, warp, etc)

Object attribute (tile strip size, warp reference point, etc)

Screen X position

Screen Y position


Two 8 bit values in DATA PACKED are combined into a single 16 bit value.  These are decoded back to two separate values by Value / 256 and Value % 256 respectively.


I also pack all in game text the same way and try to avoid using PRINT statements all together using a subroutine like this:


        #BACKTAB(TEXT_POSITION + I * 2) = (GAME_TEXT(I + #TEXT_OFFSET) / 256) * 8 + 7 + #LEVEL_BGCOLOR
        #BACKTAB(TEXT_POSITION + I * 2 + 1) = (GAME_TEXT(I + #TEXT_OFFSET) % 256) * 8 + 7 + #LEVEL_BGCOLOR





It's certainly not as convenient as using PRINT since you need to keep track of the offset of where to begin reading the text, but it has helped me reduce the footprint of all my game projects.

Having a function at the beginning of the program as shown below also helps with more easily using the subroutine:



  • Like 1
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Recently Browsing   0 members

    • No registered users viewing this page.
  • Create New...