Assembly macro with parameters
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 ============================================
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, $rtI 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 intoasm("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
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 ============================================
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
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 ============================================
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){ \
intopcode_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
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){ \
intopcode_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
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 ============================================
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)) #definemyopcode(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 areg2var(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
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
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 ============================================