A89: This sprite code in C
[Prev][Next][Index][Thread]
A89: This sprite code in C
> sprite0(x,y)
> int x;
> int y;
> {
> asm("
> move.w 8(%sp),%d0
> move.w 10(%sp),%d1
> lea sprite(PC),%a0 this command works if l remove the (PC), but l need
> to put (PC) after sprite and the compiler doesn't like it.
A few problems here:
- It should be sprite(%pc), gcc requires the % to prefix register
names and it is case sensitive.
- sprite(%pc) will *not* change the pc. It is merely a relative
addressing form. Instead of storing the absolute address of sprite
in the instruction, it will store the difference between the PC and
sprite. It does *not* change the PC. Therefore, your program will
blow up as soon as it executes the lea: it will fetch the next insn
from sprite. Boom.
Note that it is not gcc related, executing data structures usually
bombs the code regardless of the language: switching between C,
assembler or typing hex numbers directly into memory has no effect
on the result ...
> sprite: dc.w 8
> dc.w 1
> dc.b %00000000 having this line returns "bad expression." l guess
> it's maybe because % is used to signal a register, but how do l do this
> command now?
Under gcc/gas you can not use % for binary and $ for hex constants.
You don't have binary constants, you have decimal, octal and
hexadecimal constants which you write exactly the same way as if they
were C constants. That is, ten would be 10 or 012 or 0xa.
> mask: dc.b %00000000 same here.
>
> ");
> put_sprite();
> }
While in this particular case the C wrapper over an assembly function
would work this way, assuming that put_sprite does not destroy any
registers but d0, d1, a0, a1. However, this solution is anything but
efficient. A better way might be this:
(You put this into a header file or, if you only have one source file,
at the beginning of that)
static inline void sprite( int x, int y, void *data )
{
register int xx asm ( "d0" ) = x;
register int yy asm ( "d1" ) = y;
register void *pp asm ( "a0" ) = data;
asm volatile ( "
jsr put_sprite
" : /* No output parameters */
: "d" (xx), "d" (yy), "a" (pp) /* xx, yy and pp are inputs */
: "r1", "r2" ... /* List of clobbered registers */
);
}
where "r1", "r2", ... are the list of registers (without the %) that
put_sprite changes, if any. If put_sprite preserves all registers then
you just leave it empty, that is, you omit the : and everything after
it until the ); bit. Let's say put_sprite destroys d2 (I don't
know, it's for the example), so it is actually
: "d2" /* List of ... */
Now with this one if you write this:
foo()
{
/* Here would be some code */
sprite( 10, 20, &mysprite );
/* here comes yet some other code */
}
this is what compiles from it (with -O2), with my comments of what
is what:
foo:
link.w %a6,#0
move.l %d2,-(%sp) /* d2 is saved for put_sprite destroys it */
/* Here is where the some code would be */
moveq.l #10,%d0
moveq.l #20,%d1
lea mysprite,%a0
/* All that push, call, pop etc. business is removed and
substituted with parameters being loaded where they should
be: 10 to d0, 20 to d1 and the address of mysprite to a0.
It is quite a significant saving in speed and code size ! */
#APP
jsr put_sprite
#NO_APP
/* here's where the yet some other code would be */
move.l -4(%a6),%d2 /* d2 is restored */
unlk %a6
rts
Now the only question remaining is how do you store your sprites in a C
fashion. Well, easily:
#define SPRITE( name, width, height ) \
const struct { \
unsigned short w, h; \
char shape[(((width)+7)/8)*(height)]; \
char mask[(((width)+7)/8)*(height)]; \
} name = { (width),(height),
Then you can write this:
SPRITE( sprite0, 8, 1 )
{ 0x3c },
{ 0x7e }
};
This will compile to:
sprite0:
.word 8
.word 1
.byte 60
.byte 126
Note that .word is the same as dc.w and .byte is dc.b.
Say you want a 16x4 sprite, you would write:
SPRITE( bigsprite, 16, 4 )
{ 0xff, 0xff,
0x80, 0x01,
0x80, 0x01,
0xff, 0xff },
{ 0xff, 0xff,
0xff, 0xff,
0xff, 0xff,
0xff, 0xff }
};
which will generate:
bigsprite:
.word 16
.word 4
.byte -1
.byte -1
.byte -128
.byte 1
.byte -128
.byte 1
.byte -1
.byte -1
.byte -1
.byte -1
.byte -1
.byte -1
.byte -1
.byte -1
.byte -1
.byte -1
That would do, wouldn't it ?
Regards,
Zoltan
References: