Autor Tema: Multiplicación 8bit x 8bit para conseguir 16bit en C18  (Leído 4686 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado Picuino

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 5883
    • Picuino
Multiplicación 8bit x 8bit para conseguir 16bit en C18
« en: 23 de Junio de 2012, 06:18:14 »
He buscado en la documentación de microchip para el compilador C18 y en la web y no encuentro la manera de multiplicar dos bytes para conseguir un entero.

Si multiplico dos unsigned char me da como resultado otro unsigned char dentro de una variable entera (no es correcto)

Si hago un cast al primer unsigned char, la multiplicación se convierte en 16bit x 16bit y tarda demasiado.



¿Cómo puede funcionar bien esto?:

Código: [Seleccionar]
   unsigned char a, b;
   unsigned char mul;

   a = 130;
   b = 72;
   mul = a * b;

Este último código me sale mul = 0x0090 y debería ser mul = 0x2490


Saludos.

Desconectado Picuino

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 5883
    • Picuino
Re: Multiplicación 8bit x 8bit para conseguir 16bit en C18
« Respuesta #1 en: 23 de Junio de 2012, 06:30:46 »
Solucionado de una forma un poco complicada:


Código: [Seleccionar]
   unsigned char a, b;

   union {
      unsigned int word;
      struct {
          unsigned char lob;
          unsigned char hib;
      };
   } mul;


   a = 130;
   b = 72;
   mul.lob = a * b;
   mul.hib = PRODH;


No hay como publicar una duda para encontrar la solución. Dejo de todas formas mi monólogo por si a alguien más le sirve.
Saludos.

Desconectado MGLSOFT

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 7912
Re: Multiplicación 8bit x 8bit para conseguir 16bit en C18
« Respuesta #2 en: 23 de Junio de 2012, 08:19:00 »
La linea PIC18 no tiene multiplicador de 8x8 en hardware ??
Todos los dias aprendo algo nuevo, el ultimo día de mi vida aprenderé a morir....
Mi Abuelo.

Desconectado Zardoz

  • PIC10
  • *
  • Mensajes: 18
    • ZardoZ the Technomage
Re: Multiplicación 8bit x 8bit para conseguir 16bit en C18
« Respuesta #3 en: 23 de Junio de 2012, 10:41:29 »
Y digo yo si esto no seria mejor ?

Código: [Seleccionar]
unsigned char a, b;
unsigned int mul;

   a = 130;
   b = 72;
   mul = (unsigned int)a * b;

Por que por mucha multiplicación de dos bytes que hagas, si el destino también es de un byte, es imposible que te meta 16 bits en 8 bits.

Desconectado MerLiNz

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 2463
Re: Multiplicación 8bit x 8bit para conseguir 16bit en C18
« Respuesta #4 en: 23 de Junio de 2012, 10:43:45 »
es tal como te dice zardos, hay que tener bastante en cuenta ponerle el (unsigned int) delante para decirle que usaras 16bits

Desconectado Suky

  • Moderador Local
  • DsPIC33
  • *****
  • Mensajes: 6758
Re: Multiplicación 8bit x 8bit para conseguir 16bit en C18
« Respuesta #5 en: 23 de Junio de 2012, 11:49:56 »
es tal como te dice zardos, hay que tener bastante en cuenta ponerle el (unsigned int) delante para decirle que usaras 16bits

Si hago un cast al primer unsigned char, la multiplicación se convierte en 16bit x 16bit y tarda demasiado.

 :roll:

En C me parece que no queda otra que meter asm para hacerlo por hardware y leer los registros o como lo has realizado


Saludos!
No contesto mensajes privados, las consultas en el foro

Desconectado MerLiNz

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 2463
Re: Multiplicación 8bit x 8bit para conseguir 16bit en C18
« Respuesta #6 en: 23 de Junio de 2012, 13:00:13 »
asi me sale a mi:


56:                    lol=(unsigned int)(unsigned char)a*(unsigned char)0x10;
0D66  0100     MOVLB 0x0
0D68  5100     MOVF dat, W, BANKED
0D6A  0D10     MULLW 0x10
0D6C  CFF3     MOVFF PRODL, lol
0D6E  F0C2     NOP
0D70  CFF4     MOVFF PRODH, 0xC3
0D72  F0C3     NOP

Desconectado Suky

  • Moderador Local
  • DsPIC33
  • *****
  • Mensajes: 6758
Re: Multiplicación 8bit x 8bit para conseguir 16bit en C18
« Respuesta #7 en: 23 de Junio de 2012, 14:08:35 »
Buenísimo! Hace falta uso extensivo del cast  :mrgreen:
No contesto mensajes privados, las consultas en el foro

Desconectado MerLiNz

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 2463
Re: Multiplicación 8bit x 8bit para conseguir 16bit en C18
« Respuesta #8 en: 23 de Junio de 2012, 14:13:09 »
si, no veas si a veces le he dado vueltas a las conversiones, a veces en una linea uso mas casts que variables  :D todo por ahorrar algunos tcy. Solo que en dspic es mucho mejor, se acabo lo de trabajar con variables de 8bits, ni preocuparme por las TCY de una multiplicacion = 1TCY, solo me preocupan las divisiones

Desconectado Picuino

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 5883
    • Picuino
Re: Multiplicación 8bit x 8bit para conseguir 16bit en C18
« Respuesta #9 en: 23 de Junio de 2012, 15:31:28 »
¿Compilas con C18, MerLiNz?
Yo tengo la versión: MPLAB C18 v3.40 (feature limited) y opciones estandar

Cuando intento multiplicar con cast a 16 bit me compila esto:

Código: [Seleccionar]
178:                        mul.word = (unsigned int)(unsigned char)v_in * (unsigned char)s;
  0110    51E4     MOVF 0xe4, W, BANKED
  0112    6E16     MOVWF 0x16, ACCESS
  0114    6A17     CLRF 0x17, ACCESS
  0116    51E6     MOVF 0xe6, W, BANKED
  0118    6E14     MOVWF 0x14, ACCESS
  011A    6A15     CLRF 0x15, ACCESS
  011C    C0E6     MOVFF 0xe6, 0x8
  011E    F008     NOP
  0120    C015     MOVFF 0x15, 0x9
  0122    F009     NOP
  0124    C0E4     MOVFF 0xe4, 0xd
  0126    F00D     NOP
  0128    C017     MOVFF 0x17, 0xe
  012A    F00E     NOP
  012C    ECFE     CALL 0x3fc, 0
  012E    F001     NOP
  0130    C006     MOVFF 0x6, 0xef
  0132    F0EF     NOP
  0134    C007     MOVFF 0x7, 0xf0
  0136    F0F0     NOP
:shock:   21 ciclos de instrucción, sin contar con el CALL que no se dónde salta

Creo que hace un cast a 16 bits antes de multiplicar y deja los argumentos en la pila para luego saltar a una rutina de multiplicación de 16 bits.


Utilizando las dos líneas que comentaba antes me sale esto otro:

Código: [Seleccionar]
178:                        mul.lob = v_in * s;
  0110    51E6     MOVF 0xe6, W, BANKED
  0112    03E4     MULWF 0xe4, BANKED
  0114    CFF3     MOVFF 0xff3, 0xef
  0116    F0EF     NOP
179:                        mul.hib = PRODH;
  0118    CFF4     MOVFF 0xff4, 0xf0
  011A    F0F0     NOP
6 ciclos de instrucción.




En ambos casos las variables son estáticas para dar mayor rapidez:

Código: [Seleccionar]
 
   static unsigned char  s, v_in;
   static long seno_sum, coseno_sum;
   static union {
      unsigned int word;
      struct {
          unsigned char lob;
          unsigned char hib;
      };
   } mul;

Saludos.

Desconectado MerLiNz

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 2463
Re: Multiplicación 8bit x 8bit para conseguir 16bit en C18
« Respuesta #10 en: 23 de Junio de 2012, 17:54:32 »
si, con C18 full con la optimizacion al maximo, kizas es por eso, o porque las variables cambien, pero vamos que si te va bien tal y como lo haces pues ya esta, no le des mas vueltas.

Desconectado Tisco

  • PIC16
  • ***
  • Mensajes: 108
Re: Multiplicación 8bit x 8bit para conseguir 16bit en C18
« Respuesta #11 en: 23 de Junio de 2012, 18:04:52 »
asi me sale a mi:


56:                    lol=(unsigned int)(unsigned char)a*(unsigned char)0x10;
0D66  0100     MOVLB 0x0
0D68  5100     MOVF dat, W, BANKED
0D6A  0D10     MULLW 0x10
0D6C  CFF3     MOVFF PRODL, lol
0D6E  F0C2     NOP
0D70  CFF4     MOVFF PRODH, 0xC3
0D72  F0C3     NOP


A mí también me compila de esta forma poniendo
Código: [Seleccionar]
mul=(unsigned int)(unsigned char)a*(unsigned char)0x10;
mul=(unsigned int)a*0x10;
Pero si en vez de poner el segundo parámetro como un literal lo pongo como una variable
Código: [Seleccionar]
mul=(unsigned int)(unsigned char)a*(unsigned char)b;
mul=(unsigned int)a*b;
me compila como comenta Picuino, no haciendo uso del multiplicador hardware.

Nunca me había fijado en este detalle, pero me parece un fallo bastante tonto del compilador...

Desconectado Picuino

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 5883
    • Picuino
Re: Multiplicación 8bit x 8bit para conseguir 16bit en C18
« Respuesta #12 en: 24 de Junio de 2012, 03:16:53 »
Estoy utilizando la multiplicación hardware para hacer un amplificador de tipo Lock-in.

Basicamente es un sintonizador muy preciso que sólo amplifica una frecuencia determinada y no amplifica las demás frecuencias (generalmente ruido)

Si alguien quiere aportar este es el hilo:

http://www.todopic.com.ar/foros/index.php?topic=38565.0



Saludos

Desconectado Zardoz

  • PIC10
  • *
  • Mensajes: 18
    • ZardoZ the Technomage
Re: Multiplicación 8bit x 8bit para conseguir 16bit en C18
« Respuesta #13 en: 24 de Junio de 2012, 09:02:07 »
Tambien hay que tener en cuenta esto que esta en el manual:

Citar
Integer Promotions
ISO mandates that all arithmetic be performed at int precision or greater. By default, MPLAB C18 will perform arithmetic at the size of the largest operand, even if both operands are smaller than an int. The ISO mandated behavior can be instated via the -Oi command-line option.

For example:

unsigned char a, b;
unsigned i;
a = b = 0x80;
i = a + b; /* ISO requires that i == 0x100, but in C18 i == 0 */
Note that this divergence also applies to constant literals. The chosen type for constant literals is the first one from the appropriate group that can represent the value of the constant without overflow.

For example:

#define A 0x10 /* A will be considered a char unless -Oi
                  specified */
#define B 0x10 /* B will be considered a char unless -Oi
                  specified */
#define C (A) * (B)
unsigned i;
i = C; /* ISO requires that i == 0x100, but in C18 i == 0 */


Desconectado Picuino

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 5883
    • Picuino
Re: Multiplicación 8bit x 8bit para conseguir 16bit en C18
« Respuesta #14 en: 24 de Junio de 2012, 09:32:55 »
Código: [Seleccionar]
unsigned char a, b;
unsigned i;
a = b = 0x80;
i = a + b; /* ISO requires that i == 0x100, but in C18 i == 0 */

Si lo saben y lo mantienen, ellos sabrán porqué.
En el caso de la multiplicación, está claro que el asm devuelve 16bit cuando se realiza 8bit x 8bit.
Perder a propósito esa precisión es una tontería.

Código: [Seleccionar]
178:                  mul = a * b;
  0110    51E6     MOVF 0xe6, W, BANKED
  0112    03E4     MULWF 0xe4, BANKED
  0114    CFF3     MOVFF 0xff3, 0xef
  0116    F0EF     NOP
Y termina con CLRF a la parte alta de la variable mul.
¿Porqué? si casi cuesta lo mismo cargar PRODH en la parte alta de mul.

Saludos.