Divide un número de 32 bits por 16 bits en un dsPIC

0

Estoy trabajando con un dsPIC33EP64GS506 , y aquí puede encontrar su hoja de datos: link .

En la hoja de datos dsPIC (página 294) dice que admite 4 instrucciones de división:

DIV.S    Wm,Wn    Signed 16/16-bit integer divide
DIV.SD   Wm,Wn    Signed 32/16-bit integer divide
DIV.U    Wm,Wn    Unsigned 16/16-bit integer divide
DIV.UD   Wm,Wn    Unsigned 32/16-bit integer divide

Ahora, cuando trato de dividir dos variables en C, una variable de 32 bits por una variable de 16 bits, el compilador por alguna razón decide no usar estas instrucciones, pero la función ___divsi3 en su lugar, que es una implementación de software del algoritmo de división. Yo uso la versión gratuita del compilador xc16 de Microchip. Tome este código C simple, por ejemplo:

volatile int32_t num = 65537;
volatile int16_t den = 16384;
volatile int16_t res = num/den;

compila al siguiente código de ensamblaje:

MOV [W15-22], W0
MOV [W15-20], W1
MOV [W15-18], W2
ASR W2, #15, W3
RCALL ___divsi3
MOV W0, [W15-16]

¿Cómo puedo convencer a un compilador para que use la instrucción DIV.SD para dividir estas dos variables?

    
pregunta Marko Gulin

1 respuesta

2

Logré encontrar una solución. Aparentemente, hay una docena de funciones __bultin usadas para forzar al compilador ( xc16 ) a usar instrucciones específicas de ensamblaje o series de instrucciones. Por ejemplo, para obligar al compilador a usar instrucciones específicas DIV , se puede usar una de las siguientes funciones __builtin :

signed int __builtin_divf(signed int num, signed int den);
signed int __builtin_divmodsd(signed long dividend, signed int divisor, signed int *remainder);
unsigned int __builtin_divmodud(unsigned long dividend, unsigned int divisor, unsigned int *remainder);
int __builtin_divsd(const long num, const int den);
unsigned int __builtin_divud(const unsigned long num, const unsigned int den);

Sin embargo, uno debe estar seguro de que el resultado (es decir, el cociente) se ajusta a un registro de 16 bits, de lo contrario, los resultados son inesperados. Todas estas funciones builtin_div se ejecutan dentro de 18 ciclos de reloj, mientras que la función ___divsi3 que el compilador normalmente usa para la división de 32/16 bits lleva hasta 500 ciclos de reloj.

Para volver a mi ejemplo desde el principio, el código C tendría el siguiente aspecto:

volatile int32_t num = 65537;
volatile int16_t den = 16384;
volatile int16_t res = __builtin_divsd(num, den);

El compilador produce el siguiente código de ensamblaje:

MOV [W15-16], W0
MOV [W15-20], W1
MOV [W15-18], W2
REPEAT #0x11
DIV.SD W4, W2
MOV W0, [W15-14]

Caso cerrado.

    
respondido por el Marko Gulin

Lea otras preguntas en las etiquetas