GP2X I Might Start Developing For The Gp2x


jmetal88

Erm.... Woohoo!
Joined
Mar 31, 2004
Messages
1,838
Age
35
Location
Pittsburg, KS
Website
mikesweb.exofire.net
I just randomly started messing around with rlyeh's minilib today, and I somehow actually managed to write a program that uses the single pixel 'write to framebuffer' function to display a 32x32 pixel graphical tile on screen. :eek:

Knowing I can figure this out on my own makes me hopeful that I can develop something more useful in the future. I've had a look at SDL, but I never really wanted to try and figure it out. As for rlyeh's lib, I figured that out just by looking at his example code. I guess this means I'll be using his lib from now on! :rolleyes:

Thank you, rlyeh!
 
I'd say the next step is writing a full tile blitting routine that doesn't go pixel by pixel - that is if you're interested in low level graphics stuff. I made a text viewer for casio calculators that had its own font built in - all in assembly except keyboard input. It was fun but I wish I didn't have to make the font library (it had one built in for a smaller font like I used, but it was slow and there is _no_ info on how to link with it) and could just concentrate on the actual program.

I guess I'm hinting that you should probably try SDL (or some other pre-made graphics routines) if you're more interested in the main program than the low level stuff, but in any event, program what you enjoy :)
 
I can give you some examples or point you in the right direction, or many right directions if you want to move over to the 940t. If nothing else it gives you a completely clean (no operating system) environment to work in. Whats better is that when you start it up, the 920t has already setup most if not all of the peripherals. so you can borrow from rlyeh's library or the sdk2x, or not, you can just push bits into the frame buffers and bytes into the uart and not set them up if you dont want to.

BTW, enjoy. If you dont already have the pdf books on the soc that runs the gp2x and the pdfs on the 920t and 940t from arm. And an ARM ARM (ARM Architecture reference manual), you should get them. All are free downloads...
 
BradN posted on Jul 23 2006 at 01:01 AM said:
I'd say the next step is writing a full tile blitting routine that doesn't go pixel by pixel - that is if you're interested in low level graphics stuff. I made a text viewer for casio calculators that had its own font built in - all in assembly except keyboard input. It was fun but I wish I didn't have to make the font library (it had one built in for a smaller font like I used, but it was slow and there is _no_ info on how to link with it) and could just concentrate on the actual program.

I guess I'm hinting that you should probably try SDL (or some other pre-made graphics routines) if you're more interested in the main program than the low level stuff, but in any event, program what you enjoy :)

I dunno... From what I've experienced so far, the low level stuff seems pretty fun to write. I was intending to write a tile engine next, and from the way I wrote the pixel-by-pixel routine, I could use the exact same method to read an array containing a tile map. I'm actually curious as to how fast my routine really is - I'd like to see if it can handle a full screen at a time with decent speed.

BTW, I always did want to learn assembly, but the huge lists of instructions and the time it would take to learn always put me off. Plus, I never could figure out which instructions I would need to use together to get a certain output, so if you guys have any links to documents that would help me with ARM assembler specifically on the GP2X, I would appriciate it. :)
 
Last edited by a moderator:
jmetal88 posted on Jul 23 2006 at 06:56 AM said:
I dunno... From what I've experienced so far, the low level stuff seems pretty fun to write. I was intending to write a tile engine next, and from the way I wrote the pixel-by-pixel routine, I could use the exact same method to read an array containing a tile map. I'm actually curious as to how fast my routine really is - I'd like to see if it can handle a full screen at a time with decent speed.
This is exactly how I write my games, it's not very hard and it's nice to know exactly what is going on all the time. As you get further along, you'll find that certain things (like copying rectangles of memory) might take longer than you'd like, and then it's time to think about optimizing those things sith some assembly if you are not getting the frame rate you need.

I agree that it's a fun way to do things, though sometimes you wish that you just had a function handy to draw a line or whatever instead of writing one.

For your tile engine, once you have the squares being copied it's not too hard to move from there to add another array that contains transparency values and you use a little formula to combine one rectangle with the stuff already on the screen and voila, you now have an alpha-blending sprite engine.

And then when you need that stuff to be faster you figure out how to optimise THAT, and so it goes.
 
Last edited by a moderator:
jmetal88 posted on Jul 23 2006 at 08:56 AM said:
BTW, I always did want to learn assembly, but the huge lists of instructions and the time it would take to learn always put me off. Plus, I never could figure out which instructions I would need to use together to get a certain output, so if you guys have any links to documents that would help me with ARM assembler specifically on the GP2X, I would appriciate it. :)

Nonsense, once you learn assembler, all other languages are just syntax. All processors are pretty much the same, some registers, move or load/store (or both), branching, add, subtract. Sometimes multiply and divide.

Personally I start learning an ISA (instruction set architecture, assembly language) by writing a disassembler. Partly because some of the demo versions of compilers do not offer a disassembler (I guess they dont want you to know just how bad their compiler is until after you have paid for it). So new widget, new compiler, new assembler but no example assembly code. So I write a disassembler. But that is just me, with gcc and arm and the gp2x that is not required, unless you want to do it for fun (I find it fun). For example with the GPH tools you can write this program

int ra,rb,rc;

int main ( void )
{
ra=rb+rc;
return(0);
}

Build it with:

arm-linux-gcc -o test.elf test.c

Then disassemble it with

arm-linux-objdump -D test.elf > test.txt

Now gcc tacks on TONS of baggage, one of my dislikes of the BIG compilers like gcc. Anyway, search for <main> and eventually you find what you are looking for:

00008478 <main>:
8478: e1a0c00d mov ip, sp
847c: e92dd800 stmdb sp!, {fp, ip, lr, pc}
8480: e24cb004 sub fp, ip, #4 ; 0x4
8484: e59f3020 ldr r3, [pc, #32] ; 84ac <.text+0x140>
8488: e5932000 ldr r2, [r3]
848c: e59f301c ldr r3, [pc, #28] ; 84b0 <.text+0x144>
8490: e5933000 ldr r3, [r3]
8494: e0822003 add r2, r2, r3
8498: e59f3014 ldr r3, [pc, #20] ; 84b4 <.text+0x148>
849c: e5832000 str r2, [r3]
84a0: e3a03000 mov r3, #0 ; 0x0
84a4: e1a00003 mov r0, r3
84a8: e89da800 ldmia sp, {fp, sp, pc}
84ac: 000106d8 ldreqd r0, [r1], -r8
84b0: 000106d4 ldreqd r0, [r1], -r4
84b4: 000106dc ldreqd r0, [r1], -ip

Okay, sorry, try it this way

arm-linux-gcc -o test.elf -O3 test.c
then objdump then

00008478 <main>:
8478: e59f301c ldr r3, [pc, #28] ; 849c <.text+0x130>
847c: e59f201c ldr r2, [pc, #28] ; 84a0 <.text+0x134>
8480: e5931000 ldr r1, [r3]
8484: e5923000 ldr r3, [r2]
8488: e59f2014 ldr r2, [pc, #20] ; 84a4 <.text+0x138>
848c: e0811003 add r1, r1, r3
8490: e3a00000 mov r0, #0 ; 0x0
8494: e5821000 str r1, [r2]
8498: e12fff1e bx lr
849c: 000106c8 andeq r0, r1, r8, asr #13
84a0: 000106c4 andeq r0, r1, r4, asr #13
84a4: 000106cc andeq r0, r1, ip, asr #13


The first instruction is trying to load rb into register r3, it is a bit of a double indirect. They take r15 the program counter (pc) add an offset to it which gives the address 849c which you can see in the disassembly
(note when you use the pc it is two instructions 8 bytes for arm 4 bytes for thumb, ahead of the instruction you are using it with so 0x8478+8+28 = 0x849c. This is because of the pipeline). Then you see 0x849c and that has an address in it r3, is only getting the address of variable rb not actually the value...yet.

000106c4 <rc>:
106c4: 00000000 andeq r0, r0, r0

000106c8 <rb>:
106c8: 00000000 andeq r0, r0, r0

000106cc <ra>:
106cc: 00000000 andeq r0, r0, r0


r2 gets the address of rc
then they go another level of indirection and
r1 gets whatever is at the address stored in r3, which is the C variable rb
now r3 is free to be used again so r3 gets whatever r2 points at which is the variable rc

Instead of doing the add they now prep for the storage of the answer, some optimizer thing I assume, and r2 points at the location to store the answer, variable ra

Then they do the add
r1=r1+r3

Which is our line of c code basically ra=rb+rc

R0 gets the return value for the main() function because I wrote return(0); at the end of the function (again out of order for as of yet no apparent reason).

Then finally store the answer r1 to the memory containing the variable ra.

Then a bx lr. Read up on your branch instructions. Bx is a complicated way to do it but they do it because this is an arm/thumb compiler. if it were arm only they would normally just use mov pc,lr and you can just use mov pc,lr if you like. Note, thumb as fun as arm, but really only shines on 16 bit data/memory bus systems like the GBA, no need to add this complication right now in your life.

pc is r15, the program counter. lr is r14, when a branch happens the return address is stored in r14. sp is r13. I assume ip is r12, not sure. I think you have to go way back to understand these abbreviations, just know that gccs disassembler likes to use them, if you look the instruction up in your ARM ARM you can figure out the above, pc is r15, lr is the link register or r14, etc.

Most compilers let you mess with or destroy the contents of r0-r3 in a funtion, but if you are going to touch r4 on up you need to save them, typically on the stack.
stmdb r13!,{r4,r5,lr} is an example of a push
ldmia sp!,{r4,r5,lr} is an example of a pop
Some compilers will push lr on the stack and the pop it off into r15 to or will do the ldmia then mov pc,lr or bx lr. It varies widely from compiler to compiler and one assembly writer to another.

If you are going to call a function within a function you have to save r14 on the stack as it will get destroyed with your bl instruction.

int myfun( int x )
{
return(x+rc);
}
int main ( void )
{
ra=myfun(rb);
}


Okay that was too much, sorry. Trying to encourage you not scare you. For fun change one of them to an unsigned short instead of an int, see what happens. Sometimes using unsigned chars and unsigned shorts actually cost you extra instructions

For example

int ra;
unsigned short rb,rc;

int main ( void )
{
rb+=rc;
ra=rb;
return(0);
}

I am doing good right? rb and rc may only need to count to say 1000 decimal, so why waste the bytes to store them in a 32 bit value? That should save memory and be faster right? For speed and efficiency thats why:

00008478 <main>:
8478: e59f0028 ldr r0, [pc, #40] ; 84a8 <.text+0x13c>
847c: e59f2028 ldr r2, [pc, #40] ; 84ac <.text+0x140>
8480: e1d030b0 ldrh r3, [r0]
8484: e1d210b0 ldrh r1, [r2]
8488: e59f2020 ldr r2, [pc, #32] ; 84b0 <.text+0x144>
848c: e0833001 add r3, r3, r1
8490: e1a03803 mov r3, r3, lsl #16
8494: e1a03823 mov r3, r3, lsr #16
8498: e1c030b0 strh r3, [r0]
849c: e3a00000 mov r0, #0 ; 0x0
84a0: e5823000 str r3, [r2]
84a4: e12fff1e bx lr
84a8: 000106d2 ldreqd r0, [r1], -r2
84ac: 000106d0 ldreqd r0, [r1], -r0
84b0: 000106d4 ldreqd r0, [r1], -r4

The mov r3,r3,lsl #16 then the lsr. I am trying to store a 16 bit unsigned value in a 32 bit signed value, so it has to convert from unsigned 16 to signed 32, it does this with these two instructions. but is it always faster? You have to balance the time it takes to load and store the two extra bytes every time you access those variables, vs the two extra instructions, twice as many bytes plus extra cycles for execution, but perhaps the cache covers the instructions speed better than the loads and stores would to possibly uncached ram.

Learning assembler is one thing, watching what compilers do is the next step. And as Dzz stated and if you search for my memcpy experiment on this board, you will find, at least in the embedded world you have to know assembler enough to undo compilerisms. You may know that it is okay to store rb+rc in ra as is without controlling the upper bits, but the compiler doesnt the compiler is doing what you told it to do not what you wanted it to do...You will also find that it makes a HUGE difference what compile options, what version of gcc or other brand compiler, what options were chosen when gcc was itself compiled, etc. No two gccs or any two compilers are created equal, they are vastly different even if they carry the same name and version. Again see my memcpy info somewhere on this board, I know that it is faster to move 4 bytes (32 bits) on a 32 bit data bus at the same time instead of 8 bits at a time taking 4 times longer. Can you tell me if the compiler (suite) you are using knows this? How would you figure it out. Just having been bit by this yesterday, how do you know if the memory you are copying to/from is word aligned? Does this architecture allow for unaligned transfers, if so what is the cost/consequence? arm actually does allow unaligned transfers, and despite what the ARM ARM says it is deterministic, trust me, but ugly you dont want to do it, you cannot do 32 bit moves easily to unaligned addresses, you would have to go halfword or byte until you get to an aligned address then go aligned for speed, then patch up the odd bytes at the end. or take control of your compiler.

Must haves:
http://rts-lab.eas.asu.edu/NSF_EI/courses/...PSD1/cse421.htm

You will find the ARM ARM here, the ARM Architecture Reference Manual. this is rev E, AFAIK this is the latest rev and matches the book that you find in print everywhere (this is a free copy of that book, also available from arm if you request a technical information cd).

This has the assembly language definitions as well as the opcode bits, etc in case you want to do a dissassembler (and if you do, remember to compare your results to a hopefully known good disassembler as the arm arm, all revs, have mistakes).

Use this book to figure out what the disassembled C programs are doing.



You will at a minimum want the 920T and 940T technical reference manuals from this page:

http://www.arm.com/documentation/ARMProcessor_Cores/

If nothing else they describe the MMU and MPU (yet another reason why I like the 940t, it is simpler).

The gp2x has one of each of these cores.


http://www.mesdigital.com

Is the home of the system on a chip used in the gp2x, you will need the manual for it, it has all of the peripherals, uart, video stuff, timer stuff, etc. Using this and looking at the sdk2x or rlyeh's code you can figure out what they are doing and tweak it or change it or learn from it to do your own thing. Faster, better cheaper.

I see a data sheet here but not the manual.

This link:

http://wiki.gp2x.org/wiki/Docs_and_Papers

Has the MMSP2 manual as well as the 940t and 920t documents it appears.

Absolutely nothing to be afraid of here, there are plenty of examples between rlyeh and the HH sdk (sdk2x) and the kernel source (only a few files of interest there most are generic linux) as well as disassembly of C modules to help you understand how to write assembler modules that link into C.

ARM is a pretty good architecture to cut your assembly teeth on. I learned on the PDP-11 (no I am not that old, when I learned it the machines I learned on were antiques in the corner of the cs lab), which is by far the best ISA to learn assembler from. ARM is the leading processor on the planet so if you are going to learn anything, learn the ARM. its definitely easier to learn and use than an x86, trust me.

Eventually you will want to dabble in building a gcc cross compiler from sources, if you are learning assembler to take control of your C programs then you need to take control of your c compiler to take control of your c programs. It is much easier to build your own gcc, than to, for example try to get GPH's gcc to build good 940t binaries for example.

And you have come to the right place there are a number of good low level programmers on this board, all of which have dabbled in what you are considering doing...

And if you really get the assembly bug and want to learn more I can point you to a number of hardware demo/eval widgets for $20 or less from which you can learn 8051, or msp430 or Atmel AVR.

Also, even though old, the Zen of assembly language by Michael Abrash is an eye opener for the kind of stuff I/we are talking about here. I am fortunate enough to have an actual print copy, which is rare. It was later tacked on/into his monster zen of graphics programming book which I think was later open sourced and available for download. it is 8088/8086 which is like greek until you have had some assembly experience. But the concepts are very true today. For example if you want to do a bit blit like Dzz is talking about, is it better to do horizontal rows as groups because the memory addresses are sequential and you can save instructions and use the write buffer? Or are vertical columns better, you can still take advantage of the instruction set for speed? Abrashes rule of just test it, found that a number of times, what you thought might be fastest, wasnt, later you might figure out that is because of the cache or the write buffer or how the peripheral itself works. I think he is now essentially retired in place at Microsoft (a "graphics fellow" probably) as you dont hear much from him anymore, wow, maybe you do, he is still out there kickin it.

http://en.wikipedia.org/wiki/Michael_Abrash


Wow, I can never write a short email/note. Bottom line, I think the only reason these days for learning assembler is to take control of the compiler, generally for performance reasons. If you are not interested in performance, or are happy with C or C++ or Java or whatever high language. Then no assembly is required.

David

p.s. ISA's are not huge, even if their books are. its just a few registers, loads, stores, branches and a few math functions. Rember everything you need to know about a computer boils down to:
ONE, ZERO, AND, OR and NOT.
Everything in the computer is ones and zeros connected by and, or and not gates.
 
Last edited by a moderator:
Wow... :blink:

All that assembler stuff sounds a little mindboggling at the moment. I think I'll wait and see if I need it before I attempt to learn it. Besides, I'm still pretty new to C, even.

I did download the references you mentioned, though, so I can read through them at my leisure to get an idea of how the whole thing works.
 
Knowing assembly will make you a better programmer in any language. It's not really harder, but it is different and you need to keep track of your bits and bytes.
 
Klepto posted on Jul 23 2006 at 09:29 PM said:
Knowing assembly will make you a better programmer in any language. It's not really harder, but it is different and you need to keep track of your bits and bytes.

Then I will begin learning it. I intend to take my sweet time with it, however.
 
Last edited by a moderator:
jmetal88 posted on Jul 24 2006 at 04:39 AM said:
Then I will begin learning it. I intend to take my sweet time with it, however.

Blah posted on Jul 24 2006 at 05:38 AM said:
You should get used to C/C++ first. Try the link in my sig out, its a great reference.

I should elaborate, it really depends on where you are aiming. If you want to write a homebrew game for the gp2x then it's probably better to stick with something reasonably high level, C or C++ is everyone's 1st choice, perhaps python if you don't want to get too involved in the details. If you want to spend a few years learning how to program then assembly could be a good starting point. 6502 assembly for the Commodore 64 was one of the first languages I learned. Knowing what the computer is doing behind the scenes is a real help when it comes to understanding what's really going on.

Oh, and you need to learn to count in hex and binary. Decimal isn't much use (and IMO octal is silly :p).
 
Last edited by a moderator:
jmetal88 posted on Jul 24 2006 at 04:39 AM said:
Klepto posted on Jul 23 2006 at 09:29 PM said:
Knowing assembly will make you a better programmer in any language. It's not really harder, but it is different and you need to keep track of your bits and bytes.

Then I will begin learning it. I intend to take my sweet time with it, however.
Still looks hard to me :D I think i could learn it, given 20 years...
 
Last edited by a moderator:
Assembly is one of those deceptively simple things... You could learn the syntax in a day, but still be kind of clueless how to apply it to actually do stuff.
 
BradN posted on Jul 24 2006 at 01:53 PM said:
Assembly is one of those deceptively simple things... You could learn the syntax in a day, but still be kind of clueless how to apply it to actually do stuff.

Exactly.

It is probably a visibility thing. With your very first printf("Hello World!"); program, you can "see" it do something. Other than blinking leds or backlights its much harder to see your assembler do something. I was hoping with my example to bridge the gap, instead of trying to make assembler do something from scratch, not knowing it, instead take some C that you can see working and go backward to assembler. I think learning both C and assembler at the same time would be a good way to go. It was no accident that the class I took taught the PDP-11 and C in the same class the same semester. A great ISA for teaching assembler, as well as being the processor that C was invented on as well as the processor C borrowed from (pre and post increment and decrement for example). The first time you attempt to do some fancy print statements from assembler you realize what high level langages are all about. At the same time, the first time you realize or have someone show you that a small section of your code can have a small change and run hundreds to thousands of times faster, it may inspire you to understand what the chip is doing at the machine code level and the peripherals at the register level. To each his/her own...Sounds like you are having fun and that is all that really matters...

Anyway, back to the original question the mmsp2 document has most of what you need to understand the chip controlled by rlyehs code. Take the hex values in the register reads and writes, remove the leading 0x and trailing >>1 and search the manual for those registers (for example the code will have [0x1234>>1], just search the manual for 1234 by itself to find the register descriptions. As far as rlyehs code goes I think that is the only manual you need, unfortunately it is an incomplete/public level manual, and does not describe 100% of the chip. AFAIK it is the best we have.
 
Last edited by a moderator:
Well, this upcoming school year, I am taking a computer science class. We will be learning C in there, so maybe during the course of the class I will make a GP2X program that is workable and useful.
 
Rather than disassembling a full program, you can compile with the -S switch, and gcc will just compile and not assemble the resulting code. You end up with a much smaller chunk of stuff to work with. If you include debugging information there's a lot of extra noise, but without debugging information it's a lot easier to read by hand.

gcc -o test.s -S test.cpp -O2 ...etc...
 
whoa, now I'm feeling so better by only knowing x86 assembly :ph34r:

I always felt that x86 was the easiest, perhaps not by complexity's sake, but anyone can assembly, run and debug the code on your own computer, so the tools are easier to go

also the 16bit side of x86 is even easier as you don't have any memory protection nor i/o space protection, have you ever thougt of how easier would be to apply mmu hack without any kind of protection? ^_^
 
gfoot posted on Jul 31 2006 at 05:07 PM said:
Rather than disassembling a full program, you can compile with the -S switch, and gcc will just compile and not assemble the resulting code. You end up with a much smaller chunk of stuff to work with. If you include debugging information there's a lot of extra noise, but without debugging information it's a lot easier to read by hand.

gcc -o test.s -S test.cpp -O2 ...etc...

Hmm... I might just try that, see what's going on behind some input and display routines by themselves and stuff, maybe look through the ARM ARM, see if there's anything that I can improve on. This sounds like fun stuff, but I might have to wait for marching band to get out of the way first, so I have some energy left to think.
 
Last edited by a moderator:
Back
Top