Assembler - Departamento de Electrónica

Anuncio
UNIVERSIDAD TECNICA FEDERICO SANTA MARIA
DEPARTAMENTO DE ELECTRONICA
Assembler MSP430
Interfaz C-Assembler.
Código de arranque:
Se compila el siguiente programa:
void main(void)
{
;
}
La memoria flash de 60 KB se inicia en 0x01100.
Los vectores de interrupción, están en la zona alta de la memoria flash, desde 0xFFE0 hasta
0xFFFF. Cuando se le da energía al controlador, o se genera una señal de reset externo, se
coloca en PC la dirección almacenada en el vector asociado a RESET (0x0FFFE).
La RAM, de 2 KB, ocupa desde: 0x0200 hasta 0x09FF.
El stack se inicia en el tope de la RAM+2; es decir en 0x0A00. De este modo al efectuar
un llamado a subrutina, se decrementa en 2 el valor almacenado en el stack, y se deposita la
dirección de PC de retorno en el tope del stack. En el caso de rutinas de servicio de
interrupción además de empujar la dirección de retorno, se almacena el valor del registro de
estado del controlador (SR).
El código de autoarranque del compilador IAR: setea el stack, el vector de interrupción
para reset, y define el la rutina exit, cuya finalidad es detener la ejecución de instrucciones
después de ejecutada la rutina principal. En este caso simple, el programa principal es
traducido a la instrucción de máquina ret.
#include "msp430x14x.h"
;-----------------------------------------------------------------------------ORG
01100h
; Programa en Flash
;-----------------------------------------------------------------------------RESET:
mov.w
#0A00h, SP
; Inicia stackpointer
call
#main
call
#exit
_exit:
br
#__exit
__exit
jmp
#__exit
main:
ret
exit:
br
Prof. Leopoldo Silva Bijit.
#_exit
;
23-02-2004
1
UNIVERSIDAD TECNICA FEDERICO SANTA MARIA
DEPARTAMENTO DE ELECTRONICA
Assembler MSP430
;-----------------------------------------------------------------------------;
Vector de interrupción asociado a Reset
;-----------------------------------------------------------------------------ORG 0FFFEh
; MSP430 RESET Vector
DW RESET
;
END
Variables locales en registros.
El siguiente programa define una variable local dentro de la función main:
void main(void)
{
int i1=2;
i1+=1;
}
Se dispone de 12 registros, comienzan a usarse desde el número 15.
Se ilustra ahora sólo el código assembler de main:
main:
MOV.W
ADD.W
RET
#0x2, R15
#0x1, R15
; i1=R15 = 2
; i1+=1;
El símbolo # indica direccionamiento inmediato
Uso de registros para variables locales.
Si se definen dos variables, se ocupan el R15 para i1, y el registro R14 para i2.
void main(void)
{
int i1=2, i2=-1;
i1+=1; i2-=1;
}
Se traduce a:
main:
MOV.W
MOV.W
ADD.W
ADD.W
RET
Prof. Leopoldo Silva Bijit.
#0x2, R15
#0xffff, R14
#0x1, R15
#0xffff, R14
; i1 = R15 = 2
; i2 = R14 = -1;
; i1+=1
; i2-=1
23-02-2004
2
UNIVERSIDAD TECNICA FEDERICO SANTA MARIA
DEPARTAMENTO DE ELECTRONICA
Assembler MSP430
Empleo de registros temporales.
Si se siguen empleando registros vemos que el R10 y el R11 son preservados. Y que
emplea el R11 como temporal. Como se verá el compilador salva el contenido de los
registros R4 a R11. Los registros R12 a R15 no son salvados.
void main(void)
{
int i1=-1;
int i2=0;
int i3=1;
int i4 = 5+1;
int i5=1<<5;
i1+=1; i2-=1; i3=i1+i2+i4; i4=i3 | i2; i5=i5+2*3*4;
}
Para evitar warnings por definir variables que no se empleen, las variables se leen y
escriben.
main:
PUSH.W
PUSH.W
MOV.W
MOV.W
MOV.W
MOV.W
MOV.W
ADD.W
ADD.W
MOV.W
ADD.W
ADD.W
MOV.W
MOV.W
BIS.W
MOV.W
ADD.W
POP.W
POP.W
RET
Prof. Leopoldo Silva Bijit.
R10
R11
#0xffff, R15
#0x0, R14
#0x1, R12
#0x6, R13
#0x20, R10
#0x1, R15
#0xffff, R14
R15, R11
R14, R11
R13, R11
R11, R12
R12, R11
R14, R11
R11, R13
#0x18, R10
R11
R10
;se salvan registros
; i1 = R15 = -1
; i2 = R14 = 0;
; i3 = R12 = 1;
; i4 = R13 = 5+1 = 6
; i5 = R10 = 1<<5 = 32 = 0x20
; i1+=1
; i2-=1
; R11 se emplea como temporal.
; i3=i1+i2+i4
; i4=i3 | i2
; i5=i5+2*3*4;
23-02-2004
3
UNIVERSIDAD TECNICA FEDERICO SANTA MARIA
DEPARTAMENTO DE ELECTRONICA
Assembler MSP430
Variables locales en el frame.
Cuando el número de locales es mayor que los registros disponibles, se almacenan en el
frame de la función. Se emplean registros temporales para la compilación de expresiones
que requieren almacenamientos intermedios.
void main(void)
{ int i1 = 1, i2 = 2, i3 = 3, i4 = 4;
int i5 = 5, i6 = 6, i7 = 7, i8 = 8;
int i9 = 9, i10 = 10, i11 = 11, i12 = 12;
i1= i2+i3;
i2= i1-i2;
i3= i1 & i4;
i4= i3 | i2;
i5= i3 ^i4;
}
main:
PUSH.W
R10 ;salva registros tipo save
PUSH.W
R11
PUSH.W
R8
PUSH.W
R9
PUSH.W
R6
PUSH.W
R7
PUSH.W
R4
PUSH.W
R5
SUB.W
#0x2, SP
; crea frame
MOV.W
#0x1, R4
; i1 = R4 = 1;
MOV.W
#0x2, R5
; i2 = R5 = 2;
MOV.W
#0x3, R14
; i3 = R14 = 3;
MOV.W
#0x4, R12
; i4 = R12 = 4;
MOV.W
#0x5, R13
; i5 = R13 = 5;
MOV.W
#0x6, 0x0(SP) ; tope = 6; Direccionamiento indexado.
MOV.W
#0x7, R10
; i7 = R10 = 7;
MOV.W
#0x8, R11
; i8 = R11 = 8;
MOV.W
#0x9, R8
; i9 = R8 = 9;
MOV.W
#0xa, R9
; i10 = R9 = 10;
MOV.W
#0xb, R6
; i11 = R6 = 11;
MOV.W
#0xc, R7
; i12 = R7 = 12;
MOV.W
R5, R15
; emplea R15 como temporal
ADD.W
R14, R15
MOV.W
R15, R4
; i1= i2+i3;
MOV.W
R4, R15
SUB.W
R5, R15
MOV.W
R15, R5
; i2= i1-i2;
MOV.W
R4, R15
Prof. Leopoldo Silva Bijit.
23-02-2004
4
UNIVERSIDAD TECNICA FEDERICO SANTA MARIA
DEPARTAMENTO DE ELECTRONICA
Assembler MSP430
?Epilogue8:
?Epilogue7:
?Epilogue6:
?Epilogue5:
?Epilogue4:
?Epilogue3:
AND.W
MOV.W
MOV.W
BIS.W
MOV.W
MOV.W
XOR.W
MOV.W
ADD.W
BR
pop.w
pop.w
pop.w
pop.w
pop.w
pop.w
pop.w
pop.w
ret
R12, R15
R15, R14
R14, R15
R5, R15
R15, R12
R14, R15
R12, R15
R15, R13
#0x2, SP
#?Epilogue8
R5
R4
R7
R6
R9
R8
R11
R10
; i3= i1 & i4;
; i4= i3 | i2;
; i5= i3 ^ i4;
; desarma el frame
; rótulos automáticos
; restaura registros que deben preservarse
; por ser modificados dentro de la función.
Variables globales inicializadas.
Consideremos las siguientes definiciones de variables globales inicializadas.
int i1 = 1;
int i2 = 2;
int i3 = 3;
int i4 = 4;
int i5 = 5;
int i6 = 6;
int i7 = 7;
int i8 = 8;
int i9 = 9;
int i10 = 10;
int i11 = 11;
int i12 = 12;
void main(void)
{
i1= i2+i3;
i2= i1-i2;
i3= i1 & i4;
i4= i3 | i2;
i5= i3 ^i4;
}
Prof. Leopoldo Silva Bijit.
23-02-2004
5
UNIVERSIDAD TECNICA FEDERICO SANTA MARIA
DEPARTAMENTO DE ELECTRONICA
Assembler MSP430
Las variables globales (definidas fuera de las funciones) son almacenadas en RAM, a partir
de la dirección 0x200. Los inicializadores se almacenan en la memoria flash, a
continuación de la última instrucción del programa. Antes de invocar a main, además de
iniciar el stack pointer, se inicializan las variables estáticas en RAM, mediante la función
memcpy que es automáticamente insertada por el código de arranque.
#include "msp430x14x.h"
;-----------------------------------------------------------------------------ORG
01100h
; Programa en Flash
;-----------------------------------------------------------------------------RESET:
mov.w
#0A00h, SP
; Inicia stackpointer
mov.w
#0x200, R12
; inicio RAM
mov.w
#Inicializadores, R14
; valores iniciales de globales
push.w
#0xA
; se pasa en el tope el número
call
#memcpy
incd.w
SP
;pop
_exit:
__exit
call
call
br
jmp
#main
#exit
#__exit
#__exit
El código en C, para la función estándar memcpy es el siguiente:
void *memcpy(void * destino, const void * fuente, register int n)
{ register char *d = (char *)destino; register const char *s= (char *)fuente;
while(n--) *d++ = *s++;
return destino;
}
memcpy Copia un bloque de n bytes desde la dirección fuente hacia la dirección destino.
La siguiente implementación assembler de memcpy, copia n bytes desde la dirección fuente
(que se pasa en R14, la cual apunta a la zona de los valores iniciales de las variables
globales que se escriben en la memoria flash, inmediatamente después de la última
instrucción del programa) hacia la dirección destino (que se pasa en R12, la cual apunta al
inicio del segmento de memoria RAM). Entonces memcpy queda:
memcpy:
cpy:
push.w
mov.w
mov.w
jmp
mov.w
Prof. Leopoldo Silva Bijit.
R10
0x4(SP), R13 ; R13 =número de bytes
R12, R10
testn
R10, R15
23-02-2004
6
UNIVERSIDAD TECNICA FEDERICO SANTA MARIA
DEPARTAMENTO DE ELECTRONICA
Assembler MSP430
inc.w
mov.b
testn:
mov.w
add.w
tst.w
jne
pop.w
ret
Inicializadores:
DW
DW
DW
DW
DW
R10
;d++
@R14+,0x0(R15)
;de flash a ram. s++
R13, R15
#0xFFFF, R13
; n-R15
cpy
R10
;última instrucción del programa.
0100
0200
0300
0400
0500
;valor inicial de i1
;inicializador de i2
El direccionamiento @R14 es indirecto. Usa R14 como puntero.
Nótese que no se crea el espacio para variables globales que no se emplean en el programa,
es el caso de las variables i6 a i12, en el ejemplo que se está desarrollando.
;-----------------------------------------------------------------------------;
Segmento RAM, después de memcpy
;-----------------------------------------------------------------------------ORG 00200h
; MSP430 Inicio RAM
i1:
DW 00001h
; 200
i2:
DW 00002h
; 202
i3:
DW 00003h
; 204
i4:
DW 00004h
; 206
i5:
DW 00005h
; 208
END
El código de main ilustra el direccionamiento empleando variables en la zona de RAM.
También se muestra operadores de suma y resta, y operadores al bit.
main:
mov.w
add.w
mov.w
&i2, R15
&i3, R15
R15, &i1
; i1= i2+i3;
mov.w
sub.w
mov.w
&i1,R15
&i2,R15
R15,&i2
; i2= i1-i2;
mov.w
and.w
mov.w
&i1, R15
&i4, R15
R15, &i3
; i3= i1 & i4
Prof. Leopoldo Silva Bijit.
;El & es direccionamiento absoluto.
23-02-2004
7
UNIVERSIDAD TECNICA FEDERICO SANTA MARIA
DEPARTAMENTO DE ELECTRONICA
Assembler MSP430
mov.w
bis.w
mov.w
&i3,R15
&i2,R15
R15,&i4
; i4= i3 | i2;
mov.w
xor.w
mov.w
ret
&i3,R15
&i4,R15
R15,&i5
; i5= i3 ^i4;
Variables globales no inicializadas.
Consideremos las siguientes definiciones de variables globales no inicializadas. Se ilustra
además el tratamiento de arreglos.
int i1;
int arr[4];
int main(void)
{
i1=-1;
arr[0]=0;
arr[1]=1;
arr[2]=2;
arr[3]=3;
arr[0]=arr[1]+i1;
return(0) ;
}
Se crean las globales en RAM y se las inicia automáticamente con valores nulos, antes de
invocar a main. Lo anterior se logra invocando a la rutina memset, que inserta el código de
arranque.
#include "msp430x14x.h"
;-----------------------------------------------------------------------------ORG
01100h
; Programa en Flash
;-----------------------------------------------------------------------------RESET:
mov.w
#0A00h, SP
; Inicia stackpointer
mov.w
#0x200, R12
; inicio RAM
clr.w
R14
; valor a setear en RAM
push.w
#0xA
; se pasa en el tope el número de bytes a setear
call
#memset
incd.w
SP
;pop
call
Prof. Leopoldo Silva Bijit.
#main
23-02-2004
8
UNIVERSIDAD TECNICA FEDERICO SANTA MARIA
DEPARTAMENTO DE ELECTRONICA
Assembler MSP430
_exit:
__exit
call
br
jmp
#exit
#__exit
#__exit
Se puede describir en C, el código de memset:
void memset(void * destino, const int valor, register int n)
{ register char *d = (char *)destino;
while(n--) *d++ = valor;
}
El código de memset que genera IAR:
memset:
push.w
R10
push.w
R11
mov.w
0x6(SP), R13
mov.w
R12, R10
jmp
testn
setram:
mov.b
R14,R15
mov.w
R10,R11
inc.w
R10
mov.b
R15,0x0(R11)
testn:
mov.w
R13, R15
add.w
#0xFFFF,R13
tst.w
R15
jne
setram
pop.w
R11
pop.w
R10
ret
;número queda en frame
;en R10 inicio de RAM
;d++
;n--
;-----------------------------------------------------------------------------;
Segmento RAM, después de memset
;-----------------------------------------------------------------------------ORG
00200h
; MSP430 Inicio RAM
i1:
DW
00000h
; 200
arr:
DW
00000h
; 202 arr[0]
DW
00000h
; 204 arr[1]
DW
00000h
; 206 arr[2]
DW
00000h
; 208 arr[3]
END
El código de main ilustra la manipulación de componentes de un arreglo:
Prof. Leopoldo Silva Bijit.
23-02-2004
9
UNIVERSIDAD TECNICA FEDERICO SANTA MARIA
DEPARTAMENTO DE ELECTRONICA
Assembler MSP430
main:
mov.w
clr.w
mov.w
mov.w
mov.w
#0xFFFF,&i1
&arr
#0x1,&0x204
#0x2,&0x206
#0x3,&0x208
; i1=-1;
; arr[0]=0;
; arr[1]=1;
; arr[2]=2;
; arr[3]=3;
mov.w
add.w
mov.w
&0x204,R15
&i1,R15
R15,&arr
; arr[0]=arr[1]+i1;
clr.w
ret
R12
; return(0) ;
En este ejemplo, la función main retorna un valor entero. El valor de retorno de la función
se efectúa a través de R12.
Definición de punteros.
En el siguiente código se definen dos globales iniciadas, y un puntero a entero sin iniciar.
int *pi;
int x=1;
int y=2;
int main(void)
{
pi=&x;
y = *pi;
return(0) ;
}
El código de arranque invoca a memcpy para iniciar en RAM las variables enteras y a
memset para definir en RAM el puntero a entero, iniciado con valor nulo.
;-----------------------------------------------------------------------------;
Segmento RAM, después de memcpy y memset
;-----------------------------------------------------------------------------ORG
00200h
; MSP430 Inicio RAM
x:
DW
00001h
; 200
y:
DW
00002h
; 202
pi:
DW
00000h
; 204
END
Prof. Leopoldo Silva Bijit.
23-02-2004
10
UNIVERSIDAD TECNICA FEDERICO SANTA MARIA
DEPARTAMENTO DE ELECTRONICA
Assembler MSP430
La función main:
main:
mov.w
mov.w
mov.w
clr.w
ret
#0x200, &pi ; pi = &x
&pi, R15
; temp=pi
@R15, &y
; y = *temp;
R12
; return(0) ;
En los ejemplos a continuación se emplearán variables globales, ya que el direccionamiento
hace referencia a los nombres de las variables, y de este modo es más sencillo seguir los
ejemplos. Si se emplearan locales, habría que asociar variables a registros, y considerar que
algunos pueden ser usados como variables temporales.
Alternativas.
Ilustra el uso de la instrucción compare y los saltos condicionales.
;if (v8>v7) v6++; else v5--;
cmp.w
jge
inc.w
jmp
else:
add.w
endif:
&v8, &v7
else
; va a else si: &v8 <=&v7
&v6
endif
#0xFFFF,&v5
Luego de compilar la condición, mediante un salto condicional se genera el salto al bloque
de acciones asociados al else.
;if (v8>=v7) v6++; else v5--;
cmp.w
&v7,&v8
jl
else
; va a else si: &v7 > &v8
inc.w
&v6
jmp
endif
else:
add.w
#0xFFFF,&v5
endif:
;if (v8<v7) v6++; else v5--;
cmp.w
jge
inc.w
jmp
else:
add.w
endif:
Prof. Leopoldo Silva Bijit.
&v7,&v8
else
; va a else si: &v7 <=&v8
&v6
endif
#0xFFFF,&v5
23-02-2004
11
UNIVERSIDAD TECNICA FEDERICO SANTA MARIA
DEPARTAMENTO DE ELECTRONICA
Assembler MSP430
;if (v8<=v7) v6++; else v5--;
cmp.w
&v8,&v7
jl
else
; va a else si: &v8 > &v7
inc.w
&v6
jmp
endif
else:
add.w
#0xFFFF,&v5
endif:
;if (v8==v7) v6++; else v5--;
cmp.w
&v7,&v8
jne
else
; va a else si: &v7 != &v8
inc.w
&v6
jmp
endif
else:
add.w
#0xFFFF,&v5
endif:
;if (v8!=v7) v6++; else v5--;
cmp.w
jeq
inc.w
jmp
else:
add.w
endif:
&v7,&v8
else
; va a else si: &v7 == &v8
&v6
endif
#0xFFFF,&v5
Iteraciones.
;while (v8>v0) v0++;
lazo:
cmp.w
jge
inc.w
jmp
endwhile:
&v8,&v0
endwhile
&v0
lazo
;termina iteración si &v8 <= &v0
;do {v1++;} while (v8>v1);
repeat:
inc.w
cmp.w
jl
Prof. Leopoldo Silva Bijit.
&v1
&v8,&v1
repeat
;repite si &v8 > &v1
23-02-2004
12
UNIVERSIDAD TECNICA FEDERICO SANTA MARIA
DEPARTAMENTO DE ELECTRONICA
Assembler MSP430
; for(v8=0;v8<v7;v8++) v0--;
clr.w
&v8
testfor:
cmp.w
&v7,&v8
jge
endfor
;termina si &v7 <= &v8
add.w
#0xFFFF,&v0
inc.w
&v8
jmp
testfor
endfor:
Condicional.
;v8= (v7>v6) ? v7 : v6;
cmp.w
jge
mov.w
jmp
else:
mov.w
fuera:
&v7,&v6
else
&v7,&v8
fuera
&v6,&v8
Switch.
switch (v7) {
case 1: case 2:
v2++;
break;
case 3:
v3--;
break;
default:
v3=++v5;
}
;switch (v7) {
mov.w
dec.w
jeq
dec.w
jeq
dec.w
jeq
jmp
&v7,R15
R15
caso1
R15
caso2
R15
caso3
default
;si es caso 1
;si es 2
;si es 3
caso1:
Prof. Leopoldo Silva Bijit.
23-02-2004
13
UNIVERSIDAD TECNICA FEDERICO SANTA MARIA
DEPARTAMENTO DE ELECTRONICA
Assembler MSP430
caso2:
caso3:
default:
inc.w
jmp
add.w
jmp
inc.w
mov.w
&v2
; v2++;
siga
#0xFFFF,&v3 ; v3--;
siga
&v5
; v3=++v5;
&v5,&v3
;}
siga:
Break y Continue en iteraciones.
;for(v8=0 ;v8<10 ;v8++ ) { v6++; if(v6>8) break; v5++;}
clr.w
testfor:
&v8
cmp.w
jge
inc.w
cmp.w
jge
inc.w
inc.w
jmp
#0xA,&v8
endfor
&v6
#0x9,&v6
endfor
; es el break. Fuera del lazo.
&v5
&v8
testfor
endfor:
;for(v8=0 ;v8<10 ;v8++ ) { v6++; if(v6>8) continue; v5++;}
clr.w
&v8
testfor:
cmp.w
#0xA,&v8
jge
endfor
inc.w
&v6
cmp.w
#0x9,&v6
jge
incfor
; es el continue. Al incremento del lazo
inc.w
&v5
incfor:
inc.w
&v8
jmp
testfor
endfor:
Ejemplos de diseños de funciones.
Ejemplo1.
Sea una función f1 de tres variables.
Prof. Leopoldo Silva Bijit.
23-02-2004
14
UNIVERSIDAD TECNICA FEDERICO SANTA MARIA
DEPARTAMENTO DE ELECTRONICA
Assembler MSP430
El llamado a la función en C, v5=f1(v8,v7,v6);
Asumiendo que las variables locales están asociadas a registros: v5 con R9, v6 con R8, v7
con R11 y v8 con R10.
Se pasa el valor de v6 en el tope del stack. Luego en R14 el valor de v7 y en R12 el valor
de v8.
La forma de pasar los argumentos es una política del compilador, que en el caso de pasar
paso por registros depende de los que ya estén en uso. Es indispensable conocer ese orden
para el diseño de la función.
La compilación del llamado queda como sigue:
;v5=f1(v8,v7,v6);
push.w
mov.w
mov.w
call
incd.w
dirret: mov.w
R8
R11,R14
R10,R12
#f1
sp
R12,R9
;empuja tercer argumento
;pasa en R14 segundo argumento
;pasa en R12 primer argumento
;recupera posición de sp
;se asume valor de retorno en R12
Después de invocar a f1, los frames en el stack pueden visualizarse según:
sp
dirret
valor v6
Fondo y tope del frame de f1
Tope del frame de función que llama a f1
Para compilar el llamado lo único que se necesita conocer es el prototipo de la función f1:
int f1(int , int , int );
Si se desea incorporar el código de la función f1 en assembler, debe indicarse en el
prototipo que su definición está en otro archivo. Esto se logra anteponiendo la palabra
reservada extern, según se indica:
exter int f1(int , int , int );
Esta declaración debe figurar, en el texto en C, antes del llamado.
Para compilar la función se requiere su definición, y la forma en que se han pasado los
argumentos.
Prof. Leopoldo Silva Bijit.
23-02-2004
15
UNIVERSIDAD TECNICA FEDERICO SANTA MARIA
DEPARTAMENTO DE ELECTRONICA
Assembler MSP430
int f1(int a0, int a1, int a2)
{
a0=a1+a2;
a1=a0+a2;
return(a0);
}
f1:
mov.w
mov.w
add.w
mov.w
mov.w
add.w
mov.w
ret
0x2(SP),R15
R14,R13
R15,R13
R13,R12
R12,R13
R15,R13
R13,R14
;deja en R15 el valor del argumento a2
;en R14 se tiene a1
; R13 se usa como registro temporal
; en R12 se tiene a0
Ejemplo 2.
Si aumentamos el número de argumentos de la función, y también el número de variables
locales en registros, tendremos una visualización de la política de asignación que el
compilador utiliza para la asignación de registros.
int f1(int a0,int a1,int a2,int a3, int a4)
{
a0=a1+a2+a3+a4;
a1=a0+a2;
return(a0);
}
int main(void)
{
register int v8=8,v7=7,v6=6,v5=5,v4=4,v3=3,v2=2,v1=1;
v3=f1(v8,v7,v6,v5,v4);
return(0) ;
}
main:
push.w
push.w
push.w
push.w
push.w
push.w
R10
R11
R8
R9
R6
R7
Prof. Leopoldo Silva Bijit.
;salva registros que se usan en locales.
23-02-2004
16
UNIVERSIDAD TECNICA FEDERICO SANTA MARIA
DEPARTAMENTO DE ELECTRONICA
Assembler MSP430
dr1:
push.w
push.w
mov.w
mov.w
mov.w
mov.w
mov.w
mov.w
mov.w
mov.w
push.w
push.w
push.w
mov.w
mov.w
call
mov.w
clr.w
add.w
pop.w
pop.w
pop.w
pop.w
pop.w
pop.w
pop.w
pop.w
ret
R4
R5
#0x8,R7
#0x7,R10
#0x6,R11
#0x5,R8
#0x4,R9
#0x3,R6
#0x2,R5
#0x1,R4
R9
R8
R11
R10,R14
R7,R12
#f1
R12,R6
R12
#0x6,SP
R5
R4
R7
R6
R9
R8
R11
R10
;inicio de locales
;paso de argumentos en frame. a4
;a3
;a2
;al menos dos argumento se pasan en registros. a1
;a0
; retorno de f1 en R12
;retorno de main.
;desarma frame de la función main
;restaura registros usado en locales.
Frame de main en el stack, inmediatamente después de la invocación a f1.
sp
Prof. Leopoldo Silva Bijit.
dr1
a2
a3
a4
R5
R4
R7
R6
R9
R8
R11
R10
dr0
Fondo del frame de f1
Tope del frame de main
Fondo del frame de main
23-02-2004
17
UNIVERSIDAD TECNICA FEDERICO SANTA MARIA
DEPARTAMENTO DE ELECTRONICA
Assembler MSP430
Frame de f1, luego de salvar los registros R10 y R11(tipo save):
sp
6
8
A
R11
R10
dr1
a2
a3
a4
R5
R4
R7
R6
R9
R8
R11
R10
dr0
Tope del frame de f1
Fondo del frame de f1
Tope del frame de main
Fondo del frame de main
f1:
push.w
push.w
mov.w
mov.w
mov.w
mov.w
add.w
add.w
add.w
mov.w
mov.w
add.w
mov.w
pop.w
pop.w
ret
R10
R11
0x6(SP),R15
0x8(SP),R13
0xA(SP),R10
R14,R11
R15,R11
R13,R11
R10,R11
R11,R12
R12,R11
R15,R11
R11,R14
R11
R10
Prof. Leopoldo Silva Bijit.
; salva R10 que ocupa para a4
; salva R11 que usa como temporal
; deja en R15 el argumento a2
; deja en R13 el argumento a3
; deja en R10 el argumento a4
; a0=a1+a2+a3+a4;
; a1=a0+a2;
;restaura salvados
23-02-2004
18
UNIVERSIDAD TECNICA FEDERICO SANTA MARIA
DEPARTAMENTO DE ELECTRONICA
Assembler MSP430
Corrimientos aritméticos.
Asumiendo variables globales, la traducción de los corrimientos por constante y por
variable se ilustra a continuación:
v8=v7<<3;
v8=v7>>6;
v8=v7>>v6;
v8=v7<<v6;
/*corrimiento por constante */
/*corrimiento por variable */
El assembler implementa algunas rotaciones como sumas. Además sólo rota un bit a la vez.
Por ejemplo, empleando R12 como temporal, el desplazamiento con signo a la izquierda en
tres posiciones puede compilarse según:
mov.w
rla.w
rla.w
rla.w
mov.w
&v7,R12
R12
R12
R12
R12,&v8
También pueden desarrollarse rutinas más generales, para corrimientos de 0 a 16
posiciones. Se ilustran los códigos, a continuación, generados por el compilador IAR.
mov.w
call
mov.w
&v7,R12
#?ShiftLeft16_3
R12,&v8
; v8=v7<<3;
mov.w
call
mov.w
&v7,R12
#?ShiftRight16s_6
R12,&v8
; v8=v7>>6;
mov.w
mov.w
call
mov.w
&v7,R12
&v6,R14
#?ShiftRight16s
R12,&v8
; v8=v7>>v6;
mov.w
mov.w
call
mov.w
&v7,R12
&v6,R14
#?ShiftLeft16
R12,&v8
; v8=v7<<v6;
Las rutinas tienen diversos puntos de entrada, de acuerdo al número de corrimientos que
deben efectuarse.
Prof. Leopoldo Silva Bijit.
23-02-2004
19
UNIVERSIDAD TECNICA FEDERICO SANTA MARIA
DEPARTAMENTO DE ELECTRONICA
Assembler MSP430
; R12=R12>>R14
?ShiftLeft16:
lazoshlf:
skipshlf
?ShiftLeft16_7:
?ShiftLeft16_6:
?ShiftLeft16_5:
?ShiftLeft16_4:
?ShiftLeft16_3:
tst.b
jeq
rla.w
dec.b
jne
ret
rla.w
rla.w
rla.w
rla.w
rla.w
rla.w
rla.w
ret
A la derecha con signo:
?ShiftRight8s:
sxt
?ShiftRight16s:
tst.b
jeq
lazoshrt:
rra.w
dec.b
jne
skipshrt:
ret
?ShiftRight16s_7:
rra.w
?ShiftRight16s_6:
rra.w
?ShiftRight16s_5:
rra.w
?ShiftRight16s_4:
rra.w
?ShiftRight16s_3:
rra.w
rra.w
rra.w
ret
R14
skipshlf
R12
R14
lazoshlf
R12
R12
R12
R12
R12
R12
R12
R12
R14
skipshrt
R12
R14
lazoshrt
R12
R12
R12
R12
R12
R1
R12
Si las variables son sin signo, los llamados para corrimientos a la izquierda no cambian;
pero los corrimientos a la derecha deben convertirse en rotaciones lógicas.
Para corrimiento sin signo, se limpia el carry.
A la derecha sin signo:
?ShiftRight8u:
and.b
?ShiftRight16u:
tst.b
jeq
lazosru:
clrc
rrc.w
Prof. Leopoldo Silva Bijit.
#0xFF,R12
R14
skipsru
R12
23-02-2004
20
UNIVERSIDAD TECNICA FEDERICO SANTA MARIA
DEPARTAMENTO DE ELECTRONICA
Assembler MSP430
skipsru:
?ShiftRight16u_7:
?ShiftRight16u_6:
?ShiftRight16u_5:
?ShiftRight16u_4:
dec.b
jne
ret
clrc
rrc.w
clrc
rrc.w
clrc
rrc.w
clrc
rrc.w
R14
lazosru
R12
R12
R12
R12
?ShiftRight16u_3:
clrc
rrc.w R12
rra.w R12
rra.w R12
ret
Si el número de corrimientos es mayor que 15 el compilador debería generar un cero
(cuestión que IAR realiza). También deberían tratarse en forma especial situaciones que
podrían producir pérdidas del signo del número.
División de enteros sin signo y con signo.
La división de enteros sin signo se implementa mediante algoritmos usuales.
El siguiente segmento ilustra el llamado
mov.w
&v7,R12
mov.w
&v6,R14
call
#?DivMod16u
mov.w
R12,&v8
; v8=v7/v6;
?DivMod8u:
and.b
and.b
#0xFF,R12
#0xFF,R14
;para enteros sin signo de 8 bits
mov.w
clr.w
mov.w
bit.w
rlc.w
rlc.w
cmp.w
R14,R15
R14
#0x1,R13
#0x1,R13
R12
R14
R15,R14
;R12/R14
?DivMod16u:
rot1:
Prof. Leopoldo Silva Bijit.
23-02-2004
;R14-R15
21
UNIVERSIDAD TECNICA FEDERICO SANTA MARIA
DEPARTAMENTO DE ELECTRONICA
Assembler MSP430
rot2:
jnc
sub.w
rlc.w
jnc
rra.w
rlc.w
ret
rot2
R15,R14
R13
rot1
R13
R12
La división con signo, determina el signo del resultado (dejando positivos los operandos) y
efectúa la división sin signo. Luego coloca el signo del cuociente y el resto.
?DivMod8s:
sxt
sxt
R12
R14
?DivMod16s:
test1:
test2:
set1:
set2:
push.w R9
clr.w R9
tst.w R14
jge test1
inv.w R14
inc.w R14
bis.w #0x1,R9
tst.w R12
jge test2
inv.w R12
inc.w R12
inv.w R9
call #?DivMod16u
bit.w #0x1,R9
jeq set1
inv.w R12
inc.w R12
bit.w #0x2,R9
jeq set2
inv.w R14
inc.w R14
pop.w R9
ret
Prof. Leopoldo Silva Bijit.
23-02-2004
22
UNIVERSIDAD TECNICA FEDERICO SANTA MARIA
DEPARTAMENTO DE ELECTRONICA
Assembler MSP430
Multiplicación de enteros con signo.
El microcontrolador tiene una unidad aritmética que efectúa multiplicación de enteros.
En caso de multiplicaciones por potencias de dos, es más eficiente realizar la multiplicación
mediante sumas que utilizar el hardware de multiplicación.
;v8=v7*2;
mov.w
rla.w
mov.w
&v7,R15
R15
R15,&v8
; v8=v7*v6;
?Mul8Hw:
mov.w
mov.w
call
mov.w
&v7,R12
&v6,R14
#?Mul16Hw
R12,&v8
and.b
and.b
#0xFF,R12
#0xFF,R14
push.w
dint
nop
mov.w
mov.w
mov.w
mov.w
reti
SR
;operandos de 8 bits
?Mul16Hw:
;no se puede interrumpir
R12,&MPY
R14,&OP2
&RESLO,R12
&RESHI,R13 ;retorno en R12 y R13
PC
;recupera SR
Operaciones lógicas.
Se implementan con cortocircuitos y asignan valores 0 y 1.
; v8=v7&&v6;
tst.w
&v7
jeq
esfalso
;primer operando falso
tst.w
&v6
jeq
esfalso
mov.b
#0x1,R15
;ambos verdaderos
jmp
esverdad
Prof. Leopoldo Silva Bijit.
23-02-2004
23
UNIVERSIDAD TECNICA FEDERICO SANTA MARIA
DEPARTAMENTO DE ELECTRONICA
Assembler MSP430
esfalso:
esverdad:
clr.b
and.w
mov.w
R15
#0xFF,R15
R15,&v8
;v7=v6||v5;
yaesverdad:
esfalso:
esverdad:
tst.w
jne
tst.w
jeq
mov.b
jmp
clr.b
and.w
mov.w
&v6
yaesverdad
&v5
esfalso
#0x1,R15
esverdad
R15
#0xFF,R15
R15,&v7
tst.w
jne
mov.b
jmp
clr.b
and.w
mov.w
&v6
argverdad
#0x1,R15
setvalor
R15
#0xFF,R15
R15,&v7
;ambos son falsos
v7=!v6;
argverdad:
setvalor:
;setea a uno
Se ilustra la composición de una expresión.
;v8=(v7&&v6)&&v5;
tst.w
&v7
jeq
esfalso
tst.w
&v6
jeq
esfalso
tst.w
&v5
jeq
esfalso
mov.b
#0x1,R15
jmp
setvalor
esfalso:
clr.b
R15
setvalor:
and.w
#0xFF,R15
mov.w
R15,&v8
Prof. Leopoldo Silva Bijit.
23-02-2004
24
Descargar