Skip to contentSkip to conversation

Assembly macro with parameters

DISCUSSION Fabrizio Fazzino 6 participants 11 messages Apr 7, 2005 – Jul 9, 2005 MIPS

lore
Share & tools
lore
#0 lore raw

Hi all,
I'm working to an hardware extension of the MIPS32 instruction set and I need to convert my new instruction into an existing opcode to make it possible for the normal GCC to correctly compile the code.

Just to be clear, to obtain my new FZMIN instruction like

	FZMIN $rd, $rs, $rt

I have to convert it into

	LWC1 $rt, rd<<11 ($rs)

that is an existing (in some cases unused) opcode.

I'm currently using hardcoded values for the parameters, so fzmin(10,8,9) will be transformed into

	asm("lwc1 $9, 10<<11($8)" : : : "$10");

It works, but I need a way to set the values of the parameters at runtime; so I've tried the following macro:

	#define fzmin(rd, rs, rt) asm("lwc1 $rt, rd<<11($rs)");

As you can imagine I'm not an expert of MIPS Assembly macros:
what I've written does NOT work since the values of rd,rs,rt are NOT substituted inside the asm string.

Is there any way to do what I need? I would appreciate your help very much.

Cheers,
Fabrizio

Signature · 4 lines
============================================
   Fabrizio Fazzino - [email protected]
     Fazzino.IT - http://www.fazzino.it
============================================
#1 lore raw
Quoted 15 lines · Fabrizio Fazzino

Hi all,
I'm working to an hardware extension of the MIPS32 instruction set and I need to convert my new instruction into an existing opcode to make it possible for the normal GCC to correctly compile the code.

Just to be clear, to obtain my new FZMIN instruction like

	FZMIN $rd, $rs, $rt

I have to convert it into

	LWC1 $rt, rd<<11 ($rs)

that is an existing (in some cases unused) opcode.

Quoted 8 lines

I'm currently using hardcoded values for the parameters, so fzmin(10,8,9) will be transformed into

	asm("lwc1 $9, 10<<11($8)" : : : "$10");

It works, but I need a way to set the values of the parameters at runtime; so I've tried the following macro:

	#define fzmin(rd, rs, rt) asm("lwc1 $rt, rd<<11($rs)");

Which will leave the assembler entirely unimpressed ;-)

Quoted 6 lines

As you can imagine I'm not an expert of MIPS Assembly macros:
what I've written does NOT work since the values of rd,rs,rt are NOT substituted inside the asm string.

Is there any way to do what I need? I would appreciate your help very much.

Unless you only have a few instructions and are going for a quick hack I really suggest to add proper support for these instructions to binutils. Having working support in as, gdb, objdump will make your life so much easier.

Ralf

#2 lore raw
Quoted 8 lines · Ralf Baechle
Quoted 4 lines · Fabrizio Fazzino

It works, but I need a way to set the values of the parameters at runtime; so I've tried the following macro:

	#define fzmin(rd, rs, rt) asm("lwc1 $rt, rd<<11($rs)");

Which will leave the assembler entirely unimpressed ;-)

I thought that the compiler was able to substitute also the values inside strings... Is there any way to force it to do so?

Quoted 4 lines

Unless you only have a few instructions and are going for a quick hack I really suggest to add proper support for these instructions to binutils. Having working support in as, gdb, objdump will make your life so much easier.

The processor I'm designing probably will not be implemented in any way (we just have to simulate the VHDL hardware description), so we just need a quick-and-dirty way to make the opcode conversion.

Fabrizio

Signature · 4 lines
============================================
   Fabrizio Fazzino - [email protected]
     Fazzino.IT - http://www.fazzino.it
============================================
#3 lore raw
Quoted 18 lines · Fabrizio Fazzino
Quoted 8 lines · Ralf Baechle
Quoted 4 lines · Fabrizio Fazzino

It works, but I need a way to set the values of the parameters at runtime; so I've tried the following macro:

	#define fzmin(rd, rs, rt) asm("lwc1 $rt, rd<<11($rs)");

Which will leave the assembler entirely unimpressed ;-)

I thought that the compiler was able to substitute also the values inside strings... Is there any way to force it to do so?

Quoted 4 lines

Unless you only have a few instructions and are going for a quick hack I really suggest to add proper support for these instructions to binutils. Having working support in as, gdb, objdump will make your life so much easier.

Quoted 4 lines

The processor I'm designing probably will not be implemented in any way (we just have to simulate the VHDL hardware description), so we just need a quick-and-dirty way to make the opcode conversion.

You should probably be using .word then, and generating the instruction completely by hand.

Signature · 2 lines
Daniel Jacobowitz
CodeSourcery, LLC
#4 lore raw

After three months I still have the same problem...

Suppose I want to generate my own opcode, let's say 0xC4000000, inside a C program. Suppose this value is NOT a constant in the macro I want to write since it will contain three variable fields for the rd,rs,rt registers, so I need to calculate the opcode at least at compilation time (at runtime is NOT required).

Daniel suggested using .word and writing the function by hand, but which is the syntax I have to use?

#define myopcode(rs,rt,rd) { \
int opcode_number = 0xC4000000 | (rs<<21) | (rt<<16) | (rd<<11); \
char opcode_string[20]; \
sprintf(opcode_string, ".word 0x%X", opcode_number); \
asm(opcode_string); \
}

This doesn't work since "argument of 'asm' is not a constant string"... Furthermore I do NOT have the possibility to link the string library so I should find another solution.

Is there any common solution to write an instruction "completely by hand" ?

Many thanks in advance,

Fabrizio Fazzino

Quoted 19 lines · Daniel Jacobowitz
Quoted 7 lines · Fabrizio Fazzino
Quoted 5 lines · Ralf Baechle
Quoted 3 lines · Fabrizio Fazzino

It works, but I need a way to set the values of the parameters at runtime; so I've tried the following macro:

Quoted 6 lines
Quoted 3 lines
Quoted 1 line
	#define fzmin(rd, rs, rt) asm("lwc1 $rt, rd<<11($rs)");

Which will leave the assembler entirely unimpressed ;-)

I thought that the compiler was able to substitute also the values inside strings... Is there any way to force it to do so?

You should probably be using .word then, and generating the instruction completely by hand.

Signature · 4 lines
============================================
   Fabrizio Fazzino - [email protected]
     Fazzino.IT - http://www.fazzino.it
============================================
#5 lore raw
Quoted 12 lines · Fabrizio Fazzino

After three months I still have the same problem...

Suppose I want to generate my own opcode, let's say 0xC4000000, inside a C program. Suppose this value is NOT a constant in the macro I want to write since it will contain three variable fields for the rd,rs,rt registers, so I need to calculate the opcode at least at compilation time (at runtime is NOT required).

Daniel suggested using .word and writing the function by hand, but which is the syntax I have to use?

Quoted 7 lines

#define myopcode(rs,rt,rd) { \
int opcode_number = 0xC4000000 | (rs<<21) | (rt<<16) | (rd<<11); \
char opcode_string[20]; \
sprintf(opcode_string, ".word 0x%X", opcode_number); \
asm(opcode_string); \
}

The arguments to the asm() statement are strings not char*. They are evaluated at compile time not run time.

You will probably have to use the C preprocessor stringification and concatination operators ('#' and '##').

David Daney

#6 lore raw
In reply to Fabrizio Fazzino
Quoted 9 lines · Fabrizio Fazzino

Daniel suggested using .word and writing the function by hand, but which is the syntax I have to use?

#define myopcode(rs,rt,rd) { \
int opcode_number = 0xC4000000 | (rs<<21) | (rt<<16) | (rd<<11); \
char opcode_string[20]; \
sprintf(opcode_string, ".word 0x%X", opcode_number); \
asm(opcode_string); \
}

This is untested, but it should be a reasonable starting point:

#define myopcode(rs,rt,rd) do { \
	int opcode_number = 0xC4000000 | (rs<<21) | (rt<<16) | (rd<<11); \
	asm(".word %0" : : "i" (opcode_number)); \
} while (0)

But you may want to add code to tell GCC that these registers are used and how, because otherwise you may have little use of your macro. You'll probably have to investigate the explicit register variable GCC feature and cpp stringification. It should be straightforward though rather boring, so I'm leaving it as an exercise.

Maciej

#7 lore raw

Many thanks Maciej and David,
during these days I've learned a lot about stringification, a feature that I had never used before.

In any case I didn't have to use this feature... I was just missing the fact that the opcode evaluation didn't have to happen by declaring an int variable (in this case the value is computed at runtime) but by the preprocessor, so I solved my problem this way:

#define NEWOPCODE(base,rd,rs,rt) (base|(rs<<21)|(rt<<16)|(rd<<11)) #define myopcode(rd,rs,rt) asm(".long %0" : : "i" (NEWOPCODE(0xC4000000,rd,rs,rt)))

and then I call it simply as myopcode(10,8,9).

By the way, is there any quick way of writing a setreg(reg_num,reg_val) C macro to set the value of a register?
And another one to read the value like a reg2var(reg_num,&result) to put the value of a register inside my own C variable?
I have written my own versions for both but they have a 32-case switch statement inside so they are not so efficient...

In any case thanks a lot for your suggestions, I've put acknowledgments to [email protected] inside my code!

Fabrizio

Quoted 7 lines · David Daney

The arguments to the asm() statement are strings not char*. They are evaluated at compile time not run time.

You will probably have to use the C preprocessor stringification and concatination operators ('#' and '##').

David Daney

Quoted 12 lines · Maciej W. Rozycki

This is untested, but it should be a reasonable starting point:

#define myopcode(rs,rt,rd) do { \
	int opcode_number = 0xC4000000 | (rs<<21) | (rt<<16) | (rd<<11); \
	asm(".word %0" : : "i" (opcode_number)); \
} while (0)

But you may want to add code to tell GCC that these registers are used and how, because otherwise you may have little use of your macro. You'll probably have to investigate the explicit register variable GCC feature and cpp stringification. It should be straightforward though rather boring, so I'm leaving it as an exercise.

Maciej

Signature · 4 lines
============================================
   Fabrizio Fazzino - [email protected]
     Fazzino.IT - http://www.fazzino.it
============================================
#8 lore raw
Quoted 9 lines · Fabrizio Fazzino

In any case I didn't have to use this feature... I was just missing the fact that the opcode evaluation didn't have to happen by declaring an int variable (in this case the value is computed at runtime) but by the preprocessor, so I solved my problem this way:

#define NEWOPCODE(base,rd,rs,rt) (base|(rs<<21)|(rt<<16)|(rd<<11)) #define myopcode(rd,rs,rt) asm(".long %0" : : "i" (NEWOPCODE(0xC4000000,rd,rs,rt)))

Quoted 8 lines

and then I call it simply as myopcode(10,8,9).

By the way, is there any quick way of writing a setreg(reg_num,reg_val) C macro to set the value of a register?
And another one to read the value like a reg2var(reg_num,&result) to put the value of a register inside my own C variable?
I have written my own versions for both but they have a 32-case switch statement inside so they are not so efficient...

As long as all arguments are constant and thus known at compile time. the compiler will optimize away the switch completely (cfr. all those {put,get}_user() routines).

Gr{oetje,eeting}s,

Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- [email protected]

In personal conversations with technical people, I call myself a hacker. But when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds

#9 lore raw
In reply to Fabrizio Fazzino
Quoted 2 lines · Fabrizio Fazzino

By the way, is there any quick way of writing a setreg(reg_num,reg_val) C macro to set the value of a register?

It would make no sense as GCC would still be free to use this register
for something else, therefore either destroying your "explicitly" assigned data or getting data already there destroyed. You are really after asm constraints and explicit register variables as outlined in my previous response. See GCC documentation for how to make use of these.

BTW, how about adding support for opcodes you are interested in to
binutils instead? It would make interfacing them to GCC much easier.

Maciej

#10 lore raw
Quoted 4 lines · Maciej W. Rozycki
Quoted 2 lines · Fabrizio Fazzino

By the way, is there any quick way of writing a setreg(reg_num,reg_val) C macro to set the value of a register?

Hi guys,
just to let you know that I solved my problem this way:

// Set a register to the desired value
#define setreg(regnum,value) asm("move $" #regnum ", %0" : : "r"(value) : "$" #regnum)

// Move the content of a register to the desired variable
#define reg2var(regnum,var) asm("sw $" #regnum ", %0" : "=m"(*var) : : "memory")

Quoted 2 lines

BTW, how about adding support for opcodes you are interested in to
binutils instead? It would make interfacing them to GCC much easier.

The CPU I'm working on will never "exist"... I'm just simulating it as VHDL code, so I just needed a quick-and-dirty way of generating inside my very short test programs the new opcodes added as an extension.

Thanks to all for your precious support!

Cheers and regards,

Fabrizio

Signature · 4 lines
============================================
   Fabrizio Fazzino - [email protected]
     Fazzino.IT - http://www.fazzino.it
============================================