Inline Assembly


Staff member
I'm trying to learn by myself SH2 Assembly, but I don't understand something when I add a simple code into a C file, does someone has an idea ?

#define toto(value) asm volatile ( \

"add %1, %0 \n" /* add _F to _A */ \

"mov %0,%2 \n" /* put result into value */ \

:"=r" (value) /* _value as output : %2*/ \

:"r" (_A), /* _A as input : %0*/ \

"r" (_F) /* _F as input : %1*/ \


It seems that it adds _A and value instaed of adding _A to _F.

The result is correctly stored into value.
I'm no expert on GCC inline assembly, but I think that the register mapping is based on the order they're listed, ie. %0 refers to "value", %1 to "_A" and %2 to "_F".

EDIT: Should "_A" be added to the clobber list, as its value is modified?
I wanted to put the result into "value" and you were right, the number corresponding to a parameter (input or output) is the order of these params. It was easier than thought (input param. then output params).

I don't know where I can find docs dealing with the use of assembly with GCC in a C code.
if you want to learn SH2 asm I think you'd better use SNASMSH2 like I do... then when you get a feel of the instruction set you could bother with the weird GCC syntax...
Originally posted by vbt@Jan. 18 2003, 11:55 pm

I don't know where I can find docs dealing with the use of assembly with GCC in a C code.

GCC's own manual has a section on it, titled Assembler Instructions with C Expression Operands, but like most GNU manuals it's not as good as one would hope.

A couple of other links I managed to dig up: combines a few popular docs on inline assembly. x86-oriented like most, unfortunately. focuses on assembly programming for Linux. is a doc on using assembly in the AVR port of GCC. It differs a bit from mainstream GCC, but it seems like a pretty good document nevertheless. is IBM's tutorial on x86 assembly under Linux.

I'm still suspicious of _A being modified in your example, IMO it would be better written as

mov %1, %0

add %2, %0
which only modifies the output variable.
Antime, you know too many doc. sites and your site is really great, I use it very often.
Just a little question about Z80 ADD function, I wonder why SZ[(UINT8)res] var is no more used when this function is translated into assembly.

#define ADD(value)	


	unsigned val = value;     \

  unsigned res = _A + val;                  \

	_F = SZ[(UINT8)res] | ((res >> 8) & CF) |          \

    ((_A ^ res ^ val) & HF) |                \

    (((val ^ _A ^ 0x80) & (val ^ res) & 0x80) >> 5);    \

  _A = (UINT8)res;                      \


#define ADD(value)      \

 asm (       	\

 " addb %2,%0      \n"                   \

 " lahf         \n"                   \

 " setob %1       \n" /* al = 1 if overflow */      \

 " addb %1,%1      \n"                   \

 " addb %1,%1      \n" /* shift to P/V bit position */   \

 " andb $0xd1,%%ah   \n" /* sign, zero, half carry, carry */ \

 " orb %%ah,%1     \n"                   \

 :"=q" (_A), "=q" (_F)                     \

 :"q" (value), "1" (_F), "0" (_A)                \

What core are you using? It's difficult to tell what's going on from just a partial snippet (ie. what is the array SZ used for?)

Two things though: bit-munging is much easier in assembler and sometimes it's easier to do a table look-up than to compute the value and secondly the Z80 flags are 1:1 reproducible in the x86 flags so if you do the same operations in x86 assembly you get the flags for "free" (remember that the two share a common ancestor, Intel's 8080).
It's the Z80 core used by SMS plus and derived from MAME's Z80 core. Thanks for your answer it's really interesting. I need to learn more about Z80 internal core.
Z80 ASM is actually very easy and straightforward (although it is VERY different from SH2, but a lot like x86). I'd recommend you look here (scroll to the bottom)
If i recall correctly, the MAME Z80 uses the SZ[] array to check if the zero/sign flag should activate.

The ASM core seems to retrieve that flag directly from of the CPU. In the SH-2 attempt I made, I used comparisations to set this flag.

As for the GCC syntax, is not that terrible. I learned to use it with little more than the as exceptions doc and the Hitachi SH-2 reference. Writing code worthwile, that's where the real deal is:

#define ADD(value)

 __asm__ volatile (

 "shll16 %0     \n"

 "shll8 %0      \n" // placed just before the 32-bit boundary of the register

 "shll16 %2     \n"

 "shll8 %2      \n" // both _A and value suffer the change

 "mov %0,r1     \n" // temp store _A since we need to do add twice

 "addc %2,%0     \n" // add with carry. Carry stored in T

 "stc sr,r0     \n" // move sr to r0

 "and #1,r0     \n" // Put _F 1 if T = 1

 "or r0,%2   \n" // Set CARRY flag

 "mov r1,%0     \n" // get back the old _A value (we need r0)

 "addv %2,%0     \n" // Add again, but this time check for overflow 

 "stc sr,r0     \n" // move sr to r0

 "and #1,r0     \n" // Put _F 1 if T = 1

 "shll2 r0      \n" // move the overflow flag to his correct location

 "or r0,%2      \n" // Set OVERFLOW flag

 "xor r1,r1     \n" // Clears r1, like we do with CISC

 "cmp/eq %0,r1    \n" // If _A is zero....

 "stc sr,r0     \n" // move sr to r0

 "and #1,r0     \n" // Clear all flags but T

 "shll8 r0      \n"

 "shlr2 r0      \n" // Moves 8-2 = 6 bit positions to the left

 "or r0,%2      \n" // OR's that value, 3 flags done (ZERO)

 "shlr16 %0     \n"

 "shlr8 %0      \n" // Reset all values back 24-bits

 "mov %0,r0     \n" // Moves the result into r0 for speed

 "and #128,r0    \n" // get the last bit

 "or r0,%2     \n" // put the result on F	(SIGNAL)

 "shlr16 %2     \n"

 "shlr8 %2      \n" // both _A and value suffer the change

 :"=r" (_A), "=r" (_F)

 :"r" (value), "1" (_F), "0" (_A)


You can replace it on the MAME core, and it will compile and run correctly on a SH-2. But it's 2 instructions slower than the C built code :/
I tried to use this code instead of the C function but after that the emu seemed to be stucked

TakaIsSilly thanks again for your help