GP32 Assembler under GCC


ConsoleTom

Member
Joined
Dec 4, 2003
Messages
106
Age
48
Location
Germany
Website
Visit site
Hi !

Could anyone show me how i can use assembler routines in GCC ?

I would like to learn how to program simple assembler routines but have no idea how to use assembler in GCC.

Exactly i wonder ...
- how do i pass variables from c to my assembler routine ?
- how can a asm-routine return something to my c program ?
- how can i run my asm routine from my c program ?
- when asm routines are in seperate files (.s ?) how do i configure the makefile ?

Greetings and lot of thanks in advance

Tobias
 
Everything depends on how you want to write your asm:

Either inline, or in .s source files. Personally, I prefer having my .s source file (you can find examples on many sources, as for example Newkind (elite port), which embeds some useful code for line and dot drawing. You can assemble a .s file using as:
as -o line.o line.s
Then you get your .o file, that you can add to your makefile like this:
OBJS =\
gpmain.o\
gpstart.o\
line.o <== add this

Then you can use the funcs inside your line.o from the c, maybe you'll have to define them in a .h file first:
extern void .......

To send args to an asm func, here it is:
The first 4 datas are mapped into r0 - r3, so if your function has less that or 4 args, no problem.
After that, the data can be recovered using this method:
sub sp,sp,#8 We protect the stack so that our other args don't get overwritten
stmfd r13!,{r4-r5} We save the registers we use
ldr r4,[r13,#16] 2 values saved, plus 2 registers = 4 values, 4 bytes each
ldr r5,[r13,#20] So to read the last args, use offsets of 16 and 20 to get the right value (in this example)

I won't be very helpful for returning values, as I never used it before...

To return from thez func, use this:
ldmfd r13!,{r4-r5} Recover the saved registers
add sp,sp,#8 Leave the stack as it was
bx lr Return from the function

Here's a full example:

s. file:
@ ******** ASMSaveBitmap(unsigned char *src4, unsigned char *dst, int nbx, int nby, int height2) ********

.ALIGN
.GLOBAL ASMSaveBitmap
.TYPE ASMSaveBitmap, function
.CODE 32

@r0 = src4
@r1 = dst + 1
@r2 = nbx
@r3 = nby

@r7 = height2
@r8 = tmp
@r9 = tmpnby
@r10 = dst4

ASMSaveBitmap:

sub sp,sp,#4
stmfd r13!,{r7-r10}
LDR r7,[r13,#20]

_bx5:
MLA r10,r2,r7,r1
MOV r9,r3

_by5:
LDRB r8,[r0,+r9]
SUBS r9,r9,#1
STRB r8,[r10,+r9]
BPL _by5

SUB r0,r0,#240
SUBS r2,r2,#1
BPL _bx5

ldmfd r13!,{r7-r10}
add sp,sp,#4
bx lr

.h file:
extern void ASMSaveBitmap(unsigned char *src4, unsigned char *dst, int nbx, int nby, int height2);

.c file:
static inline void SaveBitmap(int numsurface, int dx, int dy, int width, int height, unsigned char *dest) { //Sur l'écran
int xmin = 0;
int ymin = 0;
int xmax = width - 1;
int ymax = height - 1;
int height2 = ( (height + 3) >> 2) * 4;
int decaly = screen_height - height - dy;

if(dx < 0) { //Fast clipping, décale juste le tracé
xmin = -dx;
} else if( (dx + width) > screen_width) xmax = screen_width - dx - 1;
if(dy < 0) {
ymax = height + dy - 1;
} else if( (dy + height) > screen_height) ymin = dy + height - screen_height;
if(xmin > xmax) return;
if(ymin > ymax) return;
unsigned char *src4 = gpDraw[numsurface].ptbuffer + (dx + xmax) * screen_height + decaly + ymin;
dest += (xmin * height2 + ymin + 1);
ASMSaveBitmap(src4, dest, xmax - xmin, ymax - ymin, height2);
}

Hope that helped.
 
Thanks, it helped somehow to understand it theoretically, but i don't still know how to setup the makefile. Could you show me the makefile of your example ?

I looked at many sourcecodes and found that the makefile is completly different than the ones i used for my programs.

My makefile looks like this:
-----------------------------------------------------------------------------------
# devkitadv base dir
export CCBASE=c:/devkitadv
# User options passed to the compiler
export CUSER=-DLITTLE_ENDIAN -DGP32 -W -Wall -ansi -pedantic
include $(CCBASE)/gp32.mk
#------------------------------

all: gfxtest.fxe

gpmain.o: gpmain.c

gfxtest.elf: gpmain.o
$(LINK)

gfxtest.fxe: gfxtest.gxb

clean:
del gfxtest.gxb gfxtest.fxe gfxtest.elf gpmain.o
-----------------------------------------------------------------------

Where can i assign the .o file of my assembler file in this makefile ?

Greetings

Tobias
 
Well, I don't use devkitadv, but I guess this should work:

replace this
gfxtest.elf: gpmain.o

with this:
gfxtest.elf: gpmain.o asm.o

But you should ask help to someone who uses devkitadv for that one, I'm on minigp32 (thanks to bille2 and pekele by the way).

Here's my makefile:

# Generated automatically by Visual-MinGW.
# http://visual-mingw.sourceforge.net/

CC = gcc
WRES = windres
DLLWRAP = dllwrap
CPPFLAGS =
LDBASEFLAGS = -Tlnkscript -lgpfont -lgpstdlib -lgpos -lgpgraphic -lgpstdio -lgpsound -lgpmem
INCDIRS = -I /minigp32/include/gpinclude
OPTIMIZ =
STRIP = -s

ifeq ($(MAKECMDGOALS),debug)
CFLAGS = $(INCDIRS) -g
LDFLAGS = $(LDBASEFLAGS)
else
CFLAGS = $(INCDIRS) $(OPTIMIZ)
LDFLAGS = $(STRIP) $(LDBASEFLAGS)
endif

SRCDIR = .
BINDIR = .
LIBDIRS = -L /minigp32/lib/gplib

%.o : %.rc
$(WRES) $(CPPFLAGS) $< $@

OBJS =\
gpmain.o\
gpstart.o\
asmlib.o <== here I added my asm object file

TARGET = $(BINDIR)\gpfw.exe

# Targets
all: $(TARGET)

objcopy -O binary gpfw.exe gpfw

b2fxe gpfw gpfw.fxe

debug: $(TARGET)

cleanobjs:
rm -f $(OBJS)

cleanbin:
rm -f $(TARGET)

clean: cleanobjs cleanbin

# Dependency rules
$(TARGET): $(OBJS)
$(CC) -o $(BINDIR)\gpfw.exe $(OBJS) $(INCDIRS) $(LIBDIRS) $(LDFLAGS)
 
well... asm is hard to use. You have to understand the hardware architecture first.
To know how a cache und cpu registers works basically help a lot. ASM is no kind of script to insert in your code speed things up. speed optimisations with ASM is the last line of defense...

following rules will help before you start in ASM

1. Make your code work first
2. find the speed sensitive parts
3. optimize teh code with "traditional" methods
 
Hi mATkEUpON !

At first, thanks for your help (also to others who answer)
Yesterday i managed to write a very little (only 3 lines) assembler routine and to call it from my c-prg.

In the next time i'll have many questions ...

So till the next postings

Regards

Tobias
 
Hi !

What is the difference between ARM-Assembler and Thumb ? (As i know, Thumb is 16Bit and ARM is 32Bit - are there other differences ? When is the one or other used ?)

My tries were done in 32Bit.

Other question: How do i divide a value in Assembler ? (In the docs from ARM.com i could't find a divide-command)

Greetings

Tobias
 
Well I'm not that advanced in asm, and I don't really know what thumb can bring to speed things up. All I know, as you said, is that it runs in 16 bits, so maybe for some 16-bit blitting or sound mixing...

For the divide thing, all I can tell you is that I saw a source on samsung's um_s3c2400x_rev1.1.pdf. You can find it on MrSpiv's website.
 
The main advantage of thumb is that each opcode (i.e. assembler instruction) is only 16 bits. This is useful because it means that less time (half as much) is needed to load each instruction.

Its popular on the GBA because most of the memory is connected through a 16 bit bus, meaning it takes two cycles to load a 32bit ARM instruction, while only 1 cycle to load a THUMB instruction. So a two THUMB codes will be executed in the same time as 1 ARM code. The GBA has 32k of internal RAM with a 32 bit memory bus for ARM code.

Being only 16 bits, you lose a lot of functionality. For example, there is no barrel shifter, and only jump and branch instructions are conditionally executed. But a lot of the time, being able to load twice as many instructions more than makes up for this.

On the GP32, THUMB code seems to be pretty much ignored. I think this is for a few reasons:

1) cache. The GP32 has an instruction cache (not sure if the GBA has one or not tbh), so loading opcodes is going to be less of a bottle neck.
2) Variable clock and multipliers. Any advantage THUMB code has over ARM code in speed depends greatly on the memory bus speed compared to the cpu speed (you want to be able to load 1 opcode per cpu cycle). Since this can be changed a lot on the GP32, it is harder to show an advantage for THUMB code.

You can switch between THUMB and ARM in assembler fairly easily I htink, but in C you have to mess around to get the libraries to work (interworking).

(blimey, can you tell who is trying to avoid doing any work?)
 
Back
Top