TODOPIC

Microcontroladores PIC => Almacén del Assembler => Mensaje iniciado por: KILLERJC en 09 de Octubre de 2015, 09:28:45

Título: Assembler en ARM - Probando
Publicado por: KILLERJC en 09 de Octubre de 2015, 09:28:45
Moderacion:
       <Tema Separado de Jugando en ASM con XC16 y dsPIC33F (http://www.todopic.com.ar/foros/index.php?topic=45240.0) >

Mensaje Original:

Gracias elgarbe,

La verdad que siempre dicen que Microchip uso el compilador GCC lo trasformo y lo esta cobrando, si uno observa con detenimiento. Es verdad :P, al menos para C, tal ves tiene una que otra diferencia pero hay muchas cosas que aplican por igual.
Hace poco me tienen con lo de PIC18 y me pusieron a hablar del linker/compiladores, asi que ahi aproveche y le di una repasadita a como funciona el MPASM
http://www.todopic.com.ar/foros/index.php?topic=45254.msg376641#msg376641
Y creo que de paso es la primera ves que veo colgado un codigo ASM de PIC el cual esta unido por el linker, juntos con las variables posicionadas por el linker tambien. Mas que nada por eso quise hacerlo xD

Al final yo creo que aca termine, no se que mas agregar, por que lo demas es sobre modulos. Parece que voy a tener que centrarme en ARM nomas,
Título: Re:Assembler en ARM - Probando
Publicado por: elgarbe en 09 de Octubre de 2015, 09:33:14
.... Parece que voy a tener que centrarme en ARM nomas,

pues ahí te espero, estoy avanzando con el cartel LED (http://www.todopic.com.ar/foros/index.php?topic=43643.0 (http://www.todopic.com.ar/foros/index.php?topic=43643.0)) y hay algunas cosas que me gustaría probar en ASM...

saludos
Título: Re:Assembler en ARM - Probando
Publicado por: juaperser1 en 09 de Octubre de 2015, 15:28:21
Citar
La verdad que siempre dicen que Microchip uso el compilador GCC lo trasformo y lo esta cobrando, si uno observa con detenimiento. Es verdad

claro que es verdad, no lo esconden, incluso si le das a MPLAB a las opciones de proyecto puedes tocar las opciones de GCC.

y si no os habéis dado cuenta, a cada versión nueva del compilador free, usa mas recursos, ya lo he puesto en otros post, pero lo recalco:

version free XC32, PIC32MX de 16Kb, un pograma con 8 funciones y unas cuantas variables ya no entra, bien hecho microchip ((:-)) ((:-))

un saludo
Título: Re:Assembler en ARM - Probando
Publicado por: KILLERJC en 10 de Octubre de 2015, 19:01:53
Citar
version free XC32, PIC32MX de 16Kb, un pograma con 8 funciones y unas cuantas variables ya no entra, bien hecho microchip

Casi todo parece un problema de la rutina de inicializacion + vectores de interrupcion (espero que no siga con sus "vectores alternativos" en el PIC32). Sino habria que crear un simple programa y pasarlo por dissasembler.
Lo que noto yo al menos en lo que es ARM es que utiliza las rutinas memset de C, son larguisimas! (al menos GCC). Y tal ves se puede achichar un poco mas.
Título: Re:Assembler en ARM - Probando
Publicado por: juaperser1 en 10 de Octubre de 2015, 19:16:02
Citar
version free XC32, PIC32MX de 16Kb, un pograma con 8 funciones y unas cuantas variables ya no entra, bien hecho microchip

este caso en concreto, es que me toco la moral, por que todavía en el curro y tenia soporte técnico de microchip, (por cierto creo que ahora me odian  :D :D, les he dejado en evidencia en algún seminario con los bug de los MZ y los mcp39f)

total, en este caso un pic32mx210f016b, 16Kb, intente hacer un bootloader por MSD (USB) y el ejemplo de microchip te viene con el linker para este micro+ el ejemplo etc etc. pues con el set de instrucciones reducido a MIP16 y con el compilador PRO de la versión de un mes, solo el bootloader, ocupaba 14,5Kb!!!! tal como venia el ejemplo, solo el bootloader vacio con las librerias del USB y el FAT32, no digas que ese micro puede con un bootloader MSD por que no puede.

me han dado tantos dolores de cabeza los pic32... enserio hoy por hoy en la familia PIC32MX2XX no puedes usar la uart y la flash en el mismo programa por un bug, que no han terminado de arreglar ni en la versión A2 del silicio.

esa fue la gota que me arto de microchip.


Citar
Lo que noto yo al menos en lo que es ARM es que utiliza las rutinas memset de C, son larguisimas!. Y tal ves se puede achichar un poco mas.

esto, no lo sabia, pero vamos, que he trabajado con ST un 103 y alguno mas de M4 (que por cierto tampoco migrare nunca a ST por que tambien me dieron muchos dolores de cabeza), y el ST con 32Kb entraba todo el código y sobraba mucho espacio.

en el pic32MX2xx mas chico nos tuvimos que ir a un 250 con 128Kb de memoria para que entrara, y mucho mas caro encima, el tema era migrarlo a pic por que el de ST daba muchisimos problemas y bug, pero no pudo ser por que el de 128Kb de memoria costaba muchisimo mas que el ST, así que pasamos de usar micros de 32 bit a micros de 8 bit y a trabajar con pic18 y con los compiladores antiguos.

me prometi a mi mismo no hacer ni un solo proyecto mas con pic32 ni con ST  :D :D

Citar
Lo que noto yo al menos en lo que es ARM es que utiliza las rutinas memset de C, son larguisimas!. Y tal ves se puede achichar un poco mas.

lo bueno seria, (cuando hagas el tutorial ejem ejemm... :D :D) escribir las funciones en ASM y el programa principal en C

un saludo
Título: Re:Assembler en ARM - Probando
Publicado por: KILLERJC en 10 de Octubre de 2015, 19:41:37
lo bueno seria, (cuando hagas el tutorial ejem ejemm... :D :D) escribir las funciones en ASM y el programa principal en C

Esa es la parte mas facil :P ,

Código: ASM
  1. .thumb
  2.         .text
  3.         .global _funcion
  4.  
  5. _funcion:
  6.         @aca instrucciones
  7.  
  8.         .end

Y ya tenes un codigo que podes llamar desde C e.e lo unico que falta en C es que lo definas extern con el numero de argumentos que te guste xD

EDIT: Que tipo de funciones les gustaria ver implementado en ASM ? en el Ejemplo me refiero. no me digan Ethernet por que los mando a...
Título: Re:Assembler en ARM - Probando
Publicado por: juaperser1 en 10 de Octubre de 2015, 19:55:59
Citar
Y ya tenes un codigo que podes llamar desde C e.e lo unico que falta en C es que lo definas extern con el numero de argumentos que te guste xD

clarooooo aqui el experto en ASM que facil lo ve todo  :D  :D pero habrá que guardar registros en la pila, recuperarlos, pasar los datos  a la función ASM tambien en la pila, retornar datos etc.

para ti muy fácil, para mi... no  :D :D

he hecho 4 cosas mal contadas en pic16 mezclando c y asm, y  en el procesador motorola 68000 en la uni, que literalmente tiene mas años que yo  :D :D
Título: Re:Assembler en ARM - Probando
Publicado por: elgarbe en 10 de Octubre de 2015, 21:49:22
EDIT: Que tipo de funciones les gustaria ver implementado en ASM ? en el Ejemplo me refiero. no me digan Ethernet por que los mando a...

si queres algo por donde empezar.... pues mirá, estoy armando el esqueleto de lo que será el firm del cartel RGB y hasta ahora he creado este código:

Código: C++
  1. uint8_t i, j;
  2.         uint64_t MC = 0;
  3.         MC |= 0x02 << 00;               // MC = 11.6-8.1 mA
  4.         MC |= 0x7F << 03;               //BC Red = 100%
  5.         MC |= 0x7F << 10;               //BC Green = 100%
  6.         MC |= 0x7F << 17;               //BC Blue = 100%
  7.                                                         //SID = 0; LODVLT=0; LSDVLT=0; PSMODE=0 (no PWS)
  8.         MC |= (uint64_t)0x96 << 40;             //WRITE_CMD: Bits 40 a 47 en 10010110b
  9.         MC |= (uint64_t)0x01 << 48;             //Data Select Bit = 1
  10.  
  11.         for(j=49;j>0;j--)
  12.         {
  13.                 if(MC & ((uint64_t)1<<(j-1)))           //Verifico si el bit es un 0 o un 1
  14.                 {
  15.                         HAL_GPIO_WritePin(SIN_PORT, SIN_PIN, GPIO_PIN_SET);
  16.                         HAL_GPIO_WritePin(SIN_PORT, SIN_PIN, GPIO_PIN_SET);
  17.                 }
  18.                 else
  19.                 {
  20.                         HAL_GPIO_WritePin(SIN_PORT, SIN_PIN, GPIO_PIN_RESET);
  21.                         HAL_GPIO_WritePin(SIN_PORT, SIN_PIN, GPIO_PIN_RESET);
  22.                 }
  23.                 //Pulso de CLK
  24.                 HAL_GPIO_WritePin(SCLK_PORT, SCLK_PIN, GPIO_PIN_SET);
  25.                 HAL_GPIO_WritePin(SCLK_PORT, SCLK_PIN, GPIO_PIN_RESET);
  26.         }
  27.         //una vez enviados los 49 datos hago un latch
  28.         HAL_GPIO_WritePin(LAT_PORT, LAT_PIN, GPIO_PIN_SET);
  29.         HAL_GPIO_WritePin(LAT_PORT, LAT_PIN, GPIO_PIN_RESET);

no sé si se entiende la idea, pero mas o menos es así:
El TLC5954 tiene un registro de desplazamiento de 49 bits. 48 son datos y 1 es para indicar si lo que escribo es dato (on/off de la salida) o comando (configuraciones ).
En este caso estoy configurando el TLC. Una vez que detecto si el bit es 1 o 0 escribo la señal en SIN_PIN. Como vez repito 2 veces la instruccion de escribir, esto es asi porque necesito un pequeño tiempo entre poner la señal en SIN y darle el pulso de clock. Obvio que se podría realizar todo esto mucho mejor, pero son las primeras pruebas básicas como para testear las placas tambien.
Algo interesante sería hacer uso de bit banding para poder obtener mayor frecuencia de salida.
serviría?
el micro en cuestion es un stm32f407 aunque en la placa final habrá un 401 o un 411.

Saludos!
Título: Re:Assembler en ARM - Probando
Publicado por: Carl47D en 10 de Octubre de 2015, 21:50:04
Da lo mismo llamar una función como la esta definiendo el maestro Killer a tener el ASM embebido en la función en c?

Ejemplo:
Código: ASM
  1. static void __INLINE nrf_delay_us(uint32_t volatile number_of_us) __attribute__((always_inline));
  2. static void __INLINE nrf_delay_us(uint32_t volatile number_of_us)
  3. {
  4. register uint32_t delay asm ("r0") = number_of_us;
  5. __ASM volatile (
  6. ".syntax unified\n"
  7.     "1:\n"
  8.     " SUBS %0, %0, #1\n"
  9.     " NOP\n"
  10.     " NOP\n"
  11.     " NOP\n"
  12.     " NOP\n"
  13.     " NOP\n"
  14.     " NOP\n"  
  15.     " NOP\n"  
  16.     " NOP\n"
  17.     " NOP\n"
  18.     " NOP\n"
  19.     " NOP\n"
  20.     " NOP\n"
  21.     " BNE 1b\n"
  22.     ".syntax divided\n"  
  23.     : "+r" (delay));
  24. }

En el caso que no sea lo mismo, como se definiria?
Código: ASM
  1. .thumb
  2.         .text
  3.         .global _nrf_delay_us
  4.  
  5. _nrf_delay_us:
  6.     @ Acá no supe como hacer esto:
  7.     @ register uint32_t delay asm ("r0") = number_of_us;
  8.      SUBS %0, %0, #1
  9.      NOP
  10.      NOP
  11.      NOP
  12.      NOP
  13.      NOP
  14.      NOP  
  15.      NOP  
  16.      NOP
  17.      NOP
  18.      NOP
  19.      NOP
  20.      NOP
  21.      BNE 1b
  22.      .end
Título: Re:Assembler en ARM - Probando
Publicado por: KILLERJC en 11 de Octubre de 2015, 02:19:08
A mi C con ASM inline no me gusta, es preferible realizarlo aparte en un archivo a mi parecer. si queres portarlo a otro micro y queres "probarlo" solo le presentas la version en C y ya esta funcionando. en cambio con inline no y deberias cambiar mas cosas, a no ser que el codigo sea simple... Y por ejemplo solo use Thumb-16

Citar
si queres algo por donde empezar.... pues mirá, estoy armando el esqueleto de lo que será el firm del cartel RGB y hasta ahora he creado este código:

Eso es un SPI, para mi deberias hacerlo por SPI (hasta aprovechar un QSPI o 2), tu "latch" seria el CS, seguro que podes mantener el CS hasta el ultimo dato enviado. Es decir enviar multiple bytes y luego recien ahi que se levante el CS. Y por hardware. Pero voy a intentar hacerlo. Indicame el micro que estas trabajando por que seguro que tengo que buscar los registros y esas cosas. Ya que por ejemplo vi que algunos poseen un registro especial para poner una salida a 1, mientras que otros usan la misma direccion para el encode.

PD: Estuve viendo y es un dolor de cabeza GCC sin optimizaciones :P
Y me esta siendo un dolor de cabeza acostumbrarme a ese ASM :P

Una cosa mas. Al comienzo es ponerle una constante, o tenes pensado hacer una funcion? si es asi pone como es la funcion. Ya que veo que estas enviando Rojo,Verde y Azul al 100%, todo terminaria en una constante e.e

MCH = 0x0000.0148
MCL = 0000 0bbb bbbb bggg gggg grrr rrrr r010

Estoy en lo correcto? Y b/r/g van a cambiar ? Y van a ser pasados por alguna funcion?
Que micro estamos hablando? Cortex-M3 ? M0+ ?
Da lo mismo llamar una función como la esta definiendo el maestro Killer a tener el ASM embebido en la función en c?
En el caso que no sea lo mismo, como se definiria?

En tu caso creaste una funcion, lo cual seria lo correcto. Pero no un Inline "bruto", en medio de la funcion, nuevamente prefiero tener separado lo que es ASM y C, no me gustaria que esten juntos.
Creo, realmente CREO, por que no estoy seguro, que esta es la funcion en puro Assembler

Código: ASM
  1. .syntax unified    @Permite el uso de Thumb y Thumb2
  2.         .thumb          @ Thumb
  3.         .text           @ Codigo
  4.         .global _nrf_delay_us
  5.  
  6. _nrf_delay_us:
  7.     @ Primer valor pasado por la funcion esta en R0
  8.      SUBS r0, #1   @ R0 = R0-1, Actualizo las flag SUB{S} , Si es 0 es lo mismo que esperar 2^32
  9.      NOP                 @ Thumb instruccion, por ser un inmmediato de 3 bits tiene un encode de 16bits
  10.      NOP
  11.      NOP
  12.      NOP
  13.      NOP
  14.      NOP  
  15.      NOP  
  16.      NOP
  17.      NOP
  18.      NOP
  19.      NOP
  20.      NOP
  21.      BNE.N   _nrf_delay_us      @ forzado 16bits, Salta si Z=0
  22.      BX LR                     @ Return , PC <- LR
  23.      .end

Si tenes para probarlo genial :P, asi vemos si funciona o no xD, en C solo quedaria como:

Código: C++
  1. extern void nrf_delay_us(uint32_t number_of_us);

El codigo creo que funciona. Al menos procedi a ensamblarlo y hice un dump del object, el cual me dio el codigo correctamente como lo puse.
Título: Re:Assembler en ARM - Probando
Publicado por: KILLERJC en 11 de Octubre de 2015, 05:13:17
Dividi el tema asi otra persona puede moverlo a ARM y seguimos alla, o quieren que sigamos aca y luego se mueva para alla, a mi me da lo mismo.
Y tambien lo dividi para no mezclar ARM con dsPIC

Ya con esto estan libres de hablar de ARM lo mas que quieran xD

Respuesta del disassembler:

Código: [Seleccionar]
test.o:     file format elf32-littlearm


Disassembly of section .text:

00000000 <_nrf_delay_us>:
   0: 3801      subs r0, #1
   2: 46c0      nop ; (mov r8, r8)
   4: 46c0      nop ; (mov r8, r8)
   6: 46c0      nop ; (mov r8, r8)
   8: 46c0      nop ; (mov r8, r8)
   a: 46c0      nop ; (mov r8, r8)
   c: 46c0      nop ; (mov r8, r8)
   e: 46c0      nop ; (mov r8, r8)
  10: 46c0      nop ; (mov r8, r8)
  12: 46c0      nop ; (mov r8, r8)
  14: 46c0      nop ; (mov r8, r8)
  16: 46c0      nop ; (mov r8, r8)
  18: 46c0      nop ; (mov r8, r8)
  1a: d1fe      bne.n 0 <_nrf_delay_us>
  1c: 4770      bx lr

Todas instrucciones de 16 bits
Saben que es lo peor?, una resta con un inmmediato puede tener hasta 4 opcode distinto... hay 2 de 16bits y 2 de 32 bits, ambos distintos. ... ...
Título: Re:Assembler en ARM - Probando
Publicado por: juaperser1 en 11 de Octubre de 2015, 08:45:36
yo, quiero empezar por el principio killerjc, pero despacito por que no tengo hardware para probarlo por ahora, me ocupare de eso cuando termine el tutorial de KiCad.

me gustaría que colgaras el manual del manejo del nucleo ARM.

¿sus registros son de 32 bits no?

pues quiero hacer una pregunta quizá un poco tonta:

vamos a suponer que llamamos a una función desde c que va a ser esta:

float suma (unsignen int numero1, float numero2, unsingned char numero3);

y que en ensamblador se sumen y se devuelva.

me gustaría ver, como se va llenando la pila a ser posible de manera visual, donde van quedando los datos (con celdas de excel o librecal por ejemplo)

así mas o menos si puede ser:

(https://dl.dropbox.com/s/9vkx1inymlyx55y/ensamblador.png)

y como son los pasos que va siguiendo el hardware para hacer la operación (a que soy un tocapelxtas  :D :D)

ademas de los pasos en ensamblador claro  :mrgreen: :mrgreen:

y tambien me gustaria un ejemplo de ethernet  :D :D :D

un saludo
Título: Re:Assembler en ARM - Probando
Publicado por: KILLERJC en 11 de Octubre de 2015, 08:59:44
Para eso deberia simularlo paso a paso, y es el gran problema de esto. Sino debo debuggearlo si o si. cago el micro :P.

Respecto a ARM es un dolor de cabeza todo xD. Y tenes poquitos (sarcasmo) registros. Que ademas te separa en Aplicacion, sistema y tal ves otra cosa mas. Por que viene de los otro procesadores.
Como le envie a Carl, yo estoy usando esto:

ARM®v7-M Architecture Reference Manual
https://web.eecs.umich.edu/~prabal/teaching/eecs373-f10/readings/ARMv7-M_ARM.pdf

Cortex-M4  Revision r0p0 Technical Reference Manual
http://infocenter.arm.com/help/topic/com.arm.doc.ddi0439b/DDI0439B_cortex_m4_r0p0_trm.pdf

Thumb® 16-bit Instruction Set Quick Reference Card (UAL)
https://web.eecs.umich.edu/~prabal/teaching/eecs373-f10/readings/ARM_QRC0006_UAL16.pdf

ARM® and Thumb®-2 Instruction Set Quick Reference Card
https://www.lri.fr/~de/ARM.pdf

Todos obtenibles desde el sitio de ARM, el tema es que en ARM tenes que registrarte xD, o busca por google.

GNU AS compiler:
https://sourceware.org/binutils/docs/as/

GNU LD Linker:
https://sourceware.org/binutils/docs/ld/

Por supuesto tengo el Cortex-M4F, asi que voy con esa arquitectura. si es un M0+ tenes que irte por la ARMv6-M , y el M4 y M7 posee una ARMv7E-M peeeeero es una v7 igual xD.
Lo que por ahi es complejo es calcular los ciclos, hay instrucciones que si tienen los ciclos contados pero otras que dependen del pipeline, siendo variables de 1 a 3 por ejemplo. Asi que ahi se complica mas. (No se como calcularlas)

----------------------

Una cosa tengo el codigo de GCC con 0 optimizacion y un codigo con optimizacion 1, tanto para tamaño y velocidad, mas optimizacion no modifico nada. Solo decir que es un desastre el ASM generado con 0 de optimizacion y con optimizacion creo que aun todavia se puede mejorar mas.
Título: Re:Assembler en ARM - Probando
Publicado por: elgarbe en 11 de Octubre de 2015, 09:01:27
Eso es un SPI, para mi deberias hacerlo por SPI (hasta aprovechar un QSPI o 2), tu "latch" seria el CS, seguro que podes mantener el CS hasta el ultimo dato enviado. Es decir enviar multiple bytes y luego recien ahi que se levante el CS. Y por hardware. Pero voy a intentar hacerlo. Indicame el micro que estas trabajando por que seguro que tengo que buscar los registros y esas cosas. Ya que por ejemplo vi que algunos poseen un registro especial para poner una salida a 1, mientras que otros usan la misma direccion para el encode.

PD: Estuve viendo y es un dolor de cabeza GCC sin optimizaciones :P
Y me esta siendo un dolor de cabeza acostumbrarme a ese ASM :P

Una cosa mas. Al comienzo es ponerle una constante, o tenes pensado hacer una funcion? si es asi pone como es la funcion. Ya que veo que estas enviando Rojo,Verde y Azul al 100%, todo terminaria en una constante e.e

MCH = 0x0000.0148
MCL = 0000 0bbb bbbb bggg gggg grrr rrrr r010

Estoy en lo correcto? Y b/r/g van a cambiar ? Y van a ser pasados por alguna funcion?
Que micro estamos hablando? Cortex-M3 ? M0+ ?

Si y no (a lo de SPI) el tema es que cada TLC necesita 49 bits de datos para manear las 48 salidas. Entonces el SPI debería enviar 7 bits de más. Quizá eso no afecte mucho a la velocidad vs lo que se gana por hacerlo todo por hardware. De todos modos, como es un micro que no estoy usando mucho y las librerias de ST suelen ser un dolor de cabeza, arranque haciendo el manejo con GPIO directamente así tengo mas control de lo que hago y puedo encontrar errores facilmente. Es probable que termine en un SPI.

Los 49 bits que puse ahí son de configuracion del TLC. BC es bright control y es para equalizar los colores dandole un poquito mas de corriente o menos a cada salida para uniformar el color. El MC es la corriente maxima (que luego se atenúa con BC) por grupo de colores. En principio eso es fijo.
Pero algo similar hay que hacer para asacar el ON/OFF de las salidas. Son 49 bits, con el MSB en 0 y el resto el estado de cada salida a los LED.
Lo que me gustaba es la parte de manejo de bits, verificar si es uno o cero y sacar en cuestion... Pero era sola una idea....

El micro es un M4F (x q es lo que estoy usando en varios proyectos) aunque podría ser un M0+ de NXP (lpc11u67) mucho mas acorde....


EDITO: La idea de Juanjo es mejor! empezar por el principio siempre es buena idea!  :lol:
Saludos
Título: Re:Assembler en ARM - Probando
Publicado por: juaperser1 en 11 de Octubre de 2015, 09:07:19
Citar
Por supuesto tengo el Cortex-M4F, asi que voy con esa arquitectura. si es un M0+ tenes que irte por la ARMv6-M , y el M4 y M7 posee una ARMv7E-M peeeeero es una v7 igual xD.

hombre ya que nos ponemos que sea de v7 para arriba  :D :D, y si ya sabia lo de los lios que traen los ARM con la compatibilidad para procesadores y es un lio de cojones, por eso te preguntaba, por si acaso tu ya lo tenias claro  :D :D
Título: Re:Assembler en ARM - Probando
Publicado por: KILLERJC en 11 de Octubre de 2015, 09:16:38
hombre ya que nos ponemos que sea de v7 para arriba  :D :D, y si ya sabia lo de los lios que traen los ARM con la compatibilidad para procesadores y es un lio de cojones, por eso te preguntaba, por si acaso tu ya lo tenias claro  :D :D

Lo unico claro que tengo es la piel por no salir al sol. Peeero mira como salieron las cosas del MPASM y dsPIC :P, solo ponerlo voluntad y en un dia te programas un satelite  :D
Título: Re:Assembler en ARM - Probando
Publicado por: juaperser1 en 11 de Octubre de 2015, 09:28:57
Citar
Lo unico claro que tengo es la piel por no salir al sol. Peeero mira como salieron las cosas del MPASM y dsPIC :P, solo ponerlo voluntad y en un dia te programas un satelite  :D

toda la razón del mundo, no se puede estar mas de acuerdo, pero si en vez de un satelite es una estrella de la muerte mejor que mejor :D :D

y no hablemos de piel clara, por que si me hacen una foto con flash me tengo que hechar aloevera por las quemaduras  :D :D
Título: Re:Assembler en ARM - Probando
Publicado por: Carl47D en 11 de Octubre de 2015, 15:25:03
Que tal,

Lo probé, uso PSoC Creator como IDE, este usa ARM GCC 4.9-2015-q1 como toolchain y un PSoC con un M0, pero el IDE que uso no tiene opciones para medir el tiempo que va pasando con cada instrucción, seria cosa de checar cuantos ciclos toma cada instrucción, pero al menos funciona.

Tengo la opción de añadir un archivo de GNU ASM a la carpeta de source files, lo creo y me da un snippet:

Código: ASM
  1. .syntax unified
  2.     .text
  3.  
  4. /*
  5.     .global FunctionName
  6.     .func FunctionName, FunctionName
  7.     .thumb_func
  8. FunctionName:
  9.     BX lr
  10.     .endfunc
  11. */
  12.  
  13.     .end

Le añadi las instrucciones y termino asi:

Código: ASM
  1. .syntax unified
  2.     .text
  3.     .global _delay
  4.     .func _delay, _delay
  5.     .thumb_func
  6. _delay:
  7.     SUBS    r0, #1
  8.     NOP
  9.     NOP
  10.     NOP
  11.     NOP
  12.     NOP
  13.     NOP
  14.     NOP
  15.     NOP
  16.     NOP
  17.     NOP
  18.     NOP
  19.     BNE.N   _delay
  20.     BX lr
  21.     .endfunc
  22.  
  23.     .end

Y lo añadi al main, que asi quedó:
Código: C++
  1. #include <project.h>
  2.  
  3. extern void _delay(uint16_t us);
  4.  
  5. int main(){
  6.     CyGlobalIntEnable;
  7.  
  8.     _delay(2);
  9.    
  10.     for(;;){
  11.        
  12.     }
  13. }

Lo debuggeo sin optimizaciónes y en el disassembly se ve la llamada a la función:
Código: ASM
  1. 7:     _delay(2);
  2. 0x000001F6 2002     movs        r0, #2
  3. 0x000001F8 F000F802 bl  200 <_delay>

de ahi brinca a la etiqueta <_delay>, que tiene lo mismo que la funcion creada en el archivo asm:
Código: ASM
  1. 0x00000200 <_delay>:
  2.    2:     .text
  3.    3:     .global _delay
  4.    4:     .func _delay, _delay
  5.    5:     .thumb_func
  6.    6: _delay:
  7.    7:     SUBS    r0, #1
  8. 0x00000200 3801     subs        r0, #1
  9.    8:     NOP
  10. 0x00000202 46C0     nop                 ; (mov r8, r8)
  11.    9:     NOP
  12. 0x00000204 46C0     nop                 ; (mov r8, r8)
  13.   10:     NOP
  14. 0x00000206 46C0     nop                 ; (mov r8, r8)
  15.   11:     NOP
  16. 0x00000208 46C0     nop                 ; (mov r8, r8)
  17.   12:     NOP
  18. 0x0000020A 46C0     nop                 ; (mov r8, r8)
  19.   13:     NOP
  20. 0x0000020C 46C0     nop                 ; (mov r8, r8)
  21.   14:     NOP
  22. 0x0000020E 46C0     nop                 ; (mov r8, r8)
  23.   15:     NOP
  24. 0x00000210 46C0     nop                 ; (mov r8, r8)
  25.   16:     NOP
  26. 0x00000212 46C0     nop                 ; (mov r8, r8)
  27.   17:     NOP
  28. 0x00000214 46C0     nop                 ; (mov r8, r8)
  29.   18:     NOP
  30. 0x00000216 46C0     nop                 ; (mov r8, r8)
  31.   19:     BNE.N   _delay
  32. 0x00000218 D1F2     bne.n       200 <_delay>
  33.   20:     BX lr
  34. 0x0000021A 4770     bx  lr

Tiene una ventana para ver los registros y se ve el 2 en el r0 al iniciar la función y como disminuye en una unidad cada que hace el bne.n.

Por que escribí todo esto, no se xD.

Whirlwind Tour of ARM Assembly
http://www.coranac.com/tonc/text/asm.htm (http://www.coranac.com/tonc/text/asm.htm)
Título: Re:Assembler en ARM - Probando
Publicado por: KILLERJC en 11 de Octubre de 2015, 17:45:05
Lo probaste en el hardware? o te permite simularlo paso a paso viendo los registros?
Sino lo que queda es debug y mirar el systick.

Citar
seria cosa de checar cuantos ciclos toma cada instrucción

El SUB solo ocupa 1 ciclo
El NOP = MOV Rx,Rx = ocupa 1 ciclo
El BNE = 1 + P
el BX = 1 + P

Siendo P:

Citar
The number of cycles required for a pipeline refill. This ranges from 1 to 3 depending on the alignment and width of the target instruction, and whether the processor manages to speculate the address early.

Asi que con todos los NOP, realmente no deberia existir problemas en la especulacion y tal ves considerarlo de 2 ciclos, pero eso no te asegura nada. No hay un tiempo exacto, o al menos todavia no se como calcularlo.
En el micro que tengo por ir a 120Mhz tiene como un "banco" para la flash, el cual va pidiendo instrucciones asi el nucleo no se queda parado esperando por las mismas, sino que solo busca, PERO los saltos son un dolor de cabeza y puede que el primer salto necesite hacer un pedido a la flash por X motivo ( aunque no deberia si es un Pseudo LRU ) Pero eso agrega mas complejidad a saber exactamente cuantos ciclos pasaron. Para un comportamiento deterministico debo de fijar ese banco, al menos en mi caso.

De todas formas para eso esta el SYSTICK, Aunque te pases nuevamente por unos cuantos ciclos es mas exacto que estar acumulando errores (y ocuparia menos instrucciones creo :P).
Solo notar 2 cosas:

.func .endfunc
Citar
.func emits debugging information to denote function name, and is ignored unless the file is assembled with debugging enabled.
Asi que podriamos decir que no es si o si necesario ponerlo

Y pense que el guion bajo de la funcion se iba. Pero no es asi.
Título: Re:Assembler en ARM - Probando
Publicado por: Carl47D en 11 de Octubre de 2015, 18:14:13
iba  a citar algo del link que deje  :D:
"it is so closely tied to the CPU, you can make it do everything; but that also means you have to do everything. Being close to hardware also means you're bypassing all the safety features that higher languages may have, so that it's much easier to break things. So yeah, it is harder and more dangerous. Although some may prefer the term ‘adventurous’. "

Si, lo grabé en el micro y puedo ver los registros a cada paso que da el disassembly, el codigo lo saque de una funcion para generar delays de microsegundos en un micro que corre a 16 MHz; cada ciclo es de 62.5 nanosegundos, para hacer el delay de 1 microsegundo se necesitan 16 ciclos:

SUB (1 ciclo) + NOP (11 ciclos en total) + BNE (2 ciclos) + BX (2 ciclos) = 16

Y lo del systick, no habia tenido la necesidad de ver los registros 'en vivo', supongo solo los puedo ver en la memoria, viendo la dirección del SysTick

.func .endfunc no habia buscado para que servian por eso los dejé, el guion bajo es solo parte del nombre de la función.

PD: si digo alguna barbaridad corrijanme xD.

Título: Re:Assembler en ARM - Probando
Publicado por: elgarbe en 11 de Octubre de 2015, 19:21:28
De todas formas para eso esta el SYSTICK, Aunque te pases nuevamente por unos cuantos ciclos es mas exacto que estar acumulando errores (y ocuparia menos instrucciones creo :P).

para contar ciclos de instruccion que van transcurriendo se usa el DWT (si el micro lo trae)

http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0337h/BIIFBHIF.html

tenía un programa que contaba cuantos ciclos tardaba en hacer la fft un micro que estaba usando, pero no lo encuentro...

sds.

EDITO: Aquí una explicacion para un M3 http://www.microbuilder.eu/Projects/LPC1343ReferenceDesign/DWTBenchmarking.aspx
Título: Re:Assembler en ARM - Probando
Publicado por: Carl47D en 11 de Octubre de 2015, 21:05:29
Citar
La idea de Juanjo es mejor! empezar por el principio siempre es buena idea!  :lol:
+1

Traté de contar los ciclos con el SysTick, buscaré si el micro que tengo tiene el DWT que según esto (http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka16334.html) deberia tener pero no encuentro nada en el reference manual, en total fueron 58, casi todas las instrucciones tomarón 4 ciclos, Es por el fetch/decode/execute de las instrucciones?

Como dijo Killer los ciclos no son algo seguro:
Citar
The cycle counts are based on a system with zero wait-states.

Y bue, quedo a la espera del comienzo formal del 'tuto'

Mas info:
The Effect of the ARM Cortex-M NOP Instruction (https://www.pabigot.com/arm-cortex-m/the-effect-of-the-arm-cortex-m-nop-instruction/)
Título: Re:Assembler en ARM - Probando
Publicado por: KILLERJC en 11 de Octubre de 2015, 21:29:48
Citar
Y bue, quedo a la espera del comienzo formal del 'tuto'

Me ponen entre la espada y la pared xD, lo mas lindo es que yo soy tan nuevo como todos ustedes en ASM de ARM. Asi que si.. estoy un poco (mucho) perdido.

Ahh y elgarbe hice el codigo que pedias, pero no me gusto :P lo veo muy largo xD
En algo le debo estar errando xD
Título: Re:Assembler en ARM - Probando
Publicado por: elgarbe en 11 de Octubre de 2015, 23:18:45
Citar
Y bue, quedo a la espera del comienzo formal del 'tuto'

Me ponen entre la espada y la pared xD, lo mas lindo es que yo soy tan nuevo como todos ustedes en ASM de ARM. Asi que si.. estoy un poco (mucho) perdido.

Ahh y elgarbe hice el codigo que pedias, pero no me gusto :P lo veo muy largo xD
En algo le debo estar errando xD

La diferencia es que vos ya estas familiarizado con los conceptos de ASM y nosotros ya nos olvidamos de todo. Modos de direccionamiento, set de instrucciones, etiquetas (.text, .func, etc). Pero bueno, tambien teens que ver que sea algo útil para futuros trabajos tuyos.

En cuanto a la funcion que hablamos, eso es si no tenes otro ejemplo, no pierdas tiempo en eso. Como bien sugeriste, seguramente la implementacion final será por SPI...

Saludos y gracias!
Título: Re:Assembler en ARM - Probando
Publicado por: KILLERJC en 12 de Octubre de 2015, 00:35:26
Yo comenze estudiando ejemplos de C pasados a ASM.. Y obtuve distintos resultados:

Cree el siguiente codigo en C

Código: C++
  1. /*
  2.  * main.c
  3.  */
  4. #include <stdint.h>
  5. #include "inc/tm4c1294ncpdt.h"
  6.  
  7. uint32_t suma(uint32_t a,uint32_t b);
  8.  
  9.  
  10. int
  11. main(void)
  12. {
  13.     volatile uint32_t ui32Loop;
  14.     uint32_t c;
  15.     //
  16.     // Alimentamos el puerto
  17.     //
  18.     SYSCTL_RCGCGPIO_R = SYSCTL_RCGCGPIO_R12;
  19.  
  20.     //
  21.     // Una pequeña lectura , asi esperamos mientras se habilita
  22.     //
  23.     ui32Loop = SYSCTL_RCGCGPIO_R;
  24.  
  25.     //
  26.     // Habilitamos como digital ( Digital ENable )
  27.     // Y como salida (DIReccion ) del PORTN
  28.     //
  29.     GPIO_PORTN_DIR_R = 0x01;
  30.     GPIO_PORTN_DEN_R = 0x01;
  31.  
  32.     //
  33.     // Loop
  34.     //
  35.     while(1)
  36.     {
  37.         //
  38.         // Encendemos el LED, No hace uso de la memoria, para seleccionar el bit en especial
  39.         //
  40.         GPIO_PORTN_DATA_R |= 0x01;
  41.  
  42.         //
  43.         // Un hermoso delay
  44.         //
  45.         for(ui32Loop = 0; ui32Loop < 200000; ui32Loop++)
  46.         {
  47.         }
  48.  
  49.         //
  50.         // Apagamos el led
  51.         //
  52.         GPIO_PORTN_DATA_R &= ~(0x01);
  53.  
  54.         //
  55.         // Otro hermoso delay
  56.         //
  57.         for(ui32Loop = 0; ui32Loop < 200000; ui32Loop++)
  58.         {
  59.         }
  60.  
  61.         //
  62.         // Mi suma y uso c solo para usarlo y no genere un Warning diciendo que se seteo pero no se uso
  63.         //
  64.  
  65.         c=suma(0x12345678,0x87654321);
  66.         if(!c) {c=0;}
  67.     }
  68. }

Lo unico que hace es,
- Activar el modulo
- Configurar el pin, Digital y Salida
- Escribirlo y un delay super basico

Mirando el codigo ASM, me encuentro con.... ESTO:

GCC , No optimizado.

Direccion - opcode - instruccion - comentario

Código: ASM
  1. 000002d0 <main>:
  2.  2d0:   b580            push    {r7, lr}        ; Guardo lr y r7 en el stack
  3.  2d2:   b082            sub     sp, #8          ; Resto Stack Pointer para hacer lugar a 64 bits (32bits*2 = 4bytes * 2)
  4.  2d4:   af00            add     r7, sp, #0      ; R7 = Stack Pointer , R7 es mi Frame Pointer
  5.  2d6:   4b1c            ldr     r3, [pc, #112]  ; (0x348) R3 = &SYSCTL_RCGCGPIO
  6.  2d8:   f44f 5280       mov.w   r2, #4096       ; R2 = 0x1000 (SYSCTL_RCGCGPIO_R12) , MOV a 32bits
  7.  2dc:   601a            str     r2, [r3, #0]    ; (R3)SYSCTL_RCGCGPIO = SYSCTL_RCGCGPIO_R12
  8.  2de:   4b1a            ldr     r3, [pc, #104]  ; (348) Carga nuevamente la direccion en R3
  9.  2e0:   681b            ldr     r3, [r3, #0]    ; R3 = SYSCTL_RCGCGPIO
  10.  2e2:   603b            str     r3, [r7, #0]    ; (R7+0) ui32Loop = (R3)SYSCTL_RCGCGPIO
  11.  2e4:   4b19            ldr     r3, [pc, #100]  ; (34c), R3 = &GPIO_PORTN_DIR
  12.  2e6:   2201            movs    r2, #1          ; R2=1, Actualizar las banderas
  13.  2e8:   601a            str     r2, [r3, #0]    ; (R2)GPIO_PORTN_DIR= (R2)1
  14.  2ea:   4b19            ldr     r3, [pc, #100]  ; (350) R3 = &GPIO_PORTN_DEN
  15.  2ec:   2201            movs    r2, #1          ; R2=1
  16.  2ee:   601a            str     r2, [r3, #0]    ; (R3)GPIO_PORTN_DEN = 1
  17.                                                 ; ------------- WHILE --------------
  18.  2f0:   4b18            ldr     r3, [pc, #96]   ; (354) R3 = &GPIO_PORTN_DATA
  19.  2f2:   4a18            ldr     r2, [pc, #96]   ; (354) R2 = &GPIO_PORTN_DATA
  20.  2f4:   6812            ldr     r2, [r2, #0]    ; R2 = GPIO_PORTN_DATA(R3)
  21.  2f6:   f042 0201       orr.w   r2, r2, #1      ; R2 = R2 or 0x1
  22.  2fa:   601a            str     r2, [r3, #0]    ; (R3)GPIO_PORTN_DATA = R2
  23.  2fc:   2300            movs    r3, #0          ; ---------- FOR --------------
  24.  2fe:   603b            str     r3, [r7, #0]    ; ui32Loop = 0
  25.  300:   e002            b.n     308 <main+0x38> ; Branch near 0x308
  26.  302:   683b            ldr     r3, [r7, #0]    ; R3 = ui32Loops
  27.  304:   3301            adds    r3, #1          ; uiLoops += 1
  28.  306:   603b            str     r3, [r7, #0]    ; Guardo
  29.  308:   683a            ldr     r2, [r7, #0]    ; R2 = ui32Loop
  30.  30a:   4b13            ldr     r3, [pc, #76]   ; (358) R3 = NumLoops
  31.  30c:   429a            cmp     r2, r3          ; R2 == R3 ?
  32.  30e:   d9f8            bls.n   302 <main+0x32> ; Branch lower or same R2<R3 -> 0x302
  33.                                                 ; ------------- Fin FOR ------------
  34.  310:   4b10            ldr     r3, [pc, #64]   ; (354)
  35.  312:   4a10            ldr     r2, [pc, #64]   ; (354)
  36.  314:   6812            ldr     r2, [r2, #0]    ; R2 = GPIO_PORTN_DATA
  37.  316:   f022 0201       bic.w   r2, r2, #1      ; Bit Clear (AND NOT), R2 = R2 (and not) 1
  38.  31a:   601a            str     r2, [r3, #0]    ; GPIO_PORTN_DATA = R2
  39.  31c:   2300            movs    r3, #0          ; ui32Loop = 0
  40.  31e:   603b            str     r3, [r7, #0]    ; ----------- FOR ---------------
  41.  320:   e002            b.n     328 <main+0x58> ;     igual que el anterior
  42.  322:   683b            ldr     r3, [r7, #0]
  43.  324:   3301            adds    r3, #1
  44.  326:   603b            str     r3, [r7, #0]
  45.  328:   683a            ldr     r2, [r7, #0]
  46.  32a:   4b0b            ldr     r3, [pc, #44]   ; (358)
  47.  32c:   429a            cmp     r2, r3
  48.  32e:   d9f8            bls.n   322 <main+0x52> ; ------- Fin de FOR -------------
  49.  330:   480a            ldr     r0, [pc, #40]   ; (35c) R0 = Dato1
  50.  332:   490b            ldr     r1, [pc, #44]   ; (360) R1 = Dato2
  51.  334:   f000 f816       bl      364 <suma>      ; Salto y 0x338 -> LR
  52.  338:   6078            str     r0, [r7, #4]    ; c = R0
  53.  33a:   687b            ldr     r3, [r7, #4]    ; R3 = c
  54.  33c:   2b00            cmp     r3, #0          ; c==0?
  55.  33e:   d102            bne.n   346 <main+0x76> ; NO -> 0x346
  56.  340:   2300            movs    r3, #0          ; R3=0
  57.  342:   607b            str     r3, [r7, #4]    ; c=0
  58.  344:   e7d4            b.n     2f0 <main+0x20> ; Salto a 0x2F0
  59.  346:   e7d3            b.n     2f0 <main+0x20>
  60.  348:   400fe608        .word   0x400fe608      ; SYSCTL_RCGCGPIO , Registros
  61.  34c:   40064400        .word   0x40064400      ; GPIO_PORTN_DIR
  62.  350:   4006451c        .word   0x4006451c      ; GPIO_PORTN_DEN
  63.  354:   400643fc        .word   0x400643fc      ; GPIO_PORTN_DATA
  64.  358:   00030d3f        .word   0x00030d3f      ; NumLoops 199.999, no 200.000 , variable
  65.  35c:   12345678        .word   0x12345678      ; Dato 1 pasado a Suma , argumentos
  66.  360:   87654321        .word   0x87654321      ; Dato 2 pasado a Suma
  67.  
  68. 00000364 <suma>:
  69.  364:   b480            push    {r7}            ; Guardo Frame Pointer
  70.  366:   b085            sub     sp, #20         ; Hago lugar en el stack para 20! bytes WTF!
  71.  368:   af00            add     r7, sp, #0      ; R7 = SP , Frame Pointer = Stack Pointer
  72.  36a:   6078            str     r0, [r7, #4]    ; Variables locales, guardo a
  73.  36c:   6039            str     r1, [r7, #0]    ; guardo b , ambo argumentos
  74.  36e:   687a            ldr     r2, [r7, #4]    ; R2 = a
  75.  370:   683b            ldr     r3, [r7, #0]    ; R3 = b
  76.  372:   4413            add     r3, r2          ; R3 = a + b
  77.  374:   60fb            str     r3, [r7, #12]   ; c = R3, c = a + b , como que se salte algo
  78.  376:   68fb            ldr     r3, [r7, #12]   ; R3 = c
  79.  378:   4618            mov     r0, r3          ; R0 = R3
  80.  37a:   3714            adds    r7, #20         ; R7 = R7 + 20 , Vuelvo el Stack pointer a su lugar
  81.  37c:   46bd            mov     sp, r7          ; SP = R7
  82.  37e:   f85d 7b04       ldr.w   r7, [sp], #4    ;Equivalente a POP R7
  83.  382:   4770            bx      lr              ; PC = LR(R14) and 0xFFFF.FFFE

Para notar es que es un DESASTRE!, se puede observar la cantidad de veces que se asigna una y otra ves las variables a los registros
Esta todo explicado en los comentarios Mi funcion suma es aun peor.

Luego para ver que TAN buena es la optimizacion, corri todas, desde -O1 a -O3, sin cambios aparentes, lo unico que note cambio fue cuando elegi que se priorizara la velocidad. Y no un cambio de tamaño ya que eran similares, sino, fue un cambio en la forma de tomar los datos, se eligio hacerlo todo al comienzo y luego trabajar con los registros.

GCC -O1 -Ofast

Código: ASM
  1. 00000404 <main>:
  2.  404:   b430            push    {r4, r5}
  3.  406:   4b16            ldr     r3, [pc, #88]   ; (460) SYSCTL_RCGCGPIO
  4.  408:   4816            ldr     r0, [pc, #88]   ; (464) GPIO_PORTN_DIR
  5.  40a:   4c17            ldr     r4, [pc, #92]   ; (468) GPIO_PORTN_DEN
  6.  40c:   4917            ldr     r1, [pc, #92]   ; (46c) GPIO_PORTN_DATA
  7.  40e:   4a18            ldr     r2, [pc, #96]   ; (470) 199.999
  8.  410:   f44f 5580       mov.w   r5, #4096       ; 0x1000 , usa thumb2 para tener mas rango en el inmmediato
  9.  414:   601d            str     r5, [r3, #0]    ; SYSCTL_RCGCGPIO = 0x1000
  10.  416:   b082            sub     sp, #8          ; Lugar para 8 bytes (32-32 bits las 2 variables ) en el stack
  11.  418:   681b            ldr     r3, [r3, #0]    ; R3 = SYSCTL_RCGCGPIO
  12.  41a:   9301            str     r3, [sp, #4]    ; ui32Loop = R3 , ui23Loop SP+4 y c SP+0
  13.  41c:   2301            movs    r3, #1          ; R3=1 , actualizo flags
  14.  41e:   6003            str     r3, [r0, #0]    ; GPIO_PORTN_DIR = R3
  15.  420:   2000            movs    r0, #0          ; R0=0   (ya que no uso mas la direccion de ese registro)
  16.  422:   6023            str     r3, [r4, #0]    ; GPIO_PORTN_DEN = R3
  17.  424:   680b            ldr     r3, [r1, #0]    ; R3 = GPIO_PORTN_DATA
  18.  426:   f043 0301       orr.w   r3, r3, #1      ; R3 = R3 | 0x1
  19.  42a:   600b            str     r3, [r1, #0]    ; GPIO_PORTN_DATA = R3
  20.                                                 ; -------- FOR ------------
  21.  42c:   9001            str     r0, [sp, #4]    ; ui32Loop = 0 , ( stack en memoria )
  22.  42e:   9b01            ldr     r3, [sp, #4]    ; R3 = ui32Loop
  23.  430:   4293            cmp     r3, r2          ; ui32Loop == 199999?
  24.  432:   d805            bhi.n   440 <main+0x3c> ; Salta si es mayor a 0x440
  25.  434:   9b01            ldr     r3, [sp, #4]    ; R3 = ui32Loop   ---   Esto requiere 2 instrucciones pero por lo "volatile"
  26.  436:   3301            adds    r3, #1          ; R3 ++
  27.  438:   9301            str     r3, [sp, #4]    ; ui32Loop = R3
  28.  43a:   9b01            ldr     r3, [sp, #4]    ; R3 = ui32Loop
  29.  43c:   4293            cmp     r3, r2          ; ui32Loop == 1999999?
  30.  43e:   d9f9            bls.n   434 <main+0x30> ; Salta si es menor a 0x434
  31.                                                 ; -------- Fin FOR ----------
  32.  440:   680b            ldr     r3, [r1, #0]    ; R3 = GPIO_PORTN_DATA
  33.  442:   f023 0301       bic.w   r3, r3, #1      ; R3 = R3 & ~(0x1) , Solo Thumb2
  34.  446:   600b            str     r3, [r1, #0]    ; GPIO_PORTN_DATA = R3
  35.                                                 ; --------- FOR ------------
  36.  448:   9001            str     r0, [sp, #4]    ; ui32Loop = R0 = 0 ???
  37.  44a:   9b01            ldr     r3, [sp, #4]    ; R3 = ui32Loop
  38.  44c:   4293            cmp     r3, r2
  39.  44e:   d8e9            bhi.n   424 <main+0x20>
  40.  450:   9b01            ldr     r3, [sp, #4]
  41.  452:   3301            adds    r3, #1
  42.  454:   9301            str     r3, [sp, #4]
  43.  456:   9b01            ldr     r3, [sp, #4]
  44.  458:   4293            cmp     r3, r2
  45.  45a:   d9f9            bls.n   450 <main+0x4c>
  46.                                                 ; --------- Fin FOR -------
  47.  45c:   e7e2            b.n     424 <main+0x20> ; Vuelta al comienzo, while
  48.  45e:   bf00            nop                     ; NOP de NOP, de 16bits para que lo que sigue este alineado a 32bits
  49.  460:   400fe608        .word   0x400fe608      ; DATOOOOOOSSS
  50.  464:   40064400        .word   0x40064400
  51.  468:   4006451c        .word   0x4006451c
  52.  46c:   400643fc        .word   0x400643fc
  53.  470:   00030d3f        .word   0x00030d3f
  54.  
  55. 0000033c <suma>:                                ; Suma que nadie lo uso, se puede ver que ahora lo hizo bien
  56.  33c:   4408            add     r0, r1          ; R0 = R0 + R1 , y devuelve R0 con el resultado
  57.  33e:   4770            bx      lr              ; Vuelve

Se puede ver que usa mas registros tales como R4 y R5, Lo cual le permite unas cositas mejor. El tema es......... optimizaciones, alineacion, carga seguida de memoria.

Primero notar que con las instrucciones de ASM uno no puede cargar 32bits ahi nomas, es tan asi que Thumb admite solo 8 bits, y Thumb2 11 y 15 bits en sus 2 codificaciones
Asi que lo que se hace es poner los datos como ven ahi al final.
Otra cosa a notar es que no todas las instrucciones son de 16bits, ven que algunas son de 32 y estan metidas entre medio. Es decir hay una hermosa mezcla.
Tambien ese hermoso NOP que puso para poder alinear la memoria, antes de ubicar los datos.
Finalmente la optimizacion quito mi funcion de Suma, SI la hizo correcta, pero la quito por completo, no hay ningun salto a Suma, y se puede ver que en una optimizacion de velocidad, prefiere cargar todo junto.

Eso ultimo es por un tema del pipeline, si yo cargara y luego usara una instruccion que usara ese dato, me encuentro con un problema, ya que mientras ingreso la carga (que normalmente usa 2 ciclos) y todavia no escribi mi registro, tengo la otra instruccion pidiendome los datos, por lo cual lo detiene tal ves un ciclo mas asi puede usar el dato. Haciendo esto no, ya que toma datos y luego procura que los que tomo al comienzo sean los primeros en usarse. Solo tome estos codigos para analizarlos y verlos.

Por que guarda R4 y R5 antes ? Esto es por que para C, el main es una sub-rutina, hay un programa mayor que hace una llamada al main, por eso mismo se comporta de esa forma. Entonces al usar R4 y R5 debe guardarlos y deberia de hacer un POP de esos al salir, pero.... no sale nunca gracias al while.
Título: Re:Assembler en ARM - Probando
Publicado por: KILLERJC en 12 de Octubre de 2015, 01:08:16
Con respecto a las instrucciones son bastantes especiales.

Ejemplo la instruccion de suma, con un literal

Código: [Seleccionar]
T1 : ADD<c> <Rd>,<Rn>,#<imm3>
        ADDS <Rd>,<Rn>,#<imm3>

T2 : ADD<c> <Rdn>,#<imm8>
        ADDS <Rdn>,#<imm8>

T3: ADD{S}<c>.W <Rd>,<Rn>,#<const>

T4: ADDW<c> <Rd>,<Rn>,#<imm12>

Todos son validos, los 2 primeros encoding T1 y T2 son de 16bits y los otros 2 son de 32bits , los de 32 bits permiten inmediatos de hasta 12bits,
(Con encoding me refiero a su opcode, 4 opcode por cada "instruccion" como si 1 no fuera demasiado :P)

Lo cual permite hacer:

ADD  R0,R1,#7 ; T1 -> R0 = R1 + 7    (distintos registros)
ADD  R0,#0xFF; T2 -> R0 = R0 + 255  (mismos registro)

Eso no actualiza las banderas Z,C,etc, solo cuando uno lo pide, y eso se hace con la S

ADDS R0,#0x10 ; T2 -> R0 = R0 + 16 y actualizo flags

Veran tambien que existe una <c>. Bueno esto es la condicion, para que se ejecute la instruccion. Solo algunas instrucciones pueden hacer uso de estas condiciones por si solas, tales como la instruccion B<c> (branch), como BNE (Branch Not Equal) BCS (Branch Carry Set ), etc, las demas como ADD no pueden condicionar su ejeccucion por si solas.
A lo que uno pregunta, si existe: ¿Para que sirve?

Thumb tiene una instruccion llamada IT ( if-Then ) que permite la ejecucion condicional de 4 instrucciones siguentes. Ejemplo:

ITTEE  CS

Con eso digo que If-Then Then Else Else  (condicion Carry Set), la primera instruccion esta condicionada por lo que vaya donde pusimos el CS ( en el ejemplo CS), las demas responden a lo que esta despues de IT
Es decir las 4 instrucciones van a ser:
IT TEE CS

If Then CS: 1era intruccion
Then CS: 2da intruccion
Else CC: 3ra instruccion 
Else CC: 4ra instruccion

Un ejemplo de esto en C:

Código: C++
  1. if ( ++X == 10)
  2. {
  3.   b++;
  4. }
  5. else
  6. {
  7.   b--
  8. }

Se imaginan el caos en el pipeline por eso no,2 saltos seguro, vaciar el pipeline, etc , especialmente al modificarse X antes. Pero podemos hacer esto:

Código: [Seleccionar]
ADD R0,#1 ;Aumento en 1 X
CMP R0,#0x10 ;R0==10?
ITE EQ                           ; Esto no se ejecuta, solo es indicativo para lo siguiente, pero ocupa 16bits
ADDEQ R1,#1 ;Caso If Equal Then
SUBNE R1,#1 ;Caso Else o Not Equal

Eso hace que no tome saltos sino que siga su camino pero que no lo ejecute, al principio en el encoding puse separado el ADD{S} del ADD<c>, ya que no podria actualizar las banderas mientras esta condicionalmente asi. Tamibien se puede notar que las instrucciones DEBEN tener el condicional correcto que se le da, Si se pide Mayor a, el contrario es menor o igual.
Hay algunas instrucciones que no pueden formar parte del IT y que generalmente son saltos, o que deben estar ubicados al final.

No se exactamente como se comportara con instrucciones de 16bit y 32bits mezcladas el IT, pero bueno, esto es hasta lo que vi por ahora.
Título: Re:Assembler en ARM - Probando
Publicado por: juaperser1 en 12 de Octubre de 2015, 07:30:00
Citar
Me ponen entre la espada y la pared xD, lo mas lindo es que yo soy tan nuevo como todos ustedes en ASM de ARM. Asi que si.. estoy un poco (mucho) perdido.

chicos, dejad de agobiar a killerjc, vamos a dejarlo que  aprenda y luego lo agobiamos todos a la vez ¿vale? :D :D

Citar
La diferencia es que vos ya estas familiarizado con los conceptos de ASM y nosotros ya nos olvidamos de todo. Modos de direccionamiento, set de instrucciones, etiquetas (.text, .func, etc). Pero bueno, tambien teens que ver que sea algo útil para futuros trabajos tuyos.
+1

yo en C todo lo que quieras, pero mi ensamblador se quedo en el motorola 68000 que di en la uni y en algún programa chorra que hice con un pic16, es mas, la imagen que colgué la saque de los apuntes del motorola  :D :D por si queréis verlos:

https://www.dropbox.com/sh/e57jjuynpuagjuv/AAAFt30ae3rZe5m9gbD5bJ_Ga?dl=0

yo particularmente, siendo sincero, en este foro no me entero mas que del 25% tirando alto de lo que estáis hablando, así que hasta que no me ponga al dia no podre participar mucho :(

un saludo.


Título: Re:Assembler en ARM - Probando
Publicado por: KILLERJC en 12 de Octubre de 2015, 08:05:41
Creo que termine la rutina de elgarbe, en si no era tan larga, probe hacerla en C y luego pasarla por el desamblador y me dio el doble de codigo :P

Código: ASM
  1. .syntax unified
  2.         .thumb
  3.         .text
  4.         .global Funcion
  5.  
  6.  
  7. Funcion:
  8.         PUSH    {R4,R5,R6}              ;@ Por las dudas, no pierdo nada xD
  9.         LDR     R0, =0x5FFFFFE0         ;@ Cargo R0 = MCL Invertido bit a bit
  10.         MOVS    R1, #0x25               ;@ Cargo R1 = MCH Invertido bit a bit
  11.         MOVS    R2, #8                  ;@ Cargo R2 = j
  12.         MOVS    R4, #0x00               ;@ Bit a cambiar datos
  13.         MOVS    R5, #0x00               ;@ Bit a cambiar Clock
  14.         LDR     R3, =0x1234567          ;@ Cargo direccion de registro R3 = &PUERTO
  15.         LDR     R6, [R3, #0]            ;@ Valor del Puerto R6=PUERTO
  16. 1:      RRXS    R1, R1                  ;@ Roto 1 derecha a traves del carry
  17.         ITE     CS                      ;@ Envio de la parte alta
  18.         ORRCS.N R6, R4                  ;@ Carry Set, pongo un uno (OR)
  19.         BICCC.N R6, R4                  ;@ Carry Clear, pongo un 0 (AND NOT)
  20.         STR     R6, [R3, #0]            ;@ Aplico cambios al puerto -datos-
  21.         ORRS    R6, R6, R5              ;@ A 1 -clock-
  22.         STR     R6, [R3, #0]            ;@ Aplico cambios al puerto -clock-
  23.         BICS    R6, R5                  ;@ A 0 -clock-
  24.         STR     R6, [R3, #0]            ;@ Aplico cambios al puerto -clock-
  25.         SUBS    R2, #0x1                ;@ Resto aca para que la prediccion de salto sea mas facil
  26.         BNE     1b
  27.         MOVS    R2, #31
  28.         MOVS    R1, #0x00               ;@ Bit de latch, cargo aca asi es mas rapido
  29. 1:      RRXS    R0, R0                  ;@ Envio de la parte baja
  30.         ITE     CS                     
  31.         ORRCS.N R6, R4
  32.         BICCC.N R6, R4
  33.         STR     R6, [R3, #0]            ;@ Aplico cambios al puerto -datos-
  34.         ORRS    R6, R5                  ;@ A 1 -clock-
  35.         STR     R6, [R3, #0]            ;@ Aplico cambios al puerto -clock-
  36.         BICS    R6, R5                  ;@ A 0 -clock-
  37.         STR     R6, [R3, #0]            ;@ Aplico cambios al puerto -clock-
  38.         SUBS    R2, #0x1
  39.         BNE     1b
  40.         ORRS    R6, R1
  41.         STR     R6, [R3, #0]            ;@ Aplico cambios al puerto -latch-
  42.         BICS    R6, R1
  43.         STR     R6, [R3, #0]            ;@ Aplico cambios al puerto -latch-
  44.         POP     {R4,R5,R6}
  45.         BX      LR
  46.         .end
  47.  
  48.  
  49. @       MOV     R0, =0x07FFFFFA         ;@ Cargo R0 = MCL
  50. @       MOV     R1, =0x148              ;@ Cargo R1 = MCH
  51.  
  52. @ R0 Normal:    0000 0111 1111 1111 1111 1111 1111 1010
  53. @ R0 Inverso:   0101 1111 1111 1111 1111 1111 1110 0000
  54.  
  55. @ R0 Inverso: 5FFF.FFE0
  56.  
  57. @ R1 Normal:    1 0100 1000
  58. @ R1 Inverso:   0 0010 0101
  59.  
  60. @ 0x25
  61. @ 0 0010 0101

Inverti los valores a enviar, asi enviaba desde el bit mas alto al mas bajo, lo hice en 2 partes. Primero el alto y luego el bajo. Los valores sin "tocar" son los que dice R0 Normal y R1 Normal.
Eso era mas facil que ir haciendoles AND y preguntando si era 0 o no.

Y para asegurarme que todo fuera correcto le hice un disassembler al object generado
(Lo hago por que a veces ocurre que si no esta alineado los datos al final son cualquier cosa menos datos)

Código: ASM
  1. 00000000 <Funcion>:
  2.    0:   b470            push    {r4, r5, r6}
  3.    2:   4813            ldr     r0, [pc, #76]   ; (50 <Funcion+0x50>)
  4.    4:   2125            movs    r1, #37 ; 0x25
  5.    6:   2208            movs    r2, #8
  6.    8:   2400            movs    r4, #0
  7.    a:   2500            movs    r5, #0
  8.    c:   4b11            ldr     r3, [pc, #68]   ; (54 <Funcion+0x54>)
  9.    e:   681e            ldr     r6, [r3, #0]
  10.   10:   ea5f 0131       movs.w  r1, r1, rrx
  11.   14:   bf2c            ite     cs
  12.   16:   4326            orrcs   r6, r4
  13.   18:   43a6            biccc   r6, r4
  14.   1a:   601e            str     r6, [r3, #0]
  15.   1c:   432e            orrs    r6, r5
  16.   1e:   601e            str     r6, [r3, #0]
  17.   20:   43ae            bics    r6, r5
  18.   22:   601e            str     r6, [r3, #0]
  19.   24:   3a01            subs    r2, #1
  20.   26:   d1f3            bne.n   10 <Funcion+0x10>
  21.   28:   221f            movs    r2, #31
  22.   2a:   2100            movs    r1, #0
  23.   2c:   ea5f 0030       movs.w  r0, r0, rrx
  24.   30:   bf2c            ite     cs
  25.   32:   4326            orrcs   r6, r4
  26.   34:   43a6            biccc   r6, r4
  27.   36:   601e            str     r6, [r3, #0]
  28.   38:   432e            orrs    r6, r5
  29.   3a:   601e            str     r6, [r3, #0]
  30.   3c:   43ae            bics    r6, r5
  31.   3e:   601e            str     r6, [r3, #0]
  32.   40:   3a01            subs    r2, #1
  33.   42:   d1f3            bne.n   2c <Funcion+0x2c>
  34.   44:   430e            orrs    r6, r1
  35.   46:   601e            str     r6, [r3, #0]
  36.   48:   438e            bics    r6, r1
  37.   4a:   601e            str     r6, [r3, #0]
  38.   4c:   bc70            pop     {r4, r5, r6}
  39.   4e:   4770            bx      lr
  40.   50:   5fffffe0        .word   0x5fffffe0
  41.   54:   01234567        .word   0x01234567

Esto fue "gracioso" me comi MUCHISIMAS veces el load y store, solo hacia OR y AND nomas xD. Una cosa buena es como ven ahi es que si no entra el dato lo agrega solo al final y te calcula solo el offset.

Por otra parte renegue mucho con el tema de las instrucciones, cuadno hacia un:

mov   r2, #31
Me encontraba con que me lo codificaba en 32bits, cuando esta claro que no pasa de 8 bits, intente ponerle un .N a la funcion MOV.N para forzarla a 16bits y seguia con errores, mirando el datasheet con los encoding veo:

Encoding T1

MOVS <Rd>,#<imm8>       -------------         Outside IT block.
MOV<c> <Rd>,#<imm8>   -------------       Inside IT block.

Asi es .. le faltaba la maldita S, no era "opcional" para 16bits, le puse eso y salimos andando xD, ocupando un total de 0x58

Otra cosa que aprendi, se puede poner ;@ asi si uno lo usa con otro compilador ( como el de ASM ) el mismo ; es valido, y usando el de GCC lo toma como comentario a esos 2 juntos tambien. Solo 2 instrucciones de 32bits cada una, que es una rotacion extendida por el carry.

EDIT: Otra mas que aprendi:

PUSH   {R4,R5,R6}

No podes ponerlo fuera de orden, siempre crecientes, esta mas que decir que R0-R3 se usan para pasar los datos, asi que los unicos que deberian preocuparse por esos valores si es que los usan es el que llama. Y no el llamado

Tambien le agregue un nop al final para que quede desalineado y asi ver que ocurria con el ASM:

Código: ASM
  1. 4e:     4770            bx      lr
  2.   50:   46c0            nop                     ; (mov r8, r8)
  3.   52:   0000            .short  0x0000
  4.   54:   5fffffe0        .word   0x5fffffe0
  5.   58:   01234567        .word   0x01234567

El mismo ASM me lo arregla poniendo un dato cualquiera. Si yo hubiera escrito esos .word por mi mismo, y no estuvieran alineados veria cualquier cosa. esta ves tambien le agrego al final del NOP, un .word 0x32324545

quedando:
Código: ASM
  1. BX      LR
  2.         NOP
  3.         .word 0x32324545
Y el disASM:
Código: ASM
  1. 4e:     4770            bx      lr
  2.   50:   46c0            nop                     ; (mov r8, r8)
  3.   52:   4545            .short  0x4545
  4.   54:   00003232        .word   0x00003232
  5.   58:   5fffffe0        .word   0x5fffffe0

Ahi se puede ver lo que ocurre cuando esta desalineado :P


PD: No se si el codigo funciona, segun mi logica si, pero seguro que en algo falle :P
Título: Re:Assembler en ARM - Probando
Publicado por: elgarbe en 12 de Octubre de 2015, 10:14:48

yo particularmente, siendo sincero, en este foro no me entero mas que del 25% tirando alto de lo que estáis hablando, así que hasta que no me ponga al dia no podre participar mucho :(

un saludo.

yo no sé si llego al 25% jajaja. Me parece que estamos medio lejos del ASM para ARM.
Quizás para aprender sea bueno hacer un mix, de cosas básicas, teóricas y algo de funciones simples que sirvan para algo concreto, pero bien simples.
Por ejemplo, debido al error de hard que tengo en el cartel, de los primeros 49 bits que envío a los TLC van "al derecho", pero los segundos 49 bits que tengo que enviar van "al revez". Despues voy a poner en el post del cartel como estoy pensando avanzar con el software y que cosas simples se podrían intentar en ASM. de ese modo puedo ir haciendo algo simple como para ir tomando contacto y por otra parte lo puedo testear en el micro. quizá se debería arrancar con ASM con cosas que tengan que ver con manejo de datos en memoria.
Algo que creo está faltando es el formato genera de un archivo .s para que lo pueda meter en un pryecto y compile. Explicando las partes, etiquetas, etc. Quizá explicar el startup_xxxxx.s que viene en los proyectos...

Saludos!
Título: Re:Assembler en ARM - Probando
Publicado por: KILLERJC en 12 de Octubre de 2015, 18:05:34
Bueno, como yo (repito) soy nuevo en ARM no puedo dar exactamente todo, y leerlo no es lo mismo que hacerlo para el dsPIC, el dsPIC me costo nada, fue una ... por ahi fue mas probar que otra cosa, pero este... recien estoy arrancando. El startup es simple, es una coleccion de saltos, o vectores de interrupcion + algunas funciones que son las de comienzo, el reset lo vi con un poco de ASM y vi como es que crea el copiado de memoria en C. Pero luego tenes el archivo de inicializacion de C, y ese te mete memset y vaaaaaaarias cosas mas.

Citar
de ese modo puedo ir haciendo algo simple como para ir tomando contacto y por otra parte lo puedo testear en el micro. quizá se debería arrancar con ASM con cosas que tengan que ver con manejo de datos en memoria

Por eso decia que den ideas, yo probaba y me ponia a jugar un rato xD,

Citar
Algo que creo está faltando es el formato genera de un archivo .s para que lo pueda meter en un pryecto y compile

Creo que esta, es lo minimo y compila, por ahi tal ves un align, pero bueno eso queda cuestion de cada uno:

Código: ASM
  1. .syntax unified
  2.         .thumb
  3.         .text
  4.         .global Funcion
  5.  
  6. Funcion:
  7.         BX      LR
  8.         .end
Título: Re:Assembler en ARM - Probando
Publicado por: elgarbe en 12 de Octubre de 2015, 18:30:08
Que sería eso del align? Imagino que es para que todas las instrucciones se acomoden en 32 bits, pero prácticamente como sería el tema?

Podrías intentar una función que tome un uint64 e invierta la posición de cada bit? El que esta en la posición 0 va a la pos 64 el del 1 a la pos 63 y así? Si fuese posible invertir la posición de 48 de los 64 bits mejor. Sería para reemplazar los for que tengo para enviar los datos y trabajar directamente con memoria para sacar los datos por spi...

Saludos!
Título: Re:Assembler en ARM - Probando
Publicado por: KILLERJC en 12 de Octubre de 2015, 18:56:03
el align es ( ya lo dije en el dsPIC xD ) una directiva que sirve para alinear datos/memoria.

Cuando vos haces un .align 2 (siempre potencias de 2 ) lo que estas haciendo es forzar a que lo siguiente se ubique en la posicion de memoria  multiplo de 2. Normalmente en el ARM estamos en presencia siempre de un align 2 (si es que son de 16 bits) si observas la direccion (columna izquierda del codigo que pase)

Código: ASM
  1. 0:   b470            push    {r4, r5, r6}
  2.    2:   4813            ldr     r0, [pc, #76]   ; (50 <Funcion+0x50>)
  3.    4:   2125            movs    r1, #37 ; 0x25
  4.    6:   2208            movs    r2, #8
  5.    8:   2400            movs    r4, #0

Son multiplos de 2, 0000 , 0010 ,0110 , 1000 ( el ultimo bit en 0)
Cuando tenemos un dato de 32 bits, si no alineamos a multiplos de 4, ocurriria esto:

Código: ASM
  1. 50:   46c0            nop                     ; (mov r8, r8)
  2.   52:   4545            .short  0x4545
  3.   54:   00003232        .word   0x00003232
  4.   58:   5fffffe0        .word   0x5fffffe0

Como se ve ahi en ese caso agregue un NOP a proposito y cree un .word al final con el valor 0x32324545 , al menos asi estaba en mi codigo, como no estaba bien alineado termine con mitad por un lado y mitad por el otro. No es lo que yo queria, si yo pongo un .align 4, el programa al ver que estaba en 0x52 ( 0101 0010) hubiera intentado acomodarse a esto buscando la proxima direccion de memoria multiplo de 4, es decir 0x54 ( 0101 0100). Como le respondo a Carl47D aqui no vi todavia instrucciones que especificamente accedan a Words, Half-Words, bytes, pero si en el dsPIC el cual usar una instruccion que esta preparada para un Half-Word y hacerla acceder a una direccion que no es multiplo de 2 ( 16 bits ) termina en una excepcion, o error de direccion. Aqui todavia no prove eso.

Lo que puedo observar es que las instrucciones Thumb2 uno pensaria que es obligacion ponerlas en una alineacion de 32 bits, pero estas  no son de 32, sino que se toman como 2 de 16 bits, por eso mismo hacer esto:

Código: ASM
  1. e:   681e            ldr     r6, [r3, #0]
  2.   10:   ea5f 0131       movs.w  r1, r1, rrx

O ponerle un NOP entre medio quedando asi:

Código: ASM
  1. e:      681e            ldr     r6, [r3, #0]
  2.   10:   46c0            nop                     ; (mov r8, r8)
  3.   12:   ea5f 0131       movs.w  r1, r1, rrx

Sin ningun problema

Citar
Podrías intentar una función que tome un uint64 e invierta la posición de cada bit? El que esta en la posición 0 va a la pos 64 el del 1 a la pos 63 y así? Si fuese posible invertir la posición de 48 de los 64 bits mejor. Sería para reemplazar los for que tengo para enviar los datos y trabajar directamente con memoria para sacar los datos por spi...
OK ahi veo el set de instrucciones como hacerlo

Creo que la instruccion RBIT de Thumb2 es la solucion :P

For (i = 0; i < 32; i++) : Rd = Rm[31– i]

Solo restaria acomodar los valores.
Título: Re:Assembler en ARM - Probando
Publicado por: KILLERJC en 12 de Octubre de 2015, 23:30:28
No se que tan errado este en el funcionamiento del programa, eso seria para invertir los bits

Código: ASM
  1. .syntax unified
  2.         .thumb
  3.         .text
  4.         .global Invertir
  5.  
  6.  
  7. ;@Funcion ASM que invierte los 49bits de una variable de 64bits
  8. ;@ Entrada R1:R0
  9. ;@ Salida R1:R0 Variable de 64 bits
  10.  
  11. Invertir:
  12.         RBIT    R2, R1                  ;@ R2 = Inv(R1)
  13.         RBIT    R0, R0                  ;@ R0 = Inv(R0)
  14.         LSRS    R2, R2, #15             ;@ R2 = Inv(R1) >> 15
  15.         UBFX    R3, R0, #0 ,#14         ;@ R3 = R0[14:0]
  16.         ADD.W   R3, R2, R3, LSL #17     ;@ R3 = R0[14:0] + Inv(R1)>>15 = Bajo Invertido Final
  17.         LSLS    R1, R0, #15             ;@ R1 = R0[31:15]>>15 = Alto invertido Final
  18.         MOVS    R0, R1                  ;@ R0 = Bajo Invertido Final
  19.         BX      LR                      ;@ Voler
  20.         .end
  21.  
  22. ;@ Normal
  23.  
  24. ;@ 0x0001.1234.5678.9ABC ->
  25.  
  26. ;@ Alto R1 0000 0000 0000 000,1 0001 0010 0011 0100
  27. ;@ Bajo R0 0101 0110 0111 1000 1001 1010 1011 1100
  28.  
  29. ;@ Invertido:
  30.  
  31. ;@ 0x0000.7AB2.3CD4.5891
  32.  
  33. ;@ Alto R1 0000 0000 0000 000,0 0111 1010 1011 0010
  34. ;@ Bajo R0 0011 1100 1101 010,0 0101 1000 1001 0001
  35.  
  36. ;@ Normal invertido pero cada uno Despues del RBIT:
  37.  
  38. ;@ Alto R1 0010 1100 0100 1000 1000 0000 0000 0000
  39. ;@ Bajo R0 0011 1101 0101 1001 0,001 1110 0110 1010
  40.  
  41. ;@ Shift R1>>15
  42. ;@ Alto R1 0000 0000 0000 000,0 0101 1000 1001 0001

Aunque seguro que si uso un par de Rotate sea mas corto... Ya voy a ver si logro hacerlo mas corto aun. lo que si puedo tener errores en el tema de los desplazamientos. esta complicado dividir todo por parte xD
Ahi utilize el Rotate y quedo mas corto. Sigo teniendo problemas para encontrarle la vuelta a esto de las funciones. No son demasiados claros, ni dan ejemplos ni nada, solo te ponen un pseudocodigo que tenes que adivinar que es.

Código: ASM
  1. Invertir:
  2.         RBIT    R2, R1                  ;@ R2 = Inv(R1)
  3.         RBIT    R0, R0                  ;@ R0 = Inv(R0)
  4.         RORS    R0, R0, #15             ;@ R0 = Inv(R0) >> 15 Wrap
  5.         UBFX    R1, R0, #0 ,#17         ;@ R1f = R0[16:0] = Alto invertido Final
  6.         LSL     R2, R2, #15             ;@ R2 = R2>>15 = R0f[16:0]
  7.         BFI     R0, R2, #0, #17         ;@ R0 = R0f[32:17] + R0f[16:0]
  8.         BX      LR                      ;@ Volver
  9.         .end
  10.  
  11. ;@ Normal
  12.  
  13. ;@ 0x0001.1234.5678.9ABC ->
  14.  
  15. ;@ Alto R1 0000 0000 0000 000,1 0001 0010 0011 0100
  16. ;@ Bajo R0 0101 0110 0111 1000 1001 1010 1011 1100
  17.  
  18. ;@ Invertido:
  19.  
  20. ;@ 0x0000.7AB2.3CD4.5891
  21.  
  22. ;@ Alto R1 0000 0000 0000 0000 0111 1010 1011 0010
  23. ;@ Bajo R0 0011 1100 1101 0100 0101 1000 1001 0001
  24.  
  25. ;@ Normal invertido pero cada uno Despues del RBIT:
  26.  
  27. ;@ Alto R2 0010 1100 0100 1000 1.000 0000 0000 0000
  28. ;@ Bajo R0 0011 1101 0101 1001 0001 1110 0110 1010
  29.  
  30. ;@ ROR R0>>15 = R0[32:17] + R1
  31. ;@ 0011 1100 1101 010.0 0111 1010 1011 0010
  32.  
  33. ;@ UBFX R1, R0, #0, #16
  34. ;@ Alto R1 0000 0000 0000 0000 0111 1010 1011 0010 - Final
  35.  
  36. ;@ LSL  R2, R2, #15
  37. ;@ R2 = 0000 0000 0000 0000 0101 1000 1001 0001

Sorprendentemente logre que compilara bien al instante, que sea correcto eso SI que no tengo ni idea.
Esto de no tener un maldito simulador de ARM lo estoy odiando. Si hay o son para ASM ARM o para micros de 5mil años atras. Y no tengo ganas de instalar QEMU e.e
Título: Re:Assembler en ARM - Probando
Publicado por: Carl47D en 13 de Octubre de 2015, 00:29:40
Lo que queda es simularla en Keil?
En lo que se encuentra algo para el GNU ASM
Título: Re:Assembler en ARM - Probando
Publicado por: KILLERJC en 13 de Octubre de 2015, 01:09:21
Windows XP SP3, Windows Vista or Windows 7

Uff.. adios simulador
Título: Re:Assembler en ARM - Probando
Publicado por: Carl47D en 13 de Octubre de 2015, 01:30:13
Olvide que tienes Ubuntu, igual y el link te sirve, algo viejo (2013) pero es lo unico que encontré, igual y Juanjo puede ayudarte, en resumen usa Wine Keil 4 on Ubuntu (http://invectorindia.blogspot.mx/p/keil-uvision-4-on-ubuntu.html).

O trato de hacer la prueba en el Keil que tengo, nada mas hago funcionar el codigo del delay xD
Me tira este error
Citar
delay.s(1): error: A1137E: Unexpected characters at end of line


EDIT: Son las directivas de Keil, por ejemplo en GNU es .thumb en Keil THUMB, .end en GNU y END en Keil -.-
Título: Re:Assembler en ARM - Probando
Publicado por: KILLERJC en 13 de Octubre de 2015, 02:05:38
Pero a keil lo podes hacer funcionar con GCC, busca "GCC Keil" y ahi te aparece donde tildar para que use el toolchain de GCC
Título: Re:Assembler en ARM - Probando
Publicado por: juaperser1 en 13 de Octubre de 2015, 07:35:31
Keil? IAR? pffff les puse una cruz hace muchisimo tiempo, por ser de terceros, por ser de pago y en el caso de IAR por ser una mierd@

yo probaría con un IDE propio de un micro para ARM, y lo mas seguro es que tenga simulador y debug como en el caso de microchip.

así de primeras y para linux se me ocurre KDS kinetic desing studio, el IDE GNU  GCCgratuito para los micros ARM de freescale, tiene su versión para linux no lo he probado, pero como pienso migrar dentro de no demasiado tiempo (espero) lo tengo en el tintero, espero que tenga emulador.

o si estamos hablando de ARM por que no acudir a la fuente y instalar su IDE el ARM-DS5 la  "Community Edition" es gratuita, y como el KDS basado en GCC y eclipse, y tambien disponible para linux

también estaría bien el de atmel por que como el de KDS lo mantiene la propia empresa y es gratis, pero los estupi... no sacan la versión para linux


un saludo.
Título: Re:Assembler en ARM - Probando
Publicado por: elgarbe en 13 de Octubre de 2015, 09:08:20
No se que tan errado este en el funcionamiento del programa, eso seria para invertir los bits

Código: ASM
  1. .syntax unified
  2.         .thumb
  3.         .text
  4.         .global Invertir
  5.  
  6.  
  7. ;@Funcion ASM que invierte los 49bits de una variable de 64bits
  8. ;@ Entrada R1:R0
  9. ;@ Salida R1:R0 Variable de 64 bits
  10.  
  11. Invertir:
  12.         RBIT    R2, R1                  ;@ R2 = Inv(R1)
  13.         RBIT    R0, R0                  ;@ R0 = Inv(R0)
  14.         LSRS    R2, R2, #15             ;@ R2 = Inv(R1) >> 15
  15.         UBFX    R3, R0, #0 ,#14         ;@ R3 = R0[14:0]
  16.         ADD.W   R3, R2, R3, LSL #17     ;@ R3 = R0[14:0] + Inv(R1)>>15 = Bajo Invertido Final
  17.         LSLS    R1, R0, #15             ;@ R1 = R0[31:15]>>15 = Alto invertido Final
  18.         MOVS    R0, R1                  ;@ R0 = Bajo Invertido Final
  19.         BX      LR                      ;@ Voler
  20.         .end
  21.  
  22. ;@ Normal
  23.  
  24. ;@ 0x0001.1234.5678.9ABC ->
  25.  
  26. ;@ Alto R1 0000 0000 0000 000,1 0001 0010 0011 0100
  27. ;@ Bajo R0 0101 0110 0111 1000 1001 1010 1011 1100
  28.  
  29. ;@ Invertido:
  30.  
  31. ;@ 0x0000.7AB2.3CD4.5891
  32.  
  33. ;@ Alto R1 0000 0000 0000 000,0 0111 1010 1011 0010
  34. ;@ Bajo R0 0011 1100 1101 010,0 0101 1000 1001 0001
  35.  
  36. ;@ Normal invertido pero cada uno Despues del RBIT:
  37.  
  38. ;@ Alto R1 0010 1100 0100 1000 1000 0000 0000 0000
  39. ;@ Bajo R0 0011 1101 0101 1001 0,001 1110 0110 1010
  40.  
  41. ;@ Shift R1>>15
  42. ;@ Alto R1 0000 0000 0000 000,0 0101 1000 1001 0001

Aunque seguro que si uso un par de Rotate sea mas corto... Ya voy a ver si logro hacerlo mas corto aun. lo que si puedo tener errores en el tema de los desplazamientos. esta complicado dividir todo por parte xD
Ahi utilize el Rotate y quedo mas corto. Sigo teniendo problemas para encontrarle la vuelta a esto de las funciones. No son demasiados claros, ni dan ejemplos ni nada, solo te ponen un pseudocodigo que tenes que adivinar que es.

Código: ASM
  1. Invertir:
  2.         RBIT    R2, R1                  ;@ R2 = Inv(R1)
  3.         RBIT    R0, R0                  ;@ R0 = Inv(R0)
  4.         RORS    R0, R0, #15             ;@ R0 = Inv(R0) >> 15 Wrap
  5.         UBFX    R1, R0, #0 ,#17         ;@ R1f = R0[16:0] = Alto invertido Final
  6.         LSL     R2, R2, #15             ;@ R2 = R2>>15 = R0f[16:0]
  7.         BFI     R0, R2, #0, #17         ;@ R0 = R0f[32:17] + R0f[16:0]
  8.         BX      LR                      ;@ Volver
  9.         .end
  10.  
  11. ;@ Normal
  12.  
  13. ;@ 0x0001.1234.5678.9ABC ->
  14.  
  15. ;@ Alto R1 0000 0000 0000 000,1 0001 0010 0011 0100
  16. ;@ Bajo R0 0101 0110 0111 1000 1001 1010 1011 1100
  17.  
  18. ;@ Invertido:
  19.  
  20. ;@ 0x0000.7AB2.3CD4.5891
  21.  
  22. ;@ Alto R1 0000 0000 0000 0000 0111 1010 1011 0010
  23. ;@ Bajo R0 0011 1100 1101 0100 0101 1000 1001 0001
  24.  
  25. ;@ Normal invertido pero cada uno Despues del RBIT:
  26.  
  27. ;@ Alto R2 0010 1100 0100 1000 1.000 0000 0000 0000
  28. ;@ Bajo R0 0011 1101 0101 1001 0001 1110 0110 1010
  29.  
  30. ;@ ROR R0>>15 = R0[32:17] + R1
  31. ;@ 0011 1100 1101 010.0 0111 1010 1011 0010
  32.  
  33. ;@ UBFX R1, R0, #0, #16
  34. ;@ Alto R1 0000 0000 0000 0000 0111 1010 1011 0010 - Final
  35.  
  36. ;@ LSL  R2, R2, #15
  37. ;@ R2 = 0000 0000 0000 0000 0101 1000 1001 0001

Sorprendentemente logre que compilara bien al instante, que sea correcto eso SI que no tengo ni idea.
Esto de no tener un maldito simulador de ARM lo estoy odiando. Si hay o son para ASM ARM o para micros de 5mil años atras. Y no tengo ganas de instalar QEMU e.e

Aaaaaaa, que lindo es el Asembler!!!!
RBIT!!!! (http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0489g/Cihjgdid.html)

a simple vista tiene que funcionar. Lo único es que de los 49 bits solo hay que invertir 48. Los bits 64-49 son siempre 0.
Voy a ver si lo implemento y lo pruebo en el micro.

Saludos!!!!
Título: Re:Assembler en ARM - Probando
Publicado por: elgarbe en 13 de Octubre de 2015, 10:31:10
Probé el segundo código y obtengo:

Código: [Seleccionar]
MC uint64_t 1100101100000000000000000111111111111111111111011 (Binary)
inv uint64_t 1101111111111111111111110000000000000000000000000 (Binary)

el primer código devuelve:

Código: [Seleccionar]
MC uint64_t 1100101100000000000000000111111111111111111111011 (Binary)
inv uint64_t 1111111110000000000000000000000011111111100000000000000000000000 (Binary)

más tarde hago el step by step a ver si encuentro el error.
En el main.c puse:
extern uint64_t Invertir(uint64_t dato);
inv = Invertir(MC);

Saludos!

PD: Como MC es un comando, el bit 49 es un 1. Tener en cuenta que los bits 64-49 no se deben cambiar de posicion  :?
Título: Re:Assembler en ARM - Probando
Publicado por: elgarbe en 13 de Octubre de 2015, 11:43:47
Bueno, estoy con step by step.

Cuando entra a la funcion en ASM tengo en R0 y R1 el dato de entrada. Tambien lo tengo en R2-R3. No sé si eso está bien o no.
en R0 tengo:
00000000 11111111 11111111 11111011
y en R1 tengo
00000000 00000001 10010110 00000000

El resultado del RBIT de R1 puesto en R2 es:
Código: [Seleccionar]
R1: 00000000 00000001 10010110 00000000
R2: 00000000 01101001 10000000 00000000

Luego el RBIT de R0 sobre R0 hace:

Código: [Seleccionar]
R0: 00000000111111111111111111111011
R0: 11011111111111111111111100000000

lo cual es correcto.
la siguiente instruccion, la rotate right obtiene

Código: [Seleccionar]
R0: 11111110 00000001 10111111 11111111

la siguiente instruccion cambia R1 a
Código: [Seleccionar]
R1: 00000000 00000001 10111111 11111111

la siguiente modifica R2 a
Código: [Seleccionar]
R2: 11000000 00000000 00000000 00000000

finalmente R0 se modifica a
Código: [Seleccionar]
R0: 11111110 00000000 00000000 00000000

El resultado es entones R0-R1:
Código: [Seleccionar]
00000000 00000001 10111111 11111111 - 11111110 00000000 00000000 00000000

el dato original era:
00000000 00000001 10010110 00000000 - 00000000 11111111 11111111 11111011

el resultado espera sería:
00000000 00000001 11011111 11111111 - 11111111 00000000 00000000 01101001

o sea que del bit 64 al 49 quedan donde están. Pero del 1 al 48 son rotados. Creo que no me había expresado bien en lo que necesitaba.

Despues de comer voy a ver si me sale corregirlo.
Killer, si lo corriges, por favor esperá a que lo intente yo primero para publicar la respuesta :P

Saludos!
Título: Re:Assembler en ARM - Probando
Publicado por: elgarbe en 13 de Octubre de 2015, 14:09:17
 :-/ :-/ :-/

Prgramé en asembler!!!! jajaja:

Código: ASM
  1. Invertir:
  2.         RBIT    R2, R1                  ;@ R2 = Inv(R1)
  3.         RBIT    R0, R0                  ;@ R0 = Inv(R0)
  4.         RORS    R0, R0, #16             ;@ R0 = Inv(R0) >> 16 Wrap
  5.         BFI     R1, R0, #0 ,#16         ;@ R1f = R0[16:0] = Alto invertido Final
  6.         RORS    R2, R2, #16             ;@ R0 = Inv(R0) >> 16 Wrap
  7.         BFI     R0, R2, #0, #16         ;@ R0 = R0f[32:17] + R0f[16:0]
  8.         BX      LR                      ;@ Volver
  9.         .end

que buenas instrucciones que tienen estos core!!!

ahora quedaría ver cuantos ciclos tarda y comparar con alguna ruina mas o menos optimizada para C para hacer lo mismo. Acá hay algo interesante https://graphics.stanford.edu/~seander/bithacks.html (https://graphics.stanford.edu/~seander/bithacks.html)

Saludos!
Título: Re:Assembler en ARM - Probando
Publicado por: elgarbe en 13 de Octubre de 2015, 14:25:01
Bueno, hice esta implementacion del DWT para contar ciclos de instruccion:

Código: C
  1. extern uint64_t Invertir(uint64_t dato);
  2.  
  3. int main(void)
  4. {
  5.         uint64_t MC=0, invertido = 0;
  6. //      uint8_t i;
  7.  
  8.         /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  9.         HAL_Init();
  10.  
  11.         /* Configure the system clock */
  12.         SystemClock_Config();
  13.  
  14.  
  15.         int count = 0;
  16.         volatile unsigned int *DWT_CYCCNT = (unsigned int *)0xE0001004; //address of the register
  17.         volatile unsigned int *DWT_CONTROL = (unsigned int *)0xE0001000; //address of the register
  18.         volatile unsigned int *SCB_DEMCR = (unsigned int *)0xE000EDFC; //address of the register
  19.  
  20.         *SCB_DEMCR = *SCB_DEMCR | 0x01000000;
  21.         *DWT_CYCCNT = 0; // reset the counter
  22.         *DWT_CONTROL = *DWT_CONTROL | 1 ; // enable the counter
  23.  
  24.  
  25.         GPIO_Init();
  26.         TIM4_Config();
  27.  
  28.         MC |= 0x03 << 00;                               // MC = 11.6-8.1 mA
  29.         MC |= 0x7F << 03;                               //BC Red = 100%
  30.         MC |= 0x7F << 10;                               //BC Green = 100%
  31.         MC |= 0x7F << 17;                               //BC Blue = 100%
  32.                                                                         //SID = 0; LODVLT=0; LSDVLT=0; PSMODE=0 (no PWS)
  33.         MC |= (uint64_t)0x96 << 40;             //WRITE_CMD: Bits 40 a 47 en 10010110b
  34.         MC |= (uint64_t)0x01 << 48;             //Data Select Bit = 1
  35.  
  36.         *DWT_CYCCNT = 0;
  37.         invertido = Invertir(MC);
  38.         count = *DWT_CYCCNT;
  39.  
  40.         send_config(MC);
  41.         send_config(MC);
  42.  
  43.         while(1)
  44.         {
  45.                 efecto_02(500);
  46.         }
  47. }

Pongo un breack point en count = *DWT_CYCCNT; y le doy run. Cuando el programa se detiene, el contenido de  *DWT_CYCCNT es de 37. No estoy contando los ciclos para asignar el  *DWT_CYCCNT a count ya que me deyuve justo ahí.

Saludos!
Título: Re:Assembler en ARM - Probando
Publicado por: KILLERJC en 13 de Octubre de 2015, 18:50:44
Como que tome que habia que invertir los 49 no los 48 :P.
Sabes lo que me rompi la cabeza intentando ver ese bit mas xD,, era un dolor de ....
Bueno, parece que ya lo solucionaste.

Lo que me parece raro son esos 37 ciclos. son demasiados.

Hay 6 instrucciones, de 32bits, no se si tomarlas como 12 ciclos o 6,
Supongamos 12, que luego por el pipeline se introduzca algunas bubbles por necesidad de los datos. eso lo aumentaria a cerca de 3 ciclos mas.
Sigiuiendo tenes el CALL y RETURN ( BL y BX ) eso va a depender exactamente del PC a donde se dirija, si es un salto a registro y no un literal, tomaria 3 ciclos, si es un literal 2 ciclos, si es un salto el cual no esta alineado a 32 bits tomaria 4 ciclos. entonces supongamos:
12 + 3 + 4 = 17 maximo.. incluso haciendo el doble en las instrucciones el cual NO deberia.

Esta bien que no contamos con, la asignacion de la variable a 0, la asignacion de los valores a R0 y R1 y finalmente el salto a la funcion pero no creo que en esto se vayan 20 ciclos :P, Aunque todo depende del nivel de optimizacion, si no posee optimizacion lo creo BASTANTE posible xD, como ya demostre antes el cual sin optimizacion era malisimo, utilizaba de R0 a R3, y estaba continuamente cargando R3 con los datos.

Tenemos antes:, Poner a 0 el valor de DWT_CYCCNT es aun mas, son hasta 5 ciclos para acceder a la memoria flash y tomar el dato de la direccion ( supongo no alineado ) mover 0 a un registro , otro ciclo, almacenar el dato unos 3 ciclos mas.  Mover del SP a R0/R1, 4 ciclos ( si es que no hay un double por ahi ). 13 ciclos ya aca , salto puede ser unos 4, 17ciclos y.... casi casi cerca de los 20 :P

Podrias hacer un par de cambios y probar nuevamente con algo asi?

Código: ASM
  1. .align  4
  2. Invertir:
  3.         RBIT    R0, R0                  ;@ R0 = Inv(R0)
  4.         RBIT    R2, R1                  ;@ R2 = Inv(R1)
  5.         RORS    R0, R0, #16             ;@ R0 = Inv(R0) >> 16 Wrap
  6.         RORS    R2, R2, #16             ;@ R0 = Inv(R0) >> 16 Wrap
  7.         BFI     R1, R0, #0 ,#16         ;@ R1f = R0[16:0] = Alto invertido Final
  8.         BFI     R0, R2, #0, #16         ;@ R0 = R0f[32:17] + R0f[16:0]
  9.         BX      LR                      ;@ Volver
  10.         .end

Lo que hice fue alinearlo a 32bits asi lo que lo llama va mas rapido.
Intente eliminar las dependencias en las entradas de datos.

        RBIT    R0, R0                  ;@ R0 = Inv(R0)
        RORS    R0, R0, #16             ;@ R0 = Inv(R0) >> 16 Wrap

Antes estaba asi, si en el pipeline entraba R0, para luego RORS usar R0 debia esperar que termine la primera instruccion. Por lo cual posiblemente se agregaba un "bubble" en el pipeline, es decir se retrasaba.
Creo que con el cambio de codigo no hay cambios en el funcionamiento y solo queda probarlo si efectivamente mejoro o no , tambien estaria bueno probar si el align cambia en algo o no la cantidad de ciclos.

PD: Todo esto sin contar si es que tu micro tiene un buffe de prefetch el cual un salto podria darle un miss a este buffer y dejar parado el CPU mientras se carga el buffer con el nuevo contenido. Especialmente en un salto. Lo cual te dejaria con el wait state de la flash + hasta que se cargue todo el pipeline xD

Si podes debuegearlo elgarbe, podes ir posicion por posicion. y podes medir exactamente cuanto mide los ciclos internos. Esa es otra

PD2: Esto de no poder probarlo me mata
PD3:

Ahora que son de 16 bits, te puede llegar a servir otra instruccion:

Pack halfword bottom + top
PKHBT Rd, Rn, Rm{, LSL #<sh>}
Rd[15:0] := Rn[15:0], Rd[31:16] := (Rm LSL sh)[31:16]. sh 0-31.

Pack halfword top + bottom
PKHTB Rd, Rn, Rm{, ASR #<sh>}
Rd[31:16] := Rn[31:16], Rd[15:0] := (Rm ASR sh)[15:0]. sh 1-32.

Especialmente si los pones en R2 y R3  a lo temporal y de ahi lo armas a tu gusto ( quedando creo que solo 4 instrucciones xD ), 2 RBIT y 2 Pack de esos, reduciendolo en 2 a lo que estaba.
Cuando vuelva intento ver si lo puedo escribir con esto.
Título: Re:Assembler en ARM - Probando
Publicado por: KILLERJC en 13 de Octubre de 2015, 20:54:23
Código: ASM
  1. Invertir:
  2.         RBIT    R2, R1                  ;@ R2 = Inv(R1)
  3.         RBIT    R3, R0                  ;@ R0 = Inv(R0)
  4.         LSRS    R2, R2, #16             ;@ R2:    00  : R0f[15:0]
  5.         PKHTB   R1, R1, R3, ASR #16     ;@ R1f[31:16]:R1f[15:0] = R1[31:16]:R3[31:16] = R1
  6.         PKHBT   R0, R2, R3, LSL #16     ;@ R0f[31:16]:R0f[15:0] = R3[15:0]:R2[15:0] = R0  (Aca R2 esta luego del Shift, sino hubiera sido [31:16])
  7.         .end

Una sola instruccion menos .... :/, crei que lo podia hacer con 4 pero no pude...
y 3 bytes menos en memoria de programa, por que el LSRS ocupa 16 bytes

Del analisis de el garbe saque esto, y de alli intente realizarla:

Código: [Seleccionar]
original 00000000 00000001 10010110 00000000 - 00000000 11111111 11111111 11111011
final    00000000 00000001 11011111 11111111 - 11111111 00000000 00000000 01101001
R1 R0

Luego de los RBIT

Código: [Seleccionar]
R1: 00000000 00000001 10010110 00000000   @Valor sin invertir
R2: 00000000 01101001 10000000 00000000   @Invertidos
R3: 11011111 11111111 11111111 00000000

R1:       R1f[31:16] :     XX
R2:       R0f[15:0]  :     XX     
R3:       R1f[15:0]  :     R0f[31:16]

Nuevamente, nada probado
Estoy inseguro en el tema del que posee el ASR ya que solo tomaba valores de 1 a 32, mientras que el LSL de 0 a 31 como uno esperaria :P
Título: Re:Assembler en ARM - Probando
Publicado por: Carl47D en 13 de Octubre de 2015, 21:01:02
Ustedes ya fueron y regresaron 3 veces, yo apenas voy.
Gracias a la info de Leonardo sobre el DWT pude testear la funcion de delay en un M3 y me cuenta los 16 ciclos esperados, para los que usen psoc5lp acá dejo el código:

Código: C
  1. #include <project.h>
  2.  
  3. extern void retardo(uint16_t us);
  4.  
  5. int main(){
  6.     CyGlobalIntEnable;
  7.    
  8.     (*(reg32*)CYREG_CORE_DBG_EXC_MON_CTL) |= CoreDebug_DEMCR_VC_CHKERR_Msk; /* CoreDebug_DEMCR_VC_CHKERR_Msk = 0x1000000 */
  9.     (*(reg32*)CYREG_DWT_CTRL) |= DWT_CTRL_CYCCNTENA_Msk; /* DWT_CTRL_CYCCNTENA_Msk = 0x1 */
  10.     (*(reg32*)CYREG_DWT_CYCLE_COUNT) = 0;
  11.     retardo(1);
  12.  
  13.     for(;;){
  14.        
  15.     }
  16. }
  17.  
  18. /* [] END OF FILE */

Y la subrutina:
Código: ASM
  1. .syntax unified
  2.     .text
  3.     .global retardo
  4.     .func retardo, retardo
  5.     .thumb_func
  6. retardo:
  7.     SUBS    r0, #1
  8.     NOP
  9.     NOP
  10.     NOP
  11.     NOP
  12.     NOP
  13.     NOP
  14.     NOP
  15.     NOP
  16.     NOP
  17.     NOP
  18.     NOP
  19.     BNE.N   retardo
  20.     BX      lr
  21.     .endfunc
  22.  
  23.     .end
  24.  
  25. /* [] END OF FILE */
Título: Re:Assembler en ARM - Probando
Publicado por: KILLERJC en 14 de Octubre de 2015, 00:12:09
Citar
Gracias a la info de Leonardo sobre el DWT pude testear la funcion de delay en un M3 y me cuenta los 16 ciclos esperados, para los que usen psoc5lp acá dejo el código:

Probalo con 2 y vas a tener 33 o 34, cada 1 mas que agregues le va a sumar 1 ciclo :P
Imagino, solo resta probar, xD hace varias instrucciones/funciones de una sola ves. Asi no grabas 100 veces el micro :P

EDIT: Habria que ver cuanto tarda el salir y entrar a la funcion.
De realizarse el salto podrias hacer:
Código: ASM
  1. retardo:
  2.     NOP
  3. 1: SUBS    r0, #1
  4.     NOP
  5.     NOP
  6.     NOP
  7.     NOP
  8.     NOP
  9.     NOP
  10.     NOP
  11.     NOP
  12.     NOP
  13.     NOP
  14.     BNE.N   1b
  15.     BX      lr

Asi, si se produce el salto, se realiza un NOP menos, al menos el bucle ahora tendria la misma cantidad de instrucciones si es que entra o no dentro del salto.

Ahora tenes que el bucle es fijo. Pero las instrucciones de entrada y salida son fijos. asi que seria

instrucciones de entrada,salida + N * bucle

Con lo cual seguro que no es un multiplo exacto de 16 xD, Para 1 si, pero para los demas no :/
Título: Re:Assembler en ARM - Probando
Publicado por: elgarbe en 14 de Octubre de 2015, 09:10:49
Lo que me parece raro son esos 37 ciclos. son demasiados.

Hay 6 instrucciones, de 32bits, no se si tomarlas como 12 ciclos o 6,
Supongamos 12, que luego por el pipeline se introduzca algunas bubbles por necesidad de los datos. eso lo aumentaria a cerca de 3 ciclos mas.
Sigiuiendo tenes el CALL y RETURN ( BL y BX ) eso va a depender exactamente del PC a donde se dirija, si es un salto a registro y no un literal, tomaria 3 ciclos, si es un literal 2 ciclos, si es un salto el cual no esta alineado a 32 bits tomaria 4 ciclos. entonces supongamos:
12 + 3 + 4 = 17 maximo.. incluso haciendo el doble en las instrucciones el cual NO deberia.

Ahí probé. El tema es donde pongo el break point.
Código: C
  1. *DWT_CYCCNT = 0;
  2.         invertido = Invertir(MC);
  3.         count = *DWT_CYCCNT;
Si lo pongo en Invertido=Invertir.... y hago el paso a paso, le lleva 5 ciclos para entrar a la funcion, luego 6 ciclos por las 6 instrucciones y 5 más para volver. Total 16 ciclos.
Pero si pongo el break en count=.... entonces me cuenta 37 ciclos...

Luego hice esto:

Código: C
  1. *DWT_CYCCNT = 0;
  2.         invertido = Invertir(MC);
  3.         count = *DWT_CYCCNT;
  4.  
  5.         *DWT_CYCCNT = 0;
  6.         invertido = Invertir(MC);
  7.         count = *DWT_CYCCNT;
  8.  
  9.         *DWT_CYCCNT = 0;
  10.         invertido = Invertir(MC);
  11.         count = *DWT_CYCCNT;

y puse break point en cada count=... El primero me arroja 37, el segundo 19 y el tercero 19. (siempre antes de ejecutar la instruccion count=*DWT....) El resultado lo veo en el visor de variables de Eclipse...

Saludos!
Título: Re:Assembler en ARM - Probando
Publicado por: elgarbe en 14 de Octubre de 2015, 09:15:58
Código: ASM
  1. Invertir:
  2.         RBIT    R2, R1                  ;@ R2 = Inv(R1)
  3.         RBIT    R3, R0                  ;@ R0 = Inv(R0)
  4.         LSRS    R2, R2, #16             ;@ R2:    00  : R0f[15:0]
  5.         PKHTB   R1, R1, R3, ASR #16     ;@ R1f[31:16]:R1f[15:0] = R1[31:16]:R3[31:16] = R1
  6.         PKHBT   R0, R2, R3, LSL #16     ;@ R0f[31:16]:R0f[15:0] = R3[15:0]:R2[15:0] = R0  (Aca R2 esta luego del Shift, sino hubiera sido [31:16])
  7.         .end

Una sola instruccion menos .... :/, crei que lo podia hacer con 4 pero no pude...
y 3 bytes menos en memoria de programa, por que el LSRS ocupa 16 bytes

Falta el BX      lr al final.

15 hermosos ciclos, jeje. Funciona de 10!!!
Título: Re:Assembler en ARM - Probando
Publicado por: KILLERJC en 14 de Octubre de 2015, 14:51:29
Me olvide del BX :P

Y lo feo es que usas el salto... si no fuera por el salto invertir los bits no seria nada que ocupe tiempo ( 5 ciclos ) el tema es como agregar esto a C sin salto xD. ademas que justo los datos esten en R0/R1.
Se podria intentar un codigo en C que haga lo mismo y comprarar el ASM generado, si es que vale la pena. pero no veo nada que haga una inversion de bits en C :/

O directamente construir lo que pasa del primer buffer al de video en ASM, que es donde se usaria la inversion. Lo feo que esto es solamente valido para un M3/M4
Título: Re:Assembler en ARM - Probando
Publicado por: elgarbe en 14 de Octubre de 2015, 15:24:26
No creo que en C se pueda hacer nada similar:

http://stackoverflow.com/questions/746171/best-algorithm-for-bit-reversal-from-msb-lsb-to-lsb-msb-in-c (http://stackoverflow.com/questions/746171/best-algorithm-for-bit-reversal-from-msb-lsb-to-lsb-msb-in-c)
https://graphics.stanford.edu/~seander/bithacks.html#BitReverseObvious (https://graphics.stanford.edu/~seander/bithacks.html#BitReverseObvious)

acá hay una integracion interesante de C y ASM:

http://stackoverflow.com/questions/20436466/lsb-to-msb-bit-reversal-on-arm (http://stackoverflow.com/questions/20436466/lsb-to-msb-bit-reversal-on-arm) ver la última respuesta.

Si, eso estaría bueno, hacer la rutina de conversion del buffer de video al buffer de salida en ASM aprovechando las instrucciones de manipulacion de bits/bytes/...

L oque tengo que definir es con qué micro voy a trabajar... Porque los candidatos son el stm32f411 (M4F) muy sobrado, pero es con lo que estoy trabajando en este momento (despues les cuento un error en las librerías HAL que me tuvieron 2 días renegando con el SPI  :5] en otro proyecto) o con el LPC11u67 (M0+) el cual es más acorde. Estimo que voy a volver para este proyecto a NXP...

saludos!
Título: Re:Assembler en ARM - Probando
Publicado por: KILLERJC en 14 de Octubre de 2015, 16:08:16
El M0 no tiene RBIT :P
Es mas no tiene ninguna instruccion para invertir los bits xD, asi que a mano xD
Título: Re:Assembler en ARM - Probando
Publicado por: juaperser1 en 14 de Octubre de 2015, 16:23:53
Citar
(despues les cuento un error en las librerías HAL que me tuvieron 2 días renegando con el SPI  :5] en otro proyecto)

MUERTE A ST!!!!!  :D :D :D otro que no quiero ni regalado como PIC32 :D :D

yo sigo pensando que la idea de una matriz de 3 dimensiones es buena, es lo que se utiliza para definir toda la gama de colores.


un saludo
Título: Re:Assembler en ARM - Probando
Publicado por: elgarbe en 15 de Octubre de 2015, 09:48:09
MUERTE A ST!!!!!  :D :D :D otro que no quiero ni regalado como PIC32 :D :D

Si, muerte a ST!!!! pero lamentablemente soy víctima de sus super bajos precios y tengo un monton de placas de evaluacion  :?
Les comento rapido, estoy comunicando un f411 con un ads1299 (un front end de TI para EEG) por el SPI. Es una comunicacion donde el micro manda comandos y el ads responde con datos, registros etc. El tema es que st tiene 3 funciones SPI_Transmit, SPI_Receive y SPI_TransmitReceive. Cuando quiero enviar un comando uso SPI_Transmit y todo de 10. Pero cuando quería recivir los datos del ADS ponía SPI_Receive y la cosa andaba de a ratos. Fallos aleatorios. Por ahí andaba bien unas lecturas y luego no andaba más (andar significa que el ADS me ponga la señal DRY a 0 cada x mseg para que yo pida los datos)... En fin, con un oscilloscopio de 4 canales veía CLK, DRDY, CS y MOSI cuando transmitía y MISO cuando recivía... en un momento, cuando ya no podía probar más nada por software (el transmit andaba bien, ya que podia configurar los registros sin problemas y leer 1 solo dato tmb andaba bien) decidí ver CLK, DRDY, MOSI y MISO a la vez. Cuando DRDY se iba a 0 veía que en MISO tenía datos llegando desde el ADS, pero había datos tambien saliendo por el MOSI del micro!! WTF!
Me voy como un rayo  a la implementacion del SPI_Receive y me encuentro que para poder recivir llaman a SPI_Transmit_Receive (evidentemente para que se generen los pulsos de clk tienen que hacer uso de la transmision. Pero bueno eso no sería nada, el proble es que los hijos de mil en vez de transmitir 0's transmiten datos!!!!!

Código: C
  1. /**
  2.   * @brief  Receive an amount of data in blocking mode
  3.   * @param  hspi: pointer to a SPI_HandleTypeDef structure that contains
  4.   *                the configuration information for SPI module.
  5.   * @param  pData: pointer to data buffer
  6.   * @param  Size: amount of data to be sent
  7.   * @param  Timeout: Timeout duration
  8.   * @retval HAL status
  9.   */
  10. HAL_StatusTypeDef HAL_SPI_Receive(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout)
  11. ....
  12. ....
  13. ....
  14.     if((hspi->Init.Mode == SPI_MODE_MASTER) && (hspi->Init.Direction == SPI_DIRECTION_2LINES))
  15.     {
  16.       /* Process Unlocked */
  17.       __HAL_UNLOCK(hspi);
  18.  
  19.       /* Call transmit-receive function to send Dummy data on Tx line and generate clock on CLK line */
  20.       return HAL_SPI_TransmitReceive(hspi, [color=red]pData[/color], pData, Size, Timeout);
  21.     }

En la hoja de datos del ADS pide que la linea DIN este en cero cuando el ADS está enviando datos.... Mi pregunta es, porque no mandan 0's!!!! y te aseguras que no vas a interferir con algunos integrados como estos?

saludos
Título: Re:Assembler en ARM - Probando
Publicado por: juaperser1 en 15 de Octubre de 2015, 10:19:49
Mandan datos?? Y eso para que?
Si al final no te puedes fiar ni de las librerías de los fabricantes, muchas veces son una pesadilla mas que una ayuda. :?
Cada vez que veo una librería de comunicación esperando datos con while, como pasa en microchip se me revuelve el estomago.
Vete a saber si no mandan datos por algún fallo del silicio y han intentado que funcione de esa manera.
Un saludo
Título: Re:Assembler en ARM - Probando
Publicado por: KILLERJC en 16 de Octubre de 2015, 07:33:04
En el TIVAWare (TI ), posee tambien unos cuantos comandos para el tema del SPI. al principio me resulto un poco complejo entenderlo xD por que uno estaria acostumbrado a eso, como se manejan las HAL, a enviar y recibir, Lo que yo veo que ahi en las HAL de ST estan usando los mismos datos del buffer que estas usando para recibir.

Para juanjo que le gusta tanto los while

Código: C
  1. void
  2. SSIDataPut(uint32_t ui32Base, uint32_t ui32Data)
  3. {
  4.     //
  5.     // Check the arguments.
  6.     //
  7.     ASSERT(_SSIBaseValid(ui32Base));
  8.     ASSERT((ui32Data & (0xfffffffe << (HWREG(ui32Base + SSI_O_CR0) &
  9.                                        SSI_CR0_DSS_M))) == 0);
  10.  
  11.     //
  12.     // Wait until there is space.
  13.     //
  14.     while(!(HWREG(ui32Base + SSI_O_SR) & SSI_SR_TNF))
  15.     {
  16.     }
  17.  
  18.     //
  19.     // Write the data to the SSI.
  20.     //
  21.     HWREG(ui32Base + SSI_O_DR) = ui32Data;
  22. }

No te enojes juanjo, tambien hay funciones que no son bloqueantes :P y hacen lo mismo
Lo que si, no hay una funcion de "Enviar" y "Recibir" el DataPut sirve para enviar en su forma bloqueante o no. El DataGet simplemente lee la FIFO nada mas, asi que si tu idea es leer sos vos el que mandas un 0. Y no se asume que debes enviar un 0 o lo que sea. Como que un poco costo entender esto en mi cabeza, uno espera que poner un DataGet y recibiste.

Código: C
  1. SSIDataPut(SSI_BASE,Data);
  2.         SSIDataPut(SSI_BASE,0x00);
  3.         SSIAdvDataPutFrameEnd(SSI2_BASE, 0x00);  //Esto es genial puedo controlar el CS/FSS a mi gusto!
  4.         SSIDataGet(SSI_BASE,&valor[0]); //dummy read para el primer write (generado por el "data"
  5.         SSIDataGet(SSI_BASE,&valor[0]);
  6.         SSIDataGet(SSI_BASE,&valor[1]);

Con lo cual cuando hice el driver para el Touch quedo asi. Tenia que enviar el dato, y luego recibir 16bits sin que el CS subiera, desde que escribia hasta que leia. Si ven ahi Envio los datos + 2 bytes con 0x00 a la FIFO , y luego debo leerlos.

Hay una parte fea que es la de tener que leer los datos cuando uno escribe, y que por ahi no te sirven ( especialmente en el primer dato, como se ve ) Pero eso imagino que te da la mayor flexibilidad para hacer lo que sea. Hasta ahora no tuve problemas con las librerias de TI, son todas muy basicas, funciones super simples que cargan valores a los registros directamente, incluso tienen un Macro ( HW_REG ) para acceder a la direccion que apuntan. Creo que es lo mejor poder verlo asi.
Título: Re:Assembler en ARM - Probando
Publicado por: juaperser1 en 16 de Octubre de 2015, 12:21:07
Citar
No te enojes juanjo, tambien hay funciones que no son bloqueantes :P y hacen lo mismo
Lo que si, no hay una funcion de "Enviar" y "Recibir" el DataPut sirve para enviar en su forma bloqueante o no. 

Se que hay funciones con while bien escritas, pero te invito a que le heches un vistazo a las de i2c para pic32 :D y te reto a que intentes quitarle el while, lo dejes por pulling y que funcione en un pic32mx de la serie 2.

 :D :D

Título: Re:Assembler en ARM - Probando
Publicado por: Carl47D en 24 de Octubre de 2015, 17:39:00
Que tal,
vengo con otro error n00b, estaba tratando de correr unas instrucciones simples en el cortex-m0 que tengo, la funcion es re simple, esta en formato UAL.

Código: ASM
  1. .syntax unified
  2.     .text
  3.     .global rotate
  4.     .func rotate, rotate
  5.     .thumb_func
  6. rotate:
  7.     RORS r0, r0, #3
  8.     BX lr
  9.     .endfunc
  10.  
  11.     .end
  12.  
  13. /* [] END OF FILE */

ni siquiera la puedo compilar, me tira este error:
Citar
Build error: cannot honor width suffix -- `rors r0,r0,#3'

Buscando en internet solo encontre esto:
arm-assembly-cannot-use-immediate-values-and-adds-adcs-together (http://stackoverflow.com/questions/30980160/arm-assembly-cannot-use-immediate-values-and-adds-adcs-together)

Cambie el RORS por un MOV r1, #3 y nada, ni eso compila xD
Alguna idea de porque me marca dicho error?
Título: Re:Assembler en ARM - Probando
Publicado por: Carl47D en 24 de Octubre de 2015, 20:54:24
Ya está, el problema era yo que no se leer  :mrgreen:, RORS no acepta valores inmediatos como operando, tenia que guardar el número en un registro y usar ese registro después, asi termino la función (no es nada util, solo rota el byte en r0 2 posiciones en este caso):

Código: ASM
  1. .syntax unified
  2.     .text
  3.     .func rotate, rotate
  4.     .thumb_func
  5.     .global rotate
  6. rotate:
  7.     MOVS r4, #2
  8.     RORS r0, r0, r4
  9.     BX lr
  10.     .endfunc
  11.  
  12.     .end
  13.  
  14. /* [] END OF FILE */

La llamada desde el main en c:
Código: C
  1. extern void rotate(uint8_t r);
  2.  
  3. int main(){    
  4.    
  5.     rotate(0x08);
  6.    
  7.     for(;;){
  8.     }
Título: Re:Assembler en ARM - Probando
Publicado por: KILLERJC en 24 de Octubre de 2015, 21:27:43
es jodido no tener Thumb-2... Como en ese caso, yo llegue tarde para la respuesta xD.
Título: Re:Assembler en ARM - Probando
Publicado por: Carl47D en 24 de Octubre de 2015, 21:41:45
Los M0 y M0+ solo tienen estas de Thumb-2 :/
Código: ASM
  1. BL
  2. DSB
  3. DMB
  4. ISB
  5. MRS
  6. MSR

Creo solo los ARMv7M tienen todo el set de Thumb-2, eso indica la M del final.

Encontré una página más de ASM de ARM: ARM: Intro to ASM (http://www.davespace.co.uk/arm/introduction-to-arm/)
y otra de GCC ASM Inline (http://www.ethernut.de/en/documents/arm-inline-asm.html)

Título: Re:Assembler en ARM - Probando
Publicado por: KILLERJC en 24 de Octubre de 2015, 22:10:28
Si solo tienen el BL , los data/memory barrier y las instrucciones de carga/guardar en registros especiales de la CPU, nada mas.

la M no se que indica, imagino que lo de Cortex-M

ya que el Cortex-M0+ es ARMv6M
Título: Re:Assembler en ARM - Probando
Publicado por: Carl47D en 25 de Octubre de 2015, 03:52:44
Encontré una tabla, pero solo aplica para procesadores "viejos", los procesadores clasicos tienen la forma ARM{x}{y}{z}{labels}, desde 2004, todos los nucles ARM han salido bajo la "marca" Cortex y tienen la forma Cortex-{x}{y}.

xyzDescriptionExample
7ARM7 core VersionARM7
9ARM9 core VersionARM9
10ARM10 core VersionARM10
11ARM11 core VersionARM11
1Cache, write buffer and MMUARM710
2Cache, write buffer and MMU, Process ID supportARM920
3Physically mapped cache and MPUARM1136
4Cache, write buffer and MPUARM940
5Cache, write buffer and MPU, error correcting memoryARM1156
6No cache, write bufferARM966
7AXI bus, physically mapped cache and MPUARM1176
0Standard cache sizeARM920
2Reduced cacheARM1022
6Tightly Coupled MemoryARM1156
8As for ARM966ARM968

Labels:
AttributeDescription
DSupports debugging via the JTAG interface. Automatic for ARMv5 and above
ESupports Enhanced DSP instructions. Automatic for ARMv6 and above
FSupports hardware floating point via the VFP coprocessor
ISupports hardware breakpoints and watchpoints. Automatic for ARMv5 and above
JSupports the Jazelle Java acceleration technology
MSupports long multiply instructions. Automatic for ARMv5 and above
TSupports Thumb instruction set. Automatic for ARMv5 and above
-SThis processor uses a synthesizable hardware design

y al final dice:
Citar
Differences between ARM7 and ARMv7
This is a common question — and a common mistake. There is no comparison possible; the ARM7 is a core, whereas ARMv7 is an architecture.

Para nuevo nucleos la convencion de nombres es diferente y mas facil de seguir:
Citar
The Cortex-A family is the computer family; the Application processors.
The Cortex-R family is the fast reacting family, the Real-time processor series.
The Cortex-M family is the ultra-low-powered, small form-factor family, the Micro-controller series.

Entonces la M es por que pertenecen a la serie de Microcontroladores.
Título: Re:Assembler en ARM - Probando
Publicado por: KILLERJC en 25 de Octubre de 2015, 07:21:31
Buena info, los ultimos 2 si lo sabia pero no queria arriesgarme a decir que la M era exactamente por eso jeje, no estaba 100% seguro.
Pero la nomeclatura de las antiguas arquitecturas no, ahora anda a recordar cuales el 1/2/3/4 de cada columna :P y encima luego las letras