viernes, 8 de abril de 2011

MSP430. Ciclos e Instrucciones

You also can read this text in English! MSP430: Clock Cycles & Instructions

Cuando estamos trabajando con microcontroladores o sistemas programables uno de los aspectos que debemos tener muy en cuenta es el tiempo que consume nuestro programa, función o trozo de código.

¿Por qué es importante? Por muchas razones, por ejemplo: Sincronización con algún dispositivo externo, manejo de un bus (I2C, SPI, 1-Wire, etc) y por qué no poner una situación real: En cualquier sistema de supervisión de seguridad debemos tener cuantificado el tiempo que debe transcurrir desde que ocurre la incidencia hasta que se tramita la misma.

También es un buen distintivo para saber cuando estamos enfrente de un buen diseñador, para una misma tarea, el programa óptimo será el que consuma menos recursos (y por ende, menos ciclos de reloj). Lo que pasa que en estos tiempos, los fabricantes de microcontroladores cada vez dotan de más memoria a sus dispositivos y mejoran la estructura de la CPU, y esto hace que cada vez sea más habitual programar en lenguajes de medio-alto nivel, cómo es el caso del lenguaje C.

Y nosotros, también programaremos en C ya que esta familia está dotada para tal función, pero a mí, personalmente me gusta siempre verificar la traducción que realiza el compilador a código ensamblador. No me voy a extender con más preámbulos y vamos a ir directamente al grano.

En nuestro caso, el tipo de estructura de nuestra familia de microcontroladores es del tipo Von Neumann, esto hace un poco peculiar la medida de ciclos que consume las instrucciones. Una cosa tenemos que tener clara: El número de ciclos por instrucción depende del formato de la instrucción y del modo de direccionamiento empleado.

Esto es muy importante ya que el número de ciclos no depende de la instrucción en sí. A continuación se mostrarán el número de ciclos que se necesitan para el tipo de acción que queramos realizar.

Número de Ciclos en Interrupciones y Reset.

Nº Ciclos para Interrupciones & Reset
AcciónNº Ciclos
Longitud
RETI51
Interrupción Aceptada
6
---
WDT Reset
4
---
Reset (#RST/NMI)
4
---

· NOTA: En este caso, se sigue la nomenclatura #RST para indicar señal negada.

Operandos Simples. Format-II.

Nº Ciclos para Operandos Simples

Nº Ciclos

Modo Direccionamiento
RRA, RRC, SWPB, SXT
PUSHCALL
Longitud
Ejemplo
Rn13
4
1
SWPB R5
@Rn
3
4
4
1
RRC @R9
@Rn+
3
5
5
1
SWPB @R10+
#N
No Usar
4
5
2
CALL #0F000h
x(Rn)
4
5
5
2
CALL 2(R7)
EDE
4
5
5
2
PUSH EDE
&EDE
4
5
5
2
SXT &EDE

Saltos. Format-III.

Todas las instrucciones que sean de salto su longitud es 1 (tipo palabra) y consume 2 ciclos de reloj siempre.

Operandos Dobles. Format-I.

Nº Ciclos para Operandos Dobles
Modo Direccionamiento

Fuente
Destino
Nº de Ciclos
Longitud
Ejemplo
RnRm11
MOV R5, R8
PC21
BR R9
x(Rm)
42
ADD R5, 4(R6)
EDE
42
XOR R8 ,EDE
&EDE
4
2
MOV R5, &EDE
@RnRm21
AND @R4, R5
PC21
BR @R8
x(Rm)
52
XOR @R5, 8(R6)
EDE
52
MOV @R5, EDE
&EDE
5
2
XOR @R5, &EDE
@Rn+Rm21
ADD @R5+, R6
PC31
BR @R9+
x(Rm)
52
XOR @R5, 8(R6)
EDE
52
MOV @R9+, EDE
&EDE
5
2
MOV @R9+, &EDE
#N
Rm22
MOV #20, R9
PC32
BR #2AEh
x(Rm)
53
MOV #0300h, 0(SP)
EDE
53
ADD #33, EDE
&EDE
5
3
ADD #33, &EDE
x(Rn)Rm32
MOV 2(R5), R7
PC32
BR 2(R6)
TONI
63
MOV 4(R7) ,TONI
x(Rm)63
ADD 4(R4), 6(R9)
TONI
6
3
MOV 2(R4), &TONI
EDERm32
AND EDE, R6
PC32
BR EDE
TONI
63
CMP EDE, TONI
x(Rm)63
MOV EDE, 0(SP)
TONI
6
3
MOV EDE,&TONI
&EDERm32
MOV &EDE,R8
PC32
BRA &EDE
TONI
63
MOV &EDE, TONI
x(Rm)63
MOV &EDE, 0(SP)
&TONI
6
3
MOV &EDE, &TONI


Bueno, llegados a este punto podemos calcular los ciclos de reloj que consumirá cada instrucción que escribamos para confeccionar nuestro programa o trozo de código. Pero la cosa no queda aquí, la gente de Texas Instruments han dotado a sus microcontroladores lo que ellos llaman: Registros de Generador de Constantes, por sus siglas CGx (dónde x indica el registro de generador de constante determinado, para nuestra familia existen dos: CG1 y CG2).

Valores de los CGx
RegistroIdentificador
ConstanteObservaciones
R200---Modo Registro
R2
01
(0)
Modo Direccionamiento Absoluto
R2
10
00004h
+4, Procesamiento de bit
R2
11
00008h
+8, Procesamiento de bit
R3
00
00000h
+0, Procesamiento de bit
R3
01
00001h
+1
R3
10
00002h
+2, Procesamiento de bit
R3
11
0FFFFh
1, Procesamiento de palabra

Bueno, una vez presentados los CGx vamos a intentar contestar algunas preguntas sobre ellos y por qué son importantes a la hora de calcular los ciclos de reloj de nuestro código.

· ¿Por qué son importantes? Pues básicamente porque nos ahorra ciclos de reloj. Y lo hacen de manera automática, es decir, si escribimos en ensamblador, el compilador buscará las constantes y usará de manera automática los CGx oportunos.

· ¿Qué dices? ¡No entiendo nada! Tranquilo, te lo explico con un ejemplo. Imagina que tienes un LED conectado en P1.1 y quieres cambiarlo de estado (es decir: apagarlo y encenderlo), pondrías el siguiente código para tal fin:

bic.b.....#002h, &P1OUT
bis.b.....#002h, &P1OUT

Y si queremos calcular el número de ciclos que consume cada instrucción nos vamos a las tablas anteriores, concretamente al apartado Formato-I Doble Operando y debemos fijarnos en el modo inmediato: #N. Y dentro de dicho modo, el que nos compete es el modo &EDE.

Bien, podemos comprobar que el número de ciclos de reloj necesarios son 5. ¿Son realmente 5 ciclos? Pues si lo simulamos o lo comprobamos directamente con un osciloscopio (por ejemplo), veremos que el consumo real por cada instrucción es de 4 ciclos.

¿Qué es lo que está pasando? ¿El manual está mal? No, sólo que ha entrado en juego nuestros amigos CGx, si observamos con atención la tabla de los CGx vemos que la constante 002h está recogido por CG2, ¿y esto que significa? Pues digamos que nuestro compilador lo interpreta y codifica de la siguiente manera:

mov.b.....R3, &P1OUT

Entonces si volvemos a irnos a la tabla de consumo de ciclos de reloj, esta vez tenemos que prestar atención al modo registro Rn y dentro del mismo, al modo &EDE y voilà, ahí tenemos los 4 ciclos de reloj que realmente consume la instrucción que hemos expuesto.

Y así sería si empleamos cualquiera de las seis constantes que aparecen en la tabla de CGx. La instrucción se interpretaría de manera que la fuente es empleada como modo inmediato.

Pero esto no termina aquí (ya queda poco no desesperes), disponemos en ensamblador de 24 instrucciones adicionales que se denominan: Emuladas. Por ejemplo, las instrucciones de un único operando:

clr.....dst

Esta instrucción pone a cero el registro contenido en destino, ¿y cuántos ciclos de reloj consume? Pues al manejar el valor 0000h si volvemos a revisar la tabla de los CGx, vemos que está contemplado en el registro R3, por lo tanto, vuelven a entrar en juego nuestros amigos los CGx, en este ejemplo concreto se interpretaría la instrucción como se muestra a continuación:

mov.....R3, dst

¿Y para la instrucción incremento? Si, esta que te pongo a continuación:

inc.....dst

Pues lo mismo, al contener la constante 00001h, vuelven a entrar en juego nuestros amigos los CGx interpretando la instrucción de la siguiente manera:

add.....0(R3), dst

En fin, teniendo en cuenta los CGx, no tendremos problemas en determinar cuántos ciclos de reloj consumen nuestros programas y por ende, el tiempo de ejecución. Este punto es algo que no me ha gustado de los amigos de Texas Instruments, ya que si nos vamos directamente al data sheet al consultar sobre el consumo de ciclos de reloj, no hace mención a nuestros amigos los CGx, y eso es una faena de las grandes.

Ya que podemos andar como locos comprobando y contando una y otra vez los ciclos que no nos cuadran... Es por ello y de vital importancia en estos casos, que le dediquemos una lectura a la hoja de características antes de entrar en materia para ahorrarnos neuronas.

0 comentarios: