Today, we will discuss the program from Chapter 1. But first we need to go over some more instructions.
The first instruction we need to learn is another form of STR. We've worked with 32bit values, but you can also
work with 16bit, or 8bit values. Note that you should make sure addresses used to access 32bit and 16bit values are
aligned properly. Here are some examples of loading and storing 16 and 8 bit values:
(I only use the single register addressing mode here, but any can be used.)
ldrh r0, [r1]
- The H after LDR mean "halfword" (word=32,halfword=16,byte=8 bits), this will
load the 16bit value at address contained in r1 into r0.
Note that the upper 16bits of r0 will then
be zeroed out.
ldrsh r0, [r1]
- Loads a signed word. Same as the above really, except the 16bit value will be sign-extended into the
upper bits of r0.
So if you load the 16bit value 0xFE3A (for example), r0 will be 0xFFFFFE3A. For those
who may not know, sign-extend fills the upper bits with the highest bit of the loaded value. If you
had loaded 0x0342, r0 would then be 0x00000342.
ldrb r0, [r1]
- Loads a byte (8bit) value, upper 24bits zeroed out (also called zero-extend).
ldrsb r0, [r1]
- Loads a signed byte value, it is sign-extended (value of bit 7 copied to
the rest of the higher bits).
STR has similar variants, however, it does not have the signed ones.
Branches allow us to jump to piece of code, conditionally if needed. Typically, a branch instruction looks like this:
b label_name
- will jump to the code that comes after the label. Chances are that you know what a label is.
But if you don't, it looks like this:
label:
- A label is a word (that mostly follows C identifier rules), followed by a colon.
Conditional branches look similar, except that they have one of the condition codes added to the 'b'.
The conditions
are: (copied out of a PDF written by Re-Eject)
Equal EQ Not Equal NE Carry Set CS Carry Clear CC Unsigned Higher or Same HS Unsigned Lower LO Minus/Negative MI Plus/Positive or Zero PL Overflow VS No Overflow VC Unsigned Higher HI Unsigned Lower or Same LS Signed Greater than or Equal GE Signed Less than LT Signed Greater than GT Signed Less than or Equal LE Always AL - The default Never NE - Useless, and it might even be not supported in our version of the ARM processor.
There is another register called the CPSR (Current Program Status Register), the condition (aka status) is contained in the top 4 bits of this register (each one called a "flag"), they are: zero (also set when something is equal), carry, overflow, and sign (set to the highest bit of a number). The CPSR cannot be used in MOV instructions, it just exists. There are special instructions to modify it explicitly, we'll get to those eventually, but they aren't very important. With most instructions, you have a choice to update the CPSR based on the result of the instruction. We will get to that in due time as well.
Let's go thru and discuss the program from Chapter 1
.arm
- Tells the assembler we will be using the ARM mode instructions..text
- Tells the assembler to put the following in the text (code) section (usually ROM for a GBA cart)..global main
- Tells the assembler to allow access to our main from outside this file, necessary so the linker can find the main function.main:
- A label denoting the start of our main function.mov r0, #0x4000000
- Puts the value 0x4000000 into r0. (this is the address of REG_DISPCNT, the LCD controller.)mov r1, #0x400
- Puts the value 0x400 into r1. (we can't just mov 0x403, since it can't be created by shifting up an 8 bit value)add r1, r1, #3
- Add 3 to r1 (r1 = r1 + 3), r1 now contains 0x403 (will mean mode 3 and enable BG 2, to the GFx hardware)str r1, [r0]
- Actually do the write to the address.@blank
- Comments in asm start with '@', although since we call the file .S and compile with GCC, we can use C and C++ style comments too.mov r0, #0x6000000 @ address of VRAM mov r1, #0xFF @ some redish color mov r2, #0x9600 @ the amount of 16bit writes it'll take to fill the screen. loop1: @ a label strh r1, [r0], #2 @ will store the 16bit value in r1 into address in r0, then @ add 2 to r0. (16bit values are 2 bytes long). subs r2, r2, #1 @ subtract 1 from r2 (r2 = r2 - 1). the S after SUB means to set the @ flags in CPSR based on the result. bne loop1 @ If the status doesn't reflect the result of an instruction being zero, jump to loop1. infin: @ an infinite loop b infin
Notice the S after SUB, if that weren't there, the status would never say that a zero result had happened and we'd have an infinite loop there. Math (and some other instructions) only touch the CPSR if the S is there. This is quite important.
I figured you would probably want to do this now. So that's what we'll do. If you don't have it already, pick up a copy of "Bimbo" from GbaDev, and export a copy of your favorite photo as a Binary file called "pic.bin" (no quotes, as usual) for mode 3. I'll list the entire program and use comments to explain it:
Challenge: Grab a copy of GBATek.htm from gbadev, and see if you can do the same picture in mode 4. (you will need to reduce the colors, since mode 4 is an 8bit palette'ed mode.) HINT: If you still use the binary output format, it'll output the palette first. Copy that in one loop (using write-back on your chosen address register), then use a loop similar to the one I just used to copy the picture. Palette is 0x200 bytes, Picture is 0x12c00 bytes.
The answer will be given at the end of Chapter 5.
In Chapter 5, we'll take a look at the GBA's graphics system in greater detail.
That's all for now, how about Chapter 5? Or the GBA ASM index?