GP2X Tiny Pong


gfoot

Member
Joined
Nov 15, 2005
Messages
218
Here's an attempt at getting quite a lot done in not much space. It's a playable pong game in 512 bytes.

http://www.glost.eclipse.co.uk/gfoot/gp2x/tinypong.gp2xe

It's not as crammed in as it could be - I squashed it quite a bit after getting the ball bouncing around, when I figured out a few things about ARM assembly, but I got home at nearly 2am today after a wedding celebration, and hacked the bat and game logic in the last hour, using up about 124 bytes - I haven't really condensed that code much yet.

Main techniques that I can think of which I used:

* Put everything in .text, rewrite elf headers to make .text writable, strip redundant stuff out of the elf file (now automated, I should upload the stripper too I guess)

* Learn what the S suffix does - lots of CMP instructions become redundant if you use it well. I knocked off over 100 bytes last night, mostly through this stuff, combined with...

* Use the conditional execution suffixes instead of branches when you can. My ball move and bounce code in the X direction is only three instructions. (Y is more complicated because of the bat.) They often seem to do exactly what you want them to do, and make a lot of branches redundant.

* Use the old libc4 mmap syscall, not the new one. You can then reuse the mmap parameter block for multiple mmaps. I mmap the same amount of memory for both GPIO registers and video memory - it doesn't do any harm.

* For graphics rendering, the pre- and post-increment indirect addressing modes are really handy. Aligning objects of word boundaries also lets you draw them with less instructions. You can only increment by the amount you offset the index by, with pre-indexed indirect addressing, but with plain indirect addressing you can increment it by whatever you want, which is handy.

* Don't use a stride of 320! Use 512. Multiplies are now plain shifts, which means you can do a single add instruction to combine x and y coordinates. It costs you one extra bit, which might harm your immediate constant loading, but only if you're loading funny alignments, which is worth avoiding anyway.

* Get creative with data ordreing. "/dev/mem" needs to be null-terminated, but surely you have some other variable which has its first byte zero. Failing that, at least use the next three bytes for something useful, or they'll likely get swallowed up by padding to word boundaries. I did similar things elsewhere too - my GPIO register setting iterates over a block, with one word per register to set, containing register and value. It's terminated by zero, but that zero word is also the first word of the mmap parameter block.

Things I'm not doing:

* The bat logic and game logic (lose condition) aren't optimised, they could probably get smaller

* There's some exit code there which never gets reached (2 instructions)

* My elf patcher doesn't overlap the program header with the elf header, which is normally possible on this architecture at least - saving another 2 instructions (8 bytes)

* I don't use the compression hack - I don't feel comfortable with it
 
gfoot posted on Aug 23 2006 at 08:24 PM said:
Here's an attempt at getting quite a lot done in not much space. It's a playable pong game in 512 bytes.
Ha, that's great! It's actually pretty fun to play! Nice work!
 
Last edited by a moderator:
cool.

I may be give the ARM assembly a chance with those tools

Thanks
paxl13
 
I took this idea and ran with it, while in contact with gfoot on IRC.

http://sparr.homeip.net/gp2x/tinypong_sound.gpe

Things that saved space: lots of logic optimization. zcat script stub trick. square ball.

Things that used more space: sound. start button to exit.

Gameplay changes that had no effect on size: wider paddle (because i suck at pong). inverted color. not resetting paddle and ball X coordinates.
 
Sparr posted on Aug 27 2006 at 01:42 PM said:
I took this idea and ran with it, while in contact with gfoot on IRC.

http://sparr.homeip.net/gp2x/tinypong_sound.gpe

Things that saved space: lots of logic optimization. zcat script stub trick. square ball.

Things that used more space: sound. start button to exit.

Gameplay changes that had no effect on size: wider paddle (because i suck at pong). inverted color. not resetting paddle and ball X coordinates.
That's excellent! Still 512 bytes and includes sound!

I have a lot to learn before I can get my 4k demo doing anything interesting, so far it's slow going.

Hmm, if you guys can do pong in 512 bytes I bet a platform game could be done in 4k!
 
Last edited by a moderator:
this is great .. its just like the good ol' days where load-time was a function of tape quality .. ;)
 
I've updated my original archives now...

http://www.glost.eclipse.co.uk/gfoot/gp2x/elfpatch.zip
http://www.glost.eclipse.co.uk/gfoot/gp2x/tinypong.zip

elfpatch now defaults to overlapping 8 bytes of the program header with the elf header, which saves 8 bytes (duh). It also allows you to write your own elf header in your assembly file. I couldn't work out how to get either as or ld to not add elf headers, so I did it this way. elfpatch recognizes if you've done this, by looking for the magic number, and just outputs your code if so. So basically, it just extracts your embedded elf from the code section of the executable image.

tinypong has more fun game logic (moving ceiling, different bounce angles), and comes in three variants demonstrating various tricks with the elf headers:

Firstly, tinypong-overlap8.S is basically exactly what used to come out of elfpatch - the program header overlaps the elf header by 8 bytes. It's mostly there to demonstrate how to define your own elf headers, and how elfpatch responds to it. This one is still 512 bytes, including the new game logic etc. Note especially the use of the BASE define, and how most things are written relative to 'start'... I'll explain below.

Then tinypong-overlap20.S demonstrates a more intrusive overlapping. By overlapping 20 bytes, we cut another 12 off the program of course, but the headers overlap in some important areas. In particular, we need to force a base address of 0x00200000, so that the 0x0020 overlaps correctly with the e_phentsize member of the elf header. This technique is borrowed from here: http://www.muppetlabs.com/~breadbox/softwa...iny/teensy.html

The page I just quoted goes on to embed the program header entirely in the elf header, but this isn't practical for tinypong because I need a writable .text section, and it's not trivial to arrange. However, the benefit of totally overlapping is less significant in a real program, as we can reuse bits of the headers anyway to store various data items we have. tinypong.S demonstrates this, and weighs in at 472 bytes, or thereabouts. Pay attention to the comments documenting the various fields in the headers, and how it's interleaved with actual game data.

In all cases, I've labelled the header fields, like in the web page I quoted above. I put brackets around fields whose values are (mostly) irrelevant.

There are two special cases though. p_memsz must be at least as big as p_filesz, and preferably not *too* big - it's the size of your program in memory, after loading, so you don't want to burn all your virtual address space on it.

And p_flags. In the web page, they set this to 4 (read only), noting that Linux sets the executable bit anyway, so that's ok. In fact Linux also sets the read bit, so if you just want read only and execute access to your .text section then you can put whatever you like here. Unfortunately I need write access, and that's one bit you do have to set yourself, so it's important that whatever I store here has the "2" bit set. Everything else is irrelevant.

Something I should probably note about elfpatch, particularly if you make custom elf headers, is that absolute references to locations in your program won't work - the linker will relocate them, then elfpatch will change the true addresses, breaking the absolute values. It's for this reason that whenever I need the offset to a symbol within the file, I do it relative to "start", which I also defined myself. I then add on BASE if necessary, which is the virtual base address after loading - some things are pure file offsets, though, and don't need this. Within the actual code, everything is position-independent anyway - arm instructions tend to work like that. The only issue is where one piece of data (.word) contains the address of a label.

Anyway, I hope these examples are useful to somebody! A lot of this isn't relevant if you're writing bigger demos - even at 1k the savings from this stuff are likely to be less significant compared to how much code you've got to squash. I'm impressed that sparr got sound working in 512 bytes, though, and I'm sure we'll see other 512-bytes demos too. The nice thing about such a small size is that you can't get too hung up on the project - there's a limit to what you can do, so after a few evenings, the project is done and you can move on happily.
 
great .. but how about doing something useful with all those elite assembly skills, like putting OpenGL on the 2nd processor or something ..
 
That's a bit of a big task - not exactly the kind of thing I can do in a few evenings while looking after a baby!

I'm not sure OpenGL is the right route, anyway. Allegro has built-in fixed point 3D routines, which may be better suited to the gp2x than OpenGL's very abstract interface.
 
torpor posted on Aug 28 2006 at 01:28 AM said:
great .. but how about doing something useful with all those elite assembly skills, like putting OpenGL on the 2nd processor or something ..
If your goal is to get people to stop learning about stuff and releasing things, you're well on your way. This one single post has convinced me to take a break from gp2x development for a while.

Perhaps you can find something useful to do with your elite motivational skills.

Edit to add: nice job on the program, utilities and research gfoot and sparr. Don't worry about naysayers, they would have had Picasso painting houses.
 
Last edited by a moderator:
Dzz, remember that for every twat there are ten people who actually appreciate developers' work. :)

- Alex
 
Alex. posted on Aug 28 2006 at 01:56 PM said:
Dzz, remember that for every twat there are ten people who actually appreciate developers' work. :)
Yeah, I know. It's not even so much a question of appreciation, I don't know that anybody should be grateful for a 512 byte pong game. But the idea that somebody would criticise these guys for doing something they enjoy because he doesn't think it's "useful" enough just bugs me.

I wonder if we shouldn't move development discussion to gp2xdev.org...
 
Last edited by a moderator:
Dzz posted on Aug 28 2006 at 09:24 AM said:
I wonder if we shouldn't move development discussion to gp2xdev.org...
I am not sure, its pretty empty over there :/
 
Last edited by a moderator:
Code:
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000

Incredbile oO
 
Dzz posted on Aug 28 2006 at 08:24 PM said:
Alex. posted on Aug 28 2006 at 01:56 PM said:
Dzz, remember that for every twat there are ten people who actually appreciate developers' work. :)
Yeah, I know. It's not even so much a question of appreciation, I don't know that anybody should be grateful for a 512 byte pong game. But the idea that somebody would criticise these guys for doing something they enjoy because he doesn't think it's "useful" enough just bugs me.

I wonder if we shouldn't move development discussion to gp2xdev.org...

hey, where do i criticize their work? come on.. if i didn't think it was cool, i wouldn't have commented .. saying "wow your assembly skills are elite, if only you were using them for useful things instead of pong" is more intended as a *compliment* .. like, its frustrating that elite assembly programmers are .. delivering .. ermm .. pong.

i mean, honest.. its only pong. if it were something a little more useful, like say an easily usable voxel lib (its been done in 512bytes of assembly before) i'd be impressed. i understand that, for many assembly programmers, the journey is the destination, but hey ..

and as for your comment about 'elitism' barb, i know precisely how elite it is to write assembly in as tight constraints as you can .. hey, i'm the guy who got a kick out of porting EDSAC_bcpl to GP2X, and it is for sure not so useful as pong perhaps, so you can just back down on the "twat" business, thanks very much ..
 
Last edited by a moderator:
torpor posted on Aug 28 2006 at 02:55 PM said:
hey at where do i criticize their work?
By suggesting that their time is better spent elsewhere. Let's take a parallel case. You recently posted about your accomplishment getting an alternate version of linux to compile for the gp2x. Now somebody might think "gee, only a handful of system geeks well ever care about this" and could post "great, but why don't you use your elite system skills for something useful?" you would consider that a compliment?
its frustrating that elite assembly programmers are .. delivering .. ermm .. pong.

i mean, honest.. its only pong. if it were something a little more useful, like say an easily usable voxel lib (its been done in 512bytes of assembly before) i'd be impressed.
Yes, I can see that you are very complimentary of their work.
 
Last edited by a moderator:
By suggesting that their time is better spent elsewhere.

I meant to say more like "Great, good thats done, Elite Pong in 512 Bytes, superb .. now how about something useful for your next project, like .. (3D engine)/(voxel engine)/(etc.)"

Let's take a parallel case. You recently posted about your accomplishment getting an alternate version of linux to compile for the gp2x. Now somebody might think "gee, only a handful of system geeks well ever care about this" and could post "great, but why don't you use your elite system skills for something useful?" you would consider that a compliment?

Well in fact, plenty of people did say "but what is this useful for if we've got GPH releases", and I didn't take offense: I kept my eye on the horizon for what can be done *next*..

I mean, great: pong in 512 bytes - that is elite, nobody is saying that, especially not me. What I am saying is: please, Mr. Elite, voxel renderer .. nudge nudge ..

Yes, I can see that you are very complimentary of their work.

Well, now you've got me miffed, because you're implying I'm not encouraging them .. when nothing could be further from the truth: I'm encouraging them to do something else nifty in only 512 bytes, now that pong is well and truly out of the way ..

You can understand that, right? Voxel Engine in 512 bytes == torpor Well And Truly Impressed.
 
Back
Top