I'm using a PIC18F46K22 with a hardware multiplier. The manual gives the asm code as:
MOVF ARG1, W ;
MULWF ARG2 ; ARG1 * ARG2 ->
And the result is found in two 8 bit registers PRODH and PRODL
I'm trying to incorporate it into a C function, something like:
/////////////////////////////////////////////////
// Function - Hardware multiplier for 8bit unsigned bytes
unsigned int Multiply_U8(char ARG1,char ARG2){
asm{
MOVF ARG1, W ;
MULWF ARG1 ; ARG1 * ARG2 ->
}
return((PRODH<<8) + PRODL);
}
/////////////////////////////////////////////////
This does not work I am ignorant of the asm/c code interface - any help please?
Regards Bill Legge in australia
Hardware Multiplier
Re: Hardware Multiplier
It seems to me that asm only works on global variables - could be wrong
Here is my attempt at a solution - not fully tested - only in software debug:
No doubt the code could be improved, but it seems to work
Here is my attempt at a solution - not fully tested - only in software debug:
No doubt the code could be improved, but it seems to work
Code: Select all
// PIC18F46K22 on EasyPIC v7 internal oscillator
// not fully tested, but seems to work in simulator debugger
// global variables
unsigned char G_ARG1;
unsigned char G_ARG2;
unsigned int Mul_Result;
/////////////////////////////////////////////////
// Function - Hardware multiplier for 8bit unsigned bytes
unsigned int Multiply_U8(unsigned char ARG1, unsigned char ARG2){
G_ARG1 = ARG1; // asm seems to work only on global variables
G_ARG2 = ARG2;
asm{
MOVF _G_ARG1, W, 0 ; first parameter to W register
MULWF _G_ARG2, 0 ; ARG1 * ARG2
}
return((PRODH << 8) + PRODL);
}
/////////////////////////////////////////////////
void main(){
OSCCON = 0b01000000; // HFINTOSC
C1ON_bit = 0; // Disable comparators
C2ON_bit = 0;
TRISB = 0; // all output
TRISC = 0;
ANSELB = 0; // all digital
ANSELC = 0;
Mul_Result = Multiply_U8(7, 9); // expect 7 * 9 = 63
LATB = Mul_Result; // expect 0x3f
LATC = Mul_Result >> 8; // expect 0
while(1);
}
Start every day with a smile...... (get it over with)
Re: Hardware Multiplier
Hi guys,
Simplest way is to let the compiler show you how to do it . This
corresponds to assembly in list file
Naturally, compiler knows where the function parameters are in memory but the user cannot make assumptions, so direct use of this assembly may not always work (when parameters are in another RAM Bank then the current one - same problem with global variables).
Apart from the fact that the idea of using assembly in simple multiplication routine doesn't seem to be sensible (compiler will always produce as short code and anyway hardware multiplication is so simple that it's best to do it inline, without calling a routine), here's how it can be doneThe internal Rx registers are always placed in Access Bank (no bank switching necessary) and compiler uses them for such tasks. The result is passed in R0 and R1 registers, as the compiler would have done (only using few more instructions being confused by our use of R0).
Simplest way is to let the compiler show you how to do it . This
Code: Select all
unsigned int Multiply_U8(char ARG1,char ARG2){
return ARG1*ARG2;
}
Code: Select all
;test54.c,36 :: unsigned int Multiply_U8(char ARG1,char ARG2){
;test54.c,37 :: return ARG1*ARG2;
0x005A 0x5015 MOVF FARG_Multiply_U8_ARG1, 0
0x005C 0x0216 MULWF FARG_Multiply_U8_ARG2
0x005E 0xF000CFF3 MOVFF PRODL, R0
0x0062 0xF001CFF4 MOVFF PRODH, R1
;test54.c,43 :: }
L_end_Multiply_U8:
0x0066 0x0012 RETURN 0
Apart from the fact that the idea of using assembly in simple multiplication routine doesn't seem to be sensible (compiler will always produce as short code and anyway hardware multiplication is so simple that it's best to do it inline, without calling a routine), here's how it can be done
Code: Select all
unsigned int Multiply_U8(char ARG1,char ARG2){
R0=Arg2;
WREG=Arg1;
asm{
MULWF R0
MOVFF PRODL,R0
MOVFF PRODH,R1
}
}
Re: Hardware Multiplier
Nice one janni
Good to see that you are expert in C now.
Your contributions to BASIC and PASCAL are legendary here. Now I can benefit from your new talents with C.
Many thanks
Good to see that you are expert in C now.
Your contributions to BASIC and PASCAL are legendary here. Now I can benefit from your new talents with C.
Many thanks
Start every day with a smile...... (get it over with)
Re: Hardware Multiplier
You're welcome .
BTW, almost 1/3 of my posts are on mC forums, but it always feels nice to be noticed .
BTW, almost 1/3 of my posts are on mC forums, but it always feels nice to be noticed .
-
- Posts: 235
- Joined: 28 Oct 2007 03:16
- Location: West Australia
Re: Hardware Multiplier
Wow! Thank you both very much.
I'll work on the concept and try to write some demo code based on your advice.
I did not realize that the multiply command '*' used the hardware module.
Regards Bill Legge in Australia
I'll work on the concept and try to write some demo code based on your advice.
I did not realize that the multiply command '*' used the hardware module.
Regards Bill Legge in Australia
-
- Posts: 235
- Joined: 28 Oct 2007 03:16
- Location: West Australia
Re: Hardware Multiplier
Janni - your code works just fine.
And the compiler uses the hardware multiplier as you said.
But I am confused about the asm code.
According to the PIC18F46K22 manual - Instruction Set summary, the operation MULWF:
MULWF Multiply W with f
Syntax: MULWF f {,a}
Operands: 0 f 255
a [0,1]
Operation: (W) x (f) PRODH:PRODL
Automatically stores the result in PRODH and PRODL - so why are the last two lines of your code necessary?
MOVFF PRODL,R0
MOVFF PRODH,R1
(They are! - without them the routine does not work!)
But Why?
Regards Bill Legge
And the compiler uses the hardware multiplier as you said.
But I am confused about the asm code.
According to the PIC18F46K22 manual - Instruction Set summary, the operation MULWF:
MULWF Multiply W with f
Syntax: MULWF f {,a}
Operands: 0 f 255
a [0,1]
Operation: (W) x (f) PRODH:PRODL
Automatically stores the result in PRODH and PRODL - so why are the last two lines of your code necessary?
MOVFF PRODL,R0
MOVFF PRODH,R1
(They are! - without them the routine does not work!)
But Why?
Regards Bill Legge
Re: Hardware Multiplier
Hi Bill,
I mentioned it in my post - these registers are used by compiler to pass function result. Calling code has no information what the function does inside, but reads result from Rx registers, in this case two of them as the result is of type unsigned int.
Here's how calling a function works:
- compiler forms new variables and stores there function parameters
- function is called, executes its code and places result in Rx registers
- calling code uses the result directly or copies it to assigned variable
Obviously, with inline multiplication the whole hassle is avoided.
I mentioned it in my post - these registers are used by compiler to pass function result. Calling code has no information what the function does inside, but reads result from Rx registers, in this case two of them as the result is of type unsigned int.
Here's how calling a function works:
- compiler forms new variables and stores there function parameters
- function is called, executes its code and places result in Rx registers
- calling code uses the result directly or copies it to assigned variable
Obviously, with inline multiplication the whole hassle is avoided.