Sunteți pe pagina 1din 228

Ensamblador del

PowerPC con
Mac OS X

Ensamblador del PowerPC con Mac OS X

MacProgramadores

Acerca de este tutorial


Este tutorial est dirigido a explicar el diseo y funcionamiento de las
mquinas de Apple actuales, haciendo especial hincapi en su
microprocesador: El PowerPC. La informacin que se da aqu es ms
cualitativa que cuantitativa, en el sentido de que se explica cmo est
estructurado y organizado el computador, as como la programacin de ste,
ms que a hacer hincapi en las diferencias de velocidad y rendimiento de los
diferentes modelos de PowerPC que hay actualmente en el mercado.
Aunque muchos de los aspectos que vamos a comentar son independientes
del sistema operativo que usemos, otros s que varan dependiendo del
sistema operativo en cuyo caso haremos una comparativa entre cmo se ha
implementado ese aspecto en un sistema operativo concreto. ste puede ser
o bien Darwin (el kernel open source de Mac OS X), o bien Linux (ya sea
LinuxPPC, MkLinux o cualquier otra distribucin de Linux para PowerPC),
aunque principalmente nos centraremos en explicar el diseo de Darwin.
A veces tambin haremos comparativas entre cmo se implementa un
determinado aspecto en PowerPC, y cmo se implementa en otras mquinas,
como por ejemplo las mquinas x86 de Intel. Esto ayuda al lector a tener una
visin ms global de la arquitectura de los ordenadores modernos, y
normalmente ver tambin las ventajas o inconvenientes que tiene PowerPC
frente a sus competidores.

A quin va dirigido este tutorial?


Antes de escribir un documento tcnico es importante plantearse la pregunta
de a quin va dirigido el escrito, esto ayuda a la hora de decidir qu materias
explicar y hasta qu nivel de profundidad hacerlo.
A lo largo de mis estudios e investigaciones he visto muchos libros del tipo
empezamos desde cero y lo damos todo, a veces los llaman para todos los
niveles. Este tipo de afirmaciones, aunque puedan estar impuestas por una
editorial ambiciosa, son poco realistas, especialmente cuando el escrito es
sobre un tema lo suficientemente amplio. Por mi experiencia he observado en
muchas ocasiones que este tipo de libros suelen empezar muy despacio y a
mitad del libro el autor aumenta el ritmo con el fin de poder meter un poco
ms de temario. En este tutorial he intentado hacerlo al revs: empezar ms
deprisa con los primeros temas y dedicar ms tiempo a las ltimas partes,
que adems son las ms interesantes.
Para poder conseguir este objetivo, este tutorial est diseado para personas
con ciertos conocimientos de programacin y de arquitectura de
computadores, en concreto el documento exige que el lector tenga
conocimientos de programacin en C, as como de arquitectura de
computadores al nivel que se da en una primera asignatura de arquitectura
Pg 2

Ensamblador del PowerPC con Mac OS X

MacProgramadores

de computadores de cualquier carrera tcnica o superior de Informtica. Este


requisito no excluye necesariamente a lectores autodidactas, pero estos
deben de conocer los conceptos bsicos de representacin binaria y de
organizacin de un computador. Aun as en el apndice A he explicado con
cierta profundidad los mtodos de representacin binaria de punto fijo y
punto flotante (segn el estndar IEEE 754), as como los mecanismos de
aritmtica binaria ms usados. Si el lector no conoce, o no recuerda bien
estos mtodos sera recomendable que visitase este apndice al principio del
libro, o bien, durante su lectura si encuentra dificultades para su
comprensin.
Otros requisitos, que sin ser indispensables, si que ayudaran mucho al lector
seran que el lector hubiese programado ya alguna vez en ensamblador, o
bien del PowerPC, o bien de cualquier otro microprocesador, ya que los
conceptos entre distintos procesadores varan ms bien poco. Por ltimo, y
especialmente dirigido a los ltimos temas, sera recomendable conocer el
diseo de un sistema operativo tal como se explica en un primer curso de
sistemas operativos en una carrera universitaria de informtica. Este requisito
es el menos importante ya que estos conceptos s que se explican bastante
bien a lo largo del tutorial.

Cmo leer este tutorial


En principio el tutorial est pensado para ser ledo de principio a fin siguiendo
el orden de los temas. Los apndices, por contra, estn pensados para
contener informacin que no est muy relacionada y que se puede leer en
cualquier orden o bien esquivarlos si el lector ya est familiarizado con ese
tema.
En el tutorial aparecen multitud de tablas, por ejemplo a la hora de describir
las instrucciones que existen para un determinado propsito. Es muy comn
el pasar una tabla sin fijarse en su contenido. En parte esto es normal porque
el lector se centra en los conceptos y en la estructura del documento y no en
valores concretos. Aun as recomendamos al lector que intente leer la utilidad
de esos datos resumidos en la tabla, ya que ayudan ms de lo que pudiera
parecer a poder seguir la explicacin del texto.

Pg 3

Ensamblador del PowerPC con Mac OS X

MacProgramadores

Notaciones utilizadas
En general, cuando describamos una instruccin ensamblador vamos a utilizar
las minsculas para indicar valores que tengamos que escribir literalmente,
mientras que vamos a utilizar maysculas para indicar valores que deban ser
sustituidos por su valor, es decir, si escribimos el formato de una instruccin,
escribiremos:
cmp CRF,L,rA,rB
Cuando la vayamos a ejecutar con determinados valores escribiremos:
cmp 2,0,r5,r6
Donde CRF y L han sido sustituidos por un valor, al igual que la A y B de rA y
rB, mientras que cmp se escribe literalmente por ser minsculas.

Nota legal
Este tutorial ha sido escrito por Fernando Lpez Hernndez para
MacProgramadores, y de acuerdo a los derechos que le concede la legislacin
espaola e internacional el autor prohbe la publicacin de este documento en
cualquier otro servidor web, as como su venta, o difusin en cualquier otro
medio sin autorizacin previa.
Sin embargo el autor anima a todos los servidores web a colocar enlaces a
este documento. El autor tambin anima a cualquier persona interesada en
aprender a programar el PowerPC a bajarse o imprimirse este tutorial.
Madrid, Diciembre 2005
Para cualquier aclaracin contacte con:
fernando@DELITmacprogramadores.org

Pg 4

Ensamblador del PowerPC con Mac OS X

MacProgramadores

Tabla de contenido
TEMA 1: Introduccin al PowerPC
1 La arquitectura del PowerPC ..............................................................10
2 Los entornos del PowerPC..................................................................12
3 Los registros del PowerPC..................................................................13
4 Byte ordering....................................................................................14
5 Alineacin.........................................................................................16
TEMA 2: Empezando a programar
1 Herramientas necesarias....................................................................18
2 El programa mnimo ..........................................................................21
3 El lenguaje ensamblador....................................................................23
3.1
Sintaxis del lenguaje ...................................................................23
3.2
Elementos del lenguaje ...............................................................24
3.2.1
Literales ..............................................................................25
3.2.2
Identificadores.....................................................................26
3.2.3
Las expresiones ...................................................................27
3.2.4
El location counter ...............................................................30
3.3
Las sentencias de asignacin directa ............................................31
3.4
Las definiciones ..........................................................................32
4 Acceso a memoria .............................................................................33
4.1
Segmentacin del programa ........................................................33
4.2
Las secciones .............................................................................34
4.2.1
Secciones del segmento de cdigo ........................................34
4.2.2
Secciones del segmento de datos..........................................38
4.2.3
Crear nuevas secciones ........................................................39
4.2.4
Agrupar las secciones...........................................................40
4.3
Indireccionamiento de memoria en las mquinas RISC ..................41
4.4
Modos de indireccionamiento.......................................................43
4.4.1
Indireccionamiento de registro base e ndice inmediato ..........44
4.4.2
Ejemplo...............................................................................47
4.4.3
Acceso a memoria con actualizacin de registro .....................48
4.4.4
Uso del operador ha16() ....................................................49
4.4.5
Indireccionamiento de registro base y registro ndice..............51
4.5
Carga y almacenamiento de bloques de bytes...............................54
4.6
Mnemonics.................................................................................56
5 Instrucciones de trabajo con enteros ..................................................59
5.1
El registro CR (Condition Register) ...............................................59
5.2
El registro XER ...........................................................................63
5.3
Instrucciones aritmticas.............................................................65
5.3.1
Instrucciones aritmticas de suma.........................................65
5.3.2
Instrucciones aritmticas de resta .........................................70
5.3.3
Instrucciones de negacin aritmtica.....................................72
5.3.4
Instrucciones aritmticas de multiplicacin.............................72
5.3.5
Instrucciones aritmticas de divisin......................................74
5.4
Instrucciones de comparacin de enteros .....................................75
Pg. 5

Ensamblador del PowerPC con Mac OS X

MacProgramadores

5.5
Instrucciones lgicas con enteros.................................................76
5.6
Instrucciones de rotacin y desplazamiento con enteros................78
5.6.1
Instrucciones de desplazamiento con enteros.........................79
5.6.2
Instrucciones de rotacin con enteros ...................................80
5.7
Mnemonics.................................................................................83
5.7.1
Mnemonics para la resta.......................................................83
5.7.2
Mnemonics para las operaciones de comparacin ...................84
5.7.3
Mnemonics para operaciones de desplazamiento y rotacin ....85
5.7.4
Mnemonics para acceder al registro XER................................86
5.7.5
Otros mnemonics.................................................................86
5.8
Operaciones comunes con enteros...............................................87
5.8.1
Valor absoluto .....................................................................87
5.8.2
Mximo y mnimo de un nmero sin signo .............................88
5.8.3
Mximo y mnimo de un nmero con signo ............................90
5.8.4
Resto de una divisin ...........................................................91
5.8.5
Divisin entre una constante entera ......................................92
5.8.6
Divisin de 64 bits en mquinas de 32 bits.............................96
6 Instrucciones de bifurcacin.............................................................101
6.1
Tipos de clculo de la direccin de salto de una instruccin .........101
6.1.1
Instrucciones de salto relativo.............................................102
6.1.2
Instrucciones de salto absoluto ...........................................103
6.1.3
Las instrucciones de salto condicional..................................104
6.1.4
Instrucciones condicionales de salto relativo ........................107
6.1.5
Instrucciones condicionales de salto absoluto.......................108
6.1.6
Instrucciones condicionales de salto al Count Register ..........109
6.1.7
Instrucciones condicionales de salto al Link Register.............110
6.2
Mnemonics...............................................................................112
6.2.1
Mnemonics para saltos incondicionales ................................112
6.2.2
Mnemonics para saltos condicionales...................................112
6.2.3
Mnemonics para acceder a los registros CR, CTR y LR ..........116
6.3
Implementacin en ensamblador de las sentencias de control de
flujo ms conocidas del lenguaje C ......................................................116
6.3.1
Condicional simple y doble..................................................116
6.3.2
Condicional mltiple ...........................................................117
6.4
Los bucles................................................................................120
6.4.1
Mnemonics para bucles ......................................................120
6.4.2
Bucle do-while ...................................................................121
6.4.3
Bucle while ........................................................................122
6.4.4
Bucle for ...........................................................................122
6.5
Operaciones lgicas con los bits del registro CR ..........................124
7 Instrucciones de trabajo con nmeros en punto flotante ....................127
7.1
Introduccin.............................................................................127
7.2
Los registros de punto flotante ..................................................127
7.3
El registro FPSCR......................................................................128
7.3.1
Instrucciones para acceder a los bits de registro FPSCR ........131
7.3.2
Los flags de excepcin .......................................................132
7.3.3
Los bits de condicin y el bit de clase ..................................134
7.3.4
Los bits de redondeo..........................................................136
Pg. 6

Ensamblador del PowerPC con Mac OS X

MacProgramadores

7.4
El registro CR ...........................................................................136
7.5
Manejo de traps .......................................................................137
7.6
Instrucciones de carga y almacenamiento ..................................138
7.7
Instrucciones aritmticas...........................................................140
7.8
Instrucciones de conversin ......................................................143
7.9
Instrucciones de comparacin ...................................................144
7.10
Instrucciones de movimiento de datos ....................................145
8 Incrustar cdigo ensamblador en un programa C...............................146
8.1
Integracin entre C y ensamblador ............................................146
8.2
Acceso a variables C desde ensamblador....................................146
8.3
Expresiones C como operandos de instrucciones ensamblador .....148
8.3.1
Las constraints y los modificadores......................................149
8.3.2
Expresiones C en gcc 3.1....................................................153
9 Llamada a funciones........................................................................154
9.1
Tipos de datos..........................................................................154
9.2
Mecanismo general de llamada a procedimientos ........................155
9.3
Convencin del uso de los registros ...........................................155
9.4
Estructura de la pila..................................................................157
9.4.1
Las reas del frame............................................................158
9.5
Paso de control a un procedimiento ...........................................159
9.5.1
El prlogo y el eplogo ........................................................159
9.5.2
Los procedimientos terminales ............................................164
9.5.3
Paso de parmetros ...........................................................165
9.5.4
Funciones con un nmero variable de parmetros ................168
9.5.5
Retorno de una funcin ......................................................169
9.6
Ejemplo ...................................................................................169
APNDICE A: Aritmtica binaria
1 Tcnicas bsicas de aritmtica entera ...............................................173
1.1
Nmeros sin signo ....................................................................173
1.1.1
Suma con transmisin de acarreo........................................173
1.1.2
Resta con peticin de acarreo .............................................175
1.1.3
Multiplicacin en base 2 .....................................................177
1.1.4
Divisin en base 2..............................................................178
1.2
Nmeros con signo ...................................................................181
1.2.1
Representacin ..................................................................181
1.2.2
Suma y resta de nmeros en complemento a 2 ....................182
1.3
Aspectos del sistema ................................................................183
2 Introduccin al punto flotante ..........................................................186
3 Formato de los datos en punto flotante.............................................188
3.1
Nmeros denormalizados ..........................................................191
3.2
Nmeros especiales ..................................................................192
Rangos mximos y mnimos en los nmeros en punto flotante...............194
4 El problema del redondeo en punto flotante......................................196
4.1
La precisin en punto flotante ...................................................196
4.2
Error absoluto y relativo ............................................................197
4.3
Modos de redondeo ..................................................................198
5 Las excepciones ..............................................................................199
Pg. 7

Ensamblador del PowerPC con Mac OS X

MacProgramadores

Suma en punto flotante ...................................................................201


6.1
Redondeo ................................................................................201
6.2
El algoritmo de la suma.............................................................202
7 Multiplicacin en punto flotante........................................................205
8 Divisin y resto en punto flotante .....................................................206
9 Comparaciones y conversiones.........................................................207
APNDICE B: La segmentacin
1 Que es la segmentacin? ...............................................................209
2 Etapas multiciclo .............................................................................212
3 Los riesgos .....................................................................................213
3.1
Riesgos estructurales ................................................................213
3.2
Riesgos por dependencia de datos .............................................214
3.3
Riesgos de control ....................................................................217
3.4
Saltos sin resolver ....................................................................218
3.5
Solucin software a los saltos sin resolver ..................................219
3.5.1
Estructura if.......................................................................220
3.5.2
Estructura while.................................................................220
3.5.3
Estructura do-while ............................................................221
3.5.4
Estructura for ....................................................................222
3.6
Solucin hardware a los saltos sin resolver .................................222
3.7
La serializacin .........................................................................226
4 Ms all de la segmentacin ............................................................227

Pg. 8

Tema 1
Introduccin al PowerPC

Sinopsis:

Este primer tema sirve para orientar al lector sobre el contenido del tutorial, y
ayuda a concretar una serie de conceptos bsicos que sern necesario tener
claro para leer el resto del tutorial.

Ensamblador del PowerPC con Mac OS X

MacProgramadores

1 La arquitectura del PowerPC


A lo largo de la historia de la informtica, han ido apareciendo distintas
generaciones de ordenadores. Una parte importante de estos ordenadores ha
sido el microprocesador. El microprocesador introduce una diferencia
definitiva en la forma en que trabaja un ordenador, y es a lo que nosotros
llamaremos una arquitectura. Tipos de arquitecturas de microprocesadores
conocidos a lo largo de la historia han sido, el Z80 (usado por los antiguos
Spectrum), el Motorola 68000 (usado hasta hace pocos aos por los
Macintosh), el microprocesador x86 de Intel (usado actualmente por los PCs),
los SPARC usados en las mquinas de Sun, o el PowerPC que es el que vamos
a estudiar en este tutorial. Los procesadores con una misma arquitectura
forman familias, en el sentido de que para una misma arquitectura van
surgiendo procesadores con caractersticas parecidas, pero a los que se van
aadiendo mejoras.
PowerPC es una nueva arquitectura que incorpora importantes ventajas
conceptuales respecto a los anteriores.
Una ventaja importante es que PowerPC es una arquitectura RISC (Reduced
Instruction Set Computing), es decir, que dispone de un juego de
instrucciones reducido, frente a otras arquitecturas como x86 M68000 que
se las conoce como CISC (Complex Instruction Set Computing) los cuales
disponen de un juego de instrucciones mucho ms amplio.
Aunque inicialmente los fabricantes pensaban que cuantas ms instrucciones
tuviera su microprocesador ms potente sera, estudios realizados en la
universidad de Berkeley y Stanford han demostrado que al aumentar este
juego de instrucciones aumentaba mucho la complejidad del cableado del
micro, y el nmero de ciclos de CPU que necesitaban para ejecutar una
instruccin tambin aumentaba. Adems observaron que el nmero de
instrucciones distintas que necesita un ordenador para ejecutar cualquier
programa se poda reducir a un nmero pequeo de primitivas, y que en las
mquinas CISC que estaban usando en aquel entonces muchas instrucciones
eran redundantes. Esto dio lugar a la aparicin de las mquinas RISC de las
cuales un buen ejemplo es la arquitectura SPARC o la arquitectura POWER de
IBM usada por sus mquinas RS/6000, o bien, cmo no?, el PowerPC, que es
una evolucin de la arquitectura POWER desarrollada conjuntamente por IBM,
Motorola y Apple.
El tiempo necesario para ejecutar un programa depende del producto de tres
factores: El nmero de instrucciones del programa, el nmero de ciclos de
reloj necesarios para ejecutar una instruccin y la duracin de cada ciclo
(velocidad del reloj). Los programas hechos para mquinas RISC tienen un
mayor nmero de instrucciones que su correspondiente versin CISC, pero a
cambio, el nmero de ciclos de cada instruccin disminuye. El tercer factor
Pg 10

Ensamblador del PowerPC con Mac OS X

MacProgramadores

(tiempo de cada ciclo) es un factor que depende ms de la tecnologa y


materiales empleados en la construccin del micro, y que con el tiempo se
supone ir mejorando. Para coger lo mejor de ambos mundos, POWER y su
evolucin el PowerPC, son mquinas que no siguen una arquitectura RISC
estricta (como por ejemplo SPARC), sino que incluyen instrucciones
adicionales para operaciones comunes que estn ah slo para reducir el
tamao del programa, sin por ello llegar a la complejidad de las arquitecturas
CISC.
PowerPC es una arquitectura diseada para funcionar tanto en mquinas de
32 bits como en mquinas de 64 bits, es decir, que los registros del
microprocesador y las direcciones de memoria pueden ser o bien de 32 bits o
bien de 64 bits, que es a lo que se llama la palabra (word) del computador.
Aun as, en ambos casos siguen el mismo modelo, y disponen del mismo
juego de instrucciones, que es el modelo y juego de instrucciones del
PowerPC.
Aunque esta arquitectura fue inicialmente diseada en comn, actualmente la
fabricacin de mquinas que siguen el modelo del PowerPC se ha dividido en
dos:
Por un lado Motorola est fabricando chips que siguen esta arquitectura de
uso domstico, y que aunque ha hecho algn micro de 64 bits, la mayora de
los micros de que disponen son de 32 bits.
Por otro lado IBM est fabricando microprocesadores de 32 bits como de 64
bits para sus mquinas y para las ltimas mquinas de Apple.
Apple por su parte compra los micros a Motorola (en concreto los G4
disponen de micros de la serie MPC74xx de Motorola y a IBM (los G5 son
microprocesadores que IBM ha hecho a Apple). Podemos consultar los micros
de que dispone Motorola aqu en [MICROMOTOROLA], y los micros de IBM
en [MICROIBM].
Es importante tambin destacar que los PowerPC no slo se usan para
ordenadores de escritorio, sino que se usan en videoconsolas como la
Nintendo Gamecube, o los PowerPC de Motorola de la serie MPC4xx para
dispositivos empotrados, los cuales son ms baratos de fabricar aunque por
ejemplo carecen de unidad de punto flotante y de tablas de paginacin.
Nosotros nos vamos a centrar en estudiar los micros de 32 bits, que son los
que utiliza el sistema operativo Mac OS X. Tngase en cuenta que aunque
dispongamos de una mquina G5 con un microprocesador de 64 bits,
actualmente no se utilizan sus caractersticas adicionales con el fin de
mantener compatibilidad. En cualquier caso pasar de un ensamblador de 32
bits a uno de 64 bits resulta muy fcil ya que los juegos de instrucciones
fueron pensados con el fin de que fueran similares.

Pg 11

Ensamblador del PowerPC con Mac OS X

MacProgramadores

2 Los entornos del PowerPC


Un objetivo que se fij durante el diseo del PowerPC fue que esta
arquitectura se pudiera utilizar para la fabricacin de procesadores dirigidos a
distintos dispositivos electrnicos, que iban desde los micros para mquinas
automticas y sistemas empotrados hasta los microprocesadores para
workstations y servidores de alto rendimiento.
Para ello se dividi la arquitectura del
PowerPC en tres entornos (Vase
Figura 1.1). El fabricante tiene libertad
a la hora de fabricar un micro que
implemente los tres entornos, o slo
alguno de ellos. Estos entornos son:

OEA
VEA
UISA

Figura 1.1: Entornos del PowerPC

User Instruction Set Architecture (UISA). Define el juego de


instrucciones de usuario de que dispone el micro (tambin llamado entorno
de resolucin de problemas). Aqu se definen aspectos como los registros,
tipos de datos, operaciones en punto flotante del microprocesador y formas
de acceso a memoria.
Virtual Environment Architecture (VEA). Define operaciones adicionales
de usuario, que normalmente escapan a lo que un programador de
aplicaciones puede necesitar controlar, como puedan ser las caches.
Operating Environment Architecture (OEA). Define el juego de
instrucciones del supervisor (tambin llamadas operaciones privilegiadas), que
son operaciones a las que normalmente slo tiene acceso el sistema
operativo. Como puedan ser los mtodos de paginacin o segmentacin de la
memoria, tcnicas de sincronizacin o gestin de excepciones (tambin
llamadas interrupciones). A estas instrucciones slo se puede acceder si el
micro se encuentra en modo supervisor, si est en modo usuario, que es
el modo normal de funcionamiento, slo se puede acceder a las operaciones
de UISA y VEA.
Todos los micros deben de implementar el UISA, mientras que el VEA y OEA
son opcionales, aunque si un micro implementa el OEA tambin debe de
implementar el VEA.
Por ejemplo un micro como el MPC106 de Motorola que es un micro pequeo
pensado para dispositivos empotrados puede disponer slo de UISA, mientras
que un micro de alto rendimiento como el MPC7455 de Motorola implementa
los tres entornos.

Pg 12

Ensamblador del PowerPC con Mac OS X

MacProgramadores

3 Los registros del PowerPC


En entorno UISA define el siguiente conjunto de registros:
o 32 registros de 32 bits de propsito general llamados GPR (General
Purpose Registers). Estos registros sirven para las operaciones
comunes del da a da, como sumas, comparaciones, etc. En las
mquinas de 64 bits, estos registros son de 64 bits.
o 32 registros de 64 bits para operaciones en coma flotante llamados
FPR (Floating Point Registers). Estos registros nos permiten hacer
operaciones matemticas con nmeros en representacin de punto
flotante, tanto de precisin simple como doble. El tamao de estos
registros es siempre de 64 bits, independientemente de si estamos en
una mquina de 32 bits o de 64 bits.
o Otros registros diversos como son el Condition Register (CR), FloatingPoint Status and Control Register (FPSCR), XER, Link Register (LR) y
Count Register (CTR).
El entorno VEA aade dos nuevos registros llamados TBU (Time Base Upper)
y TBL (Time Base Lower), que slo estn disponibles en los micros que
implementan VEA.
Por ltimo OEA define otros muchos registros especiales llamados SPR
(Special Purpose Registers), que no veremos hasta ms adelante, y a los que
slo se puede acceder en modo supervisor. Estos registros nos permiten
controlar cosas como las tablas de paginacin y segmentacin, la traduccin
de direcciones lgicas a direcciones virtuales y reales, el manejo de
excepciones, el acceso a dispositivos, etc. Normalmente estos registros no
son accedidos ms que por el sistema operativo.
Una caracterstica importante de los sistemas RISC, y por tanto del PowerPC
es que, a diferencia de los sistemas CISC, las nicas instrucciones que
transfieren datos entre memoria y los registros son instrucciones diseadas
con el fin de leer o escribir en memoria, y todas las dems instrucciones
siempre trabajan con datos previamente cargados en registros. El hecho de
que las instrucciones de los sistemas RISC slo puedan tener como operandos
registros disminuye mucho los modos de direccionamiento de las
instrucciones del micro, y en consecuencia la complejidad del juego de
instrucciones. Comprese esta organizacin con los sistemas CISC, donde las
instrucciones pueden tener como uno de sus operadores una direccin de
memoria, o bien un registro.
Esto tambin hace que en los sistemas RISC sea muy tpico que una
instruccin tenga hasta 3 operandos. Por ejemplo la instruccin de suma
recibe dos registros como origen y un tercero como destino. Esto tambin es
una diferencia respecto a los sistemas CISC donde las instrucciones suelen
recibir slo dos operadores, con lo que operaciones como la de suma tienen

Pg 13

Ensamblador del PowerPC con Mac OS X

MacProgramadores

que depositar el resultado de la suma en uno de los registros origen, dando


lugar a un sistema menos flexible.
Como adelantamos antes, los procesadores PowerPC tienen dos niveles de
privilegio:
Modo supervisor. Usado slo por el sistema operativo para acceder a los
recursos definidos por el OEA.
Modo usuario. Usado por las aplicaciones y el sistema operativo para
realizar operaciones consideradas no peligrosas. Es el modo que usamos
para acceder a los recursos definidos por UISA y VEA.

4 Byte ordering
Los bytes de la memoria se numeran empezando a contar por 0. Cada
nmero es la direccin de memoria de un byte. En este sentido los bytes son
unidades indivisibles y no existe problema respecto a la forma de ordenar los
bits de un byte en memoria. El problema surge con las variables cuyo tamao
es mayor a un byte.
En este caso existen dos formas de colocar los bytes que forman una variable
en memoria llamadas:
Big-Endian. Donde el byte ms significativo se coloca en la direccin de
memoria ms baja (el primero).
Little-Endian. Donde el byte menos significativo se coloca el la direccin de
memoria ms baja (el primero).
Por ejemplo, el nmero 617163 en binario se escribe como 1001 0110 1010
1100 1011. Si lo queremos guardar en memoria necesitaremos una variable
de tamao suficiente para almacenarlo.
Los tamaos tpicos de variables enteras (vistas desde el punto de vista de C)
aparecen en la Tabla 1.1:
Tipo dato
char
short
int

Tamao
(bytes)
1 byte
2 bytes
4 bytes

Rango Valores
-128..+127
-32.768..+32.767
-2.147.483.648..+ 2.147.483.647

Tabla 1.1: Tamaos tpicos de variables enteras

En nuestro caso necesitaremos una variable de tipo int. En la Figura 1.2 se


muestra como se almacenara esta variable en big-endian y en little-endian en
memoria.
Pg 14

Ensamblador del PowerPC con Mac OS X

4.1.1.1

Big-Endian

0000 0000
0
4.1.1.2

MacProgramadores

0000 1001
1

0110 1010
2

1100 1011
3

0000 1001
2

0000 0000
3

Little-Endian

1100 1011
0

0110 1010
1

Figura 1.2: Almacenamiento de variables Big-Endian y Little-Endian en memoria

En cualquier caso, cuando apuntamos a una variable en memoria siempre se


apunta al primer byte (direccin de memoria ms baja) de la variable.
Como veremos, la organizacin en big-endian tiene la ventaja de que al
escribir el nmero lo escribimos de izquierda a derecha, tal como se lee. El
nico inconveniente que tiene usar la organizacin little-endian es que
debemos de guardar los bytes del nmero al revs de como se lee, lo cual
dificulta su lectura.
Fabricantes de microprocesadores como IBM, o Sun siguen la organizacin
big endian, por desgracia hay un microprocesador muy usado, el x86 de Intel,
que usa la organizacin little-endian.
En PowerPC por defecto se usa big-endian, aunque existen tcnicas de
compatibilidad que permiten acceder a los datos de memoria en little-endian.
Esto es especialmente til para mantener compatibilidad con software escrito
para procesadores que usan little-endian y para poder acceder a estructuras
de datos donde los datos se almacenan en formato little-endian (p.e los
ficheros .bmp de Windows).
Obsrvese que en el caso de los registros del microprocesador no existe el
problema del orden de los bytes que lo componen, ya que los registros son
unidades indivisibles de 32 bits.
Si este documento le est resultando til puede plantearse el ayudarnos a
mejorarlo:
Anotando los errores editoriales y problemas que encuentre y envindlos
al sistema de Bug Report de Mac Programadores.
Realizando una donacin a travs de la web de Mac Programadores.

Pg 15

Ensamblador del PowerPC con Mac OS X

MacProgramadores

5 Alineacin
PowerPC dispone de instrucciones que permiten transferir entre memoria y
los registros tanto bytes, como halfwords (16 bits), words (32 bits), o
doublewords (64 bits). En las mquinas de 32 bits, estos ltimos slo se usan
para los datos en representacin de punto flotante con precisin doble que
queramos guardar en los FPR, mientras que en los procesadores de 64 bits,
los GPRs tienen 64 bits con lo que es su tamao por defecto.
Estas instrucciones de acceso a memoria funcionan ms rpido si el acceso lo
hacemos a una direccin de memoria que sea mltiplo del tamao de los
datos a transferir, por ejemplo si accedemos a variables de tipo int (4
bytes), el acceso ms rpido se consigue cuando accedemos a una direccin
de memoria mltiplo de 4.
Como regla general, debemos colocar las variables en zonas de memoria cuya
direccin sea mltiplo del tamao de la variable que estamos guardando.
Si esto no se hace el microprocesador tiene que hacer dos accesos a
memoria, uno para leer los cuatro primeros bytes alineados y otro para leer
los siguientes 4 bytes, para finalmente componer el valor de la variable, lo
cual enlentece el acceso.
La Tabla 1.2 muestra la alineacin recomendada para cada tamao de dato.
Operando

Longitud

byte
halfword
word
doubleword

1 byte
2 bytes
4 bytes
8 bytes

Direccin
alineada
xxxx
xxx0
xx00
x000

Tabla 1.2: Alinacin recomendada para cada tamao de dato

Una caractersticas importante de las mquinas RISC, es que todas las


instrucciones tienen el mismo tamao, a diferencia de las mquinas CISC
donde las instrucciones tienen un tamao diferente. En PowerPC todas las
instrucciones ocupan 32 bits (tanto en arquitecturas de 32 bits como de 64
bits), lo cual simplifica mucho al procesador el acceso a las instrucciones de
forma consecutiva. Adems en PowerPC las instrucciones siempre tienen que
estar alineadas en direcciones de memoria mltiplos de 4, ya que PowerPC es
literalmente incapaz de acceder a instrucciones que no estuvieran
correctamente alineadas en memoria.

Pg 16

Tema 2
EMPEZANDO A PROGRAMAR

Sinopsis:

Con este tema pretendemos que el lector aprenda a manejar el juego de


instrucciones UISA, es decir, el modo usuario, que son las instrucciones
comunes que tiene este microprocesador.
En los siguientes temas (que actualmente estamos escribiendo) pretendemos
que el lector aprenda tambin a manejar operaciones UISA ms avanzadas
as como a manejar los dems modos.

Ensamblador del PowerPC con Mac OS X

MacProgramadores

1 Herramientas necesarias
Vamos a empezar viendo qu herramientas de programacin en ensamblador
existen para Mac OS X y como se pueden usar.
Los primero que vamos a necesitar es obtener las Development Tools que
podemos conseguir gratuitamente de la Apple Developer Connection (ADC) en
[DEVTOOLS]:
Dentro de estas herramientas encontramos el conocido compilador gcc de
GNU, que es el que nos va a permitir compilar cdigo C, C++, Objective-C y
ensamblador desde la lnea de comandos.
Para probar este comando podemos escribir un fichero llamado saluda.c
como el del Listado 1.1:
#include <stdio.h>
#define MENSAJE "Hola mundo\n"
int main ()
{
printf(MENSAJE);
return 0;
}
Listado 1.1: Programa ensamblador mnimo

Y compilarlo desde la lnea de comandos con:


$ gcc saluda.c -o saluda
$ ./saluda
Hola mundo
El proceso de generacin de un ejecutable a partir de un cdigo fuente en C y
C++ tiene bsicamente 4 pasos:
1.
2.
3.
4.

Preprocesado
Generacin del cdigo ensamblado (compilacin)
Generacin del cdigo objeto (ensamblado)
Enlazado

El compilador de GNU lo que hace cuando recibe un programa en lenguaje


C es pasarlo a lenguaje ensamblador (segundo paso), y despus pasa ese
cdigo a otro subsistema llamado ensamblador, que en GNU es el comando
as (tercer paso), el cual genera el cdigo binario reubicable de ese programa
en un formato especial llamado cdigo objeto. Por ltimo el enlazador que
Pg 18

Ensamblador del PowerPC con Mac OS X

MacProgramadores

en nuestro caso es el comando de GNU ld lo que hace es juntar todos los


ficheros de cdigo objeto reubicable en otro fichero que es el fichero
ejecutable (cuarto paso).
Podemos pedir a gcc que realice todas o slo alguna de estas fases.
Si lo que queremos es slo preprocesar un fichero podemos usar la opcin -E
as:
$ gcc -E saluda.c
Vemos que por la salida estndar obtenemos el cdigo preprocesado con el
fichero <stdio.h> incluido y MENSAJE sustituido.
Si lo que queremos es obtener el cdigo ensamblador del programa C anterior
(compilar), podemos usar la opcin -S as:
$ gcc -S saluda.c
Esto genera otro fichero llamado saluda.s en el que obtendremos el cdigo
ensamblador del programa anterior.
Si queremos obtener el cdigo objeto (fichero .o) del programa usamos la
opcin -c
$ gcc -c saluda.c
Esto genera el fichero saluda.o que despus podemos enlazar junto con
otros ficheros de cdigo objeto.
Tambin podemos compilar un fichero .s (cdigo ensamblador) para obtener
su correspondiente cdigo objeto con esta misma opcin:
$ gcc -c saluda.s
En cualquier
ensamblador,
tambin la
ensamblador.

caso, para obtener el cdigo objeto de un fichero en


gcc lo que hace es llamar al comando as. Esta herramienta
podemos llamar nosotros para compilar un fichero en
Es decir, podemos hacer:

$ as saluda.s -oD.o
De hecho esta es la principal herramienta que vamos a usar para compilar los
programas en ensamblador que hagamos a lo largo de este tutorial.
Tambin , antes de continuar, conviene comentar que las Development Tools
tambin traen una herramienta visual llamada Xcode que nos permite de
Pg 19

Ensamblador del PowerPC con Mac OS X

MacProgramadores

forma ms visual compilar programas C, C++, Objective-C, Java o


ensamblador, aunque internamente esta herramienta llama a las
herramientas de GNU para compilar. En este tutorial vamos a hablar siempre
de los comandos y opciones de GNU, pero si el lector lo prefiere puede usar
esta herramienta e indicar las opciones que aqu demos en las
correspondientes opciones de que dispone Xcode.
Por ltimo, la Tabla 2.1 muestra las extensiones de fichero que reconoce el
compilador de GNU, y para que se utiliza cada una.
Extensin Descripcin
.c
Cdigo fuente C

Qu hace con ellos gcc


Preprocesa, ensambla,
compila y enlaza
Preprocesa, ensambla,
compila y enlaza

.cpp
.cc
.cxx
.C

Cdigo fuente C++

.m

Cdigo fuente Objective-C

Preprocesa, ensambla,
compila y enlaza

.h

Ficheros de cabecera C, C++ o


Objective-C
Cdigo C preprocesado (Si se lo
pasamos al compilador no lo
preprocesa)
Cdigo C++ preprocesado (Si se lo
pasamos al compilador no lo
preprocesa)
Cdigo ensamblador que no debe
ser preprocesado
Cdigo ensamblador que debe ser
preprocesado
Archivo de cdigo objeto
Librera de enlace esttico
Librera de enlace dinmico

No usados directamente

.i

.ii

.s
.S
.o
.a
.so

Ensambla, compila y
enlaza
Ensambla, compila y
enlaza
Compila y enlaza
Preprocesa, compila y
enlaza
Enlaza
Enlaza
Enlaza

Tabla 2.1: Extensiones de fichero que reconoce el compilador de GNU

Pg 20

Ensamblador del PowerPC con Mac OS X

MacProgramadores

2 El programa mnimo
Ya que sabemos cmo se usa el compilador, vamos a escribir un programa
mnimo para ver cmo se compila y enlaza un programa ensamblador en Mac
OS X.
Para ello escribimos un fichero llamado basico.s de la forma:
/* Descripcin: Programa bsico en ensamblador
* Escrito por: Fernando Lpez Hernndez
*/
.text // Empieza la seccin de cdigo
.align 2
.globl _main ; Hacemos global la funcin main()
_main:
blr ;Retorna de la funcin main
En primer lugar, en este programa hemos utilizado los 3 tipos de comentarios
que soporta el lenguaje ensamblador, los cuales se resumen en la Tabla 2.2.
Comentario
/* */
//
;

Descripcin
Comentario multilnea de C
Comentario de una sola lnea de C
Comentario de una sola lnea propio del ensamblador as

Tabla 2.2: Tipos de comentarios en lenguaje ensamblador

Los comentarios de C son comentarios que elimina el preprocesador, con lo


que cuando as va a generar el cdigo objeto, estos comentarios ya han
desaparecido. No pasa lo mismo con el tercer comentario, que es el
comentario propio de as.
Todo programa debe de disponer de la directiva .text, que como veremos
indica la parte del programa que corresponde al programa, y que en
consecuencia es de slo lectura. Ms adelante veremos otra directiva llamada
.data que sirve para indicar el trozo del programa que corresponde a los
datos, y que ser de lectura/escritura.
.align es otra directiva que pide al compilador que alinee la siguiente
instruccin a una direccin mltiplo de 4. El 2 lo que indica es que queremos
que la direccin tenga sus ltimos 2 bits a cero, es decir, de la forma xxxx
xx00, o lo que es lo mismo que sea mltiplo de 2a, siendo a la alineacin
pedida.

Pg 21

Ensamblador del PowerPC con Mac OS X

MacProgramadores

.globl sirve para declarar como global el siguiente smbolo que aparece. La
funcin main() debe de ser un smbolo global para que Mac OS X pueda
acceder a ella. Obsrvese que la funcin se llama _main y no main, esto es
as porque todos los smbolos sufren un name-mangling al estilo C (poner un
_ delante) antes de meterlos en la tabla de smbolos.
blr es la nica instruccin ensamblador que tiene el programa y que lo que
hace es retornar de la llamada a la funcin main(). Como veremos la
direccin a la que retorna esta llamada se almacena en un registro del
microprocesador llamado LR (Link Register), cuyo principal uso es almacenar
direcciones de retorno de las funciones.
Ahora ya lo podemos compilar y ejecutar:
$ gcc basico.s -o basico
$ ./basico

Pg 22

Ensamblador del PowerPC con Mac OS X

MacProgramadores

3 El lenguaje ensamblador
Ahora que ya sabemos cmo se hace un programa en ensamblador, vamos a
comentar brevemente cuales son los principales elementos del lenguaje
ensamblador, as como la sintaxis de las sentencias que soporta.

3.1 Sintaxis del lenguaje


Un programa en ensamblador esta formado por una serie de sentencias,
cada una de las cuales sigue este formato:
[etiqueta:] [instruccion [operandos]] [; comentario]
Una etiqueta es una marca que ponemos para referirnos a la direccin de
memoria de la instruccin o dato que estamos compilando. Despus podemos
usar esta etiqueta desde otros puntos del programa para referirnos a esta
direccin de memoria. Por ejemplo, las instrucciones de salto indican la
direccin a la que saltar dando el nombre de la etiqueta, o las instrucciones
de acceso a memoria tambin usan etiquetas para indicar la direccin de
memoria a la que acceder.
La instruccin puede ser uno de estos tres elementos:
o Una instruccin ensamblador, que debe ensamblar el lenguaje.
o Una directiva, las cuales no generan cdigo, si no que sirven para
cambiar el comportamiento del ensamblador durante el proceso de
ensamblado. Aunque no generan cdigo, s que pueden reservar
memoria, como veremos. Una caracterstica de las directivas es que
todas empiezan por un punto (.).
o Una macro, las cuales se crean con la directiva .macro, como veremos
en el Tema 3.
Los operandos, son parmetros que opcionalmente reciben las
instrucciones, bien sean instrucciones ensamblador, directivas o macros. Los
operandos a recibir dependen de la instruccin a ejecutar, y si hay ms de
uno se suelen separar por comas.
El comentario en ensamblador se precede por ;, y, como dijimos, tambin
podemos usar los comentarios C, aunque el preprocesador los elimina antes
de pasar el fichero al ensamblador.
Las distintas partes de la sentencia se pueden separar tanto por espacio como
por tabulador, pero normalmente existe la costumbre de separar por espacio,
excepto en el caso de la etiqueta donde se suele poder un tabulador al
Pg 23

Ensamblador del PowerPC con Mac OS X

MacProgramadores

principio de lnea si no existe la etiqueta, o bien poder un tabulador despus


de la etiqueta.
Por ejemplo:
inicio:

mflr r0
stwu r1,-80(r1)
mr r30,r1
bcl 20,31,inicio

De esta forma el programa resulta ms fcil de leer.


A continuacin se muestra el ejemplo de un programa que suma dos
nmeros. Desafortunadamente, como todava no sabemos hacer llamadas al
sistema, no vamos a poder imprimir el resultado de la ejecucin. Pero, aun as
este ejemplo nos va a servir para ver algunas instrucciones elementales de
acceso a registros y de suma.
Al programa se llamar sumaregistros.s y aparece en el Listado 2.1:
/* Descripcin: Programa que suma dos nmeros situados en
* registros
* Escrito por: Fernando Lpez Hernndez
*/
.text // Seccin de cdigo
.align 2
.globl _main
_main:
li r3,2
li r4,5
add r5,r3,r4
blr
Listado 2.1: Programa que suma el contenido de los registros

El programa usa la instruccin li para cargar en el registro r3 un 2 y en el


registro r4 un 5, para despus, con la instruccin add calcular r3+r4 y
almacenar el resultado en r5.

3.2 Elementos del lenguaje


En esta seccin vamos a comentar cules son los principales elementos que
componen el lenguaje ensamblador.

Pg 24

Ensamblador del PowerPC con Mac OS X

MacProgramadores

3.2.1 Literales
Un literal es una representacin escrita de un valor. Dentro de los literales
encontramos:
Los caracteres, los cuales se representan encerrados entre comillas simples.
Por ejemplo: 'A', 'a', '2','?'. Cuando el compilador los encuentra los
sustituye por el valor ASCII del carcter correspondiente.
li r3,'A'
Las cadenas de caracteres, las cuales se representan encerradas entre
comillas dobles, como por ejemplo "Hola mundo". El compilador las
sustituye por los cdigos ASCII de sus caracteres.
Estas se utilizan sobre todo para reservar trozos de memoria con la directiva
.ascii as:
.ascii "Hola mundo"
El compilador no pone el 0 de final de cadena, aunque si queremos que lo
ponga podemos usar la directiva .asciz
.asciz "Hola mundo"
Los nmeros enteros, los cuales se pueden representar en decimal, octal o
hexadecimal.
o Los nmeros en decimal se representan en su forma natural: 4, -37.
No pueden empezar por 0.
o Los nmeros en hexadecimal se representan precedidos por 0x, por
ejemplo: 0x45, 0xF259B4C2. Para las letras se pueden usar
maysculas o minsculas indistintamente, es decir podemos escribir
0x3F 0x3f
o Los nmeros en octal empiezan por 0. Por ejemplo, 037, 041241
Los nmeros en punto flotante, se representan de una forma un poco
especial, cuyo formato general sera:
0flt_char[{+-}[dec...][.[dec...]]e[{+-}][dec...]]
flt_char indica si el nmero es un nmero real de precisin simple (r) o de
precisin doble (d). El primer dec... indica la parte entera, el segundo
dec... la parte decimal, y por ltimo va una e seguida de la parte
exponencial del nmero. Con unos ejemplos seguro que queda ms claro:

Pg 25

Ensamblador del PowerPC con Mac OS X

Nmero
1.34
0.00045
2456

MacProgramadores

Precisin
doble
doble
float

Representacin
0d1.34e0
0d45.0e-4
0r2456.0e0

Cuando usamos uno de estos literales con las directivas .single y .double
que sirven para reservar memoria para un nmero en punto flotante de
precisin simple o doble, respectivamente, la directiva ignora el tipo del
literal, y slo se tiene en cuenta el tipo de la directiva, aun as es
recomendable indicar el tipo por claridad.
Por ejemplo:
F1:
F2:
D1:
D2:

.single 0r2456.0e0 ;
;
;
.single 0d2456.0e0 ;
.double 0d1.34e0
;
;
;
.double 0r1.34e0
;

Forma recomentable de reservar


memoria para un float de
32 bits
Tambin reserva 32 bits
Forma recomentable para
reservar memoria para un
double de 64 bits
Tambin reserva 64 bits

3.2.2 Identificadores
Un identificador es un nombre que damos a uno de estos dos elementos:
o Una etiqueta, que sirve para referirnos a un trozo del programa o a
una variable.
o Una constante, que es un nombre al que le asociamos un literal.
Cada identificador consiste en una secuencia de caracteres alfanumrica, que
no puede empezar por un nmero, y en la que se diferencian maysculas de
minsculas.
Como curiosidad, en ensamblador los identificadores pueden tener espacios,
en cuyo caso debemos de encerrarlos entre comillas dobles. Por ejemplo:
"maximo relativo"
"diferencia en pixeles"
Aunque por homogeneidad con los dems lenguajes es mejor no usar esta
forma, que da lugar a confusin con las cadenas de caracteres, y en vez de
ello usar guiones bajos o maysculas y minsculas para separar palabras.
MaximoRelativo
diferencia_en_pixeles
Pg 26

Ensamblador del PowerPC con Mac OS X

MacProgramadores

Las etiquetas deben de estar precedidas por : cuando se declaran, pero no


cuando se usan. Por ejemplo:
inicio:

stwu r1,-80(r1) ; Declaracin

bcl 20,31,inicio ; Uso

Respecto al mbito de las etiquetas, estas slo son visibles dentro del fichero
que las declara, pero podemos hacer las etiquetas de mbito global (para
poder acceder a ellas desde otros ficheros) con la directiva .globl:
.global A
A:
lwi r4,5
Esto hace a la etiqueta A accesible desde otros mdulos. La directiva debe
preceder a la etiqueta que vamos a declarar como global.
Tambin podemos usar las llamadas etiquetas numricas, que son
etiquetas que se pueden redefinir en distintas partes de un mismo fichero.
Estas etiquetas se crean con los dgitos del 0 al 9, y tambin deben de ir
precedidas por :. Aunque puede haber muchas declaraciones de la misma
etiqueta en distintas partes del fichero, slo la etiqueta numrica
inmediatamente anterior y siguiente pueden ser accedidas desde un punto
concreto del programa. Para ello usamos el nombre digitob (back) y
digitof (forward), respectivamente.
Por ejemplo:
1:
instruccionA

1:
instruccionB

b 1 ; Salta a instruccionB
b 1b ; Salta a instruccionB
b 1f ; Salta a instruccionC

1:
instruccionC

3.2.3 Las expresiones


Llamamos operando a cualquier identificador o literal que pueda ser usado
como parmetro en una instruccin, directiva o macro. Ejemplos de
operandos son final, inicio, 45, 'A'

Pg 27

Ensamblador del PowerPC con Mac OS X

MacProgramadores

Llamamos operador a un clculo que ejecutamos sobre uno o ms


operandos. El ensamblador reconoce los mismos operadores que el lenguaje
C, los cuales se resumen en la Tabla 2.3:
Operador
~
!
+
*
/
%
>>

<<

&
|
^
&&
||
<
>
<=
>=
==
!=

Nombre
Menos unrio
Negado binario
Negado lgico

Descripcin
El complemento a 2 de un nmero
Complemento a uno de un nmero
El resultado es 0 si el operando es distinto de
0, y -1 en caso contrario
Suma
La suma de dos nmeros
Resta
La resta de dos nmeros
Multiplicacin
El producto de dos nmeros
Divisin
Divisin entera de dos nmeros. Trunca los
posibles decimales
Mdulo
El resto de la divisin entera
Desplazamiento El resultado es el valor del primer operando
a la derecha
desplazado a la derecha, tantas veces como
diga el segundo operando. El desplazamiento
es siempre aritmtico, respecto a que no
modifica el bit del signo
Desplazamiento El resultado es el valor del primer operando
a la izquierda
desplazado a la izquierda, tantas veces como
diga el segundo operando. El desplazamiento
es siempre aritmtico, respecto a que no
modifica el bit del signo
and binario
El and binario de los dos operandos
or binario
El or binario de los dos operandos
xor binario
El xor binario de los dos operandos
and lgico
El resultado es 1 si ambos operandos son
distintos de 0, y 0 en caso contrario
or lgico
El resultado es 1 si alguno de los operandos
son distintos de 0, y 0 en caso contrario
Menor que
Mayor que
Menor o igual
que
Mayor o igual
que
Igual
Distinto

Tabla 2.3: Operandos que pueden aparecer en una expresin del ensamblador

Las reglas de precedencia y asociatibidad de estos operadores tambin son


las mismas que en el lenguaje C.

Pg 28

Ensamblador del PowerPC con Mac OS X

MacProgramadores

Visto esto, vamos a ver que llamamos expresin a una combinacin de


operandos y operadores. (p.e. 3*a+b)
Las expresiones siempre se evalan a valores de 32 bits, a pesar de que se
puedan usar operandos de distintos tamaos. Por ejemplo se podran usar
valores declarados con las directivas .byte (8 bits) o .short (16 bits), pero
despus de evaluar la expresin tendremos un valor de 32 bits.
Cuando se evala una expresin su resultado puede ser absoluto, reubicable
o externo, dependiendo de la expresin evaluada.
Una expresin tiene un valor absoluto si:
o Los operandos de la expresin son literales.
o Los operandos de la expresin son identificadores a los que hemos
asignado un valor literal.
o La expresin es el resultado de la diferencia de dos operandos
reubicables, y ambos operandos pertenecen a una misma seccin.
Una expresin tiene un valor reubicable si su valor se fija respecto a una
direccin de memoria base como un offset respecto a esa direccin. Cuando
este valor reubicable lo procesa el enlazador, se convierte en un valor
absoluto.
Un ejemplo tpico de expresiones reubicables son las etiquetas, las cuales
tienen una direccin respecto a la base de su seccin. Como veremos la
memoria est dividida en secciones, y las direcciones de memoria se suelen
dar respecto a la seccin en la que estamos situados.
A las expresiones reubicables slo las podemos sumar y restar valores
constantes, as como hacer la resta de expresiones reubicables (pero no la
suma). Las operaciones de multiplicacin y divisin, as como las dems
operaciones, estn prohibidas en las expresiones reubicables.
Por ltimo, una expresin es externa si alguno de sus operandos no est
definido en el fichero de la expresin, sino que es un identificador global
situado en otro mdulo.
En general, se aplican las mismas restricciones a las expresiones externas,
excepto que tampoco se puede hacer la resta de operandos si ambos son
externos, es decir externo1-externo2 est prohibido si externo1 y
externo2 son identificadores externos.

Pg 29

Ensamblador del PowerPC con Mac OS X

MacProgramadores

3.2.4 El location counter


El location counter es un smbolo que en todo momento tiene la direccin
de memoria de la instruccin que est siendo ensamblada. El smbolo usado
para referirse al location counter es el punto (.).
Este resulta a veces til como operando de una instruccin, directiva, macro o
expresin.
El location counter es por naturaleza un valor reubicable.
Existen dos directivas que nos permiten avanzar el valor del location counter:
.align alineacion [, relleno]
que nos permite avanzar el puntero a la siguiente posicin en la que haya
alineacion bits con 0 a la derecha. Es decir, a la siguiente posicin que sea
mltiplo de 2alineacion
relleno indica con que byte rellenar. Si no se indica rellena de ceros.
Por ejemplo:
.align 2
Avanza el location counter hasta la siguiente posicin que sea mltiplo de 4,
rellenando de ceros.
.org avance [, relleno]
Esta directiva avanza el location counter tantos bytes como diga avance,
rellenando con bytes con el valor de relleno, o ceros si no se indica.
Por ejemplo:
.org 100, 0xFF
Rellena los siguientes 100 bytes con 0xFF

Pg 30

Ensamblador del PowerPC con Mac OS X

MacProgramadores

3.3 Las sentencias de asignacin directa


Antes comentamos que todas las sentencias en ensamblador tenan la forma:
[etiqueta:] [instruccion [operandos]] [; comentario]
Slo existe una excepcin que son las sentencias de asignacin directa, las
cuales tienen la forma:
identificador = expresion
La cuales sirven para declarar constantes que se puedan usar ms adelante
en el programa.
Por ejemplo, el programa del Listado 2.1 lo podramos haber hecho como
muestra el Listado 2.2:
// Sentencias de asignacin directa
operando1 = 3
operando2 = 5
.text
.align 2
.globl _main
_main:
li r3,operando1
li r4,operando2
add r5,r3,r4
blr
Listado 2.2: Programa que usa sentencias de asignacin directa

El uso de las sentencias de asignacin directa es equivalente al uso de la


directiva .set, excepto que esta ltima requiere la asignacin de expresiones
absolutas.
Es decir, tambin podramos haberlo hecho como muestra el Listado 2.3:

Pg 31

Ensamblador del PowerPC con Mac OS X

MacProgramadores

// Directivas .set
.set operando1,3
.set operando2,5
.text
.align 2
.globl _main
_main:
li r3,operando1
li r4,operando2
add r5,r3,r4
blr
Listado 2.3: Programa que usa .set en lugar de identificadores

3.4 Las definiciones


Las sentencias de asignacin directa y las directivas .set slo nos permiten
almacenar valores literales:
var1
var1
.set
.set

= 3 ; Correcto
= r3 ; Error ensamblado
var1 3; correcto
var1 r3 ; Error ensamblado

En ensamblador tambin podemos usar definiciones (#define) que el


preprocesador sustituye convenientemente, lo cual es especialmente til para
asignar a los registros nombres ms significativos:
#define dividendo r3
#define divisor r4
#define cociente r5
divw cociente,dividiendo,divisor
Las definiciones pueden aparecer en cualquier parte del programa, aunque se
suelen poner al principio, y el preprocesador las sustituye por su valor antes
de pasar el programa al ensamblador.

Pg 32

Ensamblador del PowerPC con Mac OS X

MacProgramadores

4 Acceso a memoria
En esta seccin vamos a explicar una serie de conceptos fundamentales para
poder acceder a memoria.

4.1 Segmentacin del programa


Sabemos que el proceso
principalmente de dos fases:

de

generacin

de

un

ejecutable

consta

1. Ensamblado. Consiste en transformar los ficheros fuente en ficheros de


cdigo objeto (.o). Esto se puede hacer con la opcin -c de cc
2. Enlazado. El enlazador (el comando ld en nuestro caso) combina
todos los ficheros objeto en un slo fichero ejecutable.
En el fichero ejecutable generado, la distribucin del programa en memoria,
como mnimo estar dividido en dos zonas de memoria a las que se llama
segmentos1:
o Segmento de cdigo. Es donde se almacenan las instrucciones del
programa en s. En consecuencia, es un segmento de slo lectura.
o Segmento de datos. Es donde se almacenan los datos con los que
opera el programa, con lo que es un segmento de lectura/escritura.
Aunque ya explicaremos ms adelante todo esto, cada segmento se almacena
en una pgina distinta, y el separar las instrucciones en un segmento aparte
de slo lectura tiene tres ventajas:
o Si el sistema operativo quiere descargar esta pgina, no tiene que
almacenarla primero en memoria secundaria (swap), ya que puede
volver a leerla del fichero del ejecutable, cosa que no pasa con el
segmento de datos, ya que ste seguramente haya cambiado respecto
a su contenido inicial.
o Si el programa intenta realizar una operacin de modificacin de los
datos en el segmento de cdigo, lo cual seguramente se deba a una
prdida de estabilidad del programa, se produce una excepcin que
podr tratar el sistema operativo.
o Ayuda a una mejor organizacin modular del programa.
Cuando nosotros escribimos un fichero fuente, debemos indicar el segmento
en el que estamos trabajando con las directivas .text (segmento de cdigo)
y .data (segmento de datos).
1

Como veremos ms adelante existen ms segmentos, pero por simplicidad vamos a


empezar suponiendo que slo existen estos dos
Pg 33

Ensamblador del PowerPC con Mac OS X

MacProgramadores

.data

.text

Cuando el enlazador recibe los ficheros de cdigo objeto, ste fusiona todos
los segmentos de un mismo tipo bajo un nico segmento.
Otro concepto importante que va unido a los segmentos es el de
reubicacin. Cuando el compilador genera cdigo objeto, ste almacena
todas las referencias a memoria como direcciones reubicables, es decir, como
offsets respecto a una direccin base 0, que es el principio del segmento.
Cuando el enlazador rene todos los ficheros objetos para generar el
ejecutable, tiene que asignar direcciones absolutas a las direcciones relativas
que deposit el compilador, para ello simplemente concatena todos los
segmentos del mismo tipo, y luego calcula las direcciones absolutas de cada
una de las direcciones reubicables.

4.2 Las secciones


Cada segmento a su vez est dividido en una o ms secciones que nos dan
un mayor nivel de precisin a la hora de indicar como tratar los datos de esa
seccin.
Vamos a comentar qu puede tener cada seccin (del segmento de cdigo y
del de datos), para que sirve cada una, as como que directivas se usan para
delimitar cada seccin.

4.2.1 Secciones del segmento de cdigo


La Tabla 2.4 resume las directivas usadas para cada tipo de seccin que
puede contener el segmento de cdigo:
Directiva
.text

Seccin
(__TEXT,__text)

.const
.literal4

(__TEXT,__const)
(__TEXT,
__literal4)

Pg 34

Descripcin
Almacena
cdigo
de
programa
Variables constantes
Variables constantes de 4
bytes

Ensamblador del PowerPC con Mac OS X

.literal8
.cstring
.constructor
.destructor
.fvmlib_init0
.fvmlib_init1

MacProgramadores

(__TEXT,
__literal8)
(__TEXT,
__cstring)
(__TEXT,
__constructor)
(__TEXT,
__destructor)
(__TEXT,
__ fvmlib_init0)
(__TEXT,__
fvmlib_init1)

.symbol_stub

(__TEXT,
__symbol_stub)
.picsymbol_stub (__TEXT,
__picsymbol_stub)

Variables constantes de 8
bytes
Cadenas
de
caracteres
constantes
Usada
slo
por
los
constructores de C++
Usada
slo
por
los
destructores de C++
Estas secciones las debe de
usar solamente el sistema de
memoria virtual de las
libreras de enlace dinmico.
Nosotros nunca debemos
poner nada aqu.
Usadas
para
llamar
a
funciones de libreras de
enlace
dinmico.
Como
veremos ms adelante

Tabla 2.4: Directivas para cada tipo de seccin del segmento de cdigo

.text Esta directiva se usa para indicar que estamos en el segmento de


cdigo, y si no usamos ninguna otra directiva para especificar la seccin,
entonces estamos en la llamada seccin de cdigo regular, que es la
seccin por defecto, la cual debe contener nicamente instrucciones
ensamblador.
.const Esta directiva se usa para crear una seccin de datos constantes. Si
los datos no van a cambiar durante la ejecucin del programa se pueden
guardar en el segmento de cdigo (en vez de en el segmento de datos), con
las consiguientes ventajas que aporta. Por ejemplo respecto a la paginacin.
El compilador de C usa esta seccin para almacenar variables globales
marcadas como const, las tablas de salto de la sentencia switch, o los
valores de los operandos constantes de las sentencias.
.literal4 Se usa para guardar slo datos constantes de 4 bytes, es decir
enteros y variables float. Al ser slo datos de 4 bytes siempre permanecen
alineados. Durante el ensamblado el compilador rene todas las variables
declaradas en esta seccin que tengan el mismo valor, para que aparezcan
slo una vez en memoria.
.literal8 Igual que antes, pero usada para guardar datos constantes de 8
bytes. Principalmente nmeros double. Durante el ensamblado el compilador
rene todas las variables declaradas en esta seccin que tengan el mismo
valor.

Pg 35

Ensamblador del PowerPC con Mac OS X

MacProgramadores

.cstring Usada para todas las cadenas de caracteres constantes del


programa. Durante el ensamblado el compilador rene todas las variables
declaradas en esta seccin que tengan el mismo valor, para que aparezcan
slo una vez en memoria.
Estas directivas slo indican un cambio de seccin, pero no reservan
memoria. Para indicar la cantidad de memoria a reservar y valor inicial de
esta memoria reservada tenemos las directivas de la Tabla 2.5:
Directiva
.byte [valor]

Descripcin
Reserva espacio para un byte, y le asigna el valor
dado en valor, 0 si no se especifica.
.short [valor]
Reserva espacio para una variable entera de 2
bytes, y le asigna el valor dado en valor, 0 si
no se especifica.
.long [valor]
Reserva espacio para una variable entera de 4
bytes, y le asigna el valor dado en valor, 0 si
no se especifica.
.single [valor]
Reserva espacio para una variable de punto
flotante con precisin simple (4 bytes), y le asigna
el valor dado en valor, 0 si no se especifica.
.double [valor]
Reserva espacio para una variable de punto
flotante con precisin doble (8 bytes), y le asigna
el valor dado en valor, 0 si no se especifica.
.ascii cadena
Reserva espacio para la cadena dada en cadena.
No pone el 0 de final de cadena
.asciz cadena
Reserva espacio para la cadena dada en cadena.
Y pone un 0 al final de la cadena.
.fill
Pone el valor dado en valor tantas veces como
repeticiones,
diga repeticiones. El tamao de la variable
tamao, valor
puede ser 1,2 4 segn diga tamao
.space
n_bytes, Pone el valor dado en valor tantas veces como
[valor]
diga n_bytes, o ceros si no damos valor
Tabla 2.5: Directivas para indicar la cantidad de memoria a reservar y valor inicial

Estas directivas se pueden usar en cualquier seccin y lo que hacen es


reservar la memoria indicada.
Por ejemplo, podemos usar estas directivas as:
.text
.const
c1: .byte 'A'
c2: .byte 'B'
.literal4
i:
.long 12
Pg 36

Ensamblador del PowerPC con Mac OS X

MacProgramadores

f:
.float 0r1.34e0
.literal8
d:
.double 0d56.e7
.cstring
msg: .ascii
"Hola mundo\013\000"
.text ; Ahora van las instrucciones en ensamblador
; en una seccion de codigo regular
lwz r4,0(r9)
lwz r5,0(r11)
Una optimizacin que aplica el compilador a los datos marcados como
.literal4, .literal8 o .cstring es que si el mismo valor aparece
varias veces en distintos ficheros de cdigo objeto (aunque aparezcan con
distinto identificador), utiliza slo una zona de memoria para todos los
cdigos objetos que accedan a ellas.
La optimizacin que hace el compilador al reunir todas las variables con el
mismo valor en la misma direccin de memoria puede confundir al
programador, por ejemplo si hacemos:
.literal4
A1: .long
A2: .long
A3: .long
A4: .long

0
0
0
0

No estamos reservando espacio para 4 nmeros de 32 bits sino que al tener


un mismo valor (0 en nuestro ejemplo) el compilador slo reserva espacio
para un variable de 32 bits, y las etiquetas A1, A2, A3, A4 apuntan a la
misma direccin de memoria.
Si quisiramos reservar memoria para 4 variables de 32 bits cada una
deberamos de haber usando .const as:
.const
A1: .long
A2: .long
A3: .long
A4: .long

0
0
0
0

Las dems directivas que aparecen en la tabla las comentaremos cuando


hayamos avanzado ms.

Pg 37

Ensamblador del PowerPC con Mac OS X

MacProgramadores

4.2.2 Secciones del segmento de datos


La Tabla 2.6 resume las directivas usadas para cada tipo de seccin que
puede contener el segmento de datos:
Directiva
.data
.static_data
.non_lazy_symbol
_pointer

Seccin
(__DATA,__data)
(__DATA,__static_data)
(__DATA,
__nl_symbol_pointer)

.lazy_symbol
_pointer

(__DATA,
__la_symbol_pointer)

.dyld

(__DATA,__dyld)

.const_data

(__DATA,__const)

Descripcin
Seccin de datos regular
Almacena datos estticos
El compilador guarda en
esta seccin punteros a
smbolos
non-lazy
(excepto punteros a
funciones)
El compilador guarda en
esta seccin punteros a
smbolos lazy.
Esta seccin se usa para
el
enlazado
con
funciones de libreras de
enlace
dinmico.
Nosotros no debemos
usarla.
Para almacenar datos
constantes en libreras
de enlace dinmico

Tabla 2.6: Directivas usadas para cada tipo de seccin del segmento de datos

.data Es la seccin de datos regular donde se almacenan datos variables


a no ser que se especifique otra seccin.
.static_data Es una seccin que aunque actualmente no usa el
compilador, fue puesta para que el compilador pudiera separar datos globales
y estticos en secciones distintas.
Para reservar memoria en cada una de estas secciones del segmento de
datos, adems de poder usar las directivas que vimos antes para el segmento
de cdigo (.byte, .short, .long, .single, .double, .ascii, .asciz,
.fill, .space), podemos usar las dos directivas de la Tabla 2.7, las cuales
reservan memoria sin inicializar, cosa que no tiene sentido hacerlo en el
segmento de cdigo por ser de slo lectura, pero si tiene sentido en el
segmento de datos.
Estas dos directivas reservan siempre memoria dentro del segmento de datos,
con lo que aunque aparezcan en el segmento de cdigo la reserva se produce
en el segmento de datos regular.
Pg 38

Ensamblador del PowerPC con Mac OS X

Directiva
.comm etiqueta, tamao

.lcomm etiqueta, tamao

MacProgramadores

Descripcin
Reserva tamao bytes y crea la etiqueta
global etiqueta que apunta a esta zona
de memoria sin inicializar.
Igual a .comm, slo que la etiqueta es de
mbito local, con lo que no es accesible
desde fuera del mdulo

Tabla 2.7: Directivas para reservar memoria en las secciones del segmento de datos

Si aparecen en otra seccin del segmento de datos, la reserva, como


normalmente, se produce en la seccin donde aparecen.
Por ejemplo si hacemos:
.data
A:
.long 60
.static_data
B:
.long 3
.comm C, 4

; Crea una variable de 4 bytes con


; un valor de 60 en la seccin
; (__DATA,__data)
;
;
;
;
;

Crea una variable de 4 bytes con


un valor de 3 en la seccin
(__DATA,__static_data)
Reserva 4 bytes sin inicializar
en la seccin (__DATA,__static_data)

.text
; Ahora van las instrucciones en ensamblador
; en la seccin regular del segmento de cdigo
; (__TEXT,__text)
lwz r4,0(r9)
lwz r5,0(r11)
.comm D, 20 ; Reserva 20 bytes sin inicializar
; en la seccin (__DATA,__data)
; Mas instrucciones en la seccin regular
; del segmento de cdigo (__TEXT,__text)
mtlr r0
lmw r30,-8(r1)
Listado 2.4: Ejemplo de reserva de memoria

4.2.3 Crear nuevas secciones


Siempre podemos pedir un cambio de seccin usando la directiva .section

Pg 39

Ensamblador del PowerPC con Mac OS X

MacProgramadores

Esta directiva tiene el formato general:


.section segmento, seccion
segmento Indica el segmento, y en principio ser __TEXT o __DATA,
aunque existen ms segmentos que de momento no comentaremos.
seccion Indica el nombre de la seccin dentro del segmento.
Las tablas anteriores muestran el nombre que se da a cada uno de las
secciones que hemos comentado.
Obsrvese que el nombre del segmento va siempre en maysculas y el de la
seccin en minsculas.
Luego en vez de haber puesto:
.const
A:
.long 20
Podramos haberlo hecho con la directiva .section as:
.section __TEXT,__const
A:
.long 20
La ventaja de esta directiva es que nos permite crear nuevos nombres de
segmentos y secciones.

4.2.4 Agrupar las secciones


Cuando el compilador genera el cdigo objeto, rene todas las secciones del
mismo tipo que aparezcan a lo largo del fichero fuente, de forma que el
segmento del fichero objeto tiene como mucho una seccin de cada tipo.
Por ejemplo si en el fichero fuente tenemos:
.data

.const

.text

.const

Pg 40

Ensamblador del PowerPC con Mac OS X

MacProgramadores

El fichero objeto correspondiente tendr dos segmentos: de cdigo (__TEXT)


y de datos (__DATA), y el segmento de datos a su vez tendr dos secciones:
la de cdigo regular (__TEXT,__text) y las dos secciones declaradas con
.const se renen en una seccin de cdigo constante (__TEXT,__const).
Cuando el enlazador enlaza los ficheros objeto, vuelve a reunir las secciones
del mismo tipo de los distintos ficheros objeto, para que slo haya una
seccin de cada tipo en el segmento del ejecutable.

4.3 Indireccionamiento de memoria en las


mquinas RISC
Hace aos, las memoria que tenan que direccionar las mquinas era
relativamente pequea (p.e 28B 216B), con lo que las instrucciones
ensamblador podan incluir la direccin de memoria a la que acceder como
parte de la instruccin, llamado indireccionamiento inmediato o bien
usaban un registro para almacenar la direccin a la que acceder, llamado
indireccionamiento de registro.
Cuando este espacio de memoria fue creciendo, los fabricantes se dieron
cuenta de que incluir direcciones de memoria tan largas en las instrucciones
(indireccionamiento inmediato), aumentaba mucho el tamao de los
programas con lo que decidieron que las instrucciones deban de usar slo
indireccionamiento con registro.
En las mquinas CISC es muy tpico que la direccin de memoria a la que
vayamos a acceder forme parte de la instruccin.
Por ejemplo en x86 podemos usar la instruccin:
movb %al,dir
Para mover el byte bajo del registro AL a la direccin de memoria indicada en
dir.
En mquinas RISC como PowerPC
indireccionamiento de registro.
Adems,
PowerPC
memoria
memoria

SPARC

slo

se

permite

el

como comentamos en el Tema 1, todas las instrucciones de


ocupan 32 bits, con lo que no podemos meter una direccin de
(de 32 bits) dentro de la instruccin, ya que slo la direccin de
ocupara los 32 bits disponibles para codificar la instruccin

El enfoque del indireccionamiento con registro soluciona el problema, ya que


ahora la instruccin ensamblador lo nico que contiene es el nmero de
Pg 41

Ensamblador del PowerPC con Mac OS X

MacProgramadores

registro donde est la direccin de memoria a acceder. Los registros que se


usan para indicar direcciones de memoria son los GPR, de los cuales hay 32
(de r0 a r31), con lo cual la instruccin slo gasta 5 bits (25=32), en vez de
32 bits.
Sin embargo aqu surge un problema conocido como el problema del
bootstraping, que es el de cmo almacenamos la primera direccin de
memoria de 32 bits en un registro. Es decir, ninguna instruccin del PowerPC
puede permitirse el lujo de gastar 32 bits para guardar este valor que
queremos meter en un registro.
La solucin que se usa pasa por usar 2 instrucciones, una de ella carga los 16
bits altos del registro, y la otra los 16 bits bajos.
Para obtener la parte alta y la parte baja de una direccin de 32 bits (que
posiblemente saquemos de una etiqueta) se usan los operadores lo16()
hi16() y ha16() tal como se explica a continuacin.
o lo16(expresion) evala a los 16 bits bajos de expresion
o hi16(expresion) evala a los 16 bits altos de expresin
o ha16(expresion) evala a los 16 bits altos de expresin
incrementando 1 si el bit del signo de lo16(expresion) es 1. Como
vamos a explicar en breve, esto permite cargar el valor correcto de una
direccin de memoria en un registro cuando este bit vale 1.
Vamos a ver cmo se cargan los 32 bits de una direccin de memoria en dos
partes, cada una de las cuales carga 16 bits.
En primer lugar comentar que s hay instrucciones que pueden recibir como
operando un valor de 16 bits, que es el que luego cargan en el registro.
Entre ellas encontramos la instruccin:
addis rD,(rA|0),SIMM /* ADD Immediate Shift */
Esta instruccin recibe tres operandos:
rD Es el registro destino de la operacin
rA Es un registro origen de la operacin de suma.
SIMM Es un valor de 16 bits que acta como segundo operando. SIMM
significa Signed IMMediate, es decir se considera como un nmero de 16 bits
con signo.
(rA|0) es una notacin muy usada en las instrucciones del PowerPC que
significa que aqu podemos dar uno de los 32 registros de GPR excepto r0, o
bien un 0, en cuyo caso significa que este operando vale 0, con lo que en rD
se almacena el valor de sumar 0 a SIMM, es decir el valor de rD=0+SIMM.
Pg 42

Ensamblador del PowerPC con Mac OS X

MacProgramadores

La razn por la que podemos indicar cualquiera de los registros menos el r0,
es que en la codificacin binaria de la instruccin, el cdigo 0 se utiliza para
indicar un 0 binario, y no el contenido del registro r0.
Luego ahora podemos usar la instruccin:
addis r2,0,hi16(expr)
Esta instruccin carga el valor de SIMM en r2, e inmediatamente despus
desplaza este valor a la derecha 16 posiciones, para cargar los 16 bits altos
de expr en el registro r2.
A continuacin tenemos que cargar los 16 bits bajos de expr en el registro,
para lo cual podemos usar la instruccin:
ori rA,rS,UIMM /* OR Immediate */
rA es el destino de la operacin
rS es uno de los operandos.
UIMM (Unsigned IMMediate) es el otro operando.
La operacin calcula el OR binario entre rS y 0000||UIMM y lo deposita en
rA.
Luego ahora ya podemos escribir las dos instrucciones que cargan una
direccin de memoria de 32 bits en un registro.
addis r2,0,hi16(expr)
ori r2,r2,lo16(expr)
An queda por ver cundo y cmo se usa ha16(), que lo vamos a ver en el
siguiente punto.

4.4 Modos de indireccionamiento


Los modos de indireccionamiento son las formas en que podemos indicar
una direccin de memoria en la que las instrucciones de nuestro programa
quieren leer o escribir.
Como sabemos, una instruccin consta de un campo opcode, que indica que
hace la instruccin, y de unos operandos. Los operandos pueden estar
codificados directamente dentro de la instruccin, llamado operando
inmediato, o situado en memoria en cuyo caso tememos que hacer un
indireccionamiento del operando.

Pg 43

Ensamblador del PowerPC con Mac OS X

MacProgramadores

Como hemos comentado en el apartado 4.3, este indireccionamiento puede


ser un indireccionamiento inmediato, cuando en el operando almacenamos la
direccin de memoria a la que acceder (slo en mquinas CISC), o un
indireccionamiento de registro, cuando en el operando almacenamos el
registro que tiene la direccin de memoria a la que acceder.
Es muy tpico que el indireccionamiento de registro se haga sumando a el
valor del registro indireccionando una variable, lo cual permite que podamos
referirnos a direcciones de memoria contiguas (p.e. arrays, variables de un
segmento). En este caso se llama registro base al registro a cuyo contenido
le sumamos una variable llamada ndice. El ndice puede ser una constante
codificada dentro de la instruccin, en cuyo caso tenemos un
indireccionamiento de registro base e ndice inmediato, o bien ser un
segundo registro, en cuyo caso tenemos un indireccionamiento de
registro base y registro ndice.
El PowerPC dispone slo de dos modos de indireccionamiento. Estos son
relativamente pocos si los comparamos con la gran cantidad de modos de
indireccionamiento de que suelen disponer los procesadores CICS como x86 o
Motorola 68000.
En principio el disponer slo de dos modos de indireccionamiento simplifica la
construccin de programas sin penalizacin en el rendimiento, es ms al
disponer de pocos modos de indireccionamiento se simplifica el cableado del
micro, que tiene que descodificar menos instrucciones, mejorando el
rendimiento.
Como hemos dicho, los dos modos de indireccionamiento que existen en
PowerPC son:
o Indireccionamiento de registro base e ndice inmediato
o Indireccionamiento de registro base y registro ndice

4.4.1 Indireccionamiento de registro base e ndice


inmediato
Las instrucciones que usan este modo de indireccionamiento tienen codificado
dentro de la instruccin un nmero con signo de 16 bits que acta como
ndice. (operador d), al cual se le extiende el signo hasta los 32 bits y se le
suma con un GPR (operador rA) para generar la direccin efectiva a la que
acceder.
En PowerPC existe la regla de que siempre que se usan registros para
indireccionar memoria se usa la forma (rA|0), donde si rA es 0, se le suma
0 a d (en vez del contenido de r0), con lo que r0 se puede usar para

Pg 44

Ensamblador del PowerPC con Mac OS X

MacProgramadores

instrucciones que realizan operaciones aritmticas, pero no se puede usar


nunca para indireccionar.
En la Figura 2.1 se muestra cmo se genera la direccin efectiva en las
indirecciones de registro e ndice inmediato.
0

56

10 11

Opcode rD/rS

Codificacin de la instruccin

15 16

rA

d
15 16

Extensin de signo
rA=0?

31

No

GPR(rA)

GPR(rD/rS)

31

Direcin efectiva
Store
Load

Memoria principal

Figura 2.1: Indirecciones de registro e ndice inmediato

Estas instrucciones siempre reciben un operando de la forma d(rA), que


significa que rA es el registro base, y sobre el se calcula un desplazamiento
(que puede ser positivo o negativo) dado por la variable de 16 bits con signo
d.
La Tabla 2.8 y Tabla 2.9 muestran las principales instrucciones de acceso a
memoria que usan este modo de indireccionamiento:
Instruccin
lbz rD,d(rA)

lbzu rD,d(rA)

lhz rD,d(rA)

Descripcin
(Load Byte and Zero) El byte en la direccin efectiva
d(rA) se carga en el byte bajo de rD, los dems
bytes de rD quedan a 0
(Load Byte and Zero with Update) Igual a lbz slo
que la direccin efectiva se guarda en rA una vez
realizada la operacin de carga
(Load Half-word and Zero) El half-word en la direccin
efectiva d(rA)se carga en los dos bytes bajos de rD,
los dems bytes de rD quedan a 0

Pg 45

Ensamblador del PowerPC con Mac OS X

lhzu rD,d(rA)

lha rD,d(rA)

lhau rD,d(rA)

lwz rD,d(rA)

lwzu rD,d(rA)

MacProgramadores

(Load Half-word and Zero with Update) Igual a lhz


slo que la direccin efectiva se guarda en rA una
vez realizada la operacin de carga
(Load Half-word Algebraic) El half-word en la direccin
efectiva d(rA)se carga en los dos bytes bajos de rD,
los dems bytes de rD se rellenan con el bit ms
significativo del half-word cargado, es decir, expande
el signo
(Load Half-word Algebraic with Update) Igual a lha
slo que la direccin efectiva se guarda en rA una
vez realizada la operacin de carga
(Load Word and Zero) El word en la direccin efectiva
d(rA) se carga en rD. Obsrvese que al medir un
GPR 32 bits no carga 0 en el resto del registro si el
GPR es de 32 bits, pero si lo hara si la instruccin se
ejecuta en una mquina 64 bits
(Load Word and Zero with Update) Igual a lwz slo
que la direccin efectiva se guarda en rA una vez
realizada la operacin de carga

Tabla 2.8: Instrucciones de carga de enteros con indireccionamiento de registro base e


ndice inmediato

Instruccin
stb rS,d(rA)
stbu rS,d(rA)

sth rS,d(rA)

sthu rS,d(rA)

stw rS,d(rA)
stwu rS,d(rA)

Descripcin
(STore Byte) El byte menos significativo de rS se
guarda en la posicin de memoria dada por d(rA)
(STore Byte with Update) Igual a stb, slo que
despus de guardar el dato en memoria, en rA se
guarda la direccin efectiva calculada como d(rA)
(STore Half-word) El half-word menos significativo de
rS se guarda en la posicin de memoria dada por
d(rA)
(STore Half-word with Update) Igual a sth, slo que
despus de guardar el dato en memoria, en rA se
guarda la direccin efectiva calculada como d(rA)
(STore Word) El valor de rS se guarda en la posicin
de memoria dada por d(rA)
(STore Byte with Update) Igual a stw, slo que
despus de guardar el dato en memoria, en rA se
guarda la direccin efectiva calculada como d(rA)

Tabla 2.9: Instrucciones de almacenamiento de enteros con indireccionamiento de registro


base e ndice inmediato

Pg 46

Ensamblador del PowerPC con Mac OS X

MacProgramadores

4.4.2 Ejemplo
Como ejemplo el Listado 2.5 muestra un programa que calcula la suma de
dos nmeros almacenados en memoria, y deposita el resultado en una
tercera variable de memoria.
/* Descripcin: Programa que suma dos nmeros
*
situados en memoria
* Escrito por: Fernando Lpez Hernndez
*/
.data // Segmento de datos
SD:
.lcomm C,4 ; Reserva 4 bytes sin inicializar
.text // Segmento de cdigo
SC:
.const // Seccin (__TEXT,__const)
A:
.long 3
; Variable constante con el
; primer operando valiendo 3
B:
.long 5
; Variable constante con el
; segundo operando valiendo 5
.text // Seccin (__TEXT,__text)
.globl _main
.align 2
_main:
// Cargamos la direccin base del segmento
// de cdigo en r8
addis r8,0,hi16(SC)
ori r8,r8,lo16(SC)
// Cargamos la direccin base del seg de datos en r9
addis r9,0,hi16(SD)
ori r9,r9,lo16(SD)
// Cargamos A, B en r2 y r3
lwz r2,lo16(A-SC)(r8)
lwz r3,lo16(B-SC)(r8)
// Calculamos la suma en r4
add r4,r2,r3
// Guardamos el resultado que tenemos en r4 en C
stw r4,lo16(C-SD)(r9)
blr
Listado 2.5: Programa que calcula la suma de dos nmeros almacenados en memoria

El anterior programa tiene tanto un segmento de datos (.data) como un


segmento de cdigo (.text).

Pg 47

Ensamblador del PowerPC con Mac OS X

MacProgramadores

El nico dato que se guarda en el segmento de datos es la variable C, ya que


es la nica que va a ser modificada por el programa.
El segmento de cdigo tiene dos secciones:
o Una es la declarada por .const en la que declaramos las variables A y
B, ya que son variables de slo lectura, con lo que es mejor guardarlas
en el segmento de cdigo.
o La otra seccin es una seccin de cdigo regular, declarada al volver a
usar .text, en la cual se guarda el programa en s.
Obsrvese que al principio de cada segmento (que no de cada seccin)
hemos puesto una etiqueta, SD (Segmento de Datos) y SC (Segmento de
Cdigo), las cuales nos van a ser muy tiles, ya que ahora para referirnos a
cualquier otra etiqueta del segmento podemos dar una direccin relativa a
esta etiqueta.
En concreto hemos guardado en r8 el valor de SC y en r9 el valor de SD
usando el mecanismo de carga de una direccin en dos instrucciones que
comentamos antes:
// Cargamos la direccin base del seg de cdigo en r8
addis r8,0,hi16(SC)
ori r8,r8,lo16(SC)
// Cargamos la direccin base del seg de datos en r9
addis r9,0,hi16(SD)
ori r9,r9,lo16(SD)
Luego, cuando queramos referirnos a las dems etiquetas de un segmento
slo tendremos que dar un desplazamiento relativo respecto al principio del
segmento, es decir, si queremos acceder a las variables A o B usamos
lo16(A-SC)(r8) y lo16(B-SC)(r8) respectivamente. Anlogamente
cuando queramos acceder a C usaremos lo16(C-SD)(r9)

4.4.3 Acceso a memoria con actualizacin de registro


Existe una variante de las instrucciones de acceso a memoria por
indireccionamiento de registro base e ndice inmediato que son las
instrucciones de acceso a memoria por indireccionamiento de registro base e
ndice inmediato con actualizacin.
Estas instrucciones aparecen en la Tabla 2.8 y Tabla 2.9 y se caracterizan
porque son iguales a las instrucciones de acceso a memoria normales, slo
que su nombre acaba en u, por ejemplo en vez de llamarse lwz (Load Word
and Zero) se llaman lwzu (Load Word and Zero with Update).

Pg 48

Ensamblador del PowerPC con Mac OS X

MacProgramadores

Estas instrucciones despus de realizar el acceso a memoria guardan en el


registro que estamos usando para indireccionar la memoria (que suele
llamarse rA), la direccin de memoria efectiva a la que han accedido. Esto es
especialmente til a la hora de recorrer estructuras de datos como los arrays,
donde los datos ocupan posiciones de memoria consecutivas.
Por ejemplo si queremos leer un array de elementos de tipo half-word
podemos hacer un bucle as:
.data
.lcomm A,20 ; 10 elementos de 2 bytes
.text

addis r3,0,hi16(A)
ori r3,r3,lo16(A)-2
DESDE 1 HASTA 10
lhzu r2,2(r3)
; Procesamos r2
FIN_DESDE

4.4.4 Uso del operador ha16()


Hasta ahora hemos visto que para acceder a memoria primero tenemos que
cargar en un registro una direccin de memoria, para lo cual usbamos dos
instrucciones:
addis r3,0,hi16(var)
ori r3,r3,lo16(var)
Vamos a ver ahora que usando un pequeo truco vamos a poder cargar en
un registro slo la parte alta de la direccin, y despus aprovechamos el
indireccionamiento de registro base e ndice inmediato para indicar la parte
baja de la direccin, ms o menos as:
addis r3,0,ha16(var)
lwz r2,lo16(var)(r3)
Obsrvese que ahora, para cargar la parte alta de la direccin en el registro,
usamos ha16() en vez de hi16(). Como dijimos en el apartado 4.3
ha16(expr) evala a los 16 bits altos de expresin, incrementando 1 si el
bit del signo de lo16(expr) es 1.
Por qu se hace este incremento? La razn es que si el bit de signo de
lo16(expr) es 1, es que este nmero es negativo con lo que al calcular
lo16(expr)(rA), el nmero est restando al valor del registro, pero en
realidad para calcular la direccin efectiva debera de sumar a rA el valor de
lo16(expr), aunque como hemos partido el nmero de 32 bits de la
Pg 49

Ensamblador del PowerPC con Mac OS X

MacProgramadores

etiqueta en dos nmeros de 16 bits, y el ndice inmediato de la instruccin


codificada se interpreta como un SIMM (Signed IMMediate), la instruccin
interpreta el bit alto de lo16(expr) como un bit de signo, en vez de como
un bit de peso que es lo que es. Si sumamos uno a la parte alta de la
direccin, cuando este bit vale 1, solucionamos el problema.
Con un ejemplo queda ms claro.
Supongamos que queremos acceder a la direccin de 32 bits:
dir = 01101001 01101011 10010111 00110100
Si calculamos lo16(dir), hi16(dir), ha16(dir) tenemos:
lo16(dir) = 10010111 00110100
hi16(dir) = 01101001 01101011
ha16(dir) = 01101001 01101100
Es decir, como el bit alto de lo16(dir) es 1 hemos sumado 1 a ha16(dir)
Ahora cuando la instruccin calcula d(rA) como la suma de la parte alta ms
la parte baja, si intentamos calcular la direccin efectiva dir como
hi16(dir)+lo16(dir) tenemos:
hi16(dir) = 01101001 01101011 00000000 00000000
lo16(dir) = 11111111 11111111 10010111 00110100 +
_________________________________________________
dir
= 01101001 01101010 10010111 00110100
Que no es el valor de la direccin efectiva dir a la que queramos acceder.
Aqu, al ser el bit de signo de lo16(dir) negativo, se ha extendido el signo
antes de sumar.
Mientras que si la suma la hacemos de ha16(dir)+lo16(dir) si
obtenemos el valor de la direccin efectiva dir:
ha16(dir) = 01101001 01101100 00000000 00000000
lo16(dir) = 11111111 11111111 10010111 00110100 +
_________________________________________________
dir
= 01101001 01101011 10010111 00110100
Podemos modificar el ejemplo del Listado 2.5 para que use ha16() en vez de
hi16() como muestra el Listado 2.6.
Pg 50

Ensamblador del PowerPC con Mac OS X

MacProgramadores

/* Descripcin: Programa que suma dos nmeros


*
situados en memoria usando ha16()
* Escrito por: Fernando Lpez Hernndez
*/
.data // Segmento de datos
.lcomm C,4 ; Reserva 4 bytes sin inicializar
.text // Segmento de cdigo
.const // Seccin (__TEXT,__const)
A:
.long 3
; Variable constante con el primer
; operando valiendo 3
B:
.long 5
; Variable constante con el segundo
; operando valiendo 5
.text // Seccin (__TEXT,__text)
.globl _main
.align 2
_main:
// Cargamos A en r2
addis r5,0,ha16(A)
lwz r2,lo16(A)(r5)
// Cargamos B en r3
addis r5,0,ha16(B)
lwz r2,lo16(B)(r5)
// Calculamos la suma en r4
add r4,r2,r3
// Guardamos el resultado que tenemos en r4 en C
addis r5,0,ha16(C)
stw r4,lo16(C)(r5)
blr
Listado 2.6: Suma de nmeros con ha16() y hi16()

Ahora no usamos punteros a la base del segmento, sino que cuando


queremos acceder a una variable, primero cargamos la parte alta de la
direccin con:
addis r5,0,ha16(dir)
Y luego accedemos a memoria usando un indireccionamiento de registro base
e ndice inmediato:
stw r4,lo16(dir)(r5)

4.4.5 Indireccionamiento de registro base y registro ndice


Vamos a ver el otro tipo de indireccionamiento a memoria de que dispone el
PowerPC: El indireccionamiento de registro base y registro ndice.
Pg 51

Ensamblador del PowerPC con Mac OS X

MacProgramadores

La Figura 2.2 muestra cmo se genera la direccin efectiva en las


indirecciones de registro y registro ndice.
0

56

10 11

Opcode rD/rS

Codificacin de la instruccin

15 16

rA

20 21

rB

subopcode

15 16

31

0
31

GPR(rB)
rA=0?

No

GPR(rA)

GPR(rS/rS)

Direcin efectiva
Store
Load

Memoria principal

Figura 2.2: Indirecciones de registro y registro indice

Las instrucciones que usan este modo de indireccionamiento usan dos GPR
(llamados rA y rB) para calcular la direccin efectiva como la suma de estos.
A rA se le llama registro base, y a rB registro ndice. En concreto se
calcula como (rA|0)+rB, es decir, rA puede ser uno de los registros de r1
a r31 (pero no r0), o bien 0, en cuyo caso para calcular la direccin efectiva
se usa slo el valor de rB.
Las Tabla 2.10 y Tabla 2.11 muestran las principales instrucciones que usan
este modo.
Instruccin
lbzx rD,rA,rB

lbzux rD,rA,rB

lhzx rD,rA,rB

Descripcin
(Load Byte and Zero indeXed) El byte en la direccin
efectiva (rA|0)+rB se carga en el byte bajo de rD,
los dems bytes de rD quedan a 0
(Load Byte and Zero with Update indeXed) Igual a
lbzx slo que la direccin efectiva se guarda en rA
una vez realizada la operacin de carga
(Load Half-word and Zero indeXed) El half-word en la
direccin efectiva (rA|0)+rB se carga en los dos
bytes bajos de rD, los dems bytes de rD quedan a 0

Pg 52

Ensamblador del PowerPC con Mac OS X

lhzux rD,rA,rB

lhax rD,rA,rB

lhaux rD,rA,rB

lwzx rD,rA,rB

lwzux rD,rA,rB

MacProgramadores

(Load Half-word and Zero with Update indeXed) Igual


a lhzx slo que la direccin efectiva se guarda en rA
una vez realizada la operacin de carga
(Load Half-word Algebraic indeXed) El half-word en la
direccin efectiva (rA|0)+rB se carga en los dos
bytes bajos de rD, los dems bytes de rD se rellenan
con el bit ms significativo del half-word cargado, es
decir, expande el signo
(Load Half-word Algebraic with Update indeXed) Igual
a lhax slo que la direccin efectiva se guarda en rA
una vez realizada la operacin de carga
(Load Word and Zero indeXed) El word en la direccin
efectiva (rA|0)+rB se carga en rD. Obsrvese que al
medir un GPR 32 bits no carga 0 en el resto del
registro si el GPR es de 32 bits, pero si lo hara si es la
instruccin se ejecuta en una mquina 64 bits
(Load Word and Zero with Update indeXed) Igual a
lwzx slo que la direccin efectiva se guarda en rA
una vez realizada la operacin de carga

Tabla 2.10: Instrucciones de carga de enteros con indireccionamiento de registro base y


registro ndice

Instruccin
stbx rS,rA,rB

stbux rS,rA,rB

sthx rS,rA,rB

sthux rS,rA,rB

stwx rS,rA,rB
stwux rS,rA,rB

Descripcin
(STore Byte indeXed) El byte menos significativo de
rS se guarda en la posicin de memoria dada por
(rA|0)+rB
(STore Byte with Update indeXed) Igual a stbx, slo
que despus de guardar el dato en memoria, en rA se
guarda la direccin efectiva calculada como
(rA|0)+rB
(STore Half-word indeXed) El half-word menos
significativo de rS se guarda en la posicin de
memoria dada por (rA|0)+rB
(STore Half-word with Update indeXed) Igual a sthx,
slo que despus de guardar el dato en memoria, en
rA se guarda la direccin efectiva calculada como
(rA|0)+rB
(STore Word indeXed) El valor de rS se guarda en la
posicin de memoria dada por (rA|0)+rB
(STore Byte with Update indeXed) Igual a stwx, slo
que despus de guardar el dato en memoria, en rA se
guarda la direccin efectiva calculada como
(rA|0)+rB

Tabla 2.11: Instrucciones de almacenamiento de enteros con indireccionamiento de registro


base y registro ndice

Pg 53

Ensamblador del PowerPC con Mac OS X

MacProgramadores

Las instrucciones con indireccionamiento de registro base y registro ndice se


usan principalmente en dos contextos:
o Para acceder a elementos de un array por ndice. En este caso rA
puede apuntar a la base del array, y rB contener el desplazamiento
respecto al principio del array.
o Para mantener punteros a las variables de un segmento. En este caso
rA contiene la direccin de memoria de comienzo del segmento y rB
contiene el lo16(offset) de la direccin de memoria de la variable a
acceder.

4.5 Carga y almacenamiento de bloques de bytes


PowerPC, adems de las instrucciones de carga/almacenamiento que hemos
visto, dispone de operaciones que permiten cargar/almacenar muchos bytes a
la vez.
Estas instrucciones lo que hacen es cargar muchos datos de memoria a los
registros indicados en la instruccin.
Vamos a estudiar estas instrucciones divididas en dos grupos:
1) Instrucciones de carga y almacenamiento de multiples words.
Instruccin
lmw rD,d(rA)

stmw rS,d(rA)

Descripcin
(Load Multiple Word) Carga los word almacenados a
partir de d(rA) en los registros que van desde r(D)
a r(D+n) siendo n=(31-D)
(STore Multiple Word) Guarda a partir de la direccin
de memoria d(rA) los valores de los registros que
van desde r(S) a r(S+n) siendo n=(31-S)

Tabla 2.12: Instrucciones de carga y almacenamiento de multiples words

Estas instrucciones aparecen en la Tabla 2.12 y ambas instrucciones utilizan


un indireccionamiento de registro base con ndice inmediato.
La instruccin lmw carga n words en los registros que van desde rD hasta
r31.
La direccin de memoria apuntada por d(rA) debe de estar alineada a una
posicin mltiplo de 4, o se producir una excepcin.
Por ejemplo para cargar un array de 20 words desde memoria a registros
podemos hacer:
Pg 54

Ensamblador del PowerPC con Mac OS X

MacProgramadores

.const
A:
.long 3456 ; 20 enteros
.long -565

.long 1767
.text
addis r2,0,ha16(A)
lmw r11,A(r2)
La instruccin carga los registros que van de r11 a r31 con los 20 nmeros
del array A.
Si el registro usado para indireccionar (r2 en el ejemplo anterior) hubiera
estado dentro del rango rD..r31 se sobrescribe con el valor ledo de
memoria.
2) Instrucciones de carga y almacenamiento de mltiples bytes
(caracteres)
Estas instrucciones, al igual que antes, nos permiten leer un bloque de
memoria, pero a diferencia de antes:
o El nmero de bytes a leer no tiene porque ser mltiplo de 4
o La direccin de memoria donde empezamos a leer no tiene porque ser
mltiplo de 4
Las cuatro instrucciones de que disponemos aparecen en la Tabla 2.13:
Instruccin
lswi rD,rA,n

stswi rS,rA,n

lswx rD,rA,rB

stswi rS,rA,rB

Descripcin
(Load String Word Indirect) Carga los n primeros
bytes a partir de la direccin de memoria dada por
(rA|0) en los registros que van desde rD en
adelante
(Store String Word Indirect) Guarda a partir de la
direccin de memoria (rA|0) los n primeros bytes
empezando a contar por el byte ms significativo de
rD en adelante
(Load String Word indeXed) Carga los n=XER[25-31]
primeros bytes a partir de la direccin de memoria
dada por (rA|0)+rB en los registros que van desde
rD en adelante
(STore String Word indeXed) Guarda a partir de la
direccin de memoria (rA|0)+rB los n=XER[25-31]
primeros bytes empezando a contar por el byte ms
significativo de rS en adelante

Tabla 2.13: Instrucciones de carga y almacenamiento de mltiples bytes (caracteres)


Pg 55

Ensamblador del PowerPC con Mac OS X

MacProgramadores

El uso del registro XER se explica en el apartado 5.2


Por ejemplo, supongamos que tenemos una cadena de 12 caracteres en la
direccin de memoria etiquetada saludo y la queremos copiar en la direccin
de memoria mensaje (la cual tiene un tamao mximo de 255 caracteres).
Podramos realizar la copia rpidamente as:
.cstring
saludo:
.ascii "Hola mundo!\000"
mensaje: .org 255
.text
addis r2,0,hi16(saludo)
ori r2,r2,lo16(saludo)
lswi r10,r2,12 ; Rellena los registros
; r10,r11,r12,r13
addis r2,0,hi16(mensaje)
ori r2,r2,lo16(mensaje)
addi r3,0,12
mtxer r3 ; En XER cargamos el nmero
; de bytes a leer
andi r3,r3,0
stswi r10,r2,r3 ; Pasa r10,r11,r12,r13 a memoria

4.6 Mnemonics
Para simplificar algunas operaciones de programacin el lenguaje
ensamblador de PowerPC define una serie de mnemonics2 (palabras fciles
de recordar) que son instrucciones que equivalen realmente a otra instruccin
ensamblador, pero que permiten recordar una operacin cuyo nombre no
evoca al propsito de la operacin que queremos realizar.
A lo largo del estudio de los distintos grupos de instrucciones ensamblador,
vamos a acabar con una seccin dedicada a los mnemonics que existen para
operaciones comunes.
El primer mnemonic que vamos a comentar es:
mr rD,rS

equivale a

or rD,rS,rS

Este mnemonic lo que hace es copiar el contenido de rS a rD.

Aunque en castellano se pueden traducir por mnemnicos, hemos preferido mantener el


trmino ingls para facilitar la comprensin de la documentacin
Pg 56

Ensamblador del PowerPC con Mac OS X

MacProgramadores

Un caracterstica de los sistemas RISC es que intentan disponer del menor


juego de instrucciones posible, con lo que si existen varias instrucciones que
realizan la misma operacin, slo implementan una de ellas.
PowerPC no dispone de ninguna operacin de copia de datos entre registros,
porque el mnemonic mr se implementa como una instruccin or.
En PowerPC tampoco existe ninguna instruccin que cargue un nmero en
registro. De hecho, como comentamos antes sera imposible disear una
operacin que cargara 32 bits, ya que todas las instrucciones en PowerPC
ocupaban 32 bits, pero s que sera posible disear una operacin que cargara
16 bits, usando los otros 16 bits para codificar la instruccin.
Aun as en PowerPC no existe ninguna instruccin que cargue 16 bits en
registro, sino que en vez de esto se utilizan los siguientes mnemonics:
li rD,valor
lis rD,valor

equivale a
equivale a

addi rD,0,valor
addis rD,0,valor

Vemos que estn implementados como llamadas a addi (ADD Immediate) y


addis (ADD Immediate Shift). Estos mnemonics nos permiten cargar los 16
bits altos y los 16 bits bajos por separado. Pero no las dos partes, vemos
porqu.
Por ejemplo, para cargar un nmero de 32 bits en el registro r2, podemos
hacer:
numero = 1768937;
addis r2,0,ha16(numero)
addi r2,r2,lo16(numero)
Y si lo furamos a hacer con los nuevos mnemonics podramos poner:
numero = 1768937;
lis r2,ha16(numero)
li r2,lo16(numero)
Pero esto no funciona como esperamos ya que en realidad hemos hecho:
numero = 1768937;
addis r2,0,ha16(numero)
addi r2,0,lo16(numero)
Es decir, primero hemos cargado la parte alta y luego la segunda instruccin
borra el valor del registro para cargar la parte baja.
Luego, es importante recordar que la forma correcta de cargar un nmero de
32 bits en registro no es la dada anteriormente sino esta:
Pg 57

Ensamblador del PowerPC con Mac OS X

MacProgramadores

numero = 1768937;
lis r2,ha16(numero)
addi r2,r2,lo16(numero)
En la que addi suma al valor ya guardado en r2 el valor de lo16(numero)
O bien esta otra:
numero = 1768937;
lis r2,hi16(numero)
ori r2,r2,lo16(numero)
En la que usamos hi16(numero) en vez de ha16(numero), con lo que
para cargar la parte baja usamos ori, que en vez de sumar pone los bits de
la parte baja.
El ltimo mnemonic que vamos a comentar de momento, es:
la rD,d(rA)

equivale a

addi rD,rA,d

Este mnemonic se utiliza cuando en rA tenemos los 16 bits altos de la


direccin de un segmento y queremos obtener la direccin de variables de
ese segmento como un desplazamiento d respecto a esa direccin base, por
ejemplo:
SD:
.data
A:
.long 45
B:
.long 0
C:
.long 37

.text
; En r2 obtenemos la direccin base del segmento
lis r2,ha16(A)
; Hacemos que r3 apunte a A, r4 apunte a B
; y r5 apunte a C
la r3,A(r2)
la r4,B(r2)
la r5,C(r2)

Pg 58

Ensamblador del PowerPC con Mac OS X

MacProgramadores

5 Instrucciones de trabajo con enteros


Las instrucciones de trabajo con enteros cogen sus operandos de los GPRs y
depositan el resultado de la operacin en un GPR.
A no ser que se especifique lo contrario estas instrucciones tratan a los
operandos como nmeros con signo. En caso contrario se indica en el propio
nombre de la instruccin, por ejemplo, mulhwu (MULtiply High Word
Unsigned) o divwu (DIVide Word Unsigned) son instrucciones que trabajan
con nmeros sin signo.
Para el estudio de las instrucciones de trabajo con enteros las hemos dividido
en los siguientes grupos:
o
o
o
o

Instrucciones
Instrucciones
Instrucciones
Instrucciones

aritmticas con enteros


de comparacin de enteros
lgicas con enteros
de desplazamiento y rotacin de enteros

Antes de meternos con el estudio de estas instrucciones vamos a explicar dos


registros que se usan para almacenar el resultado de ejecutar estas
operaciones: Los registros CR y XER.

5.1 El registro CR (Condition Register)


El registro CR sirve para reflejar el resultado de ejecutar ciertas operaciones y
proporciona un mecanismo para realizar comprobaciones en el caso de los
saltos.
Los bits de este registro estn agrupados en campos de 4 bits llamados
CR0,CR1,...,CR7 tal como muestra la Figura 2.3:

CR0
0

CR1
34

CR2
78

11 12

CR3

CR4
15 16

CR5
19 20

CR6
23 24

CR7
27 28

31

Figura 2.3: Organizacin del registro CR en campos

En cualquier momento el valor de este registro puede ser ledo con la


instruccin:
mfcr rD /* Move From Condition register */
Que copia el contenido del registro CR en el registro rD

Pg 59

Ensamblador del PowerPC con Mac OS X

MacProgramadores

Tambin podemos modificar el contenido de cualquiera de los campos del CR


usando:
mtcrf mascara,rS /* MoveTo Condition Register Fields */
El acceso a CR es a nivel de campo, de forma que para cada campo se
modifican los 4 bits del campo o no se modifica ninguno, para ello mascara
es un nmero de 8 bits que acta como mscara a la hora de indicar que
campos del CR sern afectados, de forma que los bits de mascara que
tengan 1 indican que ese campo debe actualizarse con el contenido de sus
correspondientes 4 bits del registro rS y los que tengan 0 indican que ese
campo no debe modificarse.
Por ejemplo, si queremos copiar todos los bits del registro r2 al registro CR
haremos:
mascara=255 ; 1111 1111
mtcrf mascara,r2
Si queremos modificar slo los campos CR6 y CR7 de CR haramos:
mascara=3 ; 0000 0011
mtcrf mascara,r2
Y si slo queremos modificar CR0 haramos:
mascara=128 ; 1000 0000
mtcrf mascara,r2
El principal uso de los campos de CR es almacenar el resultado de ejecutar
operaciones de comparacin como por ejemplo cmp, las cuales veremos ms
a fondo en el apartado 5.4, y cuyos resultados se utilizan para tomar
decisiones, como por ejemplo, los saltos.
Las instruccin cmp tiene el formato:
cmp CRF,L,rA,rB
donde CRF es el nmero del campo de CR donde depositar el resultado, L en
las arquitecturas de 64 bits indica si los registros se tratan como nmeros de
32 bits o de 64 bits, pero en las mquinas de 32 bits siempre debe valer 0, y
rA, rB son los registros cuyos valores vamos a comparar.
Luego si queremos almacenar el resultado de comparar r5 y r6 en el campo
CR2 podemos hacer:
cmp 2,0,r5,r6

Pg 60

Ensamblador del PowerPC con Mac OS X

MacProgramadores

El significado de los bits del campo destino despus de realizar la operacin


es el que aparece en la Tabla 2.14.
Bit
0
1
2
3

Descripcin
El primer operando es menor al segundo
El primer operando es mayor al segundo
Los operandos son iguales
Summary Overflow (SO). Hubo un overflow. Este bit es una copia del
estado final del bit XER[SO]

Tabla 2.14: Significado de los bits de los campos de CR en las instrucciones de comparacin

Si no se especifica campo de CR, por defecto va al CR0. Por desgracia el


campo L es obligatorio indicarlo, aunque para las arquitecturas de 32 bits
siempre deba valer 0.
Por ejemplo, si queremos saber si es igual el contenido de los registros r5 y
r6 haramos:
cmp 0,r5,r6
mfcrf 128,r2 ; Copiamos el campo CR0 a r2
andi r2,4
; Quitamos todos los bits menos el bit
; que indica que que son iguales
Aqu guardamos el resultado de la operacin de comparacin en CR0
(obsrvese que no hemos indicado el campo de CR, pero s L) y despus
sacamos ese campo a r2, para ver si el bit que indica la igualdad (bit 2) est
activo.
El hecho de disponer de 8 campos distintos en CR nos permite almacenar los
resultados de distintas comparaciones, cada una de ellas en un campo
distinto. Adems como se explica en el Apndice B esto permite acelerar la
ejecucin de instrucciones al reducir las dependencias entre ellas en el
pipeline.
Otra forma de modificar el registro CR es como resultado de ejecutar una
instruccin en la que se ha pedido reflejar el resultado de una operacin con
enteros. Estas instrucciones modifican el registro CR0 y se caracterizan
porque su nombre acaba en punto (.), como por ejemplo addi., addic.
andis.
El valor que se guarda en CR0 viene dado por la tabla Tabla 2.15.
Una caracterstica de PowerPC que no encontramos en arquitecturas ms
antiguas como x86 es que la mayora de las instrucciones no modifican los
bits de condicin, con lo que se consigue acelerar el rendimiento al
desaparecer dependencias entre instrucciones.

Pg 61

Ensamblador del PowerPC con Mac OS X

Bit
0
1
2
3

MacProgramadores

Descripcin
El registro destino ha recibido un valor negativo
El registro destino ha recibido un valor positivo
El registro destino ha recibido un cero
Summary Overflow (SO). Hubo un overflow. Este bit es una copia del
estado final del bit XER[SO]

Tabla 2.15: Significado de los bits del campo de CR0 en las instrucciones con enteros
acabadas en punto (.)

Como veremos en el tema de pipelines del Tema 3, estas instrucciones


pueden ser ms lentas que sus correspondientes versiones sin punto (las que
no modifican el campo CR0), con lo que slo debemos usarlas si nos interesa
conocer este resultado.
Un buen ejemplo es cuando vamos a realizar una comparacin con el
resultado de la operacin aritmtica.
Por ejemplo, si queremos sumar el contenido de los registros r5 y r6 y saber
si el resultado es un cero haramos:
addi. r7,r5,r6
mfcrf 128,r2 ; Copiamos el campo CR0 a r2
andi r2,4 ; Quitamos todos los bits menos el bit
; que es el que indica que r7 tiene un 0
Por ltimo queda por comentar que el campo CR1 se suele utilizar para
reflejar el resultado de ejecutar una operacin con nmeros en punto flotante
con instrucciones de punto flotante acabadas en punto (.), como por ejemplo
fadd. o fabs., tal como muestra la tabla Tabla 2.16.
Bit
4
5
6
7

Descripcin
Floating-point
Floating-point
Floating-point
Floating-point

eXception (FX)
Enabled eXception (FEX)
inValid eXception (VX)
Overflow eXception (OX)

Tabla 2.16: Significado de los bits del campo de CR1 en las instrucciones en punto flotante
acabadas en punto (.)

El valor de este registro, no es ms que el contendido de los bits de otro


registro FPSCR[0-3], que como veremos en el apartado 7.4 es el que
almacena los resultados de realizar operaciones en punto flotante.

Pg 62

Ensamblador del PowerPC con Mac OS X

MacProgramadores

5.2 El registro XER


El registro XER es un registro que, al igual que CR, sirve para mostrar el
resultado de ejecutar una operacin con enteros, nos da informacin sobre
posibles problemas durante la ejecucin de la instruccin aritmtica, as como
otras informaciones asociadas a operaciones aritmticas.
La Figura 2.4 muestra las partes en que se divide este registro:

SO OV CA
0

0 0000

0000

0000

0000

0000 0

Byte Count
24 25

31

Figura 2.4: Partes del registro XER

La Tabla 2.17 describe el significado de cada uno de estos bits:


Bit
0

Nombre
SO

OV

CA

3-24
25-31

Byte
count

Descripcin
Summary Overflow. Este bit se activa cada vez que una
instruccin produce un overflow, y queda activo hasta que
se desactiva explcitamente usando mtspr (indicando a XER
como registro a modificar) o mcrxr
Overflow. Indica que la ltima instruccin a producido un
overflow
Carry, Indica que la ltima instruccin a producido un
acarreo
Reservado. Siempre vale 0
Este campo muestra el nmero de bytes transferidos
durante la ejecucin de una instruccin lswx (Load String
Word indeXed) o stswx (Store String Word indeXed)

Tabla 2.17: significado de los bits del registro XER

Lo que muestra este registro es el resultado de ejecutar la instruccin en su


totalidad, no el de ejecutar alguna de sus partes, por ejemplo la instruccin
adde (ADD Extended) calcula la suma de los tres operandos y fija los bits de
XER en base a la operacin completa, no en base a la operacin entre dos de
sus tres operandos.
PowerPC diferencia entre acarreo y overflow, considerando al overflow un
error mientras que al acarreo se le considera slo un indicador de que a la
parte alta de la suma hay que sumarle 1.
Para cada operacin aritmtica que pueda producir un acarreo suelen existir
dos instrucciones, una con indicacin de acarreo y otra sin ella. Por ejemplo
Pg 63

Ensamblador del PowerPC con Mac OS X

MacProgramadores

addi no activa el bit de acarreo si se produce y addic s que lo activa. Esto


es as porque el activar el bit de acarreo puede producir retrasos en la
ejecucin de las instrucciones siguientes del pipeline tal como se explica en el
Apndice B.
Lo mismo pasa con los overflow, hay una instruccin que no lo detecta (add)
y otra que s (addo), incluso hay una que detecta el acarreo y el overflow
(addco).
El registro XER se considera un SPR (Special Purpose Register). Cuando
avancemos ms veremos que existen muchos ms SPR, cada uno de ellos
lleva un nmero asociado. A XER se le considera el SPR nmero 1 (SPR1) y
para leerlo/modificarlo usamos dos instrucciones que nos permiten acceder a
los SPR que son:
mfspr rD,SPR /* Move From Special Purpose Register */
mtspr SPR,rS /* Move To Special Purpose Register */
Por ejemplo, si queremos leer el contenido del registro XER y pasarlo a r5
haramos:
mfspr r5,1 ; 1 indica SPR1
Y si ahora queremos ver si est activo el bit CA (CArry) haramos:
andis r5,r5,0x2000 ; Desactiva todos los bits menos
; el bit de CA
En el apartado 5.7.4 veremos mnemonics que nos permiten acceder al
registro XER de forma ms cmoda.
Es importante diferenciar entre el bit OV que indica un overflow en la ltima
instruccin y el bit SO que es un bit que se activa cuando alguna instruccin
produce un overflow y se queda activo hasta que lo desactivamos (a un bit
que cuando se activa ya no se desactiva en la siguiente instruccin se le llama
un bit de retencin). Esto nos permite saber si a lo largo de una secuencia
de operaciones aritmticas una de ellas ha producido un overflow.
La forma correcta de desactivarlo sera:
mfspr r3,1
lis r4,0x7FFFF

; Cogemos en r3 el valor de XER


; r4 es la mscara que desactiva
; el bit SO

ori r4,r4,0xFFFF
and r3,r3,r4
; Aplicamos la mscara
mtspr 1,r3
; Modificamos XER
mtcrxr 0
; En CR0[CA],CR0[OV],CR0[SO] copiamos XER

Pg 64

Ensamblador del PowerPC con Mac OS X

MacProgramadores

Aqu estamos usando la instruccin:


mtcrxr CRF /* Move to CR XeR */
La cual copia los bits CA, OV y SO de XER a CR para que los bits de CR se
sincronicen con los de XER, es decir, tengan el mismo valor que los bits de
XER.

5.3 Instrucciones aritmticas


5.3.1 Instrucciones aritmticas de suma
La Tabla 2.18 resume las instrucciones aritmticas de suma de enteros que
existen en PowerPC:
Instruccin
addi rD,rA,SIMM
addis rD,rA,SIMM
add rD,rA,rB
add. rD,rA,rB
addo rD,rA,rB
addo. rD,rA,rB
addic rD,rA,SIMM
addic. rD,rA,SIMM

addc rD,rA,rB
addc. rD,rA,rB
addco rD,rA,rB

addco. rD,rA,rB

adde rD,rA,rB
adde. rD,rA,rB

Descripcin
(ADD
Immediate)
Calcula
la
suma
de
(rA|0)+SIMM y la pone en rD.
(ADD Immediate Shift) Calcula la suma de
(rA|0)+(SIMM||0x0000) y la pone en rD
(ADD) La suma rA+rB se deposita en rD
(ADD) Igual que add, slo que CR0 se actualiza tal
como explicamos en el apartado 5.1
(ADD Overflow) Igual que add, slo que XER[OV]
se pone a 1 si hay overflow
(ADD Overflow) Igual que addo, slo que CR0 se
actualiza tal como explicamos en el apartado 5.1
(ADD Immediate Carrying) Igual que addi slo
que XER[CA] a se pone a 1 si hay acarreo
(ADD Immediate Carrying) Igual que addic slo
que CR0 se actualiza tal como explicamos en el
apartado 5.1
(ADD Carrying) Igual que add slo que XER[CA]
se pone a 1 si hay acarreo
(ADD Carrying) Igual que addc slo que CR0 se
actualiza tal como explicamos en el apartado 5.1
(ADD Carrying with Overflow) Igual que add slo
que si hay acarreo XER[CA] se pone a 1 y
XER[OV] se pone a 1
(ADD Carrying with Overflow) Igual que addco
slo CR0 se actualiza tal como explicamos en el
apartado 5.1
(ADD Extended) La suma rA+rB+XER[CA] se
pone en rD
(Add Extended) Igual que adde, slo que CR0 se
actualiza tal como explicamos en el apartado 5.1
Pg 65

Ensamblador del PowerPC con Mac OS X

addeo rD,rA,rB
addeo. rD,rA,rB

addme rD,rA
addme. rD,rA

addmeo rD,rA

addmeo. rD,rA

addze rD,rA
addze. rD,rA

addzeo rD,rA

addzeo. rD,rA

MacProgramadores

(ADD Extended with Overflow) Igual que adde,


slo que XER[OV] se pone a 1 si hay overflow
(ADD Extended with Overflow) Igual que addeo,
slo que CR0 se actualiza tal como explicamos en
el apartado 5.1
(ADD
Minus
one
Extended)
La
suma
rA+XER[CA]+0xFFFFFFFF se guarda en rD
(ADD to Minus one Extended) Igual que addme,
slo que CR0 se actualiza tal como explicamos en
el apartado 5.1
(ADD to Minus one Extended with Overflow) Igual
que addme, slo que XER[OV] se pone a 1 si hay
overflow
(ADD to Minus one Extended with Overflow) Igual
que addmeo, slo que CR0 se actualiza tal como
explicamos en el apartado 5.1
(ADD to Zero Extended) La suma rA+XER[CA] se
deposita en rD
(ADD to Zero Extended) Igual que addze, slo
que CR0 se actualiza tal como explicamos en el
apartado 5.1
(ADD to Zero Extended with Overflow) Igual que
addze, slo que XER[OV] se pone a 1 si hay
overflow
(ADD to Zero Extended with Overflow) Igual que
addzeo, slo que CR0 se actualiza tal como
explicamos en el apartado 5.1

SIMM Signed IMMediate


UIMM Unsigned IMMediate
(rA|0) El valor del registro rA o bien 0 binario
SIMM||0x0000 A SIMM se le concatena 0x0000 al final, es decir,
desplazamos SIMM 16 bits a la izquierda
XER[OV] Indica que nos estamos refiriendo al bit OV del registro XER
Tabla 2.18: Instrucciones aritmticas de suma de enteros

A todos los registros que reciben como operandos estas instrucciones se les
considera nmeros con signo.
En el Listado 2.7 aparece un programa llamado sumalong.s3 que suma dos
nmeros de 64 bits. Al tener los registros de PowerPC slo 32 bits tenemos
que usar dos registros para almacenar un nmero. Imaginemos que

En C de GNU para PowerPC el tipo long ocupa 32 bits, debiendo usarse long long para
su correspondiente tipo de 64 bits
Pg 66

Ensamblador del PowerPC con Mac OS X

MacProgramadores

queremos sumar los nmeros guardados en r2||r3 y r4||r5 y depositar la


suma en r6||r7
En este caso primero tendremos que sumar con acarreo r3+r5 y si hay
acarreo, pasarlo a la suma r2+r4. La suma r2+r4 no la hacemos con
acarreo, ya que si hubiera acarreo este se perdera, luego en este caso vamos
a considerar al acarreo un overflow, el cual podramos detectar para dar un
mensaje de error.
Para la suma con acarreo de r3+r5 vamos a usar la instruccin:
addc r7,r3,r5
Que pone la suma r3+r5 en r7, y activa el bit XER[CA] si hay acarreo.
Despus para sumar r2+r4 usamos la instruccin
addeo r6,r2,r4
Que suma r2+r4+XER[CA], y deposita la suma en r6. Adems la instruccin
tiene deteccin de overflow, que significa que activa el bit XER[OV] si se
produce desbordamiento en la suma.
Este desbordamiento se podra usar despus para dar un mensaje de error.
/* Descripcin: Programa que suma dos nmeros de 64 bits
* Escrito por: Fernando Lpez Hernndez
*/
.data // Segmento de datos
.comm C,8 ; Reserva 8 bytes sin inicializar
.text // Segmento de cdigo
.const // Seccion (__TEXT,__const)
A:
.long 30
; Parte alta
.long 0xFFFFFFFF ; Parte baja
B:
.long 50
; Parte alta
.long 0xFF
; Parte baja
.text // Seccin (__TEXT,__text)
.globl _main
_main:
.align 2
// Cargamos A en r2||r3
lis r10,ha16(A)
lwz r2,lo16(A)(r10)
lwz r3,lo16(A+4)(r10)
// Cargamos B en r4||r5
lis r10,ha16(B)

Pg 67

de
de
de
de

la
la
la
la

variable
variable
variable
variable

A
A
B
B

Ensamblador del PowerPC con Mac OS X

MacProgramadores

lwz r4,lo16(B)(r10)
lwz r5,lo16(B+4)(r10)
// Calculamos la suma en r6||r7
addc r7,r3,r5
addeo r6,r2,r4
// Guardamos el resultado que tenemos en r6||r7 en C
lis r10,ha16(C)
stw r6,lo16(C)(r10)
stw r7,lo16(C+4)(r10)
blr
Listado 2.7: Programa que suma dos nmeros de 64 bits

Otra instruccin relacionada con acarreos es:


addze rD,rA /* ADD Zero extended */
Que calcula la suma rA+XER[CA] y la deposita en rD
Esta instruccin se utiliza para saber si la operacin anterior tuvo acarreo, en
cuyo caso a rA se le suma 1, y si no hubo acarreo se queda valiendo lo
mismo.
Esta instruccin se utiliza cuando vamos a sumar nmeros de ms de 64 bits.
Como ejemplo, vamos a hacer ahora un programa llamado sumalong2.s
(que aparece en el Listado 2.8) el cual suma nmeros de 128 bits.
Para ello vamos a guardar el primer operando en r3||r4||r5||r6 y el
segundo en r7||r8||r9||r10||r11, y vamos a calcular la suma en
r12||r13||r14||r15.
La Figura 2.5 muestra la forma de utilizar las instrucciones:

r3

r4

r5

r6

r7

r8

r9

r10

addzeo r3
addo r11,r3,r7

addzeo r4
addc r12,r4,r8

addzeo r5
addc r13,r5,r9

addc r14,r6,r10

Figura 2.5: Uso de instrucciones que suman dos nmeros de 128 bits

Pg 68

Ensamblador del PowerPC con Mac OS X

MacProgramadores

/* Descripcin: Programa que suma dos nmeros de 128 bits


* Escrito por: Fernando Lpez Hernndez
*/
.data // Segmento de datos
.comm C,16 ; Reserva 16 bytes sin incializar
.text // Segmento de cdigo
.const // Seccion (__TEXT,__const)
A:
.long 1
; Parte alta de la variable
.long 1
; Parte alta de la variable
.long 1
; Parte baja de la variable
.long 1
; Parte baja de la variable
B:
.long 1
; Parte alta de la variable
.long 0xFFFFFFFF ; Parte alta de la variable
.long 0xFFFFFFFF ; Parte baja de la variable
.long 0xFFFFFFFF ; Parte baja de la variable
.text // Seccin (__TEXT,__text)
.globl _main
_main:
.align 2
// Cargamos A en r3||r4||r5||r6
lis r20,ha16(A)
lwz r3,lo16(A)(r20)
lwz r4,lo16(A+4)(r20)
lwz r5,lo16(A+8)(r20)
lwz r6,lo16(A+12)(r20)
// Cargamos B en r7||r8||r9|r10
lis r20,ha16(B)
lwz r7,lo16(B)(r20)
lwz r8,lo16(B+4)(r20)
lwz r9,lo16(B+8)(r20)
lwz r10,lo16(B+12)(r20)
// Calculamos la suma en r11||r12||r13||14
addc r14,r6,r10
addzeo r5,r5
addc r13,r5,r9
addzeo r4,r4
addc r12,r4,r8
addzeo r3,r3
addo r11,r3,r7
// Guardamos el resultado que tenemos
// en r11||r12||r13||r14 en C
lis r20,ha16(C)
stw r11,lo16(C)(r20)
stw r12,lo16(C+4)(r20)
stw r13,lo16(C+8)(r20)
stw r14,lo16(C+12)(r20)
blr
Listado 2.8: Programa que suma nmeros de 128 bits

Pg 69

A
A
A
A
B
B
B
B

Ensamblador del PowerPC con Mac OS X

MacProgramadores

La suma se va haciendo registro a registro de derecha a izquierda. Sumamos


usando addc con el fin de hacer un acarreo al siguiente registro, el cual lo
recoge con addzeo, la cual incrementa 1 al registro slo si hay acarreo. La
ltima instruccin de suma (addo) es la nica que no produce acarreo, sino
que en vez de esto provoca un overflow en caso de que haya acarreo. Este
overflow se podra detectar y actuar en consecuencia.
Obsrvese que hemos utilizado addzeo (ADD Zero Extended Overflow) y no
addze (ADD Zero Extended), esto es as porque otra cosa que podra pasar
es que el registro al que estamos pasando el acarreo (p.e. r5) este lleno, es
decir, valga 0x7FFFFFFF (todos los bits a 1 menos el de signo), en cuyo caso
al sumarle 1 se produce un overflow, que el programa debera de detectar y
corregir convenientemente pasando el acarreo al siguiente registro. Nosotros,
para simplificar el programa, y debido a que todava no hemos estudiado las
sentencias de bifurcacin no lo vamos a hacer, aunque queda explicada la
necesidad de hacerlo.

5.3.2 Instrucciones aritmticas de resta


La Tabla 2.19 resume las instrucciones aritmticas de resta de enteros que
existen en PowerPC:
Instruccin
subf rD,rA,rB
subf. rD,rA,rB
subfo rD,rA,rB
subfo. rD,rA,rB

subfc rD,rA,rB

subfc. rD,rA,rB

subfco rD,rA,rB

subfco. rD,rA,rB

Descripcin
(SUBtract From) Calcula rB-rA y lo deposita en
rD.
(SUBtract From) Igual que subf, slo que CR0 se
actualiza tal como explicamos en el apartado 5.1
(SUBtract From with Overflow) Igual que subf,
slo que XER[OV] se pone a 1 si hay overflow
(SUBtract From with Overflow) Igual que subfo,
slo que CR0 se actualiza tal como explicamos en
el apartado 5.1
(SUBtract From Carring with Overflow) Calcula rBrA y lo deposita en rD, y si hay acarreo pone
XER[CA] a 1
(SUBtract From Carring with Overflow) Igual que
subfc, slo que CR0 se actualiza tal como
explicamos en el apartado 5.1
(SUBtract From Carrying with Overflow) Igual que
subfc, slo que XER[OV] se pone a 1 si hay
overflow
(SUBtract From Carrying with Overflow) Igual que
subfco, slo que CR0 se actualiza tal como
explicamos en el apartado 5.1
Pg 70

Ensamblador del PowerPC con Mac OS X

subfe rD,rA,rB
subfe. rD,rA,rB

subfeo rD,rA,rB

subfeo. rD,rA,rB

subfme rD,rA,rB
subfme. rD,rA,rB

subfmeo rD,rA,rB

subfmeo. rD,rA,rB

subfze rD,rA,rB
subfze. rD,rA,rB

subfzeo rD,rA,rB

subfzeo. rD,rA,rB

MacProgramadores

(SUBtract
From
Extended)
Calcula
rBrA+XER[CA] y lo deposita en rD.
(SUBtract From Extended) Igual que subfe, slo
que CR0 se actualiza tal como explicamos en el
apartado 5.1
(SUBtract From Extended with Overflow) Igual que
subfe, slo que XER[OV] se pone a 1 si hay
overflow
(SUBtract From Extended with Overflow) Igual que
subfeo, slo que CR0 se actualiza tal como
explicamos en el apartado 5.1
(SUBtract From Minus one Extended) Calcula
~rA+XER[CA]+0xFFFFFFFF y lo deposita en rD.
(SUBtract From Minus one Extended) Igual que
subfme, slo que CR0 se actualiza tal como
explicamos en el apartado 5.1
(SUBtract From Minus one Extended with
Overflow) Igual que subfme, slo que XER[OV] se
pone a 1 si hay overflow
(SUBtract From Minus one Extended with
Overflow) Igual que subfmeo, slo que CR0 se
actualiza tal como explicamos en el apartado 5.1
(SUBtract
From
Zero
Extended)
Calcula
~rA+XER[CA] y lo deposita en rD.
(SUBtract From Zero Extended) Igual que subfze,
slo que CR0 se actualiza tal como explicamos en
el apartado 5.1
(SUBtract From Zero Extended with Overflow)
Igual que subfze, slo que XER[OV] se pone a 1
si hay overflow
(SUBtract From Zero Extended with Overflow)
Igual que subfzeo, slo que CR0 se actualiza tal
como explicamos en el apartado 5.1

Tabla 2.19: Instrucciones aritmticas de resta de enteros

Al igual que en la suma, a todos los registros que reciben como operandos
estas instrucciones se les considera nmeros con signo.
La operacin rB-rA tambin se puede escribir como rB+~rA+1, con lo que
podramos implementar una resta a base de sumas.
Aunque no hay ninguna operacin para la resta con un operando inmediato,
su efecto se puede conseguir con addi, con el operador inmediato negado.
Existen mnemonics para la resta que se describen en el apartado 5.7.1.

Pg 71

Ensamblador del PowerPC con Mac OS X

MacProgramadores

5.3.3 Instrucciones de negacin aritmtica


La negacin aritmtica lo que obtiene es el complemento a 2 de un nmero,
es decir el mismo nmero cambiado de signo. Por ejemplo el negado de 3 es
-3. Formalmente la operacin de complemento a 2 se define como ~rA+1
La Tabla 2.20 muestra las instrucciones de negacin aritmtica que existen:
Instruccin
neg rD,rA
neg. rD,rA
nego rD,rA
nego. rD,rA

Descripcin
(NEGate) Calcula el complemento a 2 de rA y lo
deposita en rD, es decir, calcula ~rA+1
(NEGate) Igual que neg, slo que CR0 se actualiza
tal como explicamos en el apartado 5.1
(NEGate with Overflow) Igual que neg, slo que
XER[OV] se pone a 1 si hay overflow
(NEGate) Igual que nego, slo que CR0 se
actualiza tal como explicamos en el apartado 5.1

Tabla 2.20: Instrucciones de negacin aritmtica con enteros

5.3.4 Instrucciones aritmticas de multiplicacin


La Tabla 2.21 muestra las operaciones de multiplicacin que existen en
PowerPC.
La instruccin mulli slo debe usarse cuando estemos seguros de que los 16
bits altos del registro rA estn a 0, sino se producir una perdida de datos
por desbordamiento.
Para evitar este problema es preferible cargar el nmero SIMM en un registro
y operar despus con mulhw y mullw.
La Figura 2.6 muestra un ejemplo de como se calcula el producto de dos
nmeros de 32 bits y como calcularlo usando las operaciones de PowerPC.

Pg 72

Ensamblador del PowerPC con Mac OS X

MacProgramadores

01010101 10101010 01010101 10101010 (rA)


x 11111111 00000000 11111111 00000000 (rB)

00000000 00000000 00000000 00000000


00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000
01010101 10101010 01010101 10101010
01010101 10101010 01010101 10101010
01010101 10101010 01010101 10101010
01010101 10101010 01010101 10101010
01010101 10101010 01010101 10101010
01010101 10101010 01010101 10101010
01010101 10101010 01010101 10101010
01010101 10101010 01010101 10101010
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000
01010101 10101010 01010101 10101010
01010101 10101010 01010101 10101010
01010101 10101010 01010101 10101010
01010101 10101010 01010101 10101010
01010101 10101010 01010101 10101010
01010101 10101010 01010101 10101010
01010101 10101010 01010101 10101010
01010101 10101010 01010101 10101010

01010101 01010101 00000000 10101001 00000001 01010100 01010110 00000000

mulhw rH,rA,rB

mullw rL,rA,rB

Figura 2.6: Clculo del producto de dos nmeros de 32 bits usando instrucciones PowerPC

Instruccin
mulli rD,rA,SIMM
mullw rD,rA,rB

mullw. rD,rA,rB

mullwo rD,rA,rB

Descripcin
(MULtiply Low Immediate) Los 32 bits bajos del
producto rA*SIMM se depositan en rD.
(MULtiply Low Word) Calcula los 32 bits bajos de
rA*rB. Esta instruccin se puede combinar con
mulhw para calcular un producto completo, de 64
bits
(MULtiply Low Word) Igual que mullw, slo que
CR0 se actualiza tal como explicamos en el
apartado 5.1
(MULtiply Low Word with Overflow) Igual que
mullw, slo que XER[OV] se pone a 1 si hay
overflow

Pg 73

Ensamblador del PowerPC con Mac OS X

mullwo. rD,rA,rB

mulhw rd,rA,rB

mulhw. rD,rA,rB

mulhwo rD,rA,rB

mulhwo. rD,rA,rB

mulhwu rD,rA,rB

mulhwu. rD,rA,rB

MacProgramadores

(MULtiply Low Word with Overflow) Igual que


mullwo, slo que CR0 se actualiza tal como
explicamos en el apartado 5.1
(MULtiply High Word) Calcula los 32 bits altos de
rA*rB. Esta instruccin se puede combinar con
mullw para calcular un producto completo, de 64
bits
(MULtiply High Word) Igual que mulhw, slo que
CR0 se actualiza tal como explicamos en el
apartado 5.1
(MULtiply High Word with Overflow) Igual que
mulhw, slo que XER[OV] se pone a 1 si hay
overflow
(MULtiply High Word with Overflow) Igual que
mulhwo, slo que CR0 se actualiza tal como
explicamos en el apartado 5.1
(MULtiply High Word Unsigned) El contenido de
rA y rB es considerado como nmeros de 32 bits
sin signo y calcula los 32 bits de la parte alta del
producto, depositndola en rD
(MULtiply High Word Unsigned)
Igual que
mulhwu, slo que CR0 se actualiza tal como
explicamos en el apartado 5.1

Tabla 2.21: Instrucciones aritmticas de multiplicacin de enteros

5.3.5 Instrucciones aritmticas de divisin


La Tabla 2.22 muestra las instrucciones de divisin de enteros de que dispone
PowerPC.
Instruccin
divw rD,rA,rB

divw. rD,rA,rB
divwo rD,rA,rB
divwo. rD,rA,rB

divwu rD,rA,rB

Descripcin
(DIVide Word) El dividendo es rA, el divisor es rB,
y el cociente se deposita en rD. La instruccin no
nos da el resto de la operacin.
(DIVide Word) Igual que divw, slo que CR0 se
actualiza tal como explicamos en el apartado 5.1
(DIVide Word with Overflow) Igual que divw, slo
que XER[OV] se pone a 1 si hay overflow
(DIVide Word with Overflow) Igual que divwo,
slo que CR0 se actualiza tal como explicamos en
el apartado 5.1
(DIVide Word Unsigned) Calcula la divisin con
nmeros sin signo. El dividendo es rA, el divisor
es rB, y el cociente se deposita en rD. La
Pg 74

Ensamblador del PowerPC con Mac OS X

divwu. rD,rA,rB

divwuo rD,rA,rB

divwuo. rD,rA,rB

MacProgramadores

instruccin no nos d el resto de la operacin.


(DIVide Word Unsigned) Igual que divwu, slo
que CR0 se actualiza tal como explicamos en el
apartado 5.1
(DIVide Word Unsigned with Overflow) Igual que
divwu, slo que XER[OV] se pone a 1 si hay
overflow
(DIVide Word Unsigned with Overflow) Igual que
divwuo, slo que CR0 se actualiza tal como
explicamos en el apartado 5.1

Tabla 2.22: Instrucciones aritmticas de divisin de enteros

5.4 Instrucciones de comparacin de enteros


Estas instrucciones comparan nmeros y depositan el resultado de la
comparacin en uno de los campos de CR.
El principal uso que se da a las instrucciones de comparacin es la toma de
decisiones en instrucciones de salto, las cuales estudiaremos en el apartado
6.
En la Tabla 2.23 se muestran las instrucciones de comparacin de que
dispone PowerPC. El operando CRFD es el campo de CR donde depositar el
resultado de la comparacin. El valor concreto que depositan en este campo
se explica en el apartado 5.1.
Instruccin
cmpi CRFD,L,rA,SIMM

Descripcin
(CoMPare Immediate) Compara como nmeros
con signo al nmero depositado en el registro
rA con el nmero SIMM con extensin de signo.
El resultado de la comparacin se deposita en
CRFD
cmp CRFD,L,rA,rB
(CoMPare) Compara rA y rB tratndolos como
nmeros con signo y el resultado lo deposita en
CRFD
cmpli CRFD,L,rA,UIMM (Compare Logical Immediate) El nmero
depositado en el registro rA se compara con el
nmero 0x0000||UIMM, tratando a los
operandos como nmeros sin signo. El resultado
de la comparacin se deposita en CRFD
cmpl CRFD,L,rA,rB
(CoMPare Logical) Compara a los nmeros
depositados en rA y rB como nmeros sin
signo. El resultado se deposita en CRFD
Tabla 2.23: Instrucciones de comparacin de enteros

Pg 75

Ensamblador del PowerPC con Mac OS X

MacProgramadores

Las instruccin cmpi recibe como operando un nmero con signo (SIMM) de
16 bits sobre el que realiza una extensin del signo a 32 bits, mientras que la
instruccin cmpli recibe como operando un nmero sin signo (UIMM) de 16
bits, sobre el que extiende los 16 bits altos rellenndolos con ceros.
Esto permite usar las instrucciones que reciben nmeros con signo (cmpi y
cmp) para comparaciones aritmticas, y las instrucciones que reciben
nmeros sin signo (cmpli y cmpl) para comparaciones lgicas.
Todas las instrucciones de comparacin permiten omitir el operando CRFD, en
cuyo caso el resultado se deposita en CR0. Por desgracia no podemos omitir
el campo L, que en las mquinas de 32 bits siempre debe valer 0.
Por ejemplo si queremos comparar como nmeros sin signo los registros r3 y
r4 y depositar el resultado de la comparacin en el campo 3 de CR haramos:
cmp 3,0,r3,r4
Si omitimos el campo CRFD el resultado se deposita el campo CR0:
cmp 0,r3,r4
Aunque L=0 lo hemos tenido que dar.

5.5 Instrucciones lgicas con enteros


Este grupo de instrucciones siempre consideran a los operandos como
nmeros sin signo, luego las instrucciones que reciben operandos inmediatos,
los reciben del tipo UIMM, y los extienden a 32 bits rellenando con ceros.
Las instrucciones con punto (.) modifican el campo 0 de CR tal como
explicamos en el apartado 5.1. Sin embargo, ninguna instruccin lgica
modifica los bits XER[SO,OV,CA].
La Tabla 2.24, Tabla 2.25 y Tabla 2.26 muestran las instrucciones lgicas con
enteros que existen en PowerPC.
Instruccin
andi. rD,rA,UIMM
andis. rD,rA,UIMM

Descripcin
(AND Immediate) Realiza un and lgico entre rA y
0x0000||UIMM y lo deposita en rD
(AND Immediate Shifted) Realiza un and lgico
entre rA y UIMM||0x0000 y el resultado lo
deposita en rD
Pg 76

Ensamblador del PowerPC con Mac OS X

and rD,rA,rB
and. rD,rA,rB
andc rD,rA,rB

andc. rD,rA,rB

nand rD,rA,rB

MacProgramadores

(AND) Realiza un and lgico entre rA y rB y el


resultado se deposita en rD
(AND) Igual que add, slo que CR0 se actualiza
tal como explicamos en el apartado 5.1
(AND with Complement) Realiza un and lgico
entre rA y ~rB (complemento a 1 de rB) y el
resultado lo deposita en rD
(AND with Complement) Igual que andc, slo que
CR0 se actualiza tal como explicamos en el
apartado 5.1
(No AND) Al resultado del and lgico entre rA y
rB se le hace el complemento a 1 y se deposita en
rD, es decir, en rD se guarda ~(rA&rB)

Tabla 2.24: Instrucciones que realizan un and lgico con enteros

En PowerPC no existen las respectivas operaciones andi. y andis. sin


punto(.), con lo que estas operaciones siempre modifican el campo CR0.
Instruccin
ori rD,rA,UIMM
oris rD,rA,UIMM
or rD,rA,rB
or. rD,rA,rB
orc rD,rA,rB

orc. rD,rA,rB

nor rD,rA,rB

Descripcin
(OR Immediate) Realiza un or lgico entre rA y
0x0000||UIMM y lo deposita en rD
(OR Immediate Shifted) Realiza or lgico entre rA
y UIMM||0x0000 y el resultado lo deposita en rD
(OR) Realiza un or lgico entre rA y rB y el
resultado se deposita en rD
(OR) Igual que or, slo que CR0 se actualiza tal
como explicamos en el apartado 5.1
(OR with complement) Realiza un or lgico entre
rA y ~rB (complemento a 1 de rB) y el resultado
lo deposita en rD
(OR with Complement) Igual que orc, slo que
CR0 se actualiza tal como explicamos en el
apartado 5.1
(No OR) Al resultado del or lgico entre rA y rB
se le hace el complemento a 1 y se deposita en
rD, es decir, en rD se guarda ~(rA|rB)

Tabla 2.25: Instrucciones que realizan un or lgico con enteros

Instruccin
xori rD,rA,UIMM
xoris rD,rA,UIMM

Descripcin
(eXclusive OR Immediate) Realiza un xor lgico
entre rA y 0x0000||UIMM y lo deposita en rD
(eXclusive OR Immediate Shifted) Realiza xor
lgico entre rA y UIMM||0x0000 y el resultado lo
deposita en rD
Pg 77

Ensamblador del PowerPC con Mac OS X

xor rD,rA,rB
xor. rD,rA,rB
eqv rD,rA,rB

extsb rD,rS

extsb. rD,rS

extsh rD,rS

extsh. rD,rS

cntlzw rD,rS

cntlzw. rD,rS

MacProgramadores

(eXclusive OR) Realiza un xor lgico entre rA y rB


y el resultado se deposita en rD
(eXclusive OR) Igual que xor, slo que CR0 se
actualiza tal como explicamos en el apartado 5.1
(Equivalent) Realiza un xor lgico entre rA y rB y
el resultado se le hace un complemento a 1 y se
guarda en rD. Es decir, en rD se guarda
~(rA^rB)
(EXTended Sign Byte) El byte bajo de rS se copia
en el byte bajo de rD, el resto de los bits de rD se
rellenan con el bit de signo del byte cogido de rS,
(el bit 24), es decir, se extiende el signo de byte
cogido.
(EXTended Sign Byte) Igual que extsb, slo que
CR0 se actualiza tal como explicamos en el
apartado 5.1
(EXTended Sign Half-word) El half-word bajo de
rS se copia en el half-word bajo de rD, el resto de
los bits de rD se rellenan con el bit de signo del
half-word cogido de rS, (el bit 16), es decir, se
extiende el signo de half-word cogido.
(EXTended Sign Half-word) Igual que extsh, slo
que CR0 se actualiza tal como explicamos en el
apartado 5.1
(CouNT Leading Zeros Word) La cuenta de bits 0
consecutivos de rS empezando a contar por la
izquierda se guarda en rD. Esta cuenta va de 0 a
32 ambos inclusive.
(CouNT Leading Zeros Word) Igual que cntlzw,
slo que CR0 se actualiza tal como explicamos en
el apartado 5.1

Tabla 2.26: Otras instrucciones lgicas con enteros

A eqv se le llama la operacin de equivalencia, porque comprueba que todos


los bits sean iguales en cuyo caso el resultado es 0xFFFFFFFF, en caso
contrario, los bits que diverjan valen 0. El resultado slo ser 0x00000000 si
todos los bits son distintos.

5.6 Instrucciones de rotacin y desplazamiento


con enteros
Las operaciones de rotacin y desplazamiento de bits son ms complicadas en
PowerPC que en otras arquitecturas, pero una vez que se entienden, son
especialmente potentes.
Pg 78

Ensamblador del PowerPC con Mac OS X

MacProgramadores

Ambas operaciones mueven los bits a izquierda o derecha, la diferencia est


en que las operaciones de desplazamiento pierden los bits que salen por
un extremo, entrando ceros por el otro extremo, mientras que en las
operaciones de rotacin cuando los bits salen por un extremo, entran por
el otro extremo.

5.6.1 Instrucciones de desplazamiento con enteros


La Tabla 2.27 muestra las operaciones de desplazamiento de enteros que
existen:
Instruccin
slw rD,rS,rC

srw rD,rS,rC

srawi rD,rS,C

srawi. rD,rS,C

sraw rD,rS,rC

sraw. rD,rS,rC

Descripcin
(Shift Left Word) Desplaza a la izquierda los bits
de rS tantas veces como diga rC (que debe ser
un nmero comprendido entre 0 y 31), el
resultado se copia en rD
(Shift Right Word) Desplaza a la derecha los bits
de rS tantas veces como diga rC (que debe ser
un nmero comprendido entre 0 y 31), el
resultado se copia en rD
(Shift Right Algebraic Word Inmediate) Desplaza a
la derecha los bits de rS tantas veces como diga C
(que debe ser un nmero comprendido entre 0 y
31), al resultado se le extiende el bit de signo y se
copia en rD
(Shift Right Algebraic Word Inmediate) Igual que
srawi, slo que CR0 se actualiza tal como
explicamos en el apartado 5.1
(Shift Right Algebraic Word) Desplaza a la derecha
los bits de rS tantas veces como diga rC (que
debe ser un nmero comprendido entre 0 y 31), al
resultado se le extiende el bit de signo y se copia
en rD
(Shift Right Algebraic Word) Igual que sraw, slo
que CR0 se actualiza tal como explicamos en el
apartado 5.1

Tabla 2.27: Instrucciones de desplazamiento con enteros

Entre las operaciones se diferencia claramente entre los desplazamientos sin


signo (slw y srw), y desplazamientos con signo o algebraicos (srawi y
sraw). En los desplazamientos con signo, despus de hacer el
desplazamiento se extiende el signo de forma que el bit de signo nunca se
modifica, es decir, si al empezar el desplazamiento es un 0 (positivo) se
mantiene y por la izquierda entran ceros, y si es un 1 (negativo) se mantiene
y por la izquierda entran unos.
Pg 79

Ensamblador del PowerPC con Mac OS X

MacProgramadores

Por ejemplo si hacemos:


lis r3,0xFFFF
srawi r2,r3,4
srawi r2,r3,15
srawi r2,r3,16

;
;
;
;

r3=0xFFFF0000
r2=0xFFFFF000
r2=0xFFFFFFFE
r2=0xFFFFFFFF

Sin embargo, en los desplazamientos sin signo el bit de signo no es distinto


de los dems.
Por ejemplo si hacemos:
lis r3,0xFFFF
li r4,4
srw r2,r3,r4
li r4,15
srw r2,r3,r4
li r4,16
srw r2,r3,r4

; r3=0xFFFF0000
; r2=0x0FFFF000
; r2=0x0001FFFE
; r2=0x0000FFFF

Obsrvese que faltan las operaciones de desplazamiento a la izquierda con


signo, esto es porque hay mnemonics que equivalen a estas y que
describiremos en el apartado 5.7.3.

5.6.2 Instrucciones de rotacin con enteros


Las operaciones de rotacin reciben como operandos dos nmeros: MB (Mask
Begin) y ME (Mask End), que forman una mscara, la cual indica qu bits de
los 32 bits que tiene un registro son los que nos interesan. Uno de los
nmeros indica el principio de la mscara y otro el final de la mscara, una
vez que se realiza la operacin de rotacin, slo obtenemos los bits que estn
dentro de la mscara, los bits que caigan fuera de la mscara siempre valdrn
0.
P.e. si tenemos MB=4 y ME=28 la mscara sera:
4

28

0000 1111 1111 1111 1111 1111 1111 1000


A esta mscara se le hace un and binario con el resultado de ejecutar la
rotacin y este es el valor final que se obtiene.
Las operaciones de rotacin de que dispone PowerPC se describen en la Tabla
2.28.

Pg 80

Ensamblador del PowerPC con Mac OS X

Instruccin
rlwinm rD,rS,N,MB,ME

rlwinm. rD,rS,N,MB,ME

rlwnm rD,rS,rN,MB,ME

rlwnm. rD,rS,rN,MB,ME

rlwimi rD,rD,N,MB,ME

rlwimi. rD,rD,N,MB,ME

MacProgramadores

Descripcin
(Rotate Left Word Immediate theN and with
Mask) El contenido de rS se rota a la
izquierda el nmero de veces especificado en
N. Se genera una mscara con unos desde el
bit MB hasta el bit ME, y lo dems con ceros.
Al resultado de la rotacin se le hace un and
binario con la mscara, y el resultado se
deposita en rD
(Rotate Left Word Immediate theN and with
Mask) Igual que rlwinm, slo que CR0 se
actualiza tal como explicamos en el apartado
5.1
(Rotate Left Word theN and with Mask) El
contenido de rS se rota a la izquierda el
nmero de veces especificado en los 5 bits
bajos de rN. Se genera una mscara con
unos desde el bit MB hasta el bit ME, y lo
dems con ceros. Al resultado de la rotacin
se le hace un and binario con la mscara, y el
resultado se deposita en rD
(Rotate Left Word theN and with Mask) Igual
que rlwnm, slo que CR0 se actualiza tal
como explicamos en el apartado 5.1
(Rotate Left Word Immediate then Mask
Insert) El contenido de rS se rota a la
izquierda tantas veces como diga N, del
resultado se insertan los bits indicados por los
unos de la mscara en sus respectivas
posiciones del registro rD, dejando los
anteriores bits con el valor anterior que
tuvieran en rD
(Rotate Left Word Immediate then Mask
Insert) Igual que rlwimi, slo que CR0 se
actualiza tal como explicamos en el apartado
5.1

Tabla 2.28: Instrucciones de rotacin con enteros

Obsrvese que slo existen operaciones de rotacin a la izquierda, y no


existen sus correspondientes operaciones de rotacin a la derecha, esto es
porque siguiendo el principio de las arquitecturas RISC de proporcionar un
juego de operaciones mnimas, las operaciones de rotacin n bits a la derecha
se pueden conseguir haciendo 32-n rotaciones a la izquierda.

Pg 81

Ensamblador del PowerPC con Mac OS X

MacProgramadores

Un ejemplo de cmo se utiliza rlwinm sera este: Supongamos que tenemos


el registro rS con el valor:
rS = 00000000 00000000 00000000 00000001
Y ejecutamos las operaciones:
rlwinm rD,rS,2,0,10
Obtendremos 00000000 00000000 00000000 00000100, pero como la
mascara delimita los valores que van desde MB=0 a ME=10, los elementos
que caigan fuera de este rango valdrn 0 y en rD obtenemos todos los bits a
0:
rD=00000000 00000000 00000000 00000000
Sin embargo si ejecutamos:
rlwinm rD,rS,2,0,31
Ahora la mscara va desde MB=0 hasta ME=31, es decir, abarca todos los bits
del registro y en rD obtenemos:
rD=00000000 00000000 00000000 00000100
Por contra, la instruccin rlwimi s que tiene en cuenta el valor de rD, ya
que slo se cambian los bits de rD que caen bajo la mscara, dejando los
dems bits tal como estn. Por ejemplo si tenemos los registros rS y rD con
estos valores:
rD = 11111111 11111111 11111111 11111111
rS = 00000000 00000000 00000000 00000001
Y hacemos:
rlwimi rD,rS,2,0,10
Obtenemos rD=00000000 00111111 11111111 11111111
Y si hacemos:
rlwimi rD,rS,2,0,31
Obtenemos rD=00000000 00000000 00000000 00000100

Pg 82

Ensamblador del PowerPC con Mac OS X

MacProgramadores

5.7 Mnemonics
5.7.1 Mnemonics para la resta
Como decamos en el apartado 5.3.2, aunque no hay ninguna operacin para
resta con un operando inmediato, su efecto se puede conseguir con un
mnemonic que llame a addi. En la Tabla 2.29 se detallan que mnemonics
hay para la resta inmediata.
Mnemonic
subi rD,rA,SIMM
subi. rD,rA,SIMM
subis rD,rA,SIMM
subis. rD,rA,SIMM
subic rD,rA,SIMM
subic. rD,rA,SIMM

Equivalente a
addi rD,rA,-SIMM
addi. rD,rA,-SIMM
addis rD,rA,-SIMM
addis. rD,rA,-SIMM
addic rD,rA,-SIMM
addic. rD,rA,-SIMM

Tabla 2.29: Mnemonic para la resta con un operando inmediato

Por otro lado las operaciones de resta reciben los operandos de una forma
poco natural, ya que reciben primero el sustraendo y luego el minuendo,
cuando lo normal es recibirlos al revs. Para facilitar la comprensin del
programa se han creado mnemonics que reciben los operandos en el orden
inverso como muestra la Tabla 2.30.
Mnemonics
sub rD,rA,rB

Equivale a
subf rD,rB,rA

sub. rD,rA,rB

subf. rD,rB,rA

subo rD,rA,rB

subfo rD,rB,rA

subo. rD,rA,rB

subfo. rD,rB,rA

subc

subfc rD,rB,rA

subc.

rD,rA,rB

rD,rA,rB subfc. rD,rB,rA

Pg 83

Descripcin
Calcula rA-rB y lo deposita en
rD
Igual que sub pero dejando el
CR0 el resultado de la
comparacin tal como se
explic en el apartado 5.1
Igual que sub slo que activa
el bit XER[OV] si hay overflow
Igual que subo pero dejando el
CR0 el resultado de la
comparacin tal como se
explic en el apartado 5.1
Calcula rA-rB y lo deposita en
rD, y si hay acarreo pone
XER[CA] a 1
Igual que sub. pero dejando el
CR0 el resultado de la
comparacin tal como se
explic en el apartado 5.1

Ensamblador del PowerPC con Mac OS X

subco

MacProgramadores

rD,rA,rB subfco rD,rB,rA

subco. rD,rA,rB subfco.


rD,rB,rA

Igual que subc slo que activa


el bit XER[OV] si hay overflow
Igual que subco pero dejando
el CR0 el resultado de la
comparacin tal como se
explic en el apartado 5.1

Tabla 2.30: Mnemonic para resta de dos registros operandos

5.7.2 Mnemonics para las operaciones de comparacin


Recurdese que las operaciones de comparacin de PowerPC tienen la forma:
cmp CRF,L,rA,rB
Tal que en arquitecturas de 32 bits L siempre debe valer 0. Para evitar tener
que pasar siempre un 0 en este operando se han diseado los mnemonics de
la Tabla 2.31:
Operacin
Compare Word
Immediate
Compare Word
Compare Logical Word
Immediate
Compare Logical Word

Mnemonic
cmpwi CRF,rA,SIMM

Equivalente a
cmpi CRF,0,rA,SIMM

cmpw CRF,rA,rB
cmplwi
CRF,rA,SIMM
cmplw CRF,rA,rB

cmpi CRF,0,rA,rB
cmpli CRF,0,rA,SIMM
cmpli CRF,0,rA,rB

Tabla 2.31: Mnenonics de comparacin para 32 bits

Los smbolos de la Tabla 2.32 se pueden usar en lugar de sus valores


numricos:
Smbolo Valor Descripcin
cr0
0
Campo CR0 de CR
cr1
1
Campo CR1 de CR
cr2
2
Campo CR2 de CR
cr3
3
Campo CR3 de CR
cr4
4
Campo CR4 de CR
cr5
5
Campo CR5 de CR
cr6
6
Campo CR6 de CR
cr7
7
Campo CR7 de CR
Tabla 2.32: Mnemonics para smbolos numricos

Pg 84

Ensamblador del PowerPC con Mac OS X

MacProgramadores

Estos smbolos se pueden usar en las instrucciones de comparacin cmp,


cmpi, cmpl y cmpli, as como en los mnemonics de comparacin cmpw,
cmpwi, cmplw y cmplwi. Por ejemplo, en vez de poner:
cmpw 2,rA,rB
Podemos poner:
cmpw cr2,rA,rB
Que queda mucho ms claro.

5.7.3 Mnemonics para operaciones de desplazamiento y


rotacin
Las operaciones de desplazamiento y rotacin de PowerPC proporcionan una
forma general de manipular el contenido de los registros, pero pueden
resultar difciles de entender, o de saber cmo se utilizan.
Para ayudar al programador se han creado una serie de mnemonics que
realizan las operaciones ms comunes que aparecen en la Tabla 2.33. En
concreto estos mnemonics nos permiten realizar las siguientes operaciones:
o Extract. Nos permite sacar de un registro un campo de n bits
empezando por una posicin b. Estos bits se copian en un registro
destino alineados a la izquierda o a la derecha y poniendo a 0 todos los
dems bits.
o Insert. Elegimos un campo de n bits del registro origen justificado a la
izquierda o a la derecha, e insertamos este campo de bits en el registro
destino empezando por la posicin b. Todos los dems bits del registro
destino quedan sin cambios.
o Rotate. Rota el contenido de un registro a la izquierda o a la derecha,
pero sin usar mscara.
o Shift. Desplazamiento lgico (sin bit de signo) del contenido de un
registro a la izquierda o a la derecha.
o Clear. Borra los n bit ms a la izquierda o a la derecha de un registro
o Clear left and Shift left. Borra los b bits ms a la izquierda del registro,
despus desplaza los bits del registro n posiciones a la izquierda. Esta
operacin se suele usar para escalar un valor que acta como ndice (y
que sabemos que no es negativo) al ancho de un elemento del array.
Todas estas instrucciones disponen de su equivalente versin con punto (.)
que modifican el contenido de CR0 como explicamos en el apartado 5.1

Pg 85

Ensamblador del PowerPC con Mac OS X

MacProgramadores

Operacin
EXTract and Left
Justify Word
Immediate
EXTract and Right
Justify Word
Immediate
INSert from Left
Word Immediate
INSert from Right
Word Immediate
ROTate Left Word
Immediate
ROTate Right Word
Immediate
ROT Left Word

Mnemonic
extlwi rD,rS,n,b
(n>0)

Equivalente a
rlwinm rD,rS,b,0,n-1

extrwi rD,rS,n,b
(n>0)

rlwinm rD,rS,b+n,32n,31

inslwi rD,rS,n,b
(n>0)
insrwi rD,rS,n,b
(n>0)
rotlwi rD,rS,n

rlwimi rD,rS,32b,b,(b+n)-1
rlwimi rD,rS,32b+n,b,b+n-1
rlwinm rD,rS,n,0,31

rotrwi rD,rS,n

rlwinm rD,rS,32-n,0,31

rotlw rD,rS,rN

rlwnm rD,rS,rN,0,31

Shift Left Word


Immediate
Shift Right Word
Immediate
CLeaR Left Word
Immediate
CLeaR Right Word
Immediate
CLeaR Left and
Shift Left Word
Immediate

slwi rD,rS,n (n<32)

rlwlnm rD,rA,n,0,31-n

srwi rD,rS,n (n<32)

rlwlnm rDmrS,32-n,n,31

clrlwi rD,rS,n
(n<32)
clrrwi rD,rS,n
(n<32)
clrlslwi rD,rS,b,n
(nb31)

rlwinm rD,rS,0,n,31
rlwinm rD,rS,0,0,31-n
rlwinm rD,rS,n,b-n,31n

Tabla 2.33: Instrucciones de rotacin y desplazamiento

5.7.4 Mnemonics para acceder al registro XER


Aunque disponemos de las instrucciones mtspr (Move To SPR) y mfspr
(Move From SPR), que nos permiten acceder al registro XER como registro
SPR1 que es, tambin existen mnemonics que nos permiten acceder a este
registro:
mtxer rS
mfxer rD

equivale a
equivale a

mtspr 1,rS
mfspr rD,1

5.7.5 Otros mnemonics


Existe un mnemonic que nos permite emular la operacin nop (No OPeration)
mediante una llamada a la instruccin or con operandos que hacen que la
instruccin no modifique nada:
Pg 86

Ensamblador del PowerPC con Mac OS X

nop

MacProgramadores

equivale a

or 0,0,0

Lo que hace realmente es un or binario al contenido de r0 consigo mismo.


Otro mnemonic nos permite hacer un complemento a 1 de los bits de un
registro:
not rD,rS

equivale a

nor rD,rS,rS

5.8 Operaciones comunes con enteros


En esta seccin se comentan algunas operaciones de alto nivel no triviales
que son muy tpicas de necesitar usar en un programa hecho en
ensamblador.

5.8.1 Valor absoluto


Vamos a ver cmo se calcula el valor absoluto de un nmero sin usar
sentencias condicionales, que de hecho todava no hemos visto.
El valor absoluto de un nmero se puede calcular como:
abs(a) = (a>=0) ? a : (0-a)
Es decir, si el nmero es positivo sera el mismo nmero a, y si es negativo
sera 0-a
El algoritmo que vamos a explicar nos devuelve:
Si (a0) => a
Si (a<0) => complemento2(a)
Para ello vamos a dar los siguientes pasos:
1. Calcular b de forma que:
Si (a0) => b = 00000000 00000000 00000000 00000000
Si (a<0) => b = 11111111 11111111 11111111 11111111
2. Hacer un xor a a con b. De esta forma si a0 entonces c=a pero si a<0
entonces c=complemento1(a)
3. Calcular d como: a=c-b
De esta forma:

Pg 87

Ensamblador del PowerPC con Mac OS X

MacProgramadores

Si (a0) => d=c-0


Si (a<0) => d=c+1
Obsrvese que si a<0 entonces d=c-(-1) => d=complemento1(a)-(-1)
=> d=complemento1(a)+1 => d=complemento2(a)
Si esto lo pasamos a ensamblador tenemos:
; r3 contiene
srawi r4,r3,31 ; r4 = (r3<0)
xor r5,r4,r3
; r5 = (r3<0)
sub r6,r5,r4 ; r6 = (a<0) ?

el valor de a
? -1 : 0
? -a : a
(-a+1) : a

Al acabar de ejecutar este programa r6 contiene abs(r3).


Por ejemplo, supongamos que a=-6 veamos como opera el programa con los
bits:
r3(-6)
r4(-1)
r5(+5)
r6(+6)

11111111
11111111
00000000
00000000

11111111
11111111
00000000
00000000

11111111
11111111
00000000
00000000

11111010
11111111 srawi r4,r3,31
00000101 xor r5,r4,r3
00000110 sub r6,r5,r4

Obsrvese que si a hubiera valido 6, r4 hubiera tenido todos sus bits a cero,
con lo que las operaciones xor y subf no hubieran afectado el valor de a

5.8.2 Mximo y mnimo de un nmero sin signo


Vamos a ver ahora cmo podramos calcular el mximo y mnimo de 2
nmeros positivos sin usar sentencias condicionales.
Para ello sabemos que el mximo y mnimo de dos nmeros a, b s puede
representar como:
min(a,b) = (a<=b)?a:b
max(a,b) = (a>=b)?a:b
El siguiente programa muestra un ejemplo de como calcular min(a,b). Para
ello vamos a aprovechar el hecho de que la resta de dos operandos produce
un acarreo si el sustraendo es mayor que el minuendo.
;
;
subc r5,r4,r3 ;
subfe r6,r4,r4 ;
and r5,r5,r6
;
add r7,r3,r5
;
;

r3
r4
r5
r6
r5
r7
r7

=
=
=
=
=
=
=

a
b
r4-r3
(r4>r3)?0:-1
(r4>r3)?0:(r4-r3)
(r4>r3)?r3:r4
min(r3,r4)
Pg 88

Ensamblador del PowerPC con Mac OS X

MacProgramadores

En concreto, los pasos del algoritmo son los siguientes:


1. Calculamos la diferencia entre los nmeros: c=b-a, la cual puede ser
positiva o negativa. En la instruccin subc usamos acarreo para luego poder
comprobarlo.
2. Aprovechamos el acarreo de la operacin anterior para calcular d, de forma
que d valga 0 (todos los bits a 0) si la diferencia anterior fue positiva, -1
(todos los bits a 1) si la diferencia anterior fue negativa. Para ello usamos la
instruccin subfe tal como se muestra en el programa anterior.
3. Calculamos en otra variable e la diferencia entre b-a de la forma:
Si (b-a0) => e=0
Si (b-a<0) => e=b-a
Para ello usamos la operacin and entre c y d
4. Calculamos el mnimo como a+e ya que:
Si (b-a0) => min(a,b)=a+0 => min(a,b)=a
Si (b-a<0) => min(a,b)=a+e => min(a,b)=a+(b-a)=b
Remplazando and por andc (AND with Complement to 1) el cdigo anterior
nos permite calcular max(a,b)
;
;
subc r5,r4,r3 ;
subfe r6,r4,r4 ;
andc r5,r5,r6 ;
add r7,r3,r5
;
;

r3
r4
r5
r6
r5
r7
r7

=
=
=
=
=
=
=

a
b
r4-r3
(r4>r3)?0:-1
(r4>r3)?(r4-r3):0
(r4>r3)?r4:r3
max(r3,r4)

Es decir, ahora la regla que calcula e es al revs:


Si (b-a0) => e=b-a
Si (b-a<0) => e=0
Con lo que en el paso 4 obtenemos el otro nmero, es decir:
Si (b-a0) => max(a,b)=a+e => min(a,b)=a+(b-a)=b
Si (b-a<0) => min(a,b)=a+0 => min(a,b)=a

Pg 89

Ensamblador del PowerPC con Mac OS X

MacProgramadores

5.8.3 Mximo y mnimo de un nmero con signo


El algoritmo anterior slo funciona si ambos nmeros son positivos, si los
nmeros pueden ser positivos o negativos necesitamos aplicar un algoritmo
como el siguiente:
; r3 = a
; r4 = b
xoris r5,r3,0x8000 ; c = a+128
xoris r6,r5,0x8000 ; d = b+128
; Ahora el problema es anlogo al del mnimo sin signo
subc r5,r6,r5
; e = d-c = b-a+256 = b-a
subfe r6,r6,r6
; f = (d>c)?0:-1
and r5,r5,r6
; g = (d>c)?0:(d-c)
add r5,r3,r5
; r5 = a+g
; r5 contendr la solucin
Obsrvese que cambiar el signo a un nmero con signo y interpretarle como
nmero sin signo equivale a sumar 128 al nmero. Por ejemplo:
0000 0001 (+1)
1000 0001 (129)

1111 1111 (-1)


0111 1111 (127)

Teniendo en cuenta esta apreciacin, este algoritmo calcula el min(a,b)


convirtiendo los nmeros con signo a y b a nmeros sin signo, para ello
cambia el bit de signo a cada nmero y interpreta el resultado como un
nmero sin signo.
A partir de aqu el algoritmo a aplicar es el de clculo del mnimo de nmeros
sin signo, que vimos antes.
Igual que antes, remplazando and por andc (AND with Complement to 1) el
cdigo anterior nos permite calcular max(a,b)
; r3 = a
; r4 = b
xoris r5,r3,0x8000 ; c = cambio signo a
xoris r6 ,r5,0x8000 ; d = cambio signo b
; Ahora el problema es anlogo al del mximo sin signo
subc r5,r6,r5
; e = d-c
subfe r6,r6,r6
; f = (d>c)?0:-1
andc r5,r5,r6
; g = (d>c)?0:(d-c)
add r5,r3,r5
; r5 = a+g
; r5 contendr la solucin

Pg 90

Ensamblador del PowerPC con Mac OS X

MacProgramadores

5.8.4 Resto de una divisin


La mayora de las computadoras y lenguajes de programacin truncan el
resultado de una divisin a la parte entera, descartando el resto.
Sean n el dividendo, d el divisor, c el cociente y r el resto, la operacin de
divisin en un ordenador se define como:
n = d*c+r
Donde:
Si (n0) => 0r<|d|
Si (n<0) => -|d|<r0
Ejemplos de divisin seran:
n
7
-7
7
-7

d
3
3
-3
-3

c
2
-2
-2
2

r
1
-1
1
-1

Obsrvese que segn esta regla para el valor del resto que hemos dado
siempre se cumple la frmula n=d*c+r.
La nica operacin de divisin que puede producir un desbordamiento es 231/-1, ya que el nmero -231 en 32 bits se representa como 0x80000000,
mientras que el positivo ms grande que podemos representar en 32 bits es
231-1=0x7FFFFFFF. Si se produce este caso excepcional y la divisin la
hacemos usando divw el resultado es 0 (ya que no puede representar el
nmero), mientras que si la hacemos usando divwo el resultado es tambin
0 y activa el overflow.
A continuacin se muestra el algoritmo que nos permite calcular el resto de
una divisin suponiendo que conozcamos el cociente.
El algoritmo del clculo del resto en una divisin con signo se limita a aplicar
la frmula: n=d*c+r => r=n-d*c, y es el siguiente:

divw rT,rN,rD
mullw rT,rT,rD
sub rT,rN,rT

;
;
;
;
;

rN Dividendo
rD Divisor
c = n/d
c*d
r = n-c*d

rT acaba conteniendo el resto de la divisin rN%rD.


Pg 91

Ensamblador del PowerPC con Mac OS X

MacProgramadores

En las divisiones de nmero sin signo el algoritmo es similar, slo que ahora
se usa divwu en vez de divw:

divwu rT,rN,rD
mullw rT,rT,rD
sub rT,rN,rT

;
;
;
;
;

rN Dividendo
rD Divisor
c = n/d
c*d
r = n-c*d

5.8.5 Divisin entre una constante entera


La operacin de divisin de enteros en PowerPC es considerablemente ms
lenta que la suma, resta o multiplicacin de enteros. Cuando el divisor es una
constante, podemos acelerar el proceso realizando la divisin mediante
desplazamientos a la derecha cuando el divisor sea mltiplo de 2, o bien
mediante multiplicaciones por un magic number, cuando se trate de otro
divisor.
El siguiente apartado describe tcnicas para divisin de nmeros de 32 bits.
Aun as estas tcnicas se pueden extender a nmero de 64 bits.
5.8.5.1

Divisin con signo entre una potencia de 2

Si el divisor es una potencia de 2, es decir, d=2k para 1k31, la divisin


entera se puede realizar como:
srawi rC,rN,rK
addze rC,rC
Donde rN contiene el dividendo, y rC contendr el cociente de dividir rN/d,
siendo d=2rK.
Obsrvese que si el nmero es positivo, el desplazamiento a la derecha
siempre divide entre dos.
Por ejemplo si tenemos:
r3=9 00000000 00000000 00000000 00001001
r3=4 00000000 00000000 00000000 00000100 srawi r3,r3,1
Pero si el nmero es negativo entonces un desplazamiento a la derecha slo
divide entre dos si el nmero es par. Por ejemplo:
r3=-4 11111111 11111111 11111111 11111100
r3=-2 11111111 11111111 11111111 11111110 srawi r3,r3,1

Pg 92

Ensamblador del PowerPC con Mac OS X

MacProgramadores

Si el nmero es impar nos sale uno ms de lo esperado. Por ejemplo:


r3=-5 11111111 11111111 11111111 11111011
r3=-3 11111111 11111111 11111111 11111101 srawi r3,r3,1
Este trozo de programa aprovecha el hecho de que la instruccin srawi de
PowerPC activa el bit de acarreo si rN contiene un nmero negativo e impar,
y se desplazan uno o ms bits, es decir, rK1, con lo que la instruccin
addze del programa anterior arregla este problema.
5.8.5.2

Divisin con signo por un nmero que no sea potencia de 2

Para todo divisor d distinto de 0, la divisin entre d se puede calcular como


una multiplicacin y alguna de suma o desplazamiento. La idea bsica es
multiplicar el dividendo n por un magic number (m) de forma que los 32
bits altos del producto de dos nmeros represente el cociente. Para lo cual
usaremos la instruccin mulhw de PowerPC. Con vistas a que el resultado de
la divisin quede en los 32 bits altos del producto el magic number debe estar
comprendido entre m=(232/n) y m=(264/n), ya que al multiplicar m por n
tendremos un nmero comprendido entre C=n*(232/n)=232 y
C=n*(264/n)=264, que es la parte alta que nos interesa a partir de la cual
calculamos el cociente c como c=C/232.
Los detalles son complicados, especialmente para algunos divisores, como por
ejemplo el 7.
En el Listado 2.9, Listado 2.10 y Listado 2.11 se muestran tres ejemplos de
cmo se hara la divisin con los divisores 3, 5 y 7, respectivamente. Estos
ejemplos tambin muestran cmo se obtendra el resto con una simple resta
de d*c al dividendo n.
lis rM,0x5555
;
ori rM,rM,0x5556;
mulhw rC,rM,rN ;
srwi rT,rN,31
;
add rC,rC,rT
;
mulli rT,rC,3
;
sub rT,rN,rT
;

Cargamos el magic number en rM


m=0x55555556 = (232+2)/3
c=floor(m*n/232)
Resta 1 a c si n es negativo
rC contiene el cociente
Calcula del resto como r=n-c*3
rT contiene el resto

Listado 2.9: Algoritmo de la divisin entre 3

Pg 93

Ensamblador del PowerPC con Mac OS X

lis rM,0x6666
ori rM,rM,0x6667
mulhw rC,rM,rN
srawi rC,rC,1
srwi rT,rN,31
add rC,rC,rT
mulli rT,rC,5
sub rT,rN,rT

;
;
;
;
;
;
;
;

MacProgramadores

Cargamos el magic number en rM


m=0x66666667 = (233+3)/5
c=floor(m*n/232)
c=floor(c/2)
Resta 1 a c si n es negativo
rC contiene el cociente
Calcula del resto como r=n-c*5
rT contiene el resto

Listado 2.10: Algoritmo de la divisin entre 5

lis rM,0x9249
ori rM,rM,0x2493
mulhw rC,rM,rN
add rC,rC,rN
srawi rC,rC,2
srwi rT,rN,31
add rC,rC,rT
mulli rT,rC,7
sub rT,rN,rT

;
;
;
;
;
;
;
;
;

Cargamos el magic number en rM


m=0x92492493 = (234+5)/7 - 232
c=floor(m*n/232)
c=floor(m*n/232)+n
c=floor(c/4)
Resta 1 a c si n es negativo
rC contiene el cociente
Calcula del resto como r=n-c*7
rT contiene el resto

Listado 2.11: Algoritmo de la divisin entre 7

El mtodo general de clculo del cociente c es:


1. Multiplicar el dividendo n por el magic number m
2. Obtener los 32 bits altos del producto y desplazarlo a la derecha un
nmero de veces comprendido entre 0 y 31
3. Aadir 1 si n es negativo
El mtodo general siempre se reduce a uno de estos tres casos, ilustrados
con la divisin entre 3, 5 7. En el caso de la divisin entre 3 el multiplicador
se puede representar en 32 bits, y por eso en este caso despus del mulhw el
desplazamiento a la derecha es 0. En el caso de la divisin entre 5, el
multiplicador tambin se representa con 32 bits, pero el desplazamiento a la
derecha es uno. En el caso de la divisin entre 7, el multiplicador no se puede
representar en 32 bits, pero los 32 bits bajos del multiplicador son
representables en 32 bits. Entonces, el programa multiplica por los 32 bits
bajos del multiplicador y despus corrige el producto aadiendo n*232, es
decir, aade n a la parte alta del producto. Para d=7, el desplazamiento a la
derecha es 2.
Para la mayora de los divisores, existe ms de un multiplicador que nos dan
el resultado correcto con este mtodo. En este caso, en general lo mejor es
usar el multiplicador ms bajo ya que este puede implicar un desplazamiento
de cero bits a la izquierda, ahorrndonos la instruccin srawi.

Pg 94

Ensamblador del PowerPC con Mac OS X

MacProgramadores

El procedimiento para dividir entre una constante negativa es anlogo. Esto


es as gracias a que la divisin de enteros satisface la propiedad: n/(-d)=(n/d). Con lo que para dividir entre una constante negativa, primero
dividimos entre su correspondiente constante positiva, y luego al resultado as
obtenido le cambiamos el signo.
Adems, en el caso de d=-7 podemos ahorrarnos la negacin si usamos el
siguiente algoritmo:
lis rM,0x6DB6
ori rM,0xDB6D
mulhw rC,rM,rN
sub rC,rC,rN
srawi rC,rC,2
srwi rT,rC,31
add rC,rC,rT
mulli rT,rC,-7
sub rT,rN,rT

;
;
;
;
;
;
;
;
;

Cargamos el magic number en rM


m=0x6DB6DB6D = -(234+5)/7 + 232
c=floor(m*n/232)
c=floor(m*n/232)-n
c=floor(c/4)
Aade 1 a c si n es negativo
rC contiene el cociente
Clculo del resto como r=n-c*(-7)
rT contiene el resto

Este programa es el mismo que el de la divisin entre +7, excepto que usa el
multiplicador de signo opuesto, resta en vez de aadir, y desplaza c en vez
de n a la derecha 31 posiciones. (En el caso de d=+7 tambin podramos
desplazar c en vez de n 31 veces a la derecha, pero habra menos
paralelismo en el cdigo).
El magic number usado como multiplicador al dividir entre -d es casi siempre
el negativo de magic number de d, es decir, -m (p.e. para d=7, tenamos que
m=92492493, con lo que para d=-7 tenemos que
m=-1*92492493
=0x6DB6DB6D). Las nicas excepciones a esta regla son d=3 y
d=715.827.883
La Tabla 2.34 muestra los magic number y desplazamientos para los nmeros
ms comunes.
d (decimal)
-5
-3
-2k
1
2k
3
5
6
7
9
10
11
12

m (hexadecimal)
9999 9999
5555 5555
7FFF FFFF
8000 0001
5555 5556
6666 6666
2AAA AAAB
9249 2493
38E3 8E39
6666 6667
2E8B A2E9
2AAA AAAB
Pg 95

desplazamiento
1
1
k-1
k-1
0
1
0
2
1
2
1
1

Ensamblador del PowerPC con Mac OS X

25
125

MacProgramadores

51EB 851F
1062 4DD3

3
3

Tabla 2.34: Magic number y desplazamientos para los nmeros ms comunes

El algoritmo para calcular los magic numbers y desplazamientos de los


divisores est ms all de los objetivos de este tutorial. Aquel que este
interesado en conocerlo pude hacerlo en la web de IBM en el documento
[WARREN].

5.8.6 Divisin de 64 bits en mquinas de 32 bits


Aunque PowerPC dispone de instrucciones que nos permiten obtener nmeros
de 64 bits como el producto de nmeros de 32 bits, no dispone de ninguna
instruccin que nos permita dividir nmeros de 64 bits. En este apartado
vamos a hacer un programa que nos permite dividir nmeros de 64 bits con o
sin signo. El algoritmo de divisin de nmeros sin signo que vamos a usar se
comenta con ms detalle en el apndice A.
Una vez el lector entienda el algoritmo puede modificar el cociente y resto
convenientemente para realizar divisiones de nmeros de 64 bits con signo.
En este caso es importante contemplar el caso de -263/(-1), donde el
resultado esta indefinido.
El programa lo vamos a hacer en un fichero llamado divide64.s aparece en
el Listado 2.12. Para referirnos a los registros vamos a usar definiciones
#define tal como explicbamos en el apartado 0, que nos permiten dar
nombres a los registros para recordar su utilidad ms fcilmente, de acuerdo
a la Tabla 2.35:
identificador Registro Descripcin
dvdh
r3
(DiVidenDo High) 32 bits bajos del dividendo
dvdl
r4
(DiVidenDo Low) 32 bits altos del dividendo
dvsh
r5
(DiVideSor High) 32 bits bajos del divisor
dvsl
r6
(DiVideSor Low) 32 bits altos del divisor
coch
r7
(COCiente High) 32 bits bajos del cociente
cocl
r8
(COCiente Low) 32 bits altos del cociente
resh
r9
(RESto High) 32 bits bajos del resto
resl
r10
(RESto Low) 32 bits altos del resto
ceros_dvd
r11
Nmero de ceros a la izquierda del dividendo
ceros_dvs
r12
Nmero de ceros a la izquierda del divisor
rep
r13
Repeticiones del bucle de desplazamiento a la
izquierda
tmp1
r14
Para clculos temporales
tmp2
r15
Para clculos temporales
tmp3
r16
Para clculos temporales
Tabla 2.35: #define del programa
Pg 96

Ensamblador del PowerPC con Mac OS X

MacProgramadores

El dividendo se deposita en los registros dvdh:dvdl que forman el registro


de 64 bits dvd. El divisor se deposita en dvsh:dvsl que forman el registro
de 64 bits dvs. Al acabar el algoritmo en coch:cocl se depositara el
cociente y en resh:resl el resto.
La operacin se realiza sobre el registro de 128 bits res:dvd. Cada iteracin
incluye los siguientes pasos:
1. Desplazar la combinacin res:dvd 1 bit a la izquierda. Esto carga un
1 en el bit menos significativo de res cuando el bit ms significativo de
dvd sea 1, o un 0 en el bit menos significativo de res en caso
contrario.
2. Restar a res el divisor dvs. Esto calcula la resta parcial de la divisin.
3. Si el resultado es negativo, no modificamos res e insertamos un cero
en el bit bajo de coc
4. Si el resultado es positivo ponemos el resultado en res, e insertamos
un uno en el bit bajo de coc
5. Si el nmero de iteraciones es menor al ancho de dvd, volvemos al
paso 1
Antes de empezar este bucle el programa desplaza dvd a la izquierda tantas
veces como ceros a la izquierda tenga con el fin de evitar repeticiones de
bucle innecesarias.
// Nombramos los registros
#define dvdh r3
#define dvdl r4
#define dvsh r5
#define dvsl r6
#define coch r7
#define cocl r8
#define resh r9
#define resl r10
#define ceros_dvd r11
#define ceros_dvs r12
#define rep r13
#define tmp1 r14
#define tmp2 r15
#define tmp3 r16
.data
n:
.long
d:
.long
.comm
.comm

2,1
1,0
c,8
r,8

;
;
;
;

Dividendo
Divisor
Cociente
Resto

.text
.globl _main
Pg 97

Ensamblador del PowerPC con Mac OS X

MacProgramadores

_main:
// Cargamos el dividendo y divisor en los registros
// Para ello usamos lswi (Load String Word
// Immediate) que carga 32 bytes consecutivos en
// dvdl-dvsh
lis r2,ha16(n)
addi r2,r2,lo16(n)
lswi dvdh,r2,16
// Contamos el nmero de 0 a la izquierda
// del dividendo
cntlzw ceros_dvd,dvdh
cntlzw tmp1,dvdl
cmpwi cr0,dvdh,0
bne cr0,eti1
; Si (dvdh!=0) hay ceros_dvd ceros
addi ceros_dvd,tmp1,32 ; Si (dvdh==0)
; hay ceros_dvd=32+tmp1 ceros
eti1:
// Contamos el nmero de 0 a la izquierda del
divisor
cntlzw ceros_dvs,dvsh
cntlzw tmp1,dvsl
cmpwi cr0,dvsh,0
bne cr0,eti2
; Si (dvsh!=0) hay ceros_dvs ceros
addi ceros_dvs,tmp1,32 ; Si (dvsh==0)
; hay ceros_dvs=32+tmp1 ceros
eti2:
// Determina el desplazamiento necesario para
// minimizar el nmero de iteraciones
cmpw cr0,ceros_dvs,ceros_dvs
bgt cr0,eti9
; Si (dvs>dvd) cociente = 0
li rep,64
sub rep,rep,ceros_dvd ; Repeticiones del bucle de
; desplazamiento a la
; izquierda
// Desplazamos el dvd a la izquierda
// tantas veces como ceros a la izquierda tenga
// if (ceros_dvd>=32)
cmpwi ceros_dvd,32
blt eti3
; si (ceros_dvd<32) goto eti3
// (Cuerpo if) Copiamos dvdl en dvdh
// y desplazamos convenientemente
mr dvdh,dvdl
lis dvdl,0
subi ceros_dvd,ceros_dvd,32
slw dvdh,dvdh,ceros_dvd
b eti5
eti3:// (Cuerp else) Desplazamos a la izquierda
// ceros_dvd veces a dvdh:dvdl
cmpwi ceros_dvd,0
; Si (ceros_dvd==0) goto eti5
Pg 98

Ensamblador del PowerPC con Mac OS X

beq eti5
mtctr ceros_dvd
eti4:add dvdh,dvdh,dvdh
addc dvdl,dvdl,dvdl

MacProgramadores

;
;
;
;
;
;

Fijamos el contador del


bucle
Desplazamos uno a
izquierda sumando
Si acarrea lo pasamos
a dvdh

addze dvdh,dvdh
bdnz eti4
eti5:// Empezamos el bucle de desplazamiento
lis coch,0
lis cocl,0
lis resh,0
lis resl,0
mtctr rep
; Fijamos contador del bucle
eti6:// 1. Desplazar la combinacin res:dvd 1 bit
// a la izquierda
addc dvdl,dvdl,dvdl
adde dvdh,dvdh,dvdh
adde resl,resl,resl
adde resh,resh,resh
// 2. Restar a res el divisor dvs. Esto calcula
// la resta parcial de la divisin.
lis tmp3,0
subc tmp1,resl,dvsl
subfe tmp2,dvsh,resh
subfe tmp3,tmp3,tmp3
cmpwi tmp3,0
beq eti7 ; Si(tmp3==0) => res>=dvs
// (res<dvs) 3. Si el resultado es negativo,
// no modificamos res
// y insertamos un cero en el bit bajo de coc
addc cocl,cocl,cocl
adde coch,coch,coch
b eti8
eti7:// (res>=dvs)
//4. Si el resultado es positivo ponemos el
// resultado en res y insertamos un uno en
// el bit bajo de coc
mr resl,tmp1
mr resh,tmp2
addc cocl,cocl,cocl
adde coch,coch,coch
ori cocl,cocl,1
eti8:// 5. Si el nmero de iteraciones es menor al
// ancho de dvd, volvemos al paso 1
bdnz eti6
b eti10
eti9:// Cociente==0 (dvs>dvd)
lis coch,0
Pg 99

Ensamblador del PowerPC con Mac OS X

MacProgramadores

lis cocl,0
mr resh,dvdh
mr resl,dvdl
eti10:// Guardamos los registros en memoria
// con stswi (Store String Word Immediate)
lis r2,ha16(c)
addi r2,r2,lo16(c)
stswi coch,r2,16
// Retornamos
blr
Listado 2.12: Divisin de 64 bits en mquinas de 32 bits

Pg 100

Ensamblador del PowerPC con Mac OS X

MacProgramadores

6 Instrucciones de bifurcacin
En esta seccin vamos a comentar con qu instrucciones de bifurcacin
cuenta PowerPC.
Las instrucciones de bifurcacin nos permiten alterar el flujo normal del
programa. Para ello alteran el valor del contador de programa. En PowerPC, a
diferencia de otras arquitecturas, nunca se puede hacer referencia explcita a
este registro, es decir, este registro no se puede leer en PowerPC, y slo se
puede modificar indirectamente al ejecutar instrucciones de bifurcacin. En
otros sistemas es muy tpico llamar a este registro PC (Program Counter) o IP
(Instruction Pointer). Nosotros vamos a referirnos a el como IP, aunque este
registro no tienen un nombre explcito en PowerPC, por no poder referirnos
dirctamenta a l.

6.1 Tipos de clculo de la direccin de salto de una


instruccin
Los saltos de las instrucciones de bifurcacin pueden ser condicionales o
incondicionales. Si son condicionales se utiliza el registro CR para tomar la
decisin de si hacer o no el salto.
Por otro lado las instrucciones de bifurcacin pueden ser de salto relativo o
absoluto. Las instrucciones de bifurcacin de salto absoluto especifican la
direccin completa (32 bits) de la direccin de salto, obsrvese que como
todas las instrucciones de PowerPC ocupan 32 bits, la direccin absoluta de
salto no se puede codificar dentro de la instruccin, sino que debe de estar en
un registro.
Las instrucciones de bifurcacin de salto relativo son instrucciones en las que
la direccin de salto se calcula respecto al IP (Instruction Pointer) actual,
sumndole o restndole una determinada cantidad. Al ser esta cantidad un
nmero menor de 32 bits s que se puede incrustar como operando inmediato
en la instruccin de salto. Como en la prctica la mayora de los saltos se
suelen hacer a direcciones cercanas a la posicin actual del IP estas
instrucciones resultan muy tiles.
Recurdese que las instrucciones de PowerPC siempre estaban alineadas al
tamao de palabra, con lo que los dos ltimos bits de la direccin de destino
siempre deben de valer 0. Las instrucciones de bifurcacin relativas
aprovechan esta caracterstica para no tener que codificar dentro de la
instruccin estos dos ltimos bits, sino que aprovechan para en su lugar
codifican otros 2 bits de ms peso.

Pg 101

Ensamblador del PowerPC con Mac OS X

MacProgramadores

Como veremos, el tamao de esta direccin relativa puede ser de 14 bits o de


24 bits, y como los ltimos dos bits no es necesario almacenarlos, nos
permiten dar saltos de hasta 32.768 bytes (214+2-1=32.768) y de hasta
33.554.432 bytes (224+2-1=33.554.432) respectivamente, es decir, sumamos
2 al exponente porque los dos ltimos bits no es necesario almacenarlos con
lo que podemos coger otros 2 bits de la izquierda, y le restamos 1 porque el
desplazamiento puede ser positivo o negativo.
Las instrucciones de bifurcacin tienen los siguientes tipos de clculo de la
direccin destino:
o
o
o
o
o
o

Salto
Salto
Salto
Salto
Salto
Salto

relativo
absoluto
condicional
condicional
condicional
condicional

relativo
absoluto
al Link Register
al Count Register

A continuacin vamos a describir como funciona cada uno de ellos.

6.1.1 Instrucciones de salto relativo


Las instrucciones de salto relativo generan la direccin de la siguiente
instruccin a ejecutar usando el campo LI de la instruccin. A este campo se
le concatena al final dos bits con 0 y se le extiende el signo, y este valor se
suma al IP lo cual nos da la direccin efectiva de salto de la instruccin.
Las instrucciones de salto relativo siempre deben tener el bit de la posicin 30
AA (Absolute Address) a 0, y el bit de la posicin 31 LK (LinK) puede estar
activo, en cuyo caso se guarda la direccin siguiente a la instruccin de salto
en el registro LR. El uso de este registro lo explicaremos en el apartado 6.1.7.
Las instruccin de salto relativo de que dispone PowerPC se resumen en la
Tabla 2.36:
Instruccin
b D

bl D

Descripcin
(Branch) Salta a la direccin calculada como la
suma de D ms el valor actual del IP. Esta
instruccin tiene AA=0 y LK=0
(Branch then Link) Igual que b, slo que en el
registro LR se almacena la direccin de la
siguiente instruccin a la instruccin de salto. Esta
instruccin tiene AA=0 y LK=1

Tabla 2.36: Instrucciones de salto relativo

La Figura 2.7 muestra el proceso de clculo de la direccin de salto en las


instrucciones de salto relativo:
Pg 102

Ensamblador del PowerPC con Mac OS X

MacProgramadores

5 6

29 30 31

18

LI

AA LK

(Codificacin de la instruccin)
0

5 6

29 30 31

Exten signo

LI

0 0

31
+

IP (Instruction Pointer)

31
Direccin de salto

Figura 2.7: Clculo de la direccin de salto en las instrucciones de salto relativo

6.1.2 Instrucciones de salto absoluto


Las instrucciones de salto absoluto que vamos a ver en esta seccin reciben
como operando una direccin que indica la posicin absoluta a la que realizar
el salto.
Como en una instruccin de 32 bits no se pueden codificar los 32 bits de la
direccin de salto, se codifican slo 24 bits en el campo LI, y despus se
extienden a 32 bits concatenando 2 bits con cero al final y rellenando los bits
que quedan delante con ceros.
0

5 6

29 30 31

18

LI

AA LK

(Codificacin de la instruccin)
0

5 6
Exten signo

29 30 31
LI

0 0

31
Direccin de salto

Figura 2.8: Clculo de la direccin de salto en las instrucciones de salto absoluto

Pg 103

Ensamblador del PowerPC con Mac OS X

MacProgramadores

La Figura 2.8 muestra el proceso de clculo de la direccin absoluta.


Obsrvese que al ser los primeros 6 bits siempre 0, esta instruccin slo nos
permite acceder a los primeros 226=67.108.864 bytes del espacio de memoria
de 232 bytes que tiene un proceso, con lo que es una instruccin poco usada.
Las instrucciones de salto absoluto siempre deben tener el bit de la posicin
30 AA (Absolute Address) a 1, y el bit de la posicin 31 LK (LinK) puede estar
activo, en cuyo caso se guarda la direccin siguiente a la instruccin de salto
en el registro LR. El uso de este registro lo explicaremos en el apartado 6.1.7.
Las instrucciones de salto absoluto de que dispone PowerPC se resumen en la
Tabla 2.37:
Instruccin
ba D

Descripcin
(Branch Absolute) Salta a la direccin dada en D.
Esta instruccin tiene AA=1 y LK=0
(Branch then Link Absolute) Igual que ba, slo
que en el registro LR se almacena la direccin de
la siguiente instruccin a la instruccin de salto.
Esta instruccin tiene AA=1 y LK=1

bla D

Tabla 2.37: Instrucciones de salto absoluto

El destino de esta instruccin se indica con una etiqueta, de la cual el


ensamblador coge los bits de la posicin 6 a la 29 y los codifica en el campo
LI de la instruccin. Por ejemplo, podemos hacer:
ba fin

fin: blr

6.1.3 Las instrucciones de salto condicional


Las instrucciones de salto condicional tienen una codificacin de acuerdo con
la siguiente figura:
0

5 6
OpCode

10 11
BO

15 16

29 30 31

BI

AA LK

Figura 2.9: Codificacin de las instrucciones de salto condicional

OpCode identifica la instruccin que vamos a codificar.


BI (Branch Input) especifica los bits de CR usados como condicin a evaluar
para el salto de acuerdo a la Tabla 2.38:

Pg 104

Ensamblador del PowerPC con Mac OS X

BI
Dec Bin
0 00000

Bit CRn
a evaluar
CR0[0]

1 00001

CR0[1]

2 00010

CR0[2]

3 00011

CR0[3]

4
5
6
7
8
12
16
20
24
28
9
13
17
21
25
29
10
14
18
22
26
30
11
15
19
23
27
31

00100
00101
00110
00111
01000
01100
10000
10100
11000
11100
01001
01101
10001
10101
11001
11101
01010
01110
10010
10110
11010
11110
01011
01111
10011
10111
11011
11111

CR1[0]
CR1[1]
CR1[2]
CR1[3]
CRn[0]

MacProgramadores

Descripcin
Negative (LT). El resultado de una instruccin con
punto (.) es negativo
Positive (GT). El resultado de una instruccin con
punto (.) es positivo
Zero (EQ). El resultado de una instruccin con
punto (.) es cero
Summary Overflow (SO). Copia del bit XER[SO]
de la anterior instruccin ejecutada
Copia de FPSCR[FX]
Copia de FPSCR[FEX]
Copia de FPSCR[VX]
Copia de FPSCR[OX]
Menor que:
Para enteros rA<SIMM o rA<UIMM o rA<rB
Para punto flotante fA<fB

CRn[1]

Mayor que:
Para enteros rA>SIMM o rA>UIMM o rA>rB
Para punto flotante fA>fB

CRn[2]

Igual:
Para enteros rA=SIMM o rA=UIMM o rA=rB
Para punto flotante fA=fB

CRn[3]

Summary Overflow o floating Point Unordered

Tabla 2.38: Configuracin del operando BI

Recurdese, que como explicamos en el apartado 5.1 el campo CR0 se suele


usar para comprobar el resultado de una operacin con punto (.), como por
ejemplo add., de este resultado podamos mirar si era positivo, negativo,
cero, o haba habido un overflow consultando los bits de este campo.

Pg 105

Ensamblador del PowerPC con Mac OS X

MacProgramadores

Tambin, como explicamos en el apartado 5.1 el campo CR1 lo usaban las


operaciones en punto flotante.
Los dems campos (CR2 hasta CR7) se dejaban para las operaciones de
comparacin, aunque los resultados de las comparaciones tambin se pueden
depositar en CR0 y CR1, sin embargo en la tabla hemos supuesto que se usan
para instrucciones con punto.
En la Tabla 2.38 n se refiere a los campos de CR que van desde CR2 hasta
CR7, donde los cuatro bits de cada campo se interpretan como menor que,
mayor que, igual y overflow, respectivamente.
Cada uno de los 32 valores de la tabla indica que bit de los 32 bits del registro
CR queremos comprobar.
BO (Branch Output) especifica la accin a realizar por la instruccin de salto
cuando se cumpla la condicin dada por BI de acuerdo a la Tabla 2.39.
BO
0000y
0001y
001zy
0100y
0101y
011zy
1z00y
1z01y
1z1zz

Descripcin
Decrementa el registro CTR y despus salta si CTR0
es FALSE
Decrementa el registro CTR y despus salta si CTR=0
es FALSE
Salta si la condicin es FALSE
Decrementa el registro CTR y despus salta si CTR0
es TRUE
Decrementa el registro CTR y despus salta si CTR=0
es TRUE
Salta si la condicin es TRUE
Decrementa el registro CTR y despus salta si CTR0
Decrementa el registro CTR y despus salta si CTR=0
Salta siempre

y la condicin
y la condicin
y la condicin
y la condicin

z Es un bit que se reserva para el futuro, y de momento debe ser siempre 0


y Indica si es ms probable que el salto se realice o que no se realice, su uso se explica en el
Apndice B, en principio se puede dejar siempre a 0
Tabla 2.39: Configuracin del operando BO

Bsicamente estos 5 bits codifican 6 posibles actuaciones:


o
o
o
o
o
o

Decrementar el registro CTR


Comprobar si CRT es 0
Comprobar si CTR no es cero
Comprobar si la condicin es verdadera
Comprobar si la condicin es falsa
Prediccin de salto. Se explica en el Apndice B

Pg 106

Ensamblador del PowerPC con Mac OS X

MacProgramadores

Los otros dos campos de la instruccin codificada son:


AA (Absolute Address), indica si se trata de un salto a una direccin relativa
(AA=0) o absoluta (AA=1)
LK (LinK), indica si antes de saltar, se copia (LK=1) o no se copia (LK=0), la
direccin de la siguiente instruccin a la de salto en registro LR, esto como
veremos en el apartado 6.1.7 sirve para poder retornar de la llamada a una
subrutina.
Las instrucciones de salto condicional se dividen en cuatro tipos que vamos a
explicar detallar a continuacin.

6.1.4 Instrucciones condicionales de salto relativo


Estas instrucciones realizan un salto relativo si se cumple la condicin. El
funcionamiento exacto de la instruccin se muestra en la Figura 2.10:

5 6
16

10 11
B0

15 16

29 30 31

BI

BD

AA LK

(Codificacin de la instruccin)

Cumple
condicin?

15 16
Extensin del signo

No

29 30 31
BD

0
31

AA LK
31

Instruction Pointer (IP)

Siguiente instruccin
0

31
Direccin de salto

Figura 2.10: Instrucciones condicionales de salto relativo

Las instrucciones de salto condicional relativo de que dispone PowerPC se


resumen en la Tabla 2.40:

Pg 107

Ensamblador del PowerPC con Mac OS X

Instruccin
bc BO,BI,D

bcl BO,BI,D

MacProgramadores

Descripcin
(Branch Conditional) Si se cumplen las condiciones dadas
por BI y BO salta a la direccin calculada como la suma de
D ms el valor actual del IP. Esta instruccin tiene AA=0 y
LK=0
(Branch Conditional then Link) Igual que bc, slo que en
el registro LR se almacena la direccin de la siguiente
instruccin a la instruccin de salto. Esta instruccin tiene
AA=0 y LK=1

Tabla 2.40: Instrucciones condicionales de salto relativo

Por ejemplo, imaginemos que queremos hacer una operacin slo si el valor
del registro r2 es menor a 5, entonces haramos:
cmpwi r2,5
bc 12,0,fin
; Hacemos la operacin que sea

fin: ; Otras operaciones

Aqu BI vale 0, que significa en la comparacin almacen en CR0 un menor


que, es decir, que r2<5, que es la condicin que peda el enunciado del
ejemplo y BO vale 12=01100 que significa que salte si la condicin es
verdadera.

6.1.5 Instrucciones condicionales de salto absoluto


La Figura 2.11 muestra el funcionamiento de las instrucciones condicionales
de salto absoluto. Obsrvese que en este caso el campo BD slo tiene 14 bits,
con lo que, si tenemos en cuenta los 2 ceros que siempre van al final (ya que
las instrucciones se alinean a direcciones mltiplos de cuatro) podemos
direccionar slo los 216=65.535 bytes lo cual hace que esta instruccin se
utilice muy poco en la prctica.
Instruccin
bca BO,BI,D

bcla BO,BI,D

Descripcin
(Branch Conditional Absolute) Si se cumplen las
condiciones dadas por BI y BO salta a la direccin dada en
D. Esta instruccin tiene AA=0 y LK=0
(Branch Conditional then Link Absolute) Igual que bca,
slo que en el registro LR se almacena la direccin de la
siguiente instruccin a la instruccin de salto. Esta
instruccin tiene AA=0 y LK=1

Tabla 2.41: Instrucciones condicionales de salto absoluto


Pg 108

Ensamblador del PowerPC con Mac OS X

MacProgramadores

Las instrucciones condicionales de salto absoluto que existen en PowerPC se


detallan en la Tabla 2.41.
0

5 6
16

10 11
B0

15 16

29 30 31

BI

BD

AA LK

(Codificacin de la instruccin)

Cumple
condicin?

15 16

0000 0000 0000 0000

No

29 30 31
BD

AA LK

31

Siguiente instruccin
0

31
Direccin de salto

Figura 2.11: Instrucciones condicionales de salto absoluto

6.1.6 Instrucciones condicionales de salto al Count


Register
Con las instrucciones de salto que conocemos hasta ahora tenemos un
problema si queremos saltar a una direccin de memoria absoluta que este
ms all de las direcciones a las que podemos llegar con las instrucciones de
salto absoluto que hemos visto.
Para solucionar este problema existe otra instruccin en la que la direccin de
salto se guarda en un registro llamado CTR (CounT Register).
El CTR es un registro especial (SPR), en concreto el SPR9, y para
leerlo/modificarlo usamos dos instrucciones que nos permiten acceder a los
SPR, que como vimos en el apartado 5.2 son:
mfspr rD,SPR /* Move From Special Purpose Register */
mtspr SPR,rS /* Move To Special Purpose Register */
La siguiente Figura 2.12 muestra el funcionamiento de esta instruccin.

Pg 109

Ensamblador del PowerPC con Mac OS X

MacProgramadores

Una vez puesta la direccin a la que queremos saltar en el registro CTR


podemos saltar a esta direccin con las instrucciones de PowerPC de la Tabla
2.42.

5 6
19

10 11
B0

15 16
BI

20 21
0000

29 30 31
528

LK

(Codificacin de la instruccin)

Cumple
condicin?

No

29
CTR (CounT Register)
30 31

31

||

Siguiente instruccin

00

31
Direccin de salto

Figura 2.12: Instrucciones condicionales de salto al Count Register

Instruccin
bcctr BO,BI

bcctrl BO,BI

Descripcin
(Branch Conditional to CounT Register) Salta a la
direccin de memoria almacenada en el CTR. Esta
instruccin tiene LK=0
(Branch Conditional to CounT Register then Link)
Igual que bcctr slo que almacena en el LR la
direccin de la siguiente instruccin a la
instruccin de salto. Esta instruccin tiene LK=1

Tabla 2.42: Instrucciones condicionales de salto absoluto

6.1.7 Instrucciones condicionales de salto al Link Register


Antes veamos que las instrucciones de salto, antes de saltar, podan
almacenar en el registro LR (Link Register) la direccin de la siguiente
instruccin a la instruccin de salto. Esto es especialmente til para hacer
llamadas a subrutinas, ya que ahora podemos retornar de esa llamada
volviendo a la direccin que dejamos almacenada en LR.

Pg 110

Ensamblador del PowerPC con Mac OS X

MacProgramadores

Queda por ver cmo se trata otro problema, que es el problema de que una
llamada a una subrutina llame a su vez a otra subrutina guardando esta
tambin en LR la direccin de retorno, y borrando la anterior direccin. Como
explicaremos en el apartado 8, la solucin est en guardar el valor de LR en
la pila antes de llamar a otra funcin. Las instrucciones que vamos a ver
ahora son las que nos permiten retornar de la llamada.
La Figura 2.13 muestra el funcionamiento de este tipo de instrucciones. stas
tambin tienen el bit LK con el significado habitual de guardar el valor de la
siguiente instruccin a la de salto en LR, lo cual se hace cuando este bit est
a 1. En la prctica esta opcin no se usa cuando retornamos de una subrutina
ya que en ese caso no solemos guardar la direccin de la siguiente instruccin
al retorno. Sin embargo esta opcin se puede usar si ponemos en LR la
direccin de una subrutina a la que queremos llamar.
0

5 6
19

10 11
B0

15 16
BI

20 21

29 30 31

0000

16

LK

(Codificacin de la instruccin)

Cumple
condicin?

No

29
LR (Link Register)
30 31

31

||

Siguiente instruccin

00

31
Direccin de salto

Figura 2.13: Instrucciones condicionales de salto al Link Register

Las instrucciones condicionales de salto al Link Register que tiene PowerPC se


resumen en la Tabla 2.43.
Instruccin
bclr BO,BI

bclrl BO,BI

Descripcin
(Branch Conditional to Link Register) Si se
cumplen las condiciones dadas por BI y BO salta a
la direccin dada en el registro LR. Esta
instruccin tiene LK=0
(Branch Conditional to Link Register then Link)
Igual que bclr, slo que en el registro LR se

Pg 111

Ensamblador del PowerPC con Mac OS X

MacProgramadores

almacena la direccin de la siguiente instruccin a


la instruccin de salto. Esta instruccin tiene LK=1
Tabla 2.43: Instrucciones condicionales de salto al Link Register

Por ltimo comentar que adems de cargar el LR usando instrucciones con el


bit LK=1, el LR es un registro especial (SPR), en concreto el SPR8 y para
leerlo/modificarlo usamos mfspr y mtspr.

6.2 Mnemonics
Vamos a empezar con mnemonics tpicos para las operaciones de bifurcacin.

6.2.1 Mnemonics para saltos incondicionales


Para los saltos incondicionales existen cuatro mnemonics que se resumen en
la Tabla 2.44:
Mnemonic
blr
blrl

bctr
bctrl

Descripcin
(Branch to LR) Salta a la direccin de
memoria almacenada en el registro LR
(Branch to LR and Link) Igual que blr slo
que en LR se almacena la direccin de
memoria de la siguiente instruccin a la
instruccin de salto.
(Branch to CTR) Salta a la direccin de
memoria almacenada en el registro CTR
(Branch to CTR and Link) Igual que bctr
slo que en LR se almacena la direccin de
memoria de la siguiente instruccin a la
instruccin de salto.

Equivale a
bclr 20,0
bclrl 20,0

bcctr 20,0
bcctrl 20,0

Tabla 2.44: Mnemonics de salto incondicional

blr es un mnemonic que ya hemos usado muchas veces para retornar de


una funcin main().
Ninguno de estos mnemonics reciben operandos ya que la direccin de salto
estar ya almacenada en los registros LR o CTR.

6.2.2 Mnemonics para saltos condicionales


Debido a la complejidad de codificar los operandos BI y BO de las
instrucciones de salto condicional, se han creado una serie de mnemonics que
se describen en la Tabla 2.45 y Tabla 2.46:

Pg 112

Ensamblador del PowerPC con Mac OS X

Condicin del salto


Salto si la condicin se cumple
Salto si la condicin no se
cumple

MacProgramadores

bc
bt
bf

Instruccin a que equivale


bca
bctr
bcctr
bta
btlr
btctr
bfa
bflr
bfctr

Tabla 2.45: Mnemonics de salto condicional sin actualizacin de LR

Condicin del salto


Salto si la condicin se cumple
Salto si la condicin no se
cumple

bc
btl
bfl

Instruccin a que equivale


bca
bctr
bcctr
btla
btlrl
btctrl
bfla
bflrl
bfctrl

Tabla 2.46: Mnemonics de salto condicional con actualizacin de LR

Estos mnemonics no reciben el operando BO, pero s que tienen que recibir 2
operandos:
o El operando BI con la condicin a evaluar
o La direccin de salto si se cumple la condicin
Es decir, estas instrucciones tienen la forma:
MNEMONIC BI, ETIQUETA
Por ejemplo podemos hacer:
cmpwi cr5,r3,0
bf 22,fin
Que significa que no salte si CR5 tiene el bit de igualdad activo, es decir, si la
comparacin anterior concluy que r3 vala 0. Vase el apartado 6.1.3 para
una mejor descripcin del operando BI.
Para simplificar la codificacin del operando BI se han creado una serie de
smbolos tal como describe la siguiente Tabla 2.47.
Smbolo Valor Descripcin
lt
0
Less Than
gt
1
Greater Than
eq
2
EQual
so
3
Summary Overflow
un
3
UNordered
Tabla 2.47: Smbolos para el operando BI

Pg 113

Ensamblador del PowerPC con Mac OS X

MacProgramadores

Por ejemplo en el ejemplo anterior podramos haber hecho:


cmpwi cr5,r3,0
bf cr5+eq,fin
Donde queda mucho ms claro poner cr5+eq que poner 22.
En caso de que para la comparacin se usara el campo CR0 no hara falta
poner cr0, es decir, podemos hacer:
cmpwi cr0,r3,0
bf eq,fin
Y bf usara el campo cr0 para comprobar la condicin.
Tambin se han hecho mnemonics que no reciben ni el operando BI, ni el
operando BO como muestra la Tabla 2.48 y Tabla 2.49:
Condicin del salto
Branch if less than
Branch if less than or equal
Branch if equal
Branch if greater than or equal
Branch if greater than
Branch if not less than
Branch if not equal
Branch if not greater than
Branch if summary overflow
Branch if not summary overflow
Branch if unordered
Branch if not unordered

Instruccin a que equivale


bc
bca
bclr
bcctr
blt
blta
bltlr
blrctr
ble
blea
blelr
blectr
beq
beqa
beqlr
beqctr
bge
bgea
bgelr
bgectr
bgt
bgta
bgtlr
bgctr
bnl
bnla
bnllr
bnlctr
bne
bnea
bnelr
bnectr
bng
bnga
bnglr
bngctr
bso
bsoa
bsolr
bsoctr
bns
bnsa
bnslr
bnsctr
bun
buna
bunlr
bunctr
bnu
bnua
bnulr
bnuctr

Tabla 2.48: Mnemonics de salto condicional sin actualizacin de LR

Condicin del salto


Branch if less than
Branch if less than or equal
Branch if equal
Branch if greater than or equal
Branch if greater than
Branch if not less than
Branch if not equal
Branch if not greater than
Branch if summary overflow

Instruccin a que equivale


bcl
bcla
bclrl
bcctrl
bltl bltla bltlrl bltctrl
blel blela blelrl blectrl
beql beqla beqlrl beqctrl
bgel bgela bgelrl bgectrl
bgtl bgtla bgtlrl
bgctrl
bnl
bnlla bnllrl bnlctrl
bnel bnela bnelrl bnectrl
bngl bngla bnglrl bngctrl
bsol bsola bsolrl bsoctrl
Pg 114

Ensamblador del PowerPC con Mac OS X

Branch if not summary overflow


Branch if unordered
Branch if not unordered

MacProgramadores

bnsl
bunl
bnul

bnsla
bunla
bnula

bnslrl
bunlrl
bnulrl

bnsctrl
bunctrl
bnuctrl

Tabla 2.49: Mnemonics de salto condicional con actualizacin de LR

La Tabla 2.50 ayuda a entender y recordar las instrucciones anteriores:


Abreviatura
lt
le
eq
ge
gt
nl
ne
ng
so
ns
un
nu

Descripcin
Less Than
Less than or Equal
EQual
Greater than or Equal
Greater Than
Not Less
Not Equal
Not Greater than
Summary Overflow
Not Summary Overflow
UNordered (para comparaciones en punto flotante)
Not Unordered (para comparaciones en punto flotante)

Tabla 2.50: Abreviaturas para los mnemonics de comparacin

Obsrvese que las instrucciones que actualizan LR se escriben igual que las
que no lo actualizan, pero se las aade una l al final. La excepcin esta en
las instrucciones de tipo bcla donde la l se pone antes de la ltima a. Por
ejemplo, en vez de poner bleal se pone blela.
Todas estas instrucciones reciben como primer operando el campo de CR a
comprobar, y como segundo operando la direccin de salto. El primero de los
operandos se puede omitir, en cuyo caso se supone que es el CR0.
Es decir el formato general de estos mnemonics es:
MNEMONIC [CRF,] ETIQUETA
Para indicar el campo de CR a comprobar se puede usar su valor numrico o
bien uno de los mnemonics definidos en la tabla del apartado 5.7.2.
Por ejemplo, si queremos hacer algo slo cuando en r3 haya un nmero
menor de 0 haramos:
cmpwi cr2,r3,0
bge cr2,fin
; Hacer algo

fin: ; Otras cosas

Pg 115

Ensamblador del PowerPC con Mac OS X

MacProgramadores

6.2.3 Mnemonics para acceder a los registros CR, CTR y LR


CTR y LR son registros especiales (en concreto SPR9 y SPR8
respectivamente), que comentamos que podamos acceder a ellos con las
instrucciones:
mfspr rD,SPR /* Move From Special Purpose Register */
mtspr SPR,rS /* Move To Special Purpose Register */
Adems existen mnemonics que nos permiten acceder a ellos ms fcilmente
que se muestran en la Tabla 2.51:
Mnemonic
mfctr rD
mtctr rS
mflr rD
mtlr rS

Descripcin
(Move From CTR) Copia el contenido de CTR en rD
(Move to CTR) Copia el contenido de rS en CTR
(Move From LR) Copia el contendo de LR en rD
(Move To LR) Copia el contenido de rS en CTR

Tabla 2.51: Mnemonics para acceso a los registro CTR y LR

Tambin tenemos mnemonics que nos permiten encender, apagar, copiar e


invertir un determinado bit del registro CR que se resumen en la Tabla 2.52:
Mnemonic
crset B
crclr B
crmove B1,B2
crnot B1,B2

Descripcin
CR SET
CR CLeaR
CR MOVE
CR NOT

Equivalente a
creqv B,B,B
crxor B,B,B
cror B1,B2,B2
crnor B1,B2,B2

Tabla 2.52: Mnemonics para acceder a un bit del registro CR

Donde B es el bit que queremos modificar.

6.3 Implementacin en ensamblador de las


sentencias de control de flujo ms conocidas
del lenguaje C
En esta seccin vamos a detallar como se implementaran en ensamblador
cada una de la sentencias de control de flujo del lenguaje C.

6.3.1 Condicional simple y doble


Las condicionales simple y doble son las sentencias if e if-else de C, las
cuales van a evaluar una expresin cuyo resultado se deposita en un campo
de CR y en funcin de este resultado se ejecuta una y otra parte.
Pg 116

Ensamblador del PowerPC con Mac OS X

MacProgramadores

Por ejemplo, si queremos codificar el ensamblador la sentencia de control de


flujo siguiente:
if (a>0)
{
// Hacer esto
}
else if (a<0)
{
// Hacer lo otro
}
else
{
// Hacer lo de ms all
}
Haramos algo as:

if:

cmpwi rA,0 ; rA contiene el valor de a


ble else_if

; Hacer esto

b fin_if
else_if:
beq else
; Hacer lo otro

b fin_if
else:
; Hacer lo de ms all

fin_if:

Al no indicar a cmpwi campo de CR con el que trabajar, por defecto estamos


trabajando con CR0.

6.3.2 Condicional mltiple


La condicional mltiple en C se representa por la sentencia switch, y puede
implementarse de muchas formas: secuencias de if-else, tablas de salto,
tablas hash, progresin aritmtica, algoritmos de bsqueda en rboles
binarios o ternarios, test de rango, combinaciones, etc. Nosotros vamos a ver
tres formas tpicas.
Pg 117

Ensamblador del PowerPC con Mac OS X

MacProgramadores

Imaginemos que tenemos la sentencia de control de flujo switch siguiente:


switch (x)
{
case 10:
case 11:
case 12:
case 13:
case 14:
case 15:
// Hacer algo
}
La podemos codificar en ensamblador mediante una serie de varios ifelse as:
lis r2,ha16(segmento) ; r2 apunta a los 16 bits
; altos del segmento
lwz r3,lo16(x)(r2)
; Cargamos x en r3
cmpwi cr0,r3,10
beq cr0,etiq10 ;if (x==10) goto etiq10
cmpwi cr0,r3,11
beq cr0,etiq11 ;if (x==11) goto etiq11
cmpwi cr0,r3,12
beq cr0,etiq12 ;if (x==12) goto etiq12
cmpwi cr0,r3,13
beq cr0,etiq13 ;if (x==13) goto etiq13
cmpwi cr0,r3,14
beq cr0,etiq14 ;if (x==14) goto etiq14
cmpwi cr0,r3,15
beq cr0,etiq15 ;if (x==15) goto etiq15
b fuera
etiq10:
etiq11:
etiq12:
etiq13:
etiq14:
etiq15:
;Hacer algo

fuera:
Tambin lo podemos implementar como un test de rango as:
lis r2,ha16(segmento) ; r2 base del segmento
lwz r3,lo16(x)(r2)
; Cargamos x en r3
subi r4,r3,10 ; r4 = r3-10
cmpli cr3,r4,5 ; Comparacin lgica (r4,5)
Pg 118

Ensamblador del PowerPC con Mac OS X

MacProgramadores

bgt cr3,fuera ; if r4<0 or r4>5


; Hacer algo

fuera:
El test de rango es especialmente til cuando, como en el ejemplo anterior,
todos los valores en un determinado rango ejecutan el mismo cdigo.
Obsrvese que cmpli comprueba tanto la condicin r4<0 como r4>5 ya
que, como estamos haciendo una comparacin lgica (sin signo), si se
cumpliera que r4<0 entonces r4 sera negativo y su primer bit sera 1, con lo
que r4 sera considerado un nmero muy grande.
Una tercera forma de hacer esta comparacin es usando una tabla de salto,
en la cual tenemos guardadas las direcciones a las que hay que saltar para
cada caso.
Por ejemplo para codificar un switch as:
switch (x)
{
case 0:
// Cdigo del caso
case 1:
// Cdigo del caso
case 2:
// Cdigo del caso
case 3:
// Cdigo del caso
case 4:
// Cdigo del caso
case 5:
// Cdigo del caso

0
1
2
3
4
5

Haramos un programa en ensamblador tal que as:


lis r2,ha16(segmento) ; r2 apunta a base del segmento
lwz r3,lo16(x)(r2)
; Cargamos x en r3
lis r7,ha16(tabla)
; Carga la direccin de tabla en r7
addi r7,r7,lo16(tabla)
slwi r4,r3,2 ; Multiplica por 4 (bytes/entrada tabla)
lwzx r5,r7,r4 ; r5 = tabla[x]
mtctr r5
; Carga el CounT Register
bctr
; Branch to CounT Register

Pg 119

Ensamblador del PowerPC con Mac OS X

MacProgramadores

tabla contiene las direcciones a las que hay que saltar en cada caso, lo cual
es especialmente til cuando todos los casos son valores consecutivos que
saltan a direcciones distintas.

6.4 Los bucles


Recurdese que en el Tema 1 comentbamos que PowerPC no es una
mquina 100% RISC en el sentido de que se le haban aadido instrucciones
para operaciones comunes que aunque no eran estrictamente necesarias,
ayudaban a reducir el tamao del programa y a ejecutar operaciones
comunes ms rpido. Una de estas son las instrucciones pensadas para
bucles, especialmente los bucles con contador, las cuales ejecutan ms rpido
que si implementramos el bucle con instrucciones condicionales normales.
En el apartado 6.1.3 vimos, aunque no usamos, que el operando BO tena
formas en las que decrementaba el registro CRT en cada comprobacin, este
decremento es el que se recomienda usar en los bucles con contador, ya que
se consigue mejor rendimiento que las operaciones de restar/comprobar
normales del PowerPC.

6.4.1 Mnemonics para bucles


Para las instrucciones de salto en los bucles se han creado los mnemonics que
se resumen en la Tabla 2.53 y Tabla 2.54:
Equivale a
Condicin de salto
bc
bca
bclr
bdnz
bdnza
bdnzlr
Decrementa CTR y salta si CTR0
Decrementa CTR y salta si CTR0 y la condicin bdnzt bdnzta bdnztlr
es true
Decrementa CTR y salta si CTR0 y la condicin bdnzf bdnzfa bdnzflr
es false
bdz
bdza
bdzlr
Decrementa CTR y salta si CTR=0
bdzta
bdztlr
Decrementa CTR y salta si CTR=0 y la condicin bdzt
es true
bdzfa
bdzflr
Decrementa CTR y salta si CTR=0 y la condicin bdzf
es false
Tabla 2.53: Mnemonics para bucles sin actualizacin de LR

Equivale a
bc
bca
bclr
Condicin de salto
bdnzl
bdnzla
bdnzlrl
Decrementa CTR y salta si CTR0
Decrementa CTR y salta si CTR0 y la bdnztl bdnztla bdnztlrl
condicin es true
Pg 120

Ensamblador del PowerPC con Mac OS X

Decrementa CTR
condicin es false
Decrementa CTR y
Decrementa CTR
condicin es true
Decrementa CTR
condicin es false

MacProgramadores

y salta si CTR0 y la bdnzfl bdnzfla bdnzflrl


salta si CTR=0
y salta si CTR=0 y la

bdzl
bdztl

bdzla
bdztla

bdzlrl
bdztlrl

y salta si CTR=0 y la

bdzfl

bdzfla

bdzflrl

Tabla 2.54: Mnemonics para bucles con actualizacin de LR

La Tabla 2.55 ayuda a recordar las abreviaturas usadas por estos mnemonics:
Abreviatura
t
f
d
z
nz

Descripcin
True
False
Decrement
Zero
Not Zero

Tabla 2.55: Abreviaturas de los mnemonics para bucles

Todos estos mnemonics actan sobre el registro CTR y slo reciben como
operando la direccin a la que saltar, es decir, tienen la forma:
MNEMONIC ETIQUETA
A continuacin vamos a poner ejemplos de cmo se usan estos mnemonics
para cada uno de los bucles de C.

6.4.2 Bucle do-while


Vamos a empezar viendo cmo se implementa un bucle do-while.
Imaginemos que queremos calcular la suma de los 100 primeros nmeros, es
decir 1+2+3+...+100. Para ellos podramos hacer un bucle en C as:
int acumulador = 0;
int contador = 1;
do
{
acululador += contador;
contador++;
}
while (contador<=100);
Este programa le podemos pasar a ensamblador tal que as:
li r2,0
; r2 es el acumulador
li r3,1
; r3 es el contador
do: add r2,r2,r3 ; r2 += r3
Pg 121

Ensamblador del PowerPC con Mac OS X

MacProgramadores

add r3,r3,1 ; r3++


cmpwi r3,100
ble do
; r3<=100
fin:
Aunque al ser la condicin un contador es preferible usar el registro CTR de
esta manera:
li r2,0
li r3,1
li r4,100
mtctr r4
do: add r2,r2,r3
add r3,r3,1
bdnz do
fin:

;
;
;
;
;
;
;

r2 es el acumulador
r3 es el contador
Numero de repeticiones
Carga el CTR
r2 += r3
r3++
Hasta que CTR llege a 0

Obsrvese que el contador se lleva en r3 y no se coge el valor del CTR, eso


es as porque el acceso al registro CTR es ms lento que el acceso a un GPR,
con lo que es preferible llevar el contador en un registro aparte, aunque la
condicin de terminacin la pongamos en CTR.

6.4.3 Bucle while


El bucle anterior tiene la condicin de salida al final, con lo que siempre se
repite al menos una vez, si movemos la comprobacin al principio, ya
podemos hacer un bucle que se repita como mnimo cero veces.
Como ejemplo vamos a hacer un bucle que cuente la longitud de una cadena
de caracteres, tal como hace la funcin strlen() de C.
lis r2,ha16(texto) ; Carga la direccin de texto en r2
addi r2,r2,lo16(texto)
lis r3,0
; r3 es el contador
bucle:
lbzu r4,1(r2)
; Lee caracter en r4, incrementa r2
cmpwi cr3,r4,0
beq fuera
add r3,r3,1
; Incrementamos r3
b bucle
; Repetimos
fuera:
; r3 contendr la cuenta de
; caracteres sin contar el 0

6.4.4 Bucle for


Por ltimo vamos a implementar un bucle for en ensamblador. Este tiene
bsicamente estos cuatro pasos:
Pg 122

Ensamblador del PowerPC con Mac OS X

MacProgramadores

for (inicializacin;condicin;actualizacin)
{
cuerpo
}
Los cuales se detallan en la Figura 2.14:
Inicializacin

Actualizacin

Condicin

No

Fin

Cuerpo

Figura 2.14: Estructura de la sentencia for

En caso de que el bucle deba repetirse un determinado nmero de veces


conocido antes de empezar el bucle podemos usar el registro CTR. Al igual
que explicamos antes podemos mantener un contador aparte en un GPR si
necesitsemos usar el contador para los clculos.
Las sentencias break y continue que pudieran encontrarse en el cuerpo
del bucle pueden implementarse como un salto incondicional.
Como ejemplo vamos a hacer un programa que dado un nmero nos dice si
es primo, para ello hacemos un bucle que divida al nmero por todos sus
divisores y si es divisible por alguno de ellos entonces es que no es primo.
El programa en ensamblador le vamos a hacer en un fichero llamado
primo.s:

Pg 123

Ensamblador del PowerPC con Mac OS X

.data
SD: .comm esprimo, 4
n:
.long 13

MacProgramadores

; Aqu se deposita si es primo


; Nmero que queremos ver
; si es primo

.text
.globl _main
_main:
lis r2,ha16(SD)

; r2 apunta a la base del


; segmento de datos
lwz r3,lo16(n)(r2) ; r3 es el nmero a comprobar
addi r4,r3,-2;
; Calculamos el contador para CTR
mtctr r4
; Fijamos el CTR
; Inicializacin
addi r4,r3,-1
; r4 es el contador
; Condicin. Acaba si llega a 1 el contador
; significando que es primo
bucle:
cmpwi r4,1
beq primo
; Cuerpo
; Dividimos y multiplicamos r3 por r4
; Si es el mismo nmero es que es divisible
divw r5,r3,r4
mullw r5,r5,r4
cmpw r5,r3
beq noprimo
;Actualizacin
addi r4,r4,-1
bdnz bucle
primo:
li r10,1
b fin
noprimo:
li r10,0
fin: stw r10,lo16(esprimo)(r2)
blr

6.5 Operaciones lgicas con los bits del registro CR


Podemos realizar operaciones lgicas con los bits (no los campos) del registro
CR, cuyo resultado podemos volver a guardar en otro campo de CR.
Las operaciones de este tipo de que dispone PowerPC se muestran en la
Tabla 2.56:

Pg 124

Ensamblador del PowerPC con Mac OS X

Instruccin
crand CRBD,CRBA,CRBB

cror CRBD,CRBA,CRBB

crxor CRBD,CRBA,CRBB

crnand CRBD,CRBA,CRBB

crnor CRBD,CRBA,CRBB

creqv CRBD,CRBA,CRBB

crandc CRBD,CRBA,CRBB

crorc CRBD,CRBA,CRBB

mcrf CRD,CRS

MacProgramadores

Descripcin
Al bit de la posicin CRBA se le hace un and
binario con el bit de la posicin CRBB y el
resultado se almacena en el bit CRBD
Al bit de la posicin CRBA se le hace un or
binario con el bit de la posicin CRBB y el
resultado se almacena en el bit CRBD
Al bit de la posicin CRBA se le hace un xor
binario con el bit de la posicin CRBB y el
resultado se almacena en el bit CRBD
Al bit de la posicin CRBA se le hace un nand
binario con el bit de la posicin CRBB y el
resultado se almacena en el bit CRBD
Al bit de la posicin CRBA se le hace un nor
binario con el bit de la posicin CRBB y el
resultado se almacena en el bit CRBD
Al bit de la posicin CRBA se le hace un xor
binario con el bit de la posicin CRBB y el
complemento a 1 del resultado se almacena
en el bit CRBD
Al bit de la posicin CRBA se le hace un and
binario con el bit de la posicin CRBB y el
complemento a 1 del resultado se almacena
en el bit CRBD
Al bit de la posicin CRBA se le hace un or
binario con el bit de la posicin CRBB y el
complemento a 1 del resultado se almacena
en el bit CRBD
Los 4 bits del campo CRS se copian en el
campo CRD

Tabla 2.56: Operaciones lgicas con campos del registro CR

La principal utilidad de estas instrucciones es hacer operaciones lgicas con


los resultados de comparaciones que aparezcan en una expresin. Por
ejemplo imaginemos que queremos pasar a ensamblador este trozo de
programa C:
if (a>5 && b>3){
// Haz algo
}
Podemos realizar las comparaciones relacionales con cmpwi, depositar cada
resultado en un campo distinto de CR y luego usar crand para comprobar
ambos resultados:
Pg 125

Ensamblador del PowerPC con Mac OS X

MacProgramadores

cmpwi cr2,rA,5
cmpwi cr3,rB,3
crand 17,9,13
bng cr4,fin
; Haz algo

fin:
Hay que tener en cuenta que crand opera a nivel de bit de CR, no a nivel de
campo de CR, con lo que tenemos que decirle que bits origen leer y en que
bit destino depositarlo.
Como los bits de CR estn ordenados como muestra la Figura 2.3, si las
comparaciones las depositamos en los campos CR2 y CR3, el bit que indica si
se cumple la condicin mayor que es el segundo de los 4 bits del campo,
luego tendremos que leer los bits 9 y 13. Para depositar el resultado en CR4
debemos depositarlo tambin en el segundo bit de CR4 que es el bit 17.
Por ltimo, bng comprueba si cr4 contiene la condicin mayor que en cuyo
caso significa que cr2 y cr3 tambin cumplan la condicin.

Pg 126

Ensamblador del PowerPC con Mac OS X

MacProgramadores

7 Instrucciones de trabajo con nmeros en


punto flotante
En este apartado vamos a estudiar las instrucciones de que dispone PowerPC
para ejecutar operaciones con nmeros en punto flotante. Durante su estudio
vamos a suponer que el lector ya conoce la representacin de nmeros en
punto flotante tal como est definida en el estndar IEEE 754. Si el lector no
conoce este sistema de numeracin, o no lo recuerda adecuadamente, le
recomendamos que lea el apartado A antes de continuar.

7.1 Introduccin
La arquitectura de PowerPC dispone de un procesador de nmeros en punto
flotante que cumple estrictamente con el estndar IEEE 754. El procesador
soporta directamente un subconjunto de las operaciones descritas en el IEEE
754 debindose implementar las dems operaciones por software.
Respecto a los formatos de tipos de datos, PowerPC soporta slo los tipos
simple y doble. El tipo doble extendido no lo soporta PowerPC directamente
debindose implementar el trabajo con nmeros en este formato por
software.
El procesador de PowerPC tiene como tipo de dato por defecto los
en formato doble, lo cual significa que a no ser que se lo
explcitamente todos los clculos y los resultados se obtienen sobre
tipo doble. Aun as el procesador dispone de instrucciones para
entre representaciones simple y doble, as como de operaciones
permiten trabajar directamente con datos en formatos simple.

nmeros
pidamos
datos de
convertir
que nos

7.2 Los registros de punto flotante


El procesador de PowerPC dispone de 32 registros destinados al trabajo con
nmeros en punto flotante llamados FPR (Floating Point Registers). Cada uno
de estos registros tiene 64 bits con lo que pueden almacenar un nmero en
formato doble. Para referirnos a estos registros desde el lenguaje
ensamblador usaremos los nombres f0 a f31.
Los registros FPR siempre trabajan con nmeros en formato doble, aunque
podemos leer/almacenar en memoria tanto nmeros en formato simple como
en formato doble. Las reglas que sigue PowerPC son las siguientes:
o Si leemos un dato de memoria en formato doble, ste se pasa
directamente a un registro FPR, mientras que cuando leemos un dato
de memoria en formato simple este se transforma a formato doble
antes de almacenarse en el registro.
Pg 127

Ensamblador del PowerPC con Mac OS X

MacProgramadores

o Cuando pasamos un dato de un registro FPR a memoria ste se puede


almacenar en memoria en formato doble directamente. Tambin
podemos pasar un dato de un registro FPR en formato doble a
memoria en formato simple, en cuyo la instruccin transforma el dato
de formato doble a simple antes de pasarlo a memoria.
Por otro lado, el sistema de punto flotante dispone de otros dos registros que
permiten modificar el funcionamiento de la unidad de punto flotante, as
como obtener resultados de esta, que son los registros FPSCR y CR.
FPSCR (Floating Point Status and Control Register) es un registro de
32 bits que almacena el estado de la unidad de punto flotante de procesador.
En l se indican cosas como el modo de redondeo a utilizar, o el estado de las
excepciones del procesador.
CR (Condition Register) es el mismo registro que usan las instrucciones de
trabajo con enteros o las de bifurcacin, y que tambin lo utiliza el sistema de
punto flotante. El campo CR1 del registro CR se puede usar para reflejar el
resultado de ejecutar operaciones de punto flotante con punto (p.e. fadd.),
al igual que pasaba con el campo CR0 en las instrucciones de trabajo con
enteros. Tambin podemos usar cualquiera de los campos del registro CR
para reflejar el resultado de las comparaciones en punto flotante.

7.3 El registro FPSCR


El registro FPSCR (Floating Point Status and Control Register) se encuentra
dividido en campos de 4 bits llamados FPSCR0 hasta FPSCR7, y muchas de las
operaciones que trabajan con l operan en estos campos. La siguiente Figura
2.15 muestra los principales campos del registro FPSCR y cual es su utilidad.

34

78

11 12

15 16

Flags de
exception
invlida

Flags de
summary
exception
Flags de
exception

19 20

23 24

Flags de
habilitacin
de excepcin
Cdigos de
condicin

27 28

31

Bits de
redondeo

Figura 2.15: Campos del registro FPSCR

La Tabla 2.57 describe detalladamente el propsito de cada uno de los bits


del registro FPSCR.

Pg 128

Ensamblador del PowerPC con Mac OS X

Campo Bit
0

MacProgramadores

Nombre Descripcin

FX

FEX

VX

OX

UX

ZX

XX

VXSNAN

VXISI

VXIDI

10

VXZDZ

11

VXIMZ

12

VXVC

13

FR

Floating Point Exception Summary.


Cualquier excepcin en punto flotante,
activa implcitamente este bit.
Floating Point Enabled Exception
Summary. Cualquier excepcin
habilitada que se produzca, activa este
bit.
Floating Point Invalid Operation
Exception Summary. Este bit indica la
ocurrencia de cualquiera de las Invalid
Operation Exception.
Floating Point Overflow Exception.
Activo cuando se produce un overflow
Floating Point Underflow Exception.
Activo cuando se produce un underflow
Floating Point Zero Divide Exception.
Activo cuando se produce una divisin
entre cero
Floating Point Inexact Exception. Indica
que se ha tenido que hacer un
redondeo.
Floating Point Invalid Operation
Exception for Signaling NAN. Se
produce cuando uno de los operandos
es un signaling NaN.
Floating Point Invalid Operation
Exception for Infinite Sustract Infinite.
Se activa cuando pedimos calcular .
Floating Point Invalid Operation
Exception for Infinite Divide Infinite. Se
produce cuando pedimos calcular /.
Floating Point Invalid Operation
Exception for Zero Divide Zero. Se
produce cuando pedimos calcular 0/0.
Floating Point Invalid Operation
Exception for Infinite Multiply Zero. Se
produce cuando pedimos calcular *0.
Floating Point Invalid Operation
Exception for Invalid Compare. Se
produce cuando intentamos comparar
nmeros sin relacin de orden.
Floating Point Fraction Rounded. Se
Pg 129

Bit
retenido
S
No

No

S
S
S
S
S

S
S
S
S

No

Ensamblador del PowerPC con Mac OS X

14

FI

15

FPRF

16
17
18
19
20
21

VXSOFT

22

VXSQRT

23

VXCVI

24

VE

25

OE

26

UE

27

ZE

28
29

XE
NI

MacProgramadores

pone a 1 si la ltima instruccin de


redondeo o conversin increment la
fraccin, sino se pone a 0.
Floating Point Fraction Inexact. La
ltima instruccin necesit de
redondeo.
Floating Point Result Class Descriptor.
Las instrucciones aritmticas, de
redondeo y de conversin deben
encender este bit para indicar el
resultado de acuerdo a la tabla del
apartado 7.3.3
Floaintg Point Less Than or Negative
Floating Point Greater Than or Positive
Floating Point Equal or Zero
Floating Point Unordered or NaN
Reservado
Floaintg Point Invalid Operation
Exception for Software Request.
Permite que el programa cause una
excepcin que est asociada a una
instruccin de punto flotante. P.e.
puede ser usada por un programa que
calcula la raz cuadrada de un nmero,
si el operando de entrada es negativo.
Esto permite emular instrucciones no
implementadas en hardware
Floating Point Invalid Operation
Exception for Invalid Square Root.
Floating Point Invalid Operation
Exception for Invalid Integer Convert
Floating Point Invalid Operation
Exception Enable
Floating Point Overflow Exception
Enable
Floating Point Underflow Exception
Enable
Floating Point Zero Divide Exception
Enable
Floating Point Inexact Exception Enable
Floating Point no IEEE 754 mode. Si
activamos este bit, los resultados no
cumplen con el estndar IEEE 754 y los
dems bits de FPSCR pueden tener
significados distintos a los indicados
aqu. El funcionamiento que tendra el
procesador sera dependiente del
Pg 130

No
No

No
No
No
No
S

S
S
-

Ensamblador del PowerPC con Mac OS X

30
31

RN

MacProgramadores

modelo y debe consultarse el manual


de usuario del microprocesador usado.
Floating Point Rounding Control:
00 - Redondeo al ms cercano (por
defecto)
01 - Redondeo a cero
10 - Redondeo a +
11 - Redondeo a -

Tabla 2.57: Asignacin de bits en el registro FPSCR

7.3.1 Instrucciones para acceder a los bits de registro


FPSCR
A los bits del registro de FPSCR podemos acceder a nivel de registro, a nivel
de campo o a nivel de bit individual.
La siguiente Tabla 2.58 resume las instrucciones de que dispone PowerPC
para acceder a los bits de registro FPSCR.
Instruccin
mffs fD
mffs. fD

mtfsf FM,fD
mtfsf. FM,fD

mtcrfs CRFD,FS

mtfsfi FD,UIMM
mtfsfi. CRFD,UIMM
mtfsb0 BD
mtfsb0. BD

Descripcin

Nivel
acceso
(Move From FPSCR) El contenido de Registro
FPSCR se deposita en los bits 32-63
de fD. El contenido de los bits 0-31
de fD queda indefinido.
(Move To FPSCR Fields) Los bits 32- Registro
63 del registro fD se copian al
registro FPSCR bajo el control de la
mscara de campos FM, la cual
indica que campos se deben copiar.
FM puede tener hasta 8 bits de los
cuales los activos indican los
campos a copiar.
(Move To CR from FPSCR) El Campo
contenido del campo FS del registro
FPSCR se copia en el campo CRFD
del registro CR. Todos los bits de
excepcin copiados (excepto FEX y
VX) son borrados en FPSCR
(Move To FPSCR Field Immediate) El Campo
contenido de UIMM se deposita en el
campo FD
(Move To FPSCR Bit 0) El bit de la Bit
posicin BD del registro FPSCR es
Pg 131

Ensamblador del PowerPC con Mac OS X

mtfsb1 BD
mtfsb1. BD

MacProgramadores

borrado. Los bits FEX y VX no


pueden borrarse explcitamente
(Move To FPSCR Bit 1) El bit de la Bit
posicin BD del registro FPSCR es
encendido. Los bits FEX y VX no
pueden encenderse explcitamente

Tabla 2.58: Instrucciones para acceso a los bits de FPSCR

Como es habitual, las instrucciones de la Tabla 2.58 que llevan punto (.)
producen una actualizacin del registro CR.

7.3.2 Los flags de excepcin


El sistema de punto flotante del ensamblador del PowerPC dispone de los
mismos cinco flags de excepcin que recomienda el estndar IEEE 754, slo
que algunos de ellos estn desdoblados en varios flags con el fin de poder
precisar mejor la causa de la excepcin.
En concreto estos cinco flags de excepcin son:
1. VX (Invalid Operation). Este flag se activa cuando se ejecuta cualquier
instruccin de punto flotante con operandos no vlidos. Para concretar ms la
causa de la excepcin tenemos los flags:
o VXSNAN (Invalid Operation Signaling NaN). Se activa cuando uno de
los operandos es un signaled NaN.
o VXISI (Invalid Operation Infinite Sustract Infinite). Se activa cuando
pedimos calcular -.
o VXIDI (Floating Point Invalid Operation Exception for Infinite Divide
Infinite). Se produce cuando pedimos calcular /.
o VXZDZ (Floating Point Invalid Operation Exception for Zero Divide
Zero). Se produce cuando pedimos calcular 0/0.
o VXIMZ (Floating Point Invalid Operation Exception for Infinite Multiply
Zero). Se produce cuando pedimos calcular *0.
o VXVC (Floating Point Invalid Operation Exception for Invalid Compare).
Se produce cuando intentamos comparar nmeros sin relacin de
orden.
2. OX (Overflow Exception). Se produce cuando el nmero calculado es
tan grande que no se puede representar en el formato utilizado y hay que
representarlo como .
3. UX (Underflow Exception). Se produce cuando el nmero calculado es
tan pequeo que no se puede representar en el formato utilizado y hay que
representarlo como 0.
4. ZX (Zero Exception). Se produce cuando intentamos dividir entre 0.

Pg 132

Ensamblador del PowerPC con Mac OS X

MacProgramadores

5. XX (Inexact Exception). Se activa cuando las ltimas instrucciones de


punto flotante produjeron un redondeo (es un bit de retencin). Para
concretar ms sobre el redondeo se usan estos otros dos flags:
o FI (Fraction Inexact). Se activa cuando la ltima instruccin de punto
flotante produjo un redondeo (no es de retencin).
o FR (Fraction rounded). Si el redondeo se hizo hacia arriba se pone a 1,
si se hizo hacia abajo se pone a 0.
La Figura 2.16 muestra ms claramente cuando se activa cada uno de los bits
de XX:

Redondeo?

FI <- 0
FR <- 0

FI <- 1

Fracin
incrementada?

FR <- 1

FR <- 0

Figura 2.16: Proceso de activacin de los flags de excepcin

7.3.2.1

Los flags de habilitacin de excepcin

Para que se activen los flags de excepcin debemos de habilitar los llamados
flags de habilitacin de excepcin, de los cuales hay uno para cada tipo
principal, tal como muestra la Tabla 2.59:
Flag
VE
OE
UE
ZE
XE

Tipo de excepcin que activa


Invalid Operation Exception
Overflow Exception
Underflow Exception
Zero Divide Exception
Inexact Exception

Tabla 2.59: Flags de habilitacin de excepcin

Pg 133

Ensamblador del PowerPC con Mac OS X

7.3.2.2

MacProgramadores

Los flags de resumen

Adems de estos flags tenemos los flags de resumen (summary), los


cuales se activan cuando se produce cualquier excepcin, estos flags son
tiles ya que lo primero que podemos hacer es comprobar estos flags viendo
si ha habido algn problema, y cuando se activan podemos llamar a una
rutina que determine la causa exacta del problema.
Los flags de resumen son:
o FX (Floating Point Exception Summary). Cualquier excepcin en punto
flotante activa implcitamente este bit.
o FEX (Floating Point Enabled Exception Summary). Cualquier excepcin
habilitada que se produzca activa este bit.
FX se activa aunque los flags de habilitacin de excepcin estn
deshabilitados, pero en este caso no se activarn los flags que indican la
causa de la excepcin. FEX se activa slo si se a producido alguna excepcin
para la que sus flags de habilitacin de excepcin estaban activos.

7.3.3 Los bits de condicin y el bit de clase


Los bits 16-19 indican el resultado de una comparacin, la cual debe activar
slo uno de los cuatro bits < (menor que), > (mayor que), = (igual) ? (sin
relacin de orden).
Los bits 16-19 combinados con el bit 15 (bit de clase) nos pueden servir para
saber a que clase pertenece el resultado de una instruccin de punto flotante
(nmero normalizado, nmero denormalizado, cero, NaN o infinito).
La Tabla 2.60 muestra cmo se deben interpretar estos bits.

Pg 134

Ensamblador del PowerPC con Mac OS X

Result Flags
(Bits 15-19)
C
< >
0
0
0

=
0

?
1

MacProgramadores

Resultado para
una comparacin

Resultado para
otra operacin
No aplicable

0
0
0
0
0
1

0
0
0
1
1
0

0
1
1
0
0
0

1
0
0
0
0
0

0
0
1
0
1
1

1
1

0
0

0
1

1
0

0
0

Sin relacin de
orden
== (Igual)
> (Mayor que)
No aplicable
< (Menor que)
No aplicable
Sin relacin de
orden
== (Igual)
> (Mayor que)

< (Menor que)

+0
Nmero normalizado positivo
+
Nmero normalizado negativo
-
Quiet NaN
-0
Nmero denormalizado
positivo
Nmero denormalizado
negativo

Tabla 2.60: Floating Point Result Flags FPSCR[FPRF]

Por ejemplo, para saber de qu tipo es el nmero que obtenemos como


resultado de una suma en punto flotante podramos hacer un programa tal
que as:
fadd f0,f1,f2
mcrfs 2,3
mcrfs 3,4
bun 3,infinito

;
;
;
;
;
;
;
;
;

beq 3,cero
b normal
infinito:
bt 11,NaN

Fija los valores de FPSCR[15-19]


de acuerdo al tipo de f0
Copia los bits FPSCR[12-15] a CR2
Copia los bits FPSCR[16-19] a CR3
Si el bit 3 de CR3 es 1
el resultado es infitito o NaN
Si CR3[2]=1
Es un nmero normalizado
o denormalizado

; Si BI=11, es decir, CR2[3]=1


; (Summary Overflow o Floating Point
; Unordered) f0 es un Quiet NaN

; f0 es infinito
NaN:

; f0 es NaN
cero:
; f0 es 0
normal:
bt 11,denormal

;
;
;
;
; f0 es un nmero

Si BI=11, es decir, CR2[3]=1


(Summary Overflow o Floating Point
Unordered) indica que f0
es un nmero denormalizado
normalizado
Pg 135

Ensamblador del PowerPC con Mac OS X

MacProgramadores

denormal:
; f0 es un nmero denormalizado
En el programa pasamos los bits FPSCR[15-19] al registro CR para comprobar
su valor y decidir la clase del resultado de la suma de acuerdo a la tabla
anterior.

7.3.4 Los bits de redondeo


Los bits 30 y 31 de FPSCR sirven para indicar el modo de redondeo a aplicar
de acuerdo a la Tabla 2.61:
Bit
30
0
0
1
1

Bit 31
0
1
0
1

Modo redondeo
Al ms cercano
A cero
A +
A -

Tabla 2.61: Modo de redondeo

7.4 El registro CR
Si usamos las instrucciones con punto (.), el resultado de su ejecucin
adems de almacenarse en el registro FPSCR se almacena en el campo CR1
del registro CR. Despus podemos comprobar este campo para obtener
informacin sobre el valor obtenido.
La Tabla 2.62 muestra cules son los bits del registro FPSCR que se copian al
registro CR en caso de usar instrucciones con punto.
Bit
4
5
6
7

Descripcin
Contiene el valor del bit FX del registro FPSCR que indica que alguna
excepcin se ha producido
Contiene el valor del bit FEX del registro FPSCR que indica que
alguna excepcin para la que su flag de habilitacin de excepcin
estaba encendido se ha producido
Contiene el valor del bit VX del registro FPSCR que indica que alguna
invalid exception se ha producido
Contiene el valor del bit OX del registro FPSCR que indica que se ha
producido un desbordamiento

Tabla 2.62: Bits del registro FPSCR copiados al registro CR

El valor del campo CR1 del registro CR se puede consultar tras ejecutar una
instruccin para ver si se ha producido una excepcin de la siguiente manera:

Pg 136

Ensamblador del PowerPC con Mac OS X

MacProgramadores

fadd. f0,f1,f2
bt 5,excepcion ; Si FEX est activo
; No ha habido excepcion

excepcion:
mcrfs 2,1
; Copia FPSCR[4-7] a CR2
bt 6,invalid
; Miramos los bits de CR para ver que
bt 7,overflow ; tipo de excepcin se ha producido
bt 8,underflow
bt 9,divbyzero
bt 10,inexact
invalid:
mcrfs 2,2
; Copia FPSCR[8-11] a CR2
mcrfs 3,3
; Copia FPSCR[12-15] a CR3
mcrfs 4,5
; Copia FPSCR[20-23] a CR4
; Ahora podemos saber el tipo exacto de invalid
; operation en base al flag de excepcin invalid
; operation que est activo
overflow:
; Se ha producido un overflow
underflow:
; Se ha producido un underflow
divbyzero:
; Se ha intentado dividr entre cero
inexact:
; Redondeo inexacto

7.5 Manejo de traps


PowerPC permite tanto usar flags de habilitacin de traps, como usar flags de
habilitacin de excepcin, ser el diseador del sistema operativo quien deba
tomar esta decisin.
Por defecto Mac OS X usa la opcin de los flags de habilitacin de excepcin
que se considera la ms adecuada, pero si el diseador de un sistema lo
considera oportuno (p.e. por razones de compatibilidad hacia atrs como pasa
en Linux) puede usar traps. Para ello debe encender los registros FE0 y FE1
del registro MSR, que es un registro de superusuario que comentaremos en el
Tema [pendiente], con lo cual slo puede ser modificado por el sistema
operativo.
La Tabla 2.63 describe los valores que pueden tomar los flags FE0 y FE1:

Pg 137

Ensamblador del PowerPC con Mac OS X

MacProgramadores

FE0 FE1 Descripcin


0
0
Ignore Exceptions Mode. Las excepciones en punto flotante no
invocan a un handle de traps
0
1
Imprecise Nonrecoverable Mode. Cuando se produce una
excepcin de punto flotante, se llama al handle de traps de la
excepcin. Podra no ser posible identificar la instruccin o dato
que caus la excepcin porque los datos de la instruccin que
provoc la excepcin pueden ser usados por otras instrucciones
de punto flotante que se estn ejecutando.
1
0
Imprecise Recoverable Mode. Cuando se produce una excepcin
de punto flotante, se llama al handle de traps de la excepcin.
Siempre es posible saber la instruccin y dato que produjo la
instruccin porque los datos de la instruccin que provoc la
excepcin no pueden ser usados por otras instrucciones de punto
flotante que se estn ejecutando.
1
1
Precise Mode. El sistema nunca ejecuta concurrentemente dos
instrucciones de punto flotante, con lo que siempre es posible
saber la instruccin que produjo la excepcin. Este modo slo
debe ser usado en depuracin ya que puede degradar mucho el
rendimiento del sistema.
Tabla 2.63: Valores que pueden tomar los flags FE0 y FE1

El uso de traps lo veremos en el Tema [pendiente], el resto del tema


supondremos que los traps estn desactivados.

7.6 Instrucciones de carga y almacenamiento


Antes de que PowerPC pueda operar con un dato en punto flotante situado en
memoria, debe de cargarlo en alguno de los FPR. Anlogamente PowerPC
puede depositar los datos en memoria una vez que acaba de trabajar con
ellos.
Como se explic en el aparatado 7.2, los registros FPR siempre trabajan con
nmeros en formato doble, aunque podemos leer/almacenar en memoria
tanto nmeros en formato simple como en formato doble.
Las instrucciones de acceso a memoria para punto flotante (al igual que
pasaba con las de acceso a memoria con enteros) se pueden dividir en dos
tipos:
o Instrucciones de acceso con indireccionamiento de registro base e ndice
inmediato
o Instrucciones de acceso con indireccionamiento de registro base y registro
ndice

Pg 138

Ensamblador del PowerPC con Mac OS X

MacProgramadores

Vase el apartado 4.4 para una mejor descripcin de estos modos de


indireccionamiento.
En concreto las instrucciones de acceso con indireccionamiento de registro
base e ndice inmediato aparecen en la Tabla 2.64 y Tabla 2.65:
Instruccin
lfs fD,d(rA)

lfsu fD,d(rA)

lfd fD,d(rA)
lfdu fD,d(rA)

Descripcin
(Load Floating-point Single) El word en la direccin de
memoria d(rA) se interpreta como un nmero en
punto flotante de precisin simple, y se carga en fD
convertido a punto flotante de precisin doble
(Load Floating-point Single with Update) Igual a lfs,
slo que rA se actualiza con el valor de d(rA)
despus de leer la memoria
(Load Floating-point Double) El doble-word en la
direccin de memoria d(rA) se carga en fD
(Load Floating-point Double with Update) Igual a
lfd, slo que rA se actualiza con el valor de d(rA)
despus de leer la memoria

Tabla 2.64: Instrucciones de carga de nmeros en punto flotante con indireccionamiento de


registro base e ndice inmediato

Instruccin
sfs fD,d(rA)

sfsu fD,d(rA)

sfd fD,d(rA)

sfdu fD,d(rA)

Descripcin
(Store Floating-point Single) El contenido de fD se
convierte a precisin simple y se guarda en el word de
la direccin de memoria apuntada por d(rA)
(Store Floating-point Single with Update) Igual a sfs,
slo que rA se actualiza con el valor de d(rA)
despus de escribir la memoria
(Store Floating-point Double) El contenido de fD se
guarda en memoria, en el doble-word apuntado por
d(rA)
(Store Floating-point Double with Update) Igual a
sfd, slo que rA se actualiza con el valor de d(rA)
despus de escribir la memoria

Tabla 2.65: Instrucciones de almacenamiento de nmeros en punto flotante con


indireccionamiento de registro base e ndice inmediato

Y las instrucciones de acceso con indireccionamiento de registro base y


registro ndice aparecen en la Tabla 2.66 y Tabla 2.67:
Instruccin
lfsx fD,rA,rB

Descripcin
(Load Floating-point Single indeXed) El word en la
direccin de memoria (rA|0)+rB se interpreta como
un nmero en punto flotante de precisin simple, y se
Pg 139

Ensamblador del PowerPC con Mac OS X

lfsux fD,rA,rB

lfdx fD,rA,rB
lfdux fD,rA,rB

MacProgramadores

carga en fD convertido a punto flotante de precisin


doble
(Load Floating-point Single with Update indeXed) Igual
a lfsx, slo que rA se actualiza con el valor de
(rA|0)+rB despus de leer la memoria
(Load Floating-point Double indeXed) El doble-word en
la direccin de memoria (rA|0)+rB se carga en fD
(Load Floating-point Double with Update indeXed)
Igual a lfdx, slo que rA se actualiza con el valor de
(rA|0)+rB despus de leer la memoria

Tabla 2.66: Instrucciones de carga de nmeros en punto flotante con indireccionamiento de


registro base y registro ndice

Instruccin
sfsx fD,rA,rB

sfsux fD,rA,rB

sfdx fD,rA,rB

sfdux fD,rA,rB

Descripcin
(Store Floating-point Single indeXed) El contenido de
fD se convierte a precisin simple y se guarda en el
word de la direccin de memoria apuntada por
(rA|0)+rB
(Store Floating-point Single with Update indeXed)
Igual a sfsx, slo que rA se actualiza con el valor de
(rA|0)+rB despus de escribir la memoria
(Store Floating-point Double indeXed) El contenido de
fD se guarda en memoria, en el doble-word apuntado
por (rA|0)+rB
(Store Floating-point Double with Update indeXed)
Igual a sfdx, slo que rA se actualiza con el valor de
(rA|0)+rB despus de escribir la memoria

Tabla 2.67: Instrucciones de almacenamiento de nmeros en punto flotante con


indireccionamiento de registro base y registro ndice

7.7 Instrucciones aritmticas


PowerPC dispone de las operaciones aritmticas que propone el estndar
IEEE 754:
o
o
o
o
o
o
o

Suma
Resta
Multiplicacin
Multiplicacin-suma
Divisin
Raz cuadrada (opcional)
Redondeo a entero (opcional)

Pg 140

Ensamblador del PowerPC con Mac OS X

MacProgramadores

Las dos ltimas son operaciones opcionales, lo que significa que no todos los
micros las poseen, debemos de consultar el manual del microprocesador para
ver si la soporta.
La operacin de multiplicacin-suma se proporciona con el fin de poder
realizar operaciones de multiplicacin seguidas de una suma con un nico
redondeo, lo cual proporciona ms precisin que hacer dos redondeos.
La Tabla 2.68 describe ms concretamente las instrucciones:
Instruccin
fadd fD,fA,fB
fadd. fD,fA,fB
fadds fD,fA,fB
fadds. fD,fA,fB
fsub fD,fA,fB
fsub. fD,fA,fB
fsubs fD,fA,fB
fsubs. fD,fA,fB
fmul fD,fA,fB
fmul. fD,fA,fB
fmuls fD,fA,fB
fmuls. fD,fA,fB
fmadd fD,fA,fB,fC
fmadd. fD,fA,fB,fC
fmadds fD,fA,fB,fC
fmadds. fD,fA,fB,fC
fmsub fD,fA,fB,fC
fmsub. fD,fA,fB,fC
fmsubs fD,fA,fB,fC
fmsubs. fD,fA,fB,fC
fnmadd fD,fA,fB,fC
fnmadd. fD,fA,fB,fC
fnmadds fD,fA,fB,fC
fnmadds. fD,fA,fB,fC
fnmsub fD,fA,fB,fC
fnmsub. fD,fA,fB,fC
fnmsubs fD,fA,fB,fC
fnmsubs. fD,fA,fB,fC
fdiv fD,fA,fB
fdiv. fD,fA,fB
fdivs fD,fA,fB
fdivs. fD,fA,fB

Descripcin
(Floating Add) En fD obtenemos la
suma fA+fB
(Floating Add Single) En fD
obtenemos la suma fA+fB
(Floating Substract) En fD obtenemos
el valor de fA-fB
(Floating Sustract Single) En fD
obtenemos el valor de fA-fB
(Floating Multiply) En fD obtenemos
el producto fA*fB
(Floating Multiply Single) En fD
obtenemos el producto fA*fB
(Floating Multiply-Add) En fD
obtenemos fA*fB+fC
(Floating Multiply-Add Single) En fD
obtenemos fA*fB+fC
(Floating Multiply-Substract) En fD
obtenemos fA*fB-fC
(Floating Multiply-Subtract Single) En
fD obtenemos fA*fB-fC
(Floating Negative Multiply-Add) En
fD obtenemos -(fA*fB+fC)
(Floating Negative Multiply-Add
Single) En fD obtenemos (fA*fB+fC)
(Floating Negative Multiply-Substract)
En fD obtenemos -(fA*fB-fC)
(Floating Negative Multiply-Subtract
Single) En fD obtenemos -(fA*fBfC)
(Floating Divide) en fD obtenemos el
resultado de dividir fA/fB.
(Floating Divide Single) en fD
obtenemos el resultado de dividir
Pg 141

Precisin
Doble
Simple
Doble
Simple
Doble
Simple
Doble
Simple
Doble
Simple
Doble
Simple
Doble
Simple
Doble
Simple

Ensamblador del PowerPC con Mac OS X

fsqrt fD,fS
fsqrt. fD,fS
fsqrts fD,fS
fsqrts. fD,fS
fres fD,fS
fres. fD,fS

frsqrte fD,fS
frsqrte. fD,fS

fsel fD,fA,fB,fC
fsel. fD,fA,fB,fC

MacProgramadores

fA/fB
(Floating SQuare RooT) en fD
obtenemos la raz cuadrada de fS.
Esta operacin es opcional
(Floating SQuare RooT Single) En fD
obtenemos la raz cuadrada de fS.
Esta operacin es opcional
(Floating Reciprocal Estimate Simple)
En fD obtenemos 1/fS. Esta
operacin es opcional. No existe su
correspondiente operacin para
nmeros de precisin doble
(Floating Reciprocal SQuare Root
Estimate) En fD obtenemos
1/sqrt(fS). Esta operacin es
opcional. No existe su
correspondiente operacin para
nmeros con precisin simple
(Floating Select) El valor de fA se
compara con 0. Si fA es mayor o
igual que 0, fB se deposita en fD,
sino fC se deposita en fD. La
comparacin ignora el signo de 0 (+0
-0). Esta operacin es opcional.

Doble

Simple

Simple

Doble

Doble

Tabla 2.68: Instrucciones aritmticas

Todas ellas disponen de una versin con punto (.) que actualiza el registro
CR.
Casi todas las operaciones se proporcionan tanto para precisin simple como
para precisin doble. Las instrucciones de precisin simple se diferencian
porque tienen una s al final de su nombre.
En la divisin decimal no se desperdicia el resto como pasa en la divisin
entera, es decir, si hacemos:
; f1 = 7.0
; f2 = 2.0
fdiv f0,f1,f2 ; f3 = 3.5
La operacin fsel se utiliza para conseguir el mismo efecto que el operador
?: del lenguaje C, donde asignamos un valor u otro a fD en funcin de una
condicin sin hacer saltos, los cuales como se explica en el Apndice B,
degradan ms el rendimiento del programa.

Pg 142

Ensamblador del PowerPC con Mac OS X

MacProgramadores

7.8 Instrucciones de conversin


IEEE 754 requiere que el sistema de numeracin en punto flotante disponga
de las siguientes operaciones de conversin:
o
o
o
o
o

De punto flotante a entero


De entero a punto flotante
De punto flotante a entero, con el resultado en punto flotante
Entre todos los formatos de punto flotante que existan
Entre punto flotante binario y punto flotante decimal

En ensamblador de PowerPC dispone de algunas de estas conversiones,


debindose implementar las dems conversiones por software.
PowerPC dispone de tres instrucciones de conversin que aparecen en la
Tabla 2.69:
Instruccin
frsp fD,fS
frsp. fD,fS

fctiw fD,fS
fctiw. fD,fS

fctiwz fD,fS
fctiwz. fD,fS

Descripcin
(Floating Round to Single Precision) Redondea el
dato almacenado en fS al nmero ms cercano que
pueda ser representado en formato simple, y los
guarda en fD (en formato doble)
(Floating Convert To Integer Word) El nmero
almacenado en fD lo convierte a entero de 32 bits,
usando el modo de redondeo activo, y lo deposita en
los bits fD[32-63], quedando los bits fD[0-31]
indefinidos.
(Floating Convert To Integer Word round toward
Zero) El nmero almacenado en fD lo convierte a
entero de 32 bits eliminando los decimales, y lo
deposita en los bits fD[32-63], quedando los bits
fD[0-31] indefinidos.

Tabla 2.69: Instrucciones de conversin

Adems de estas tres instrucciones, podemos realizar conversiones entre


formatos simple y doble utilizando las operaciones de carga/almacenamiento
de datos en memoria. En concreto para convertir de simple a doble podemos
usar la instruccin lfs (Load Floating-point Single) que carga un dato que
tengamos en formato simple en memoria en un dato de formato doble en
registro. Para convertir de doble a simple podemos usar la instruccin stfs
(STore Floating-point Single) que almacena un dato que tengamos en formato
doble en un registro a formato simple en memoria.

Pg 143

Ensamblador del PowerPC con Mac OS X

MacProgramadores

7.9 Instrucciones de comparacin


Las operaciones de comparacin en punto flotante comparan el contenido de
dos registros FPR (esta comparacin considera que +0=-0).
La comparacin puede ser de dos tipos:
o Con relacin de orden. Si uno de los operandos es un quiet NaN se
activa el flag de excepcin VXVC (suponiendo que el flag de
habilitacin de excepcin VE est activo).
o Sin relacin de orden. Si uno de los operandos es un quiet NaN no
activa ningn flag de excepcin.
Sea la comparacin con o sin relacin de orden, si se encuentra un signaling
NaN se activa el bit VXSNAN (suponiendo que el flag de habilitacin de
excepcin VE est activo).
En cualquier caso, en el campo de CR que hayamos especificado a la
instruccin, se activarn los bits del campo de acuerdo a la Tabla 2.70:
Bit
0
1
2
3

Significado
fA < fB
fA > fB
fA = fB
fA ? fB (unordered)

Tabla 2.70: Reglas de activacin de los campos del registro CR

Adems de los bits del campo CR que especifiquemos, los bits FPSCR[16-19]
tambin se activan convenientemente.
Las instrucciones de comparacin de que dispone PowerPC se detallan en la
Tabla 2.71:
Instruccin
fcmpo CRFD,fA,fB

fcmpu CRFD,fA,fB

Descripcin
(Floating CoMPare Ordered) Compara fA con fB,
produciendo una VXVC si alguno de los operandos es
un NaN. El resultado se deposita en el campo de CR
dado por CRFD.
(Floating CoMPare Unordered) Compara fA con fB,
pudiendo ser alguno de los operandos en un NaN. El
resultado se deposita en el campo de CR dado por
CRFD.

Tabla 2.71: Instrucciones de comparacin

Pg 144

Ensamblador del PowerPC con Mac OS X

MacProgramadores

La diferencia entre estas dos instrucciones es que fcmpo se usa cuando no


esperamos encontrar un NaN, mientras que fcmpu se usa cuando queremos
contemplar esta posibilidad.

7.10

Instrucciones de movimiento de datos

Las instrucciones de movimiento de datos nos permiten copiar el contenido de


un registro FPR a otro, permitindonos modificar el signo durante la copia.
Estas instrucciones no alteran el registro FPSCR, y slo las que tienen punto
(.) alteran el registro CR y se detallan en la Tabla 2.72.
Instruccin
fmr fD,fS
fmr. fD,fS
fneg fD,fS
fneg. fD,fS
fabs fD,fS
fabs. fD,fS
fnabs fD,fS
fnabs. fD,fS

Descripcin
(Floating Move Register) Copia el contenido de fS a
fD
(Floating Negate) Copia el contenido de fS a fD y
cambia el signo durante la copia
(Floating ABSolute value) Copia el contenido de fS a
fD y pone el bit de signo a 0 durante la copia
(Floating Negate ABSolute value) Copia el contenido
de fS a fD y pone el bit de signo a 1 durante la copia

Tabla 2.72: Instrucciones de movimiento de datos

Pg 145

Ensamblador del PowerPC con Mac OS X

MacProgramadores

8 Incrustar cdigo ensamblador en un


programa C
8.1 Integracin entre C y ensamblador
En esta seccin vamos a comentar varias tcnicas que permiten incrustar
instrucciones ensamblador dentro de un programa C. Para ello tenemos la
directiva asm, un ejemplo de su uso sera el siguiente:
#include <stdio.h>
int main () {
asm ( "addis r2,r3,1 \n sub r5,r6,r7" );
return 0;
}
Cuando el compilador de C encuentra la directiva asm, el texto que est
dentro de las comillas se pasa tal cual al ensamblador, para que lo ensamble
junto con el resto del programa. Obsrvese que las instrucciones se separan
por \n, que es la forma de indicar un retorno de carro.
Si ahora hicisemos:
$ gcc -S cyasm.c
Siendo cyasm.c el programa anterior, veramos que las instrucciones dentro
de la directiva asm aparecen en el programa ensamblador correspondiente.

8.2 Acceso a variables C desde ensamblador


Si usamos la directiva asm, un problema que acabaremos encontrndonos, es
el de cmo acceder desde ensamblador a las variables C de nuestro
programa. Para ello tenemos que conocer el name-mangling que utiliza C
para sus variables. En C a todas las variables globales y funciones se les
asigna una etiqueta global que corresponde con el nombre de la funcin o
variable precedida por un guin bajo (_).
Cuando nos refiramos a las variables C desde ensamblador tendremos que
usar este nombre. Por ejemplo:
#include <stdio.h>
int G=4;
int main () {
asm ( "addis r2,0,ha16(_G) \n lwz r3,lo16(_G)(r2) \n"
"addi r3,r3,1 \n stw r3,lo16(_G)(r2)" );
Pg 146

Ensamblador del PowerPC con Mac OS X

MacProgramadores

printf("La variable incrementada es %i",G);


return 0;
}
Este programa accede desde ensamblador a la variable G, usando el nombre
_G y la incrementa en 1.
A las variables locales no se les asigna nombre, con lo que tenemos que usar
otras tcnicas para acceder a ellas desde ensamblador, como veremos en
breve.
C++ utiliza un name-mangling distinto sobre todo a la hora de referirse a las
funciones, ya que al poder estar las funciones sobrecargadas, C++ almacena,
adems del nombre de la funcin, los tipos de sus parmetros.
Por ejemplo si declaramos la funcin:
int suma(int a, int b);
El nombre que le da C es _suma
Sin embargo en C++ cuando tenemos las funciones sobrecargadas:
int suma(int a, int b);
int suma(int a, int b, int c);
Los nombres que usa C++ para estas funciones son _suma__Fii y
_suma__Fiii respectivamente.
Para poder saber el nombre que da a los smbolos C++ podemos usar el
comando nm (Name Mangling), que recibe como argumento un fichero .o, o
un fichero ejecutable (con informacin de depuracin), y nos muestra los
smbolos que contiene:
$ nm cyasm.o
0000007c D _G
000000a0 s ___FRAME_BEGIN__
00000000 T _main
U _printf
U _suma__Fii
U _suma__Fiii
U dyld_stub_binding_helper

Pg 147

Ensamblador del PowerPC con Mac OS X

MacProgramadores

8.3 Expresiones C como operandos de


instrucciones ensamblador
Desde las instrucciones ensamblador puestas en la directiva asm podemos
usar expresiones C como operandos de las instrucciones ensamblador. Esto
permite una mejor integracin entre C y ensamblador, ya que podemos
acceder a variables C que estn guardadas en registros directamente, en vez
de tener que leer un dato de memoria y pasarlo a un registro o viceversa.
El siguiente ejemplo muestra cmo podemos dividir dos nmeros usando la
instruccin ensamblador divw:
#include <stdio.h>
int main () {
int dividendo=14;
int divisor=3;
int cociente;
asm ( "divw %0,%1,%2" : "=r" (cociente)
: "r" (dividendo) , "r" (divisor));
printf("El resultado de la divisin es %i",cociente);
return 0;
}
Aqu despus de la instruccin ensamblador se ponen los operandos de salida,
y los operandos de entrada separados por dos puntos (:). Si hay ms de un
operando se pueden separar por comas. Si no hay operandos de salida se
debe de poner dos veces el smbolo de dos puntos. "=r" y "r" son lo que se
llama constraints, y las explicaremos en el siguiente apartado. La r significa
que queremos trabajar con un registro GPR, y en los operandos de salida es
obligatorio usar el smbolo = para indicar que es un operando de salida.
Despus de las constraints se pone entre parntesis la expresin C que
queremos asociar al operando. Aqu decimos expresin C, y no variable
porque dentro del parntesis se pueden poner expresiones C arbitrarias como
por ejemplo 2*a+b, y no slo el nombre de una variable. El compilador ya se
encargar de buscar el registro que contiene el resultado de evaluar esta
expresin. Una restriccin importante es que los operandos de salida slo
pueden contener expresiones Lvalues (y el compilador comprueba que sea
as), mientras que los operandos de entrada pueden contener cualquier
expresin.
Dentro de la instruccin, a los operandos nos referimos usando los nombres
%0 a %9, con lo que el mximo nmero de operandos est limitado a 10.

Pg 148

Ensamblador del PowerPC con Mac OS X

MacProgramadores

Una vez sustituidos los operandos en la instruccin (o instrucciones)


ensamblador, la instruccin se pasa al ensamblador. Si hay varias
instrucciones debemos colocar \n al final de cada lnea (excepto la ltima que
no es necesaria) de la forma:
int ret;
asm ("li r0,0x6009\n"
"sc\n"
"mr %0,r3\n"
: "=r" (ret) /* operando de salida */
: /* no hay operandos de entrada*/ );

8.3.1 Las constraints y los modificadores


Cada operando lleva asociadas unas constraints que indican el tipo del
operando segn la Tabla 2.73:
Constraint
r
b
f
m
i
F
X

Significado
Registro GPR
Registro GPR distinto de r0
Registro FPR
Referencia a memoria
Operando inmediato entero. Son literales cuyo valor es
conocido en tiempo de compilacin
Operando inmediato en punto flotante de doble precisin. Son
literales cuyo valor es conocido en tiempo de compilacin
Se acepta un operando de cualquier tipo: registro, direccin de
memoria o operando inmediato.

Tabla 2.73: Constraints de una expresin C

Lo posibles modificadores que pueden acompaar a una constraint estn en


la Tabla 2.74:
Modificador Significado
=
Operando de slo escritura. No se garantiza que contenga el
valor previo de la variable
+
Operando de lectura/escritura. Antes de usarse va a contener
el valor de la variable o expresin, y despus de ejecutarse las
instrucciones
ensamblador
su
valor
se
guardar
apropiadamente
&
No asignar el mismo registro al operando de entrada y de
salida
Tabla 2.74: Modificadores de una constraint

Estos modificadores siempre se aplican al operando de salida. En caso de


usarlos se colocan delante de la constraint. P.e. "+r"
Pg 149

Ensamblador del PowerPC con Mac OS X

MacProgramadores

Como vimos, en PowerPC haba instrucciones como:


addi rD,(rA|0),SIMM
En la que el segundo operando poda recibir o bien un 0, o bien un GPR de
r1 a r31, pero no el registro r0. De esta forma podamos sumar 0 a SIMM y
almacenar el resultado en rD.
Esto puede producir problemas si intentamos compilar instrucciones como:
asm

( "addi %0,%1,1" : "=r" (H) : "r" (G));

Ya que si el compilador tiene la variable G en el registro r0, al compilar


tenemos:
addi r3,r0,1
Y como acabamos de decir, r0 no puede ser usado como segundo operando.
En este caso debemos de usar la constraint b, que significa usar uno de los
registros de r1 a r31. Con lo que el problema no se producir. Es decir la
forma correcta de codificar la instruccin anterior es:
asm

( "addi %0,%1,1" : "=r" (H) : "b" (G));

La r del primer operando no hace falta cambiarla por b, ya que este


operando puede usar al registro r0, es el segundo operando el que no puede.
Adems de poder referirnos a registros podemos referirnos a direcciones de
memoria, en cuyo caso usamos la constraint m. Por ejemplo, si hacemos:
asm ( "lwz r3,%0":/*sin salida*/:"m" (N) );
El compilador lo sustituye por:
lis r9,r31,ha16(_N)
addi r9,lo16(_N)(r9)
lwz r3,0(r9)
Es decir, el compilador carga en un registro (r9 en nuestro caso) la direccin
de memoria de N y nos hace un indireccionamiento de registro base e ndice
inmediato a la variable N.

Pg 150

Ensamblador del PowerPC con Mac OS X

MacProgramadores

Los operandos marcados con la constraint = son operandos de slo salida y


deben de usarse slo para escritura, es decir, nunca debe usarse un operando
para lectura/escritura.
Por ejemplo este programa compilara correctamente, pero al ejecutarlo no
da el resultado esperado:
#include <stdio.h>
int N=4;
int main () {
asm ( " addi %0,%0,1 " : "=r" (N) );
printf("N incrementada vale %i",N);
return 0;
}
La razn de fallo es que el compilador considera a %0 un parmetro de salida,
con lo que no lo carga de memoria, y el resultado del registro est indefinido.
Si queremos que un operando de salida disponga del valor correcto de la
entrada debemos marcarlo con la constraint + como muestra el siguiente
ejemplo:
#include <stdio.h>
int N=4;
int main () {
asm ( " addi %0,%0,1 " : "+r" (N) );
printf("N incrementada vale %i",N);
return 0;
}
Ahora el programa si funcionara correctamente, ya que en el registro
asignado a %0 estar el valor correcto de N el cual luego ser sobrescrito.
Otra forma, ms compleja pero igual de vlida, de resolver este problema es
declarar dos operandos, uno de lectura y otro de escritura. La conexin entre
estos debe de expresarse con constraints que indican que ambos deben de
estar en el mismo registro cuando la instruccin se ejecute.
En concreto, la forma correcta de hacerlo sera esta:
#include <stdio.h>
int N=4;
int main () {
asm ( " addi %0,%1,1 " : "=r" (N) :"0" (N) );
printf("N incrementada vale %i",N);
return 0;
}

Pg 151

Ensamblador del PowerPC con Mac OS X

MacProgramadores

La constraint "0" puesta en el registro de entrada garantiza que el registro


de entrada y de salida sean el mismo, aunque, carga de memoria el valor del
operando antes de ejecutar la instruccin (y lo guarda despus de ejecutarla).
Curiosamente para la expresin que representa el operando de entrada y de
salida podemos usar la misma expresin o expresiones distintas. La
constraints "0" se encarga de que el registro que usemos sea el mismo. Los
dgitos como constraints slo se permiten como operandos de entrada, y
deben de referirse a operandos de salida.
Slo este tipo de constraints garantizan que un operando est en el mismo
lugar que otro, el mero hecho de que dos operandos usen la misma
expresin C (N en nuestro caso), no es suficiente para garantizar que nos
refiramos al mismo registro en el cdigo ensamblador. Es decir, el siguiente
programa podra no asignar el mismo registro a %0 que a %1:
asm

( " addi %0,%1,1 " : "=r" (N) :"r" (N) );

Otra cosa importante es que podemos evitar los efectos laterales que se
produciran si el programa C estuviese usando uno de los registros que
usamos desde ensamblador. Por ejemplo, esta instruccin dara problemas si
el registro r3 estuviese siendo usado por el programa C.
asm ( "lwz r3,%0":/*sin salida*/:"m" (N) );
Para evitar esto, podemos avisar al compilador de que la instruccin modifica
el registro r3, usando la llamada lista de registros modificados, que se
pone en un tercer campo separada por dos puntos:
asm ( "lwz r3,%0":/*sin salida*/:"m" (N): "r3" );
Aqu podemos proteger cuantos registros sean necesarios poniendo su
nombre entre comillas y separndolos por comas.
Tambin si nuestro programa ensamblador modifica el registro CR debemos
de indicarlo bajo el nombre "cc", por ejemplo:
asm ( "lwz r3,%0 \n"
"cmpwi r3,0 \n"
"beq fin \n"
"addi r3,r3,1 \n fin:"
: /*sin salida*/ : "m" (N) : "r3", "cc" );
Adems si nuestro programa ensamblador modifica la memoria de una forma
impredecible, debemos aadir "memory" a la lista de registros modificados.
En principio, el compilador de C puede asignar el mismo registro a un
operando de entrada y de salida, y suponer que el dato de entrada ser
Pg 152

Ensamblador del PowerPC con Mac OS X

MacProgramadores

consumido antes de producir la salida. Esto normalmente es cierto, pero si el


programa ensamblador est formado por varias instrucciones esto podra no
ser cierto, ya que una instruccin posterior podra intentar leer un registro
que una instruccin anterior haya modificado. En este caso debemos de poner
al operando de salida la constraint "&" para evitar que se le asigne el mismo
registro que use un operando de entrada.
Por ltimo debemos comentar que la directiva asm supone que las
instrucciones que estamos ejecutando no tienen ms efectos laterales que el
de modificar los operandos de salida. Esto no significa que no podamos usar
instrucciones con efectos laterales, sino que debemos tener cuidado con las
optimizaciones que pudiera hacer el compilador, ya que si los operandos de
salida no se usan en ningn punto del programa el optimizador del
compilador podra eliminar nuestras instrucciones ensamblador. Tambin
podra aplicar otras optimizaciones como sacarlas fuera de un bucle,
remplazar dos instrucciones que calculan una subexpresin por una sola
guardando el operando de salida en un registro y ejecutar la instruccin una
sola vez.
Podemos prevenir el que el compilador aplique estas optimizaciones usando el
modificador volative:
asm volatile ( "lwz r3,%0":/*sin salida*/:"m" (N) );

8.3.2 Expresiones C en gcc 3.1


A partir de la versin 3.1 de gcc es posible especificar los operandos de
entrada y de salida usando nombres simblicos, los cuales podemos usar
luego dentro del cdigo ensamblador. Estos nombres se ponen entre
corchetes delante de la constraint del operando y nos podemos referir a ellos
desde dentro del cdigo ensamblador como %[nombre], en vez de usar %n
siendo n el nmero del parmetro. Es decir, podemos hacer cosas como:
#include <stdio.h>
int main () {
int dividendo=14;
int divisor=3;
int cociente;
asm ( "divw %[c],%[n],%[d]"
: [c] "=r" (cociente)
: [n] "r" (dividendo)
, [d] "r" (divisor));
printf("El resultado de la divisin es %i",cociente);
return 0;
}

Pg 153

Ensamblador del PowerPC con Mac OS X

MacProgramadores

Los nombres simblicos que damos a los operandos no tienen por qu


coincidir con los nombres de las variables C a las que los asociamos.

9 Llamada a funciones
Vamos a ver ahora cul es el mecanismo de llamada a funciones en Mac OS
X. Esto nos va a permitir poder llamar a funciones escritas en otros lenguajes,
como p.e. C, desde ensamblador, o viceversa, poder llamar a funciones
escritas en ensamblador desde C.

9.1 Tipos de datos


Mac OS X define los tipos de datos de la Tabla 2.75:
Tipo C o C++
unsigned char
char
signed char
unsigned short
short
signed short
unsigned int
unsigned long
int
signed int
long
signed long
bool
unsigned long long
long long
signed long long
float
double
long double
puntero

Tamao
(en bytes)
1
1

Rango Valores

2
2

0 a 65.535
-32.768 a 32.767

0 a 4.294.967.295

-2.147..483.648 a 2.147.483.647

4
8
8

0 (falso) 1-4.294.967.295 (true)


0 a 18.446.744.073.709.551.615
-9.223.372.036.854.775.808
a
9.223.372.036.854.775.807
Ver Apndice A
Ver Apndice A
Ver Apndice A
0 a 0xFFFFFFFF

4
8
16
4

0 a 255
-128 a 127

Tabla 2.75: Tipos de datos de Mac OS X

Adems de estos tipos la Tabla 2.76 muestra los tipos de datos para AltiVec.
Tipo C o C++

Tamao
(en bytes)
vector
unsigned 16 (1 byte
char
cada)
vector char
16 (1 byte
Pg 154

Rango Valores
0 a 255
-128 a 127

Ensamblador del PowerPC con Mac OS X

vector signed char


vector
unsigned
short
vector signed short
vector unsigned int
vector int
vector signed int
vector bool char
vector bool short
vector bool int
vector float
vector pixel

MacProgramadores

cada)
16 (2 bytes
cada)
16 (2 bytes
cada)
16 (4 bytes
cada)
16 (4 bytes
cada)
16 (1 byte
cada)
16 (2 bytes
cada)
16 (4 bytes
cada)
16 (4 bytes
cada)
16 (3 bytes
cada)

0 a 65.535
-32.768 a 32.767
0 a 4.294.967.295
-2.147..483.648 a 2.147.483.647
0 (falso) 1-255(true)
0 (falso) 1-65.535 (true)
0 (falso) 1-4.294.967.295(true)
Ver Apndice A
formato de pixel 1/5/5

Tabla 2.76: Tipos de datos de AltiVec

9.2 Mecanismo general de llamada a


procedimientos
La interfaz entre dos procedimientos se define en trminos de un
procedimiento que llama (caller) y un procedimiento llamado
(callee). El caller computa los parmetros que debe recibir el callee, los
deposita en la pila, y pasa el control al callee. El callee recoge los parmetros,
realiza unas operaciones y calcula un valor (o quiz no), y retorna el control a
la siguiente sentencia a la sentencia que le llam.

9.3 Convencin del uso de los registros


Los registros del procesador se clasifican en dedicados, voltiles y no
voltiles: Los registros dedicados tienen asignado un uso especifico que
nosotros no deberamos de usar para otros propsitos. Los registros
voltiles (tambin llamados de scratch) se pueden usar para hacer cualquier
clculo en ellos y su contenido no se garantiza que se mantenga tras llamar a
una subrutina, con lo que nosotros tampoco tendremos que preocuparnos de
salvaguardar su valor. A estos registros tambin se les llama caller-save
registers, porque el procedimiento que llama es el que debe encargarse de
guardar su valor (si le interesa) antes de llamar a otro procedimiento. Por
ltimo, los registros no voltiles son registros que podemos usar en
cualquier momento, pero su contenido debe de ser guardado antes de
modificarlos en el contexto del procedimiento local, y restaurados antes de
Pg 155

Ensamblador del PowerPC con Mac OS X

MacProgramadores

abandonar el procedimiento. A estos procedimientos tambin se les llama


callee-save registers porque es el procedimiento llamado quien debe de
guardar su valor antes de modificarlos.
La Tabla 2.77 describe cual es la convencin del uso de registros en Mac OS X
Grupo Registro
GPR

FPR

AltiVec

GPR0

Tipo
registro
Voltil

GPR1
GPR2

Dedicado
Voltil

GPR3-GPR10

Voltil

GPR11
GPR12

Voltil
Voltil

GPR13-GPR31

No voltil

FPR0
FPR1-FPR13

Voltil
Voltil

FPR14-FPR31

No voltil

v0-v2
v3-v13

Voltil
Voltil

v14-v19
v20-v31

Voltil
No voltil

vrsave

No voltil

Uso
Usado normalmente para almacenar el
LR de retorno de la funcin
Puntero a la cima de la pila
En Mac OS Classic era un registro
dedicado que se usaba como puntero a
la TOC (Table Of Content) o a la GOT
(Global Offset Table). Mac OS X usa un
esquema de direccionamiento
diferente y este registro es un registro
de propsito general como otro
cualquiera.
Estos 8 registros se usan para pasar
los parmetros de las llamadas a
funciones. Una vez recibimos los
parmetros se pueden usar para
scratch si se desea
Contiene la direccin de salto cuando
llamamos a funciones de enlace
dinmico. Si no estamos llamando a
una funcin de enlace dinmico se
usa como un registro ms
Sus valores se conservan entre
llamadas a procedimientos
Registro de scratch
Usado para paso de parmetros en
punto flotante. Una vez recibimos los
parmetros se pueden usar para
scratch si se desea
Sus valores se conservan entre
llamadas a procedimientos
Registros de scratch
Usado para el paso de parmetros de
este tipo
Registros de scratch
Sus valores se conservan entre
llamadas a procedimientos
Indica los vectores que deben ser
guardados en un cambio de contexto
Pg 156

Ensamblador del PowerPC con Mac OS X

SPR

LR

No voltil

CR

CTR
XER
FPSCR
CR0-CR1

Voltil
Voltil
Voltil
Voltil

CR2-CR4
CR5-CR7

No voltil
Voltil

MacProgramadores

Almacena la direccin de retorno de la


rutina llamada
Usado en bucles y saltos
Excepciones de punto fijo
Excepciones de punto flotante
Para consultar el resultado de una
operacin aritmtica o para
comparaciones
Para comparaciones
Para comparaciones

Tabla 2.77: Convencin de uso de los registros de Mac OS X

9.4 Estructura de la pila


El modelo de programacin de Mac OS X define que un proceso consta de un
segmento de cdigo, un segmento de datos donde se depositan las variables
globales, y un segmento de pila por cada hilo activo donde se depositan las
variables locales al hilo y con el que se lleva el control de las llamadas a
funciones que haga el hilo.
La pila crece avanzando de direcciones altas a direcciones bajas, y para
gestionarla se usa un nico puntero a la cima de la pila (stack pointer)
almacenado, por convenio, en el registro GPR1.

rea de parmetros

rea de parmetros
Caller

rea de enlace

La pila crece hacia abajo

GPR1

Caller
Nuevo
frame

rea de enlace
Registros guardados
Variables locales
Callee
rea de parmetros
rea de enlace

GPR1

Figura 2.17: Creacin de un frame en la pila

Pg 157

Ensamblador del PowerPC con Mac OS X

MacProgramadores

Cada vez que una funcin llama a otra se crea en la pila un nuevo frame, el
cual almacena toda la informacin que necesita el procedimiento para sus
autogestin.
La Figura 2.17 muestra la creacin de un frame en la pila tras llamar a un
procedimiento. Como vamos a ver, GPR1 en todo momento apunta a la cima
de la pila con la que estamos trabajando.

9.4.1 Las reas del frame


El frame est dividido en las cuatro reas que vamos a comentar a
continuacin:
El rea de parmetros. Se trata de un trozo de memoria donde el caller
deposita los parmetros que va a pasar al callee, es decir, en el frame de un
procedimiento no estn sus parmetros sino los parmetros del procedimiento
al que va a llamar. Despus, el procedimiento al que llame deber
aparselas para acceder a los parmetros que estn en el frame del que le
ha llamado.
Como un procedimiento puede llamar a varios procedimientos, este rea
deber tener un tamao suficiente como para acoger la lista de parmetros
ms larga de todos los procedimientos a los que vaya a llamar.
A esta rea se la considera voltil en el sentido de que una vez que llamamos
a un procedimiento, ste si quiere puede modificar el valor de los parmetros
aqu depositados, esto se hace, por ejemplo, cuando una funcin como parte
de un clculo que est llevando a cabo, modifica el valor de sus parmetros,
depositando en ellos valores intermedios que necesita para calcular un valor
final.
El rea de enlace est formado por 3 palabras y tiene un offset relativo a la
posicin del puntero a pila antes de llamar al procedimiento.
Los valores de este rea lo fija en parte el caller (al que pertenece el rea de
enlace) y en parte el callee, en cada llamada que le hagamos. En concreto
aqu encontramos:
o Offset 0: Back chain. El caller (el dueo del rea) guarda aqu el valor
del puntero a pila antes de que el callee lo decremente para crear un
nuevo frame.
o Offset 4: El callee guarda aqu el valor del registro CR. Este valor slo
tiene que guardarlo el callee si modifica algn campo no voltil de CR
(CR2-CR4 son los no voltiles) durante su ejecucin.
o Offset 8: El callee guarda aqu la direccin de retorno al caller, es decir,
el valor del registro LR. Este valor lo guarda el callee slo si el callee

Pg 158

Ensamblador del PowerPC con Mac OS X

MacProgramadores

modifica el valor de este registro (llama a otro procedimiento), sino no


hace falta guardarlo.
Obsrvese que el rea de enlace est en una posicin fija que el callee puede
conocer (a un determinado offset de la posicin del puntero a la cima del
frame del caller). Esto es necesario para que el callee pueda acceder a la
informacin del rea de enlace, as como al rea de parmetros, que est
inmediatamente despus del rea de enlace. A estos datos debe de acceder el
callee antes de decrementar el puntero a pila (crear su frame), es decir, el
callee debe recoger los parmetros y fijar los valores del rea de enlace,
antes de crear su frame.
El rea de registros guardados es donde un procedimiento debe
almacenar el valor de todos los registros no voltiles que vaya a usar. En caso
de que el procedimiento slo use registros voltiles (que es lo habitual) esta
rea medir 0 bytes. La forma en que el procedimiento almacene los registros
se deja a eleccin del programador.
El rea de variables locales es un rea adicional de memoria que puede
reservar el procedimiento si ste va a almacenar variables locales en
memoria. Si todas las variables locales se almacenan en registro esta rea
medir 0 bytes.

9.5 Paso de control a un procedimiento


Cuando un procedimiento (caller) quiere pasar el control a otro (callee), en
principio lo nico que tiene que hacer es usando la instruccin bl (Brach then
Link), o alguna de sus variantes, saltar a la direccin en la que se encuentra
el procedimiento que queremos ejecutar. Esta instruccin deposita en el
registro LR la direccin de la siguiente instruccin a la instruccin de salto,
que es lo que llamamos la direccin de retorno.

9.5.1 El prlogo y el eplogo


Cada procedimiento va a ser el responsable de crear y destruir su propio
frame. Esta accin se lleva a cabo por un trozo de programa llamado
prlogo, que se deposita antes del cuerpo de la rutina, y por otro llamado
eplogo, que se encarga de destruir el frame y que se pone despus del
cuerpo de la rutina.
Vamos a comentar qu acciones son las que se realizan en el prlogo y
eplogo de la llamada a una funcin.
Antes de nada debemos comentar que el orden concreto en que se ejecutan
las acciones del prlogo y eplogo, no vienen dados por las especificaciones
Pg 159

Ensamblador del PowerPC con Mac OS X

MacProgramadores

de Mac OS X, sino que la especificaciones se limitan a decir qu acciones hay


que llevar a cabo y no en qu orden deben de ejecutarse.
El prlogo es el que se encarga de crear en la pila un nuevo frame y de
guardar todos los valores que deban ser preservados. En concreto sus
responsabilidades son:
o Si el registro LR va a ser modificado por una futura llamada a
procedimiento, ste debe ser guardado en el rea de enlace de su
caller.
o Si los campos no voltiles del registro CR (CR2-CR4) van a ser
modificados, el callee debe guardar el registro CR en el rea de enlace
de su caller
o Decrementar el puntero a pila para crear su nuevo frame. La
especificacin dice que el puntero a frame siempre debe apuntar a
direcciones mltiplos de 16, con lo que durante el decremento si es
necesario se deja un padding con el fin de cumplir esta condicin.
o El callee guarda en su rea de enlace el valor del puntero a pila tal
como se lo di el caller.
o Guardar el valor de los registros no voltiles que vayan a ser
modificados en el rea de registros guardados.
Obsrvese que un procedimiento puede saber en tiempo de compilacin cul
es el tamao de su frame, para lo cual calcula la suma de cada una de las
reas que forman el frame, tamaos que son todos conocidos en tiempo de
compilacin.
En la especificacin se recomienda que el guardar el puntero a pila y
decrementarlo se haga en un slo paso usando la instruccin:
stwu r1,-tamanoFrame(r1)
La cual guarda el valor del registro r1 en la direccin apuntada por
-tamanoFrame(r1) y despus decrementa el valor de r1.
A continuacin se muestra un ejemplo de cmo se implementara el prlogo.
.set tamanoFrame,16
miFuncion:
; Prlogo
mflr r0
stw r0,8(r1)

; Tamao del frame

; Recoge en r0 el LR
; Guarda el LR en el rea de enlace
; del caller
mfcr r0
; Recoge en r0 el CR
stw r0,4(r1)
; Guarda el CR en el rea de enlace
; del caller
stwu r1,-tamanoFrame(r1) ; Crea su frame

Pg 160

Ensamblador del PowerPC con Mac OS X

MacProgramadores

En este ejemplo suponemos que no existen variables locales ni hay que


guardar registros no voltiles luego necesitamos crear un frame de 12 bytes
para el rea de enlace, pero como la especificacin dice que los frames
siempre deben de tener un tamao mltiplo de 16, creamos un frame de 16
bytes con un padding de 4 bytes.
Al final de ejecutar la funcin el eplogo destruye el frame y retorna el control
al caller. En concreto las responsabilidades del eplogo son:
o
o
o
o
o

Restaurar el valor de los registros no voltiles guardados.


Restaurar el valor del puntero a pila.
Si se modificaron los campos no voltiles del registro CR, restaurarlo.
Si se modific el valor del registro LR, restaurarlo.
Retornar a la direccin almacenada en LR.

A continuacin se muestra un ejemplo de cmo implementar el eplogo.


.set tamanoFrame,16
miFuncion:

; Eplogo
lwz r1,0(r1)
lwz r0,4(r1)
mtcrf 255,r0
lwz r0,8(r1)
mtlr r0
blr

; Tamao del frame

;
;
;
;
;
;
;
;
;
;

Recoge el puntero a pila de su


rea de enlace con lo que el
frame queda destruido
Recoge el CR del rea de enlace
del caller
Recupera el valor del CR
Recoge el LR del rea de enlace
del caller
Fija la direccin de retorno
Retorna

Lo primero que hace el eplogo es destruir el frame del callee recuperando el


valor de r1, que tiene almacenado en el rea de enlace del callee, y despus
recupera los valores de CR y LR para finalmente retornar.
Por ltimo vamos a ver que realmente el compilador gcc de Mac OS X acta
como aqu hemos explicado. Para ello vamos a crear un fichero llamado
llamadas.c que aparece en el Listado 2.13:
void funcion_b(void)
{
}
void funcion_a()
{

Pg 161

Ensamblador del PowerPC con Mac OS X

MacProgramadores

funcion_b();
}
int main ()
{
funcion_a();
return 0;
}
Listado 2.13: Ejemplo de funciones

Y lo vamos a compilar para generar su correspondiente cdigo ensamblador


con el comando:
$ gcc -S llamadas.s
Usando la versin 2.95.2 del compilador obtenemos una salida como la del
Listado 2.14 (la cual puede variar ligeramente en otra versin del
compilador):
.text
.align 2
.globl _funcion_b
_funcion_b:
; Prologo
stmw r30,-8(r1) ; Guarda r30 y r31 en su rea de
; registro guardados
stwu r1,-48(r1) ; Crea su frame de 48 bytes
; (3*16 bytes)
mr r30,r1
; Pone el puntero a pila en r30
L6:
; Eplogo
lwz r1,0(r1)
; Recoge el puntero a pila del
; rea de enlace del caller
lmw r30,-8(r1) ; Recupera los valores de r30 y r31
blr
; Retorna
.align 2
.globl _funcion_a
_funcion_a:
; Prlogo
mflr r0
; Recoge en r0 el LR
stmw r30,-8(r1) ; Guarda r30 y r31 en su rea de
; registro guardados
stw r0,8(r1)
; Guarda el LR en el rea de enlace
; del caller
stwu r1,-80(r1) ; Crea su frame de 80 bytes
; (5*16 bytes)
mr r30,r1
; Pone el puntero a pila en r30
; Llamada
bl _funcion_b
Pg 162

Ensamblador del PowerPC con Mac OS X

MacProgramadores

L7:
; Eplogo
lwz r1,0(r1)
lwz r0,8(r1)

;
;
;
;
;
;
;

mtlr r0
lmw r30,-8(r1)
blr
.align 2
.globl _main
_main:
; Prlogo
mflr r0
stmw r30,-8(r1) ;
;
stw r0,8(r1)
;
;
stwu r1,-80(r1) ;
;
mr r30,r1
;
; Llamada
bl _funcion_a
; Eplogo
li r3,0
;
main()
b L8
L8:
lwz r1,0(r1)
;
;
lwz r0,8(r1)
;
;
mtlr r0
lmw r30,-8(r1) ;
blr
;

Recoge el puntero a pila del


rea de enlace del caller
Recoge el LR del rea de enlace
del caller
Fija la direccin de retorno
Recupera los valores de r30 y r31
Retorna

Guarda r30 y r31 en su rea de


registros guardados
Guarda LR en el rea de enlace
del caller
Crea su frame de 80 bytes
(5*16 bytes)
Pone el puntero a pila en r30

Pone un 0 en el retorno de la

Recupera el puntero a pila del


rea de enlace de su caller
Recupera el LR del rea de enlace
de su caller
Restaura los registros r30 y r31
Retorna

Listado 2.14: Cdigo ensamblador generado por gcc

Hemos comentado el cdigo ensamblador generado para facilitar su


comprensin.
Vemos que el funcionamiento del compilador es bsicamente el que hemos
estudiado, aunque en este caso vemos una pequea desoptimizacin debida a
que el registro r30 y r31 son continuamente guardados y recuperados en
cada llamada a funcin sin razn aparente. De hecho podramos eliminar las
instrucciones que manejan estos registros y el programa seguira funcionando
exactamente igual.
Estas desoptimizaciones se deben a que no hemos pedido a gcc ninguna
optimizacin, el lector puede ejecutar ahora el compilador con optimizacin
as:
Pg 163

Ensamblador del PowerPC con Mac OS X

MacProgramadores

$ gcc -S -O3 llamadas.c


Obteniendo el cdigo del Listado 2.15:
.text
.align 2
.globl _funcion_b
_funcion_b:
blr
.align 2
.globl _funcion_a
_funcion_a:
b _funcion_b
.align 2
.globl _main
_main:
mflr r0
stw r0,8(r1)
stwu r1,-64(r1)
bl _funcion_a
li r3,0
lwz r0,72(r1)
la r1,64(r1)
mtlr r0
blr
Listado 2.15: Cdigo ensamblador generado por gcc optimizado

Que como se puede apreciar a simple vista es un programa mucho ms


pequeo y optimizado.

9.5.2 Los procedimientos terminales


Recurdese que al estar el puntero a pila situado en la cima de la pila (y
crecer la pila en direcciones decrecientes de memoria) un procedimiento
siempre accede a direcciones con offset positivo respecto al puntero a pila.
Esto aunque habitual no es obligatorio, ya que las posiciones que estn ms
all del puntero a pila, que es lo que se llama la zona vaca (vase Figura
2.18), estn sin usar y si el procedimiento lo desea tambin puede usarlas.
Esto es lo que hacen los llamados procedimientos terminales, que son
aquellos que no llaman a ningn otro procedimiento. En este caso, muchas
veces, estos procedimientos no crean un nuevo frame para ellos, sino que
mantienen el puntero a pila en la posicin que lo tena el caller, y si necesitan
trabajar con variables locales en memoria lo que hacen es usar la zona vaca.

Pg 164

Ensamblador del PowerPC con Mac OS X

MacProgramadores

El procedimiento terminal tambin guardara


el valor del CR en el rea de enlace del
caller (si fuese necesario), pero al no tener
que fijar un nuevo frame el trabajo realizado
por el prlogo y el eplogo es mnimo.

rea de parmetros
Caller
rea de enlace

9.5.3 Paso de parmetros

GPR1

El procedimiento de paso de parmetros


que vamos a ver es el que define Mac OS X
para C. Para C++ y Objective-C estos
mecanismos varan ligeramente.

Zona
vaca

Los parmetros se pasan depositando el Figura 2.18: Zona vaca en


los procedimientos terminales
procedimiento que llama los parmetros en
su rea de parmetros y recogindolos el procedimiento llamado del rea de
parmetros de su caller.
Como el caller puede llamar a varias funciones durante su ejecucin, el
tamao del rea de parmetros del caller debe ser el mayor de los tamaos
que va a necesitar para llamar a cada una de las funciones que llama (o
puede llamar). Este es un tamao que siempre se puede saber en tiempo de
compilacin mirando el prototipo de cada una de las funciones que llama.
Los parmetros se colocan en el rea de parmetros con una alineacin de 4
bytes, en concreto:
o Si el parmetro mide 4 bytes se coloca a continuacin sin ms.
o Si el parmetro es menor a 4 bytes (p.e. char o short), se alinea a 4
bytes ocupando el parmetro la parte baja de la palabra de 4 bytes. El
contenido de los bytes ms significativos queda sin definir.
o Si el parmetro es mayor a 4 bytes (p.e. un struct o un array) se
rellenan a la derecha (posiciones altas) con un padding para ocupar un
tamao mltiplo de 4 bytes.
Por ejemplo consideremos una rutina con el siguiente prototipo:
void hazAlgo(int pi1, float pf2,double pd3,short ps4,
double pd5, char pc6, short ps7, float pf8, int pi9);
Para ver cmo se colocan estos bytes en el rea de parmetros, primero
convertimos los parmetros en una estructura tal que as:

Pg 165

Ensamblador del PowerPC con Mac OS X

MacProgramadores

struct Parametros
{
int pi1;
float pf2;
double pd3;
short ps4;
double pd5;
char pc6;
short ps7;
float pf8;
short ps9;
};

+44
+40
+36

ps9
pf8
ps7

+32

pc6

+28
pd5
+20

Esta estructura sirve como plantilla


para construir el rea de parmetros
de la pila. El elemento que acaba en
la direccin de memoria ms baja es
pi1, y a partir de ah van ocupando
direcciones de memoria positivas a lo
largo
del
rea
de
memoria,
respetando las reglas de padding que
hemos dado. Luego la organizacin
exacta de los parmetros sera la de
la Figura 2.19.

ps4

+16
pd3
+8
+4
0

pf2
pi1
Zona vaca

Figura 2.19: Ejemplo de organizacin


de parmetros en la pila

En principio esta sera la forma que tendra el rea de parmetros, pero la


especificacin define una optimizacin muy importante que dice que:

"Las 8 primeras palabras de los parmetros no se pasan en la pila, sino que


se usan los registros para pasar los parmetros.
Esta optimizacin es muy importante porque la mayora de las funciones
tienen pocos parmetros y as evitamos tener que acceder a memoria para
hacer el paso de parmetros.
Sin embargo, la especificacin es un poco caprichosa respecto a la forma
correcta de pasar estos parmetros en registros. Veamos que dice
exactamente.
En primer lugar la especificacin dice que los parmetros correspondientes a
las 8 primeras palabras se pasan en los registros GPR3 al GPR10. Aun as, el
espacio del rea de parmetros que ocuparan estos parmetros en el rea de
parmetros (y que no ocupan por pasarse en registros) debe quedar
reservado (a pesar de no contener los datos). Esto se hace por varias
razones:

Pg 166

Ensamblador del PowerPC con Mac OS X

MacProgramadores

o Proporciona un espacio de memoria al callee para guardar el valor de


los registros si este tuviera que usar los registros con otros fines (p.e.
para pasar parmetros a una subrutina).
o Para simplificar la depuracin algunos compiladores escriben los
parmetros en el rea de parmetros de la memoria, esto permite al
depurador ver el valor de los parmetros con slo leer de memoria.
o Las rutinas con un nmero variable de parmetros nunca usan los
registros sino que guardan los parmetros en memoria.
Otra peculiaridad es que si los parmetros son de tipo float o double se
pasan en los registros FPR1 a FPR13, aunque los registros que hubieran
ocupado si los hubiramos guardado en GPRs quedan reservados, pero sin
contener el valor, es decir, no se pueden usar para pasar parmetros de tipos
escalares. Esta regla en principio no tiene ninguna utilidad prctica, y slo da
lugar a un desperdicio, pero la regla se mantiene por compatibilidad con otros
sistemas programables en PowerPC, como puedan ser AIX de IBM.

+44
+40
+36

ps9
pf8
ps7

+32

pc6

+28

GPR8
ps4

+16
pd3
+8
+4
0

GPR10
GPR9

pd5
+20

FPR4

FPR3

GPR7
GPR6
GPR5

pf2

GPR4

pi1

GPR3

FPR2
FPR1

Zona vaca
Figura 2.20: Ejemplo de organizacin real de parmetros en la pila

Por ltimo respecto a los parmetros que sean vectores (AltiVec) estos se
pasan en los registros v2 a v13, y en el caso de los vectores, su presencia no
afecta a los registros GPR ni FPR. El caller no debe reservar espacio en el rea
de parmetros de la pila a no ser que su nmero exceda el nmero de
parmetros que podemos pasar en los registros de AltiVec.

Pg 167

Ensamblador del PowerPC con Mac OS X

MacProgramadores

En el ejemplo anterior tenemos que cambiar la distribucin de los parmetros


para que se pasen de acuerdo a la regla que hemos visto, con lo que ahora la
distribucin de parmetros quedara como muestra la Figura 2.20.
Vemos que los parmetros pi1 a pc6 no se guardan realmente el memoria
sino en registros. Tambin observamos como parmetros como pf2, pd3
pd5 producen un consumo de GPRs a pesar de que su valor no se almacena
en estos registros, sino en FPRs.

9.5.4 Funciones con un nmero variable de parmetros


En C podemos crear funciones que reciban un nmero variable de
parmetros. Estas funciones denotan la parte variable con una elipsis (...) al
final de la lista de parmetros. La funcin puede tener un nmero fijo de
parmetros al principio, los cuales suelen dar informacin sobre los
parmetros que van despus.
Un ejemplo de funcin de este tipo sera:
double suma(int n,...)
{
double s = 0.0;
double* p = (double*)(&n+1);
while (n>0)
{
s += p[n-1];
n--;
}
return s;
}
A la hora de ejecutarla la ejecutaramos as:
double s = suma(3,4.5,6.7,3.2);
En este caso todos los parmetros variables se almacenan en su
correspondiente posicin del rea de parmetros de la memoria, esto permite
que recojamos estos parmetros accediendo mediante un puntero a la zona
de memoria que ocupan. En el ejemplo anterior el puntero p se calcula
como:
double* p = (double*)(&n+1);
Una vez tenemos el puntero al rea de parmetros ya podemos leerlos.

Pg 168

Ensamblador del PowerPC con Mac OS X

MacProgramadores

9.5.5 Retorno de una funcin


Cuando una funcin retorna un valor, la forma de devolverlo depende del tipo
del valor retornado:
o Si es un valor escalar de 4 bytes se retorna en el registro GPR3 sin
ms.
o Si es un valor menor de 4 bytes (p.e. char o short) se retorna en la
parte baja del registro GPR3. El contenido de los bytes ms
significativos queda sin definir.
o Los valores de tipo long long (8 bytes) se devuelven en GPR3:GPR4
conteniendo GPR3 los bytes ms significativos.
o Los valores de tipo float y double se devuelven en el registro FPR1.
o Los valores de tipo long double (16 bytes) se devuelven en los
registros FPR1:FPR2 siendo la parte alta la que se coloca en FPR1.
o Los datos compuestos (p.e. estructuras y arrays) se almacenan en
memoria gestionada por el caller, y en la llamada el caller debe de
indicar la direccin de memoria donde desea obtener el retorno,
poniendo en GPR3 un puntero a esta zona de memoria. Al ser
considerado GPR3 como un parmetro no se garantiza su valor en el
retorno. En consecuencia en ese tipo de funciones GPR4 contendr el
primer parmetro de la funcin.

9.6 Ejemplo
Para acabar este apartado vamos a hacer un ejemplo de como se
implementara una funcin recursiva que calcula el factorial de un nmero en
ensamblador.
Esta funcin ensamblador la vamos a poner en un fichero llamado
factorial.s que aparece en el Listado 2.16, y la vamos a llamar desde un
programa C que vamos a hacer en el fichero factorial.c que aparece en
el Listado 2.17.
.set tamanoFrame,16
.text
.align 2
.globl _factorial
_factorial:
; Prlogo
mflr r0
stw r0,8(r1)
stwu r1,-tamanoFrame(r1)

;
;
;
;

Pg 169

Recoge en r0 el LR
Guarda el LR en el rea
de enlace del caller
Crea su frame

Ensamblador del PowerPC con Mac OS X

MacProgramadores

; Cuerpo de la funcin
cmpwi r3,1
; Si (n>1)
bgt sigue
li r3,1
; Retorna 1
b epilogo
sigue:
stw r3,tamanoFrame+12(r1) ; Guarda r3 en el rea de
; parmetros del padre
; para poder hacer otra
; llamada recursiva
subi r3,r3,1
; Decrementa n
bl _factorial
; Llama a factorial
mr r4,r3
; Recoge el retorno y
; lo guarda en r4
lwz r3,tamanoFrame+12(r1) ; Recupera el parmetro
; del rea de enlace
; del padre
mulhw r5,r3,r4
; Calcula n*factorial(n-1)
cmpwi r5,0
; Si hay acarreo
bne acarreo
; devolvemos 0
mullw r3,r3,r4
; r3 = n*factorial(n-1)
b epilogo
acarreo:
li r3,0
epilogo:
; Eplogo
lwz r1,0(r1)
; Recoge el puntero a pila
; de su rea de enlace
; con lo que destruye
; el frame
lwz r0,8(r1)
; Recoge el LR del rea de
; enlace del caller
mtlr r0
; Fija la direccin de
; retorno
blr
; Retorna
Listado 2.16: Llamada a una funcin C

Como la funcin se vuelve a llamar a s misma tiene que guardar el parmetro


pasado en el registro r3 en el rea de parmetros del caller antes de
llamarse recursivamente, y cuando retorna de la llamada vuelve a ir a
memoria a recuperar el parmetro guardado para poder calcular
n*factorial(n-1).
La funcin comprueba si durante la multiplicacin hay acarreo, es decir, si
mulhw da un nmero distinto de cero, en cuyo caso es que el nmero
calculado no cabe en un registro de 32 bits y retorna 0 indicando que no se
pudo calcular.

Pg 170

Ensamblador del PowerPC con Mac OS X

MacProgramadores

#include <stdio.h>
int factorial(int n);
int main()
{
int n=100002;
int sol = factorial(n);
printf("El factorial de %i es %i",n,sol);
return 0;
}
Listado 2.17: Funcin llamada desde ensamblador

Pg 171

Apndice A
Aritmtica binaria

Sinopsis:

En este apndice se pretende hacer un repaso a todos los conceptos


relacionados con la representacin de nmeros, tanto en punto fijo como en
punto flotante4, as como los temas relacionados con la aritmtica binaria.
Aunque, como se dijo en el prlogo, este libro presupone que el lector est
familiarizado con la representacin binaria y su aritmtica, un repaso podra
ayudar a un lector que llevase algn tiempo sin tocar este tema.

En castellano muchas veces se les llama coma fija y coma flotante, ya que en castellano el
delimitador de la parte fraccionaria es la coma y no el punto

Ensamblador del PowerPC con Mac OS X

MacProgramadores

1 Tcnicas bsicas de aritmtica entera


1.1 Nmeros sin signo
Vamos a empezar viendo la aritmtica con nmeros binarios sin signo y en el
siguiente apartado comentaremos los aspectos de los nmeros binarios con
signo.

1.1.1 Suma con transmisin de acarreo


La suma de nmeros binarios se realiza sumando los dgitos de la misma
magnitud de acuerdo a la Tabla A.1:
ai
0
0
1
1
0
0
1
1

bi
0
1
0
1
0
1
0
1

ci
0
0
0
0
1
1
1
1

si
0
1
1
0
1
0
0
1

ci+1
0
0
0
1
0
1
1
1

Tabla A.1: Proceso de suma de nmeros binarios

a (an-1...a1a0) y b (bn-1...b1b0) son los dgitos a sumar, s (sn-1...s1s0)


es la suma y c (cn-1...c1c0) el acarreo. Si hay acarreo en el nivel i, el
acarreo se pasa al nivel i+1.
Por ejemplo para sumar 23 y 56, primero los pasamos a binario, y despus
aplicando la regla anterior tenemos:
0001 0111 (23)
0011 1000 (56) +

0100 1111 (79)


Vemos que en el quinto bit empezando por la derecha ha habido acarreo, al
igual que en el sexto bit, y ste se ha llevado hasta el sptimo bit.
Si queremos hacer un sumador hardware que pueda calcular la suma de
nmeros de n bits: an-1...a1a0 y bn-1...b1b0 necesitamos unos
componentes llamados semisumadores, y otros llamados sumadores
completos.

Pg 173

Ensamblador del PowerPC con Mac OS X

MacProgramadores

El semisumador toma dos bits ai y bi como entrada, y produce como salida


un bit de suma si y un bit de acarreo ci+1. Como ecuaciones lgicas:
si=ai*(~bi) + (~ai)*bi
ci+1=ai*bi.
Al semisumador tambin se le denomina sumador (2,2), ya que toma 2
entradas y produce 2 salidas. El sumador completo es un sumador (3,2) y se
define por las ecuaciones lgicas:
si = ai*(~bi)*(~ci) + (~ai)*bi*(~ci) + (~ai)*(~bi)*ci
+ ai*bi*ci
ci+1 = aibi + aici + bici
A la entrada al sumador ci se le denomina el acarreo de entrada, mientras
que la salida del sumador ci+1 es el acarreo de salida.
El problema principal a la hora de construir un sumador para nmeros de n
bits es propagar los acarreos. La forma ms obvia de resolver esto es con un
sumador de transmisin de acarreo (ripple-carry adder), que consta
de n sumadores completos tal como muestra la Figura A.1:
an-1 bn-1

an-2 bn-2

Sumador
completo

cn

sn-1

a1

Sumador
completo

cn-1

b1

ao

Sumador
completo

sn-2

cn

sn-1

bo

Sumador
completo

c1

Figura A.1: Sumador de transmisin de acarreo

El bit menos significativo entra por el sumador ms a la derecha. Vemos que


la salida del i-simo sumador alimenta el acarreo del sumador (i+1)-simo.
Como el acarreo de orden inferior es 0, el primer sumador basta con que sea
un semisumador. Sin embargo, ms tarde veremos que inicializar el bit de
acarreo de orden inferior a 1, es til para realizar la resta.

Pg 174

Ensamblador del PowerPC con Mac OS X

MacProgramadores

1.1.2 Resta con peticin de acarreo


La resta acta de forma parecida a la suma, slo que ahora cuando el bit del
minuendo es 0 y el bit de sustraendo es 1, en vez de pasar un bit al dgito
de mayor peso, se le pide un bit.
Segn esto el proceso de resta de nmeros binarios sera el de la Tabla A.2:
ai
0
0
1
1
0
0
1
1

bi
0
1
0
1
0
1
0
1

ci
0
0
0
0
1
1
1
1

si
0
1
1
0
1
0
0
1

ci+1
0
1
0
0
1
1
0
1

Tabla A.2: Proceso de resta de nmeros binarios

Por ejemplo para calcular 56-23, primero los pasamos a binario, y despus
aplicando la regla anterior tenemos:
0011 1000 (56)
0001 0111 (23)
0010 0001 (33)
Ya en el bit ms a la derecha vemos que hemos tenido que pedir al nivel
superior, y el acarreo de peticin se ha mantenido hasta el cuarto bit
empezando a contar por la derecha.
an-1 bn-1

an-2 bn-2

Sumador
completo

cn

sn-1

a1

Sumador
completo

cn-1

b1

ao

Sumador
completo

sn-2

Figura A.2: Circuito restador

Pg 175

cn

sn-1

bo

Sumador
completo

c1

Ensamblador del PowerPC con Mac OS X

MacProgramadores

Lo ms curioso de todo es que si quisiramos hacer un restador hardware,


bastara con aprovechar el circuito del sumador, invirtiendo las entradas del
sustraendo y poniendo a 1 el bit de acarreo de ms a la derecha como
muestra la Figura A.2.
Realmente aqu lo que estamos haciendo es:
1. Pasar el sustraendo a complemento a 2.
2. Sumar el minuendo al sustraendo en complemento a 2.
3. Descartar el overflow.
Por ejemplo si tenemos:
14
7
7

(minuendo)
(sustraendo)
(diferencia)

1111
0111
0111

1. Pasamos el sustraendo a complemento a 2


Binario

Complemento a 1

0111

Complemento a 2

1000

1001

2. Sumar el minuendo al sustraendo en complemento a 2


1110 (minuendo)
+ 1001 (sustraendo en complemento a 2)

10111

3. Descartar el overflow
1110 (minuendo)
+ 1001 (sustraendo en complemento a 2)

10111

0 - Suma
1 - Resta
an-1 bn-1

an-2 bn-2

a1

b1

A0

b0

xor

xor

xor

xor

Sumador
completo

Sumador
completo

Sumador
completo

Sumador
completo

cn

sn-1

cn-1

sn-2

Figura A.3: Circuito sumador-restador


Pg 176

cn

sn-1

c1

Ensamblador del PowerPC con Mac OS X

MacProgramadores

La razn por la cual el circuito anterior funciona como restador puede


entenderse mejor ahora. Los cuatro inversores convierten el sustraendo
binario en su forma en complemento a 1 y el acarreo con su bit de entrada
puesto a 1 convierte el sustraendo en complemento a 2.
Ahora podramos construir un circuito sumador-restador como el de la Figura
A.3. El circuito sumador-restador tiene una entrada adicional de control. Si
esta entrada est a 0, significa que queremos sumar, y las puertas XOR dejan
pasar la misma entrada que reciben. Si la entrada de control est a 1,
significa que queremos restar, con lo que las puertas XOR invierten la entrada
y se activa el bit de acarreo.

1.1.3 Multiplicacin en base 2


La multiplicacin binaria es muy parecida a la multiplicacin decimal, se
colocan multiplicando y multiplicador de forma que el multiplicando se
multiplica por cada uno de los bits del multiplicador convenientemente
desplazado, y al final se suman.
Por ejemplo, para calcular 34*67 en binario, haramos:
00100010 (34)
x 01000011 (67)

00100010
00100010
00000000
00000000
00000000
00000000
00100010
00000000

000100011100110
El multiplicador hardware ms sencillo opera sobre dos nmeros sin signo
produciendo cada vez un bit como muestra la Figura A.4. Los nmeros que
vamos a multiplicar son an-1...a1a0 y bn-1...b1b0 los cuales se colocan en
los registros A y B (con el bit menos significativo a la derecha, como es
habitual). El registro P se pone inicialmente a cero:

Pg 177

Ensamblador del PowerPC con Mac OS X

MacProgramadores

Desplazamiento
P

1 bit
n bits

B
Figura A.4: Circuito multiplicador

El algoritmo repite los siguientes dos pasos:


1. Si el bit menos significativo de A es 1, entonces el registro B se suma
con el registro P; en caso contrario, el registro P se mantiene como
est.
2. Los registros A y P se desplazan un bit a la derecha de forma que el bit
menos significativo de P se pasa al bit ms significativo de A, y el bit
menos significativo de A, que no se vuelve a usar ms en el algoritmo,
se pierde.
Despus de n pasos el producto aparece en los registros P:A, conteniendo A
los bits menos significativos.

1.1.4 Divisin en base 2


Este algoritmo se puede implementar fcilmente en hardware usando tres
registros tal como muestra la Figura A.5:
Desplazamiento
P

1 bit
n bits

B
Figura A.5: Circuito divisor

Pg 178

Ensamblador del PowerPC con Mac OS X

MacProgramadores

Para calcular la divisin a/b el algoritmo ms sencillo procede de la siguiente


forma:
Se pone el dividendo a en el registro A, y el divisor b en el registro B.
Despus se habilita un tercer registro P que inicialmente se pone a 0.
Al final de la ejecucin del algoritmo A contendr el cociente, y P el resto de
la divisin.
El algoritmo consiste en repetir n veces los siguientes pasos (n es el nmero
de bits de los registros con los que estamos trabajando):
1. Desplazar la combinacin P:A 1 bit a la izquierda. Esto carga un 1 en el
bit menos significativo de P cuando el bit ms significativo de A sea 1,
o un 0 en el bit menos significativo de P en caso contrario.
2. Restar a P el divisor B. Esto calcula la resta parcial de la divisin.
3. Si el resultado es negativo, no modificamos P e insertamos un cero en
el bit bajo de A
4. Si el resultado es positivo ponemos el resultado en P, y insertamos un
1 en el bit bajo de A
5. Si el nmero de iteraciones es menor a n, volvemos al paso 1
A continuacin se muestra un ejemplo de como se ejecutara la divisin:
65/15 usando registros de 16 bits.
Inicialmente tendremos:
A= 00000000 01000001
B= 00000000 00001111
P= 00000000 00000000

(65)
(15)
(0)

Pasos 1-9:
Como los 9 bits ms a la izquierda de A son ceros, P recibir 9 bits 0 y P-B
siempre ser negativo con lo que el programa se limitar a desplazar los
ceros a la izquierda obteniendo:
A= 10000010 00000000
B= 00000000 00001111
P= 00000000 00000000

(65)
(15)
(0)

Luego los registros P:A acaban teniendo:


P:A= 00000000 00000000 10000010 00000000
Las ltimas 7 repeticiones son las que van depositando en A el cociente de la
divisin, y en P el resto.

Pg 179

Ensamblador del PowerPC con Mac OS X

MacProgramadores

10 paso:
Desplazamos
P:A= 00000000 00000001 00000100 00000000
B= 00000000 00001111
B>P y no hacemos nada ms.
11 paso:
Desplazamos
P:A= 00000000 00000010 00001000 00000000
B= 00000000 00001111
B>P y no hacemos nada ms.
12 paso:
Desplazamos
P:A= 00000000 00000100 00010000 00000000
B= 00000000 00001111
B>P y no hacemos nada ms.
13 paso:
Desplazamos
P:A= 00000000 00001000 00100000 00000000
B= 00000000 00001111
B>P y no hacemos nada ms.
14 paso:
Desplazamos
P:A= 00000000 00010000 01000000 00000000
B= 00000000 00001111
En este desplazamiento finalmente (P>B) con lo que calculamos P-B y lo
guardamos en P. Adems ponemos un 1 en A.
Luego acabamos teniendo:

Pg 180

Ensamblador del PowerPC con Mac OS X

MacProgramadores

P:A= 00000000 00000001 01000000 00000001


B= 00000000 00001111
15 paso:
Desplazamos
P:A= 00000000 00000010 10000000 00000010
B= 00000000 00001111
B>P y no hacemos nada ms.
16 paso:
Desplazamos
P:A= 00000000 00000101 00000000 00000100
B= 00000000 00001111
B>P y finalmente hemos acabado.
Ahora tenemos que el cociente es A=4 y que el resto est en P=5.
Obsrvese que el divisor hardware es muy parecido al multiplicador hardware.
La principal diferencia est en que el par de registros P:A se desplaza a la
derecha cuando se multiplica y a la izquierda cuando se divide. Si permitimos
que el par de registros P:A se puedan desplazar a la izquierda y a la derecha
indistintamente, podemos aprovechar el mismo hardware para hacer un
multiplicador-divisor.

1.2 Nmeros con signo


1.2.1 Representacin
Hay cuatro mtodos para representar nmeros con signo: signo-magnitud,
complemento a dos, complemento a uno y polarizado (biased). En el sistema
de signo-magnitud el bit de orden superior es el bit de signo, y los n-1 bits
inferiores son la magnitud del nmero. En el sistema de complemento a
dos, un nmero y su negativo suman 2n. En el complemento a uno, el
negativo de un nmero se obtiene negando cada bit. En el sistema
polarizado, se toma una polarizacin fija de forma que la suma de la
polarizacin y el nmero que se est representando sea siempre no negativo.
Un nmero se representa primero sumndolo a la polarizacin y dicha suma
se codifica como un nmero ordinario sin signo.

Pg 181

Ensamblador del PowerPC con Mac OS X

MacProgramadores

Ejemplo: Cunto es -3 representado en cada uno de estos formatos?


La representacin binaria de 3 es 0011. En signo-magnitud -3 sera 1011. En
complemento a dos 0011+1101=10000, luego sera 1101. En complemento a
uno negamos todos los bits y tenemos 1100. Usando una polarizacin de 8, 3
se representa como 0011+1000=1011, es decir 3+8=11, y -3 se representa
como 0101 ya que
-3+8=5.
Negar un nmero en complemento a 2 es fcil, slo hay que pasarlo a
complemento a 1 (negar todos sus bits) y luego sumarle 1.
Por ejemplo si queremos negar el 27 hacemos:
00011011
11100100
1

11100101

(27)
(complemento a 1)
+
(-27)

Si ahora lo queremos volver a negar aplicamos el mismo procedimiento:


11100101
00011010
1

00011011

(-27)
(complemento a 1)
+
(27)

1.2.2 Suma y resta de nmeros en complemento a 2


La gran ventaja que tiene representar los nmeros en complemento a 2 es
que para hacer una suma basta con sumarlos como si fueran nmeros sin
signo. Por ejemplo si queremos calcular 34+(-17), primero los representamos
en complemento a 2 y luego sumamos.
Primero empezamos calculando la representacin de -17:
00010001
11101110
1

11101111

(17)
(complemento a 1)
+
(-17)

Y luego los sumamos:


00100010 (34)
11101111 (-17) +

100010001 (17)
Pg 182

Ensamblador del PowerPC con Mac OS X

MacProgramadores

Vemos que la suma produce un acarreo en el bit de orden superior que


simplemente se descarta.
La resta de nmeros en complemento a 2 tambin se hace como la resta de
nmeros sin signo:
Por ejemplo para calcular 34-(-17) hacemos:
00100010 (+34)
11101111 (-17)
100110011 (+51)
El desbordamiento (overflow) se produce cuando el resultado de la
operacin no cabe en la representacin que se est utilizando. Para nmeros
sin signo detectar el desbordamiento es fcil: se presenta justo cuando hay
un acarreo de salida del bit ms significativo. Para el complemento a dos las
cosas son ms complicadas: el desbordamiento se presenta, exactamente,
cuando el acarreo de entrada del bit de orden superior es diferente del
acarreo de salida (que es descartado) del bit de orden superior. En el ejemplo
de la suma 34+(-17) anterior el acarreo de entrada del bit de orden superior
es 1 y el acarreo de salida tambin 1, con lo que no hay desbordamiento,
pero si calculamos:
(-80)+(-120) tendremos:
10110000 (-80)
10001000 (-120) +

100111000 (56)
Ahora el acarreo de entrada del bit ms significativo es 0, mientras que el
acarreo de salida del bit ms significativo es 1, al ser distintos indica que ha
habido un desbordamiento.

1.3 Aspectos del sistema


Cuando se disea un repertorio de instrucciones, hay una serie de cuestiones
relativas a la aritmtica entera que es necesario aclarar:
Primero, qu debe hacerse cuando hay un desbordamiento de enteros?
Antes de nada aclarar que no debe confundirse el desbordamiento (overflow)
con el acarreo. Cuando sumamos o restamos nmeros en complemento a 2,
es normal que se produzca un acarreo en el ltimo bit, que simplemente se
descarta. El desbordamiento es distinto, se debe a que el nmero obtenido no
es correcto ya que no se puede representar en un registro del tamao usado.
Pg 183

Ensamblador del PowerPC con Mac OS X

MacProgramadores

P.e. 34+(-17) produca un acarreo que se descartaba sin ms. (-80)+(-120)


produce un desbordamiento que hace que el resultado de la suma obtenido
en el registro no sea el correcto.
El problema del desbordamiento se complica por el hecho de que detectar el
desbordamiento es diferente dependiendo de si los operandos son enteros
con o sin signo.
Consideremos primero la aritmtica sin signo. Hay tres enfoques: poner a 1
un bit de desbordamiento, causar un trap en caso de desbordamiento, o no
hacer nada con el desbordamiento. En el ltimo caso el software tiene que
comprobar si se va a producir o no desbordamiento, con lo que es la solucin
menos apropiada y de hecho slo se us en las mquinas MIPS.
En PowerPC el enfoque que se ha seguido es el de que las instrucciones no
producen un trap, sino que activan un flag que indica que la excepcin se ha
producido. En las instrucciones de punto fijo existen tres flag, que se detallan
en la Tabla A.3, en el registro XER que indican que la excepcin se ha
producido:
Flag
SO

OV
CA

Descripcin
(Summary Overflow) Se activa cuando hay un overflow y queda
activo hasta que lo desactivamos explcitamente con mtxer. Es til
para saber si durante la ejecucin de una serie de instrucciones
hubo un overflow
(OVerflow) Indica si la ltima operacin aritmtica produjo
overflow
(Carry) Indica si la ltima operacin aritmtica produjo acarreo

Tabla A.3: Flags de excepcin en PowerPC

Despus PowerPC dispone de varias operaciones, unas en las que no se


detecta nada (addi y add), otras en las que slo se detecta el acarreo (addc
y adde) y otras en las que se activa el overflow (addco, addeo, addmeo y
addzeo).
Qu ocurre en el caso de la aritmtica con signo?. Obsrvese que mientras
que el la aritmtica sin signo el acarreo implica overflow, aqu puede ser
deseable ignorarlo, como pasa en el caso de la suma de nmeros en
complemento a 2, donde el acarreo simplemente se ignora. Esta es la razn
de que existan instrucciones como addi o add que lo ignoran. Adems el
ignorar el acarreo puede ser til en circunstancias en las que por la lgica del
programa sabemos que no se va a producir, porque acelera la ejecucin de
instrucciones tal como se explica en el Apndice B.
Una segunda cuestin est relacionada con la multiplicacin. El resultado de
la multiplicacin de dos nmeros de n bits deber ser de 2n bits, o deber

Pg 184

Ensamblador del PowerPC con Mac OS X

MacProgramadores

devolver los n bits de orden inferior, sealando desbordamiento si el resultado


sobrepasa los n bits?.
El argumento en favor de un resultado de n bits es que, virtualmente en
todos los lenguajes de alto nivel, la multiplicacin es una operacin cuyos
argumentos son variables enteras y cuyo resultado es una variable entera del
mismo tipo. Por tanto no hay forma de generar cdigo que utilice un
resultado de doble precisin. El argumento a favor de 2n bits es que lo pueda
utilizar una rutina, en lenguaje ensamblador, para acelerar sustancialmente la
multiplicacin de enteros en mltiple precisin.
En PowerPC se ha buscado una solucin intermedia y para multiplicar
nmeros de 32 bits usamos las instrucciones mullw (MULtiply Low Word)
mulhw (MULtiply High Word) que nos proporcionan la parte alta y baja de los
64 bits resultados del producto. Si slo nos interesa la parte baja (como es
habitual) usamos slo mullw.

Pg 185

Ensamblador del PowerPC con Mac OS X

MacProgramadores

2 Introduccin al punto flotante


Se han inventado varias formas de representar nmeros no enteros. Una de
ellas es utilizar punto fijo, es decir, utilizar aritmtica entera e imaginar el
punto binario en algn sitio en medio del nmero. Sumar dos de tales
nmeros suele hacerse mediante una suma entera, mientras que la
multiplicacin requiere algn desplazamiento extra.
Sin embargo slo hay una representacin no entera cuyo uso se ha extendido
ampliamente, y es la representacin en punto flotante. En este sistema, la
representacin de un nmero se divide en tres partes: un signo, un
exponente y una mantisa. Y el valor del nmero as representado se
calcula como:
n = (signo) mantisa * 2exponente
Aunque sta es la frmula que se usa para guardar un nmero en un
ordenador, a la que llamaremos punto flotante binario, nosotros tambin
usaremos en nuestros ejemplos otra representacin a la que llamaremos
punto flotante decimal:
n = (signo) mantisa * 10exponente
Aunque esta frmula no vale para calcular nmeros en binario, si que nos
ser til en los ejemplos ya que las personas estamos ms familiarizadas con
nmeros en base 10.
Un ejemplo de representacin en punto flotante decimal sera un nmero
con un signo negativo, una mantisa de 1,5 y un exponente de -2, lo cual est
representando el nmero: -1,5*10-2=-0,015.
Un ejemplo de representacin en punto flotante binario sera un nmero
con signo positivo, una mantisa de 1.01b y un exponente de +10b, que
pasado a decimal 1,01b es el nmero 1,25d y +10b pasado a decimal es el
+2, luego sera el nmero 1,25*22=5
Obsrvese que la mantisa nunca tiene signo, ya que el signo se separa aparte
en el campo destinado a tal propsito, sin embargo el exponente siempre es
un nmero con signo.
Obsrvese tambin que un mismo nmero en punto flotante puede tener
muchas
representaciones.
P.e.
-1,5*10-2=-0,15*10-1=-0,015*100=0,00015*101
Para simplificar la representacin se a creado el concepto de nmero en
punto flotante normalizado, donde decimos que un nmero est
Pg 186

Ensamblador del PowerPC con Mac OS X

MacProgramadores

normalizado si la mantisa tiene un slo dgito a la izquierda de la coma. P.e. 7,5*103 est normalizado, -75*102 no. En binario tambin se normalizan los
nmeros. Por ejemplo 1,0110*2-11 est normalizado, pero 1011,0*2-110 no lo
est.

Pg 187

Ensamblador del PowerPC con Mac OS X

MacProgramadores

3 Formato de los datos en punto flotante


El estndar IEEE 754 especifica cuatro formatos para almacenar nmeros en
notacin de punto flotante: simple, doble, simple extendido, doble
extendido. Todos los formatos tienen los tres campos que explicbamos
antes, slo que cada uno de ellos tiene un tamao mayor o menor que les da
ms o menos precisin.
A la hora de almacenar un nmero en punto flotante, a ste se le hace una
modificacin llamada empaquetamiento que consiste en:
o Normalizar la mantisa de forma que a la izquierda del punto binario
aparezca un slo 1 y coger de sta slo los bits que estn a la derecha
del punto binario, que es a lo que se llama la fraccin.
o Al exponente se le polariza (vase el apartado 1.2) con el fin de
almacenar el nmero como un nmero sin signo. A esto es a lo que se
llama el exponente polarizado, en contraposicin al exponente que
tenemos cuando desempaquetamos el nmero que se llama
exponente no polarizado. Como polarizacin se utiliza 2n-1 siendo n
el nmero de bits del campo destinado a almacenar el exponente.
Ejemplo: Los nmeros de precisin simple utilizan 1 bit para el signo, 23
para la fraccin y 8 para el exponente polarizado Cmo se empaquetara el
nmero en punto flotante 150*2-9?
Primero debemos de pasar la mantisa a notacin binaria, con lo que tenemos:
mantisa = 150 = 10010110
Ahora debemos normalizar la mantisa para lo que transformamos en el
nmero: 1,0010110 * 2-2, es decir, al mover la coma binaria 7 posiciones a la
izquierda el exponente aumenta en 7 unidades.
Ahora ya podemos representar mantisa y exponente en binario:
mantisa = 1,0010110
exponente = 11111110 (-2)
Por ltimo empaquetamos el nmero, para lo cual, la fraccin se calcula como
los dgitos a la derecha de la coma y el exponente polarizado se calcula como
el exponente no polarizado ms 2n-1=27=128, es decir el exponente
polarizado ser -2+128=126:
fraccin = 0010110 00000000 00000000 00000000
exponente polarizado = 01111110
Pg 188

Ensamblador del PowerPC con Mac OS X

MacProgramadores

Como el signo es positivo valdr 0, con lo que la representacin del nmero


empaquetado en una variable de tipo simple ser la que se muestra en la
Figura A.6:
Signo Exponente polarizado
0

0111 1110

1b

8b

Fraccin
0010110 00000000 00000000
23b

Figura A.6: Representacin de un nmero simple

De los cuatro formatos definidos por el IEEE 754, slo el formato simple es
obligatorio de implementar, el formato doble es recomendado y todas las
implementaciones de IEEE 754 existentes lo implementan. Por ltimo los
formatos simple extendido y doble extendido slo los tienen algunas
implementaciones. PowerPC implementa los formatos simple, doble y doble
extendido, pero no el simple extendido.
En lenguaje C estos formatos estn representados por los tipos de datos de la
Tabla A.4:
Formato IEEE 754
Simple
Doble
Doble extendido

Tipo C
float
double
long double

Tabla A.4: Tipos de datos C para nmeros un punto flotante

El tamao de los campos para los formatos simple y doble est estandarizado
por el IEEE 754 y son los que se muestran el la Tabla A.5, pero el tamao de
los campos para los formatos simple extendido y doble extendido no estn
estandarizados por el IEEE 754, sino que el IEEE754 slo da unos tamaos
mnimos para cada campo.
Formato
simple
doble
simple
extendido
doble extendido

Signo
1
1
1

Exponente Fraccin
8
23
11
52
10
32

16

64

Tabla A.5: Tamaos de los campos de cada uno de los formatos del IEEE 754

El formato simple extendido actualmente no lo implementa nadie, pero el


doble extendido si que est implementado, tanto por Intel, como por

Pg 189

Ensamblador del PowerPC con Mac OS X

MacProgramadores

PowerPC y SPARC, aunque la forma en que lo implementan vara de un


microprocesador a otro.
Vamos a ver ms detenidamente como lo implementa cada uno: Tanto
PowerPC como SPARC lo implementan en un nmero de 128 bits (16 Bytes)
como muestra la Figura A.7:
Signo Exponente

1b

Fraccin

15b

112b
16 B

Figura A.7: Representacin de los double extendidos en PowerPC y SPARC

Intel, sin embargo, lo implementa en un nmero de 96 bits (12 bytes) como


el que muestra la siguiente figura:
Sin usar

16b

Explicit
Signo Exponente leading
1b

15b

Fraccin

1b

63b
12 B

Figura A.8: Representacin de los double extendidos por Intel

La especificacin de Intel dice que de los 12 bytes slo se usan 10 bytes


dejando 2 bytes vacos. El bit explicit leading almacena el 1 que hay a la
izquierda de la fraccin, que aunque normalmente es implcito, aqu se hace
explcito. Esto ser til cuando veamos los nmeros desnormalizados en el
apartado 3.1 donde veremos que aqu puede ir un 0.
Por ltimo comentar que los exponentes con valor mximo y mnimo (0 y 255
en el caso del formato simple) se utilizan con valores especiales, como
muestra la Tabla A.6, y que comentaremos en los siguientes apartados.
Valor especial
0
Nmero denormalizado
+
-
NaN

Signo
01
01
0
1
01

Exponente
0
0
mximo
mximo
mximo

Tabla A.6: Representacin de valores especiales

Pg 190

Fraccin
0
cualquiera
0
0
!=0

Ensamblador del PowerPC con Mac OS X

MacProgramadores

El nmero 0 es uno de estos valores especiales y se representa poniendo


todos los bits a cero, salvo quiz el de signo que se puede activar para
representar el -0. A efectos prcticos 0 y -0 son idnticos, pero existen
determinadas ocasiones en las que se comportan de forma diferente, por
ejemplo al calcular 1/-0 = -. en principio el lector no debera de darle ms
importancia, salvo para recordar que el cero en notacin de punto flotante se
puede representar de dos formas distintas.

3.1 Nmeros denormalizados


Antes comentamos que la mantisa era igual a la fraccin con un 1 delante de
la coma binaria. Esto nos limita el nmero ms pequeo que podemos
representar. Por ejemplo en notacin simple donde el exponente tiene 8 bits y
la fraccin tiene 23 bits, el nmero ms pequeo que podemos representar es
el 1*2-127, que en decimal nos viene a dar el nmero 5,8*10-39.
Una caracterstica del estndar IEEE 754 es que permite representar nmeros
por debajo de este umbral, a los que llaman nmeros denormalizados,
para ello lo que hacemos es dejar el exponente polarizado a 0 de forma que
ahora la parte fraccionaria se interpreta como si a la izquierda de la coma
hubiera un 0 en vez de un 1.
Por ejemplo, si encontramos el nmero simple empaquetado que muestra la
Figura A.9:
Signo Exponente
0

0000 0000

1b

8b

Fraccin
0010000 00000000 00000000
23b

Figura A.9: Ejemplo de nmero denormalizado

Este nmero se interpreta como 0,001*2-128


Cuando un nmero es tan pequeo que ya no se puede representar como un
nmero normalizado se dice que el nmero de ha degradado (underflow).
Por qu el estndar permite almacenar nmeros denormalizados en vez de
simplemente redondearlos a 0?, una razn es que de esta forma el
programador puede saber que se est acercando a un nmero
peligrosamente pequeo, lo cual es especialmente til en el clculo de
algunos valores matemticos como los lmites. Si por ejemplo nosotros
hacemos un programa que busca calcular:
lim 1/x
x->

Pg 191

Ensamblador del PowerPC con Mac OS X

MacProgramadores

El programa podra determinar que hemos entrado en un nmero


denormalizado y detener un supuesto bucle. Esto es a lo que se llama el
degradamiento gradual a cero.
Para una discusin matemtica ms a fondo sobre este tema puede consultar
[UNDERFLOW].

3.2 Nmeros especiales


Otra peculiaridad del estndar IEEE 754 es que nos permite representar los
valores + y -, para ello utiliza los patrones de bits especiales de la Figura
A.10:
+

1111 1111

000000 00000000 00000000

1111 1111

000000 00000000 00000000

Figura A.10: Representacin de + y -

Es decir, el exponente se pone al mximo valor, la fraccin se pone a cero y


el bit de signo indica si es + -.
Cuando el resultado de un clculo es tan grande que no se puede representar
en el formato utilizado se usa esta forma de devolver infinito.
Por ltimo la otra gran peculiaridad del estndar IEEE 754 es que puede
representar nmeros no vlidos que se obtienen en clculos especiales como
por ejemplo 0/0, +(-), o la raz de un nmero negativo. Estos son valores
indefinidos en el campo de los nmeros reales y se representan con el valor
especial NaN (Not a Number). Este valor se codifica dejando el exponente
a su valor mximo y dejando una fraccin distinta de cero tal como muestra
la Figura A.11, con lo que ms que haber un nmero NaN, hay una familia
completa de NaN.
NaN

1111 1111

xxxxxxx xxxxxxxx xxxxxxxx

Figura A.11: Representacin de NaN

El valor NaN se propaga entre las operaciones aritmticas, de forma que si


uno de los operandos de una operacin aritmtica es NaN, el resultado de la
operacin tambin ser NaN.
Pg 192

Ensamblador del PowerPC con Mac OS X

MacProgramadores

Los NaN pueden ser de dos tipos: quiet NaN y signaling NaN. Cuando un
signaling NaN se encuentra en una operacin aritmtica, si est activo el
tratamiento de excepciones se produce una excepcin. Cuando se encuentra
un quiet NaN no se produce la excepcin.
Los signaling NaN no tienen por qu ser producidos por operaciones
aritmticas no vlidas, nosotros mismos podemos crearlos manualmente, por
ejemplo para rellenar un rea de memoria sin inicializar, de forma que si el
programa encuentra un nmero de estos podemos saber que el programa a
accedido a un trozo de memoria sin inicializar.
Cuando realizamos una operacin aritmtica que produce un resultado no
vlido obtenemos un signaling NaN. Si usamos este valor para ejecutar otra
operacin aritmtica este produce un quiet NaN. Esto es til porque si hay un
problema de clculo, la excepcin slo se producir una vez.
Los NaN toman distintos valores en su parte fraccionaria indicando la causa
del error. La Tabla A.7 muestra los valores que puede tomar el campo de la
fraccin:
Decimal
1
2
4
8
9
17
21
33

Hexadecimal
0x01
0x02
0x04
0x08
0x09
0x11
0x15
0x21

34

0x22

36

0x24

37

0x25

38
40

0x26
0x28

42

0x2A

Significado
Raz cuadrada invalida (p.e. raz de -1)
Suma invalida (p.e. (+)-(-))
Divisin invlida (p.e. 0/0)
Multiplicacin invlida (p.e. 0*)
Resto invlido (p.e. x%0)
Intento de convertir cadena ASCII invlida
Intento de crear un NaN con cdigo cero
Parmetro
invlido
para
una
funcin
trigonomtrica (p.e. sin(), cos(), tan())
Parmetro
invlido
para
una
funcin
trigonomtrica inversa (p.e. acos(), asin(),
atan())
Parmetro invlido para una funcin logartmica
(p.e. log() o ln())
Parmetro invlido para una funcin exponencial
(p.e. exp())
Parmetro invlido para una funcin financiera
Parmetro invlido para una funcin hiperblica
inversa (p.e. acosh() o asinh())
Parmetro invlido para una funcin gamma (p.e.
gamma() o lgamma())

Tabla A.7: Significado de la parte fraccionaria de un NaN

Pg 193

Ensamblador del PowerPC con Mac OS X

MacProgramadores

Para indicar si el nmero es un signaling NaN o un quiet NaN se usa el bit


ms significativo de la fraccin. Para indicar la causa del NaN se usan los
valores de la tabla anterior puestos a la derecha de la fraccin y desplazados
8 posiciones a la izquierda tal como muestra la Figura A.12:

Signaling NaN

1111 1111

000000 xxxxxxxx 00000000

Quiet NaN

1111 1111

100000 xxxxxxxx 00000000

Figura A.12: Representacin signaling NaN y quiet NaN

3.3 Rangos mximos y mnimos en los nmeros en


punto flotante
Para acabar de ver el formato de los nmeros en punto flotante vamos a
hacer un estudio de cules son los rangos de los nmeros mximos y mnimos
que podemos representar con cada formato.
Los rangos exactos se describen en la Tabla A.8:
Formato
Simple
Doble
Doble extendido

Mnimo
denormalizado
3,5*10-46
1,2*10-324
1,6*10-4966

Mnimo
normalizado
5,8*10-39
1,1*10-308
1,6*10-4932

Mximo
1,7*1038
8,9*10307
5,9*104931

Tabla A.8: Rangos de los distintos tipos de datos en punto flotante

Vamos a explicar cmo se calculan estos rangos. Slo vamos a ver cmo se
calcularan para el formato simple, aunque el mismo razonamiento se puede
aplicar para los dems tipos.
El nmero mximo representable en formato simple sera aquel que tiene
activos todos los bits de la fraccin y el exponente toma el valor mximo
+126, ya que +127 se usa para representar los infinitos, luego este nmero
sera:
1,1111111 11111111 11111111 * 2126 2127 = 1,7*1038
Para calcular el nmero mnimo normalizado sera aquel que tiene el 1 de la
izquierda de la coma de la mantisa, pero toda la parte fraccionaria a 0 y como
exponente -127 (-128 se usa para representar el cero y los nmeros
denormalizados), luego sera:
Pg 194

Ensamblador del PowerPC con Mac OS X

MacProgramadores

1,0000000 00000000 00000000*2-127 = 5,8*10-39


Por ltimo el nmero denormalizado ms pequeo que se puede representar
en formato simple sera aquel que tiene el exponente a -128 y la mantisa con
un cero a la izquierda de la coma, y la fraccin con todo ceros excepto el bit
menos significativo que estar a 1.
0,0000000 00000000 00000001*2-128 = 2-151 = 3,5*10-46

Pg 195

Ensamblador del PowerPC con Mac OS X

MacProgramadores

4 El problema del redondeo en punto flotante


4.1 La precisin en punto flotante
Un hecho evidente con el que nos vamos a encontrar cuando trabajamos con
nmeros en punto flotante es que tenemos que representar infinitos nmeros
reales usando slo un conjunto finito (aunque muy grande) de nmeros
binarios en notacin de punto flotante. Para afrontar este problema vamos a
utilizar redondeos, donde lo que hacemos es representar un nmero real
usando el nmero en punto flotante ms cercano a l.
Un caso claro donde se aprecian los problemas de redondeo es en el hecho
de que los nmeros en punto flotante decimal y punto flotante binario se
representan de forma distinta. Por ejemplo el nmero 183234,373 tiene una
representacin exacta en punto flotante decimal, pero si lo intentamos pasar
a notacin de punto flotante binaria obtenemos un nmero peridico:
1,0110010 11110000 10011000...
Esto provoca que al almacenar este nmero en formato simple (float) en un
ordenador y luego recuperarlo, en vez de volver a obtener el 183234,373
obtengamos el 183234,3729999... Este problema se acenta ms cuando ms
grande es el nmero.
Un hecho importante que conviene resaltar es el de que los nmeros en
punto flotante se encuentran desigualmente distribuidos, de forma que los
nmeros pequeos (los ms cercanos a 0) estn ms juntos entre s que los
nmeros ms grandes (los ms cercanos a ).
Para ver este hecho podemos dibujar los nmeros en una lnea de
coordenadas suponiendo que tenemos nmeros en notacin de punto flotante
binario con una parte fraccionaria de 3 bits. En este caso se cumple la regla
de que entre 2n-1 y 2n habr un total de 8 nmeros uniformemente
distribuidos. Esta regla ser cierta para cualquier n, aunque la distancia se
dobla cada vez que incrementamos n tal como observamos en la Figura A.13.

0 2-1 20

21

22

23

Figura A.13: Distribucin de los nmeros en punto flotante

Pg 196

24

Ensamblador del PowerPC con Mac OS X

MacProgramadores

O sea, el nmero de elementos entre cada par 2n-1 y 2n es constante, aunque


no su separacin, lo cual produce el efecto indicado.
Esto implica que la precisin que consiguen los redondeos cuando estamos
trabajando con nmeros pequeos sea mucho mayor que la que se consigue
cuando estemos trabajando con nmeros grandes. Obsrvese que en parte
esto es normal, ya que no es la misma la precisin con la que trabaja, por
ejemplo, un microscopio, en la que una micra puede echar a perder todos los
clculos, que la precisin que necesita un astrnomo al calcular la distancia
de la tierra al sol, o la distancia entre galaxias, donde unos miles de metros
ms o menos son inapreciables.

4.2 Error absoluto y relativo


Ya que los errores de redondeo son inherentes a los nmeros en punto
flotante, es importante buscar un mtodo para medirlos. Consideremos como
ejemplo un sistema de representacin de nmeros en punto flotante decimal
y con una fraccin de 3 dgitos. Si el resultado de un clculo en punto flotante
nos da 3,12*10-2, y el clculo con una precisin infinita es 0,0314, es claro
que el error es de dos unidades en el ltimo dgito. Del mismo modo, si el
nmero real 0,0314159 se representa en nuestro sistema de punto flotante
como 3,14*10-2, entonces el error es de 0,159 unidades del ltimo dgito. Un
mtodo muy usado para medir los errores es medir el error usando como
magnitud las unidades en el ltimo dgito (uud), en el ejemplo anterior
los errores serian respectivamente 0,2 uud y 0,159 uud.
Se sabe que si un sistema de clculo en punto flotante calcula correctamente
los valores (con precisin infinita), el error mximo que puede cometer es de
0,5 uud. Esto se debe a que despus de calcular un valor (con precisin
infinita) debe representarlo en punto flotante, con lo que el redondeo produce
una perdida de precisin mxima de 0,5 uud.
En general se busca que los sistemas aritmticos que diseemos tengan un
error mximo de 0,5 uud, en cuyo caso al sistema aritmtico se le considera
correcto.
Tngase en cuenta que ste es un sistema de medicin de errores relativo ya
que si por ejemplo un nmero que estamos calculando con precisin infinita
vale 4,56323*1020 y el sistema de punto flotante nos devuelve el nmero
4,56*1020, aunque el error es de 0,323 uud, el error absoluto es de
323*1017=32.300.000.000.000.000.000 unidades. Sin embargo, los errores de
redondeo que se pueden producir en nmeros pequeos son tambin
pequeos. Por ejemplo en precisin simple si intentamos representar un
nmero con exponente 0 el error mximo que podemos cometer durante el
redondeo es de 0,5 uud, es decir 2-23/2=5,9*10-9, que es un nmero bastante
pequeo.
Pg 197

Ensamblador del PowerPC con Mac OS X

MacProgramadores

4.3 Modos de redondeo


El estndar IEEE 754 define 4 modos de redondeo, los cuales indican cmo
realizar un redondeo cuando un nmero real no se puede representar
exactamente en la notacin de punto flotante utilizada.
El modo por defecto es el modo de redondeo al ms cercano, que
redondea a un nmero par en caso de empate. Por ejemplo si tenemos una
fraccin de 3 dgitos 1,4015 se redondeara a 1,402
Los otros modos de redondeo son redondeo hacia cero, redondeo hacia
+ y redondeo hacia -. Todo sistema de numeracin en punto flotante
que siga el estndar IEEE 754 debe disponer de un mecanismo que nos
permita cambiar este modo de redondeo. En el caso de PowerPC se usa el los
flag RN del registro FPSCR para indicar el tipo de redondeo de acuerdo a la
Tabla A.9.
Flags RN
00
01
10
11

Modo de redondeo
Redondeo al ms cercano
Redondeo a 0
Redondeo a +
Redondeo a -
Tabla A.9: Modos de redondeo

Pg 198

Ensamblador del PowerPC con Mac OS X

MacProgramadores

5 Las excepciones
Cuando se produce una situacin anmala en la ejecucin de instrucciones de
punto flotante se produce una excepcin. IEEE 754 recomienda que existan
flags asociados a las excepciones, en el caso de PowerPC estos flags estn en
el registro FPSCR. Al empezar un programa su ejecucin todos los flag de
excepcin estn apagados. Cuando se produce una excepcin se activa el
flag apropiado, pero la aplicacin se contina ejecutando. Despus la
aplicacin puede consultar los flag de excepcin o bien modificarlos.
El estndar tambin recomienda que para cada tipo de excepcin haya un
flag de habilitacin de trap de excepcin, de forma que si hay una
excepcin con su flag de trap habilitado se llame al manejador de trap.
Adems recomienda el uso del flag de habilitacin de excepcin, que
cuando estn activos indican que si una excepcin se produce se encienda su
correspondiente flag de excepcin. Si estn apagados, el flag de excepcin
no se encender a pesar de que se produzca la excepcin. Los
microprocesadores que slo disponen de flags de habilitacin de excepcin no
permite que el sistema operativo pueda reaccionar ante una excepcin, sino
que es el propio programa el que, tras ejecutar una instruccin, debe de
comprobar si se ha encendido algn flag de excepcin.
El usar los flags de habilitacin de excepcin se considera mejor que el uso de
traps, ya que a la hora de ejecutar instrucciones como:
fdiv f0,f1,f2
fadd f2,f3,f4
En un sistema segmentado (ver Apndice B para una descripcin de los
sistemas segmentados) se podran intentar ejecutar las dos instrucciones
concurrentemente, donde la instruccin fdiv tarda ms que la instruccin
fadd, y si ahora se produjese una excepcin en una de ellas el gestor de
traps tendra problemas para saber cual de ellas ha producido la excepcin.
PowerPC permite tanto usar flags de habilitacin de traps como usar flags de
habilitacin de excepcin, ser el diseador del sistema operativo quien deba
tomar esta decisin.
IEEE 754 define cinco tipos de excepciones que vamos a detallar. Las
implementaciones son libres de disponer de ms flags de excepcin si lo
consideran apropiado, tal como pasa en PowerPC que dispone de una gran
cantidad de flags de excepcin, aunque bsicamente las excepciones se
pueden resumir en estas cinco.

Pg 199

Ensamblador del PowerPC con Mac OS X

MacProgramadores

Adems estos flag pueden ser flags retenidos (sticky), no serlo, o bien
existir un flag de retenido y su correspondiente de no retenido, a eleccin de
la implementacin.
Las cinco excepciones que define IEEE 754 son:
1. Invalid Operation. Ocurre si algn operando es invlido para la
operacin que estamos realizando. Esto ocurre siempre que un operando sea
un NaN. Tambin ocurre en los casos descritos en la Tabla A.10:
Operacin
Suma o resta
Multiplicacin
Divisin
Resto
Raz cuadrada
Comparacin

Invalid Operation
Suma o resta de infinitos. P.e. (+)+(-)
0*
0/0 /
x%y si y=0 x=
Con un operando negativo
Cuando los operandos son o NaN

Tabla A.10: Causas de una Invalid Operation

2. Underflow. Ocurre cuando el resultado de la operacin es demasiado


pequeo para ser almacenado en el formato utilizado. En este caso el nmero
toma el valor 0 y activa el flag de excepcin.
3. Overflow. Ocurre cuando el nmero obtenido es demasiado grande para
ser almacenado en el formato utilizado. En este caso el nmero toma el valor
y activa el flag de excepcin.
4. Divide-by-zero. Ocurre cuando dividimos un nmero entre cero. Tambin
ocurre cuando intentamos calcular el logaritmo de 0 que es -.
5. Inexact. Ocurre siempre que hay que redondear un nmero por no existir
una representacin exacta de ese nmero en punto flotante. Se usa porque el
programa puede estar interesado en saber si ha habido redondeo, los cuales
se vuelven especialmente perjudiciales cuando hay una acumulacin de
operaciones con redondeo.

Pg 200

Ensamblador del PowerPC con Mac OS X

MacProgramadores

6 Suma en punto flotante


Hay dos diferencias entre la aritmtica en punto flotante y la aritmtica
entera: Debemos mantener un campo para el signo, otro para exponente y
otro para la parte fraccionaria, y el resultado de una operacin en punto
flotante, habitualmente, se ha de redondear al nmero ms cercano
representable en el formato utilizado.

6.1 Redondeo
Con el fin de poder desarrollar software que se pueda ejecutar de la forma
ms homognea posible en distintas plataformas, el estndar del IEEE 754 ha
definido una regla respecto a cmo deben de realizarse las operaciones
aritmticas entre nmeros en punto flotante:

El resultado de una operacin aritmtica entre dos nmeros en punto


flotante, ha de ser el mismo que si primero se realizase la operacin con
precisin infinita, y despus se redondease ese resultado a un nmero
representable en el formato que estemos utilizando, usando el mtodo de
redondeo que est actualmente activo.
Esta regla que en principio parece difcil de cumplir, por la dificultad que tiene
un ordenador para realizar clculos con precisin infinita, no es tan difcil
como parece, de hecho, veremos que podemos obtener los resultados que
pide la regla, con slo un poco ms de esfuerzo.
En el caso de la suma, para obtener el resultado de la forma pedida lo nico
que tenemos que hacer es aadir dos bits de guarda al final de los registros
sumadores, y un bit de retencin (stricky bit). Veamos cmo se hace
esto.
Para facilitar el estudio vamos a suponer que tenemos un sistema de punto
flotante decimal con tres bit para la mantisa. Hay dos formas de redondeo
que se pueden presentar durante la suma:
El primer caso requiere redondeo debido al acarreo de salida a la izquierda.
Por ejemplo:
2,34*102
8,51*102 +

10,85*102 > Redondea a 10,8*102


El segundo caso requiere redondeo debido a exponentes desiguales, Por
ejemplo:

Pg 201

Ensamblador del PowerPC con Mac OS X

MacProgramadores

2,34*102
2,56*100 +

2,3656*102 > Redondea a 2,37*102


De hecho es posible que se den a la vez ambas formas:
9,51*102
6,42*101 +

10,152*102 > Redondea a 10,2*102


En cada uno de estos casos la suma se debe calcular con ms dgitos con el
fin de realizar correctamente el redondeo. Se ha demostrado que para que el
resultado de una suma en punto flotante sea el mismo que si redondesemos
el resultado de una suma con precisin infinita, basta con disponer de dos bits
adicionales a la derecha de los registros del sumador, llamados bits de
guarda.
La situacin peor sera una situacin como esta:
4,5674*100
2,5001*10-4 +

4,56765001*100 > Redondea a 4,5677*100


Aunque aqu pudiera parecer que se necesita mantener doble nmero de
dgitos para realizar un redondeo correcto, ya que el 1 ms a la derecha de
2,5001 determina si el resultado es 4,5676 4,5677, despus de una
pequea reflexin se puede ver que slo es necesario saber si hay o no ms
dgitos distintos de cero pasadas las posiciones de guarda, esta informacin
se puede almacenar en un slo bit llamado bit de retencin (stricky bit), que
se implementa examinando cada dgito que est despreciado debido a un
desplazamiento. Tan pronto como aparece un dgito distinto de cero, el bit de
retencin se pone a 1 y permanece con este valor. Para implementar el
redondeo al par ms cercano simplemente aadimos el bit de retencin a la
derecha del dgito ms a la derecha justo antes de redondear.

6.2 El algoritmo de la suma


Las notaciones ei y mi se utilizan aqu para referirnos al exponente y la
mantisa desempaquetados del nmero en punto flotante ai. Suponiendo que
los nmeros en punto flotante a1 y a2 no contengan valores especiales, el
procedimiento bsico para sumarlos consta de cinco pasos:

Pg 202

Ensamblador del PowerPC con Mac OS X

MacProgramadores

1. Si e1<e2, intercambiar los operandos para que satisfagan la regla de


que d=e1-e20
2. Desplazar m2 a la derecha d posiciones con el fin de equiparar los
exponentes, es decir que e1=e2. Dicho con ms precisin, poner m2
alineado a la izquierda de un registro con |m|+2 bits, siendo |m| el
nmero de bits de la fraccin en la notacin utilizada, al que sumamos
2 bits de guarda. Despus desplazamos a la derecha los bits d veces y,
si durante el desplazamiento, por la derecha del registro sale algn 1
activamos el bit de retencin
3. Aadir el bit de retencin a m2
4. Sumar m1+m2 as puestos en registros de |m|+2 bits, depositando el
resultado en un registro de |m|+3 bits. Si hubiese acarreo en el bit
ms significativo durante la suma desplazar una posicin a la derecha
el resultado as obtenido y aumentar en una unidad el exponente del
resultado.
5. Redondear el resultado usando el modo de redondeo que est activo
para que quepa en un registro de |m| bits.
Ejemplo: Vamos a ver como procede el algoritmo sobre un nmero en
notacin flotante decimal con mantisa de 5 dgitos. Para ello usaremos los
valores del ejemplo anterior a1=4,5674*100 y a2=2,5001*10-4
En el paso 1 e1=0 y e2=-4 con lo que d=4 y no es necesario intercambiarlo.
En el paso 2 los dgitos quedan como:
m1= 4567400
m2= 0000250
Quedando como bits de guarda de a2 5 y 0, y como bit de retencin el or
binario de 0,0,1 que es 1.
En el paso 3 aadimos el bit de retencin a m2
m1= 4567400
m2= 0000251
En el paso 4 sumamos obteniendo:
m3= 04567651
Al no haber habido acarreo en el dgito ms significativo no hace falta
desplazar, con lo que en el paso 5 tras redondear obtenemos:
a3= 4,5677*100

Pg 203

Ensamblador del PowerPC con Mac OS X

MacProgramadores

Vemos que el resultado es el mismo que si hubiramos usado un sumador de


precisin infinita y luego hubiramos redondeado, con lo que el resultado es
correcto.
El paso 4 involucra la suma de nmeros con signo y magnitud, y en s mismo
tiene tres pasos:
a. Convertir cualquier nmero negativo en su complemento a dos
b. Realizar una suma de |m|+4 bits en complemento a dos: |m|+3
bits de magnitud y 1 bit de signo
c. Si el resultado es negativo, realizar otra complementacin a dos
para volver a poner el resultado en la forma de signo y magnitud.

Pg 204

Ensamblador del PowerPC con Mac OS X

MacProgramadores

7 Multiplicacin en punto flotante


Vamos a ver cmo se hara la multiplicacin en punto flotante suponiendo que
los operandos de entrada no contienen valores especiales.
La multiplicacin en punto flotante es parecida a la multiplicacin entera que
vimos en el apartado 1.1.3. Debido a que los nmeros en punto flotante se
almacenan en forma de signo-magnitud, el multiplicador slo necesita tratar
con nmeros sin signo. Si las mantisas son nmeros sin signo de |m| bits,
entonces el producto puede tener hasta 2|m| bits y se debe redondear a un
nmero de |m| bits. Adems de multiplicar las mantisas se deben de sumar
los exponentes.
Sean a1 y a2 los nmeros a multiplicar de los cuales hemos desempaquetado
las mantisas m1 y m2 y los exponentes e1 y e2, el algoritmo que nos permite
realizar la multiplicacin de nmeros en punto flotante sera:
1. Usando el multiplicador del apartado 1.1.3 multiplicar las dos mantisas
m1 y m2 para obtener un producto de 2|m| bits en los registros P:A.
Adems los bits que se pierden por la derecha de A segn avanza el
algoritmo, se les debe de hacer un or binario con el bit de retencin.
2. Al acabar el algoritmo se suma el bit de retencin al P:A, lo cual ser
luego til para determinar el redondeo a aplicar.
3. Redondear el registro P:A de 2|m| bits a un registro de |m| bits
usando el modo de redondeo que est activo obteniendo as la nueva
mantisa m3.
4. Para calcular el exponente resultado e3, se calcula como la suma de los
exponentes de los operandos de entrada e1 y e2.
Ejemplo: Multiplicar los nmeros en punto flotante decimal a1=67,45*102 y
a2=34,98*100 usando una mantisa de |m|=4 bits
Primero multiplicamos las mantisas obteniendo el resultado en un registro de
8 bits:
67,45
x 34,98

2359,4010
Ahora redondeamos el nmero obteniendo la mantisa resultado m3=2359
El exponente resultado se obtiene como la suma de los exponentes de
entrada e1 e2, luego e3=2+0=2
Finalmente tenemos que el producto 67,45*102*34,98*100=2359*102
Pg 205

Ensamblador del PowerPC con Mac OS X

MacProgramadores

8 Divisin y resto en punto flotante


Podemos obtener el algoritmo de la divisin en punto flotante a partir del
algoritmo de la divisin de enteros que vimos en el apartado 1.1.4 de forma
similar a como hemos obtenido el algoritmo de multiplicacin en punto
flotante a partir del algoritmo de multiplicacin de enteros. Adems este
algoritmo nos proporciona el resto de la divisin el cual es til a la hora de
hacer los redondeos.
Sea a1 el dividendo y a2 el divisor desempaquetados sus respectivas mantisas
m1 y m2 y sus exponentes e1 y e2. El algoritmo para calcular a3=a1/a2 sera el
siguiente:
1. Usando el divisor de enteros del apartado 1.1.4 dividir las dos mantisas
m1 y m2 para obtener un cociente de |m| bits en el registro A y un
resto en el registro P.
2. Si el resto r3 as obtenido es mayor a la mitad del divisor entonces al
cociente se le suma uno, si no se deja igual, es decir, si 2*r3>a2
entonces a2=a2+1, si 2*r3=a2 se aplica el mtodo de redondeo que
est activo, si no a2 se deja como est.
3. Para calcular el exponente resultado e3, se calcula como e3=e1-e2.
Ejemplo: Dados los nmeros en punto flotante decimal a1=23,52*102 y
a2=12,75*100 calcular a1/a2 usando una mantisa de |m|=4 bits.
Primero dividimos las mantisas:
Dividendo=2352
Divisor=1275
Obteniendo:
Cociente = 1844
Resto = 900
Ahora como el resto es mayor a 1/2 cociente debemos sumar uno al cociente
obteniendo:
Cociente = 1845
Resto = 900
Por ltimo calculamos el exponente e3=e1-e2=2-0=2, con lo que finalmente
tenemos que el resultado de la divisin es:
(23,52*102) / (12,75*100) = 18,45*102
Pg 206

Ensamblador del PowerPC con Mac OS X

MacProgramadores

9 Comparaciones y conversiones
IEEE 754 define que un sistema en punto flotante debe de disponer de
operaciones que permitan comparar nmeros en punto flotante. La tricotoma
comparativa usual de los nmeros reales se extiende en el estndar para que
slo una de estas cuatro comparaciones sea cierta:
o
o
o
o

a<b
a>b
a=b
a y b no mantienen relacin de orden

Si a b valen NaN, entonces se dice que a no mantiene una relacin de


orden respecto a b, en caso contrario se cumple una de las otras tres
condiciones: <,>,=
IEEE 754 tambin requiere que el sistema de numeracin en punto flotante
disponga de las siguientes operaciones de conversin:
o
o
o
o
o

De punto flotante a entero


De entero a punto flotante
De punto flotante a entero, con el resultado en punto flotante
Entre todos los formatos de punto flotante que existan
Entre punto flotante binario y punto flotante decimal

Estas conversiones puede proporcionarlas el propio sistema hardware


(ensamblador) o bien proporcionarse por software (libreras numricas en C).

Pg 207

Ensamblador del PowerPC con Mac OS X

MacProgramadores

Apndice B
La segmentacin

Sinopsis:

Este apndice est pensado para lectores que desconozcan en que consiste la
segmentacin, la cual se menciona repetidamente en distintos contextos de
los temas anteriores.
Actualmente todos los microprocesadores de alto rendimiento que se fabrican
son segmentados. A continuacin vamos a ver en que consiste la
segmentacin y las ventajas de rendimiento que introduce.

Pg 208

Ensamblador del PowerPC con Mac OS X

MacProgramadores

1 Que es la segmentacin?
La segmentacin (pipelines) es un tcnica usada por los
microprocesadores ms avanzados (la mayora de los procesadores actuales:
Pentium, SPARC, PowerPC, Alpha,...) por la cual se solapa la ejecucin de
varias instrucciones.
En las mquinas segmentadas una instruccin se divide en varias etapas o
segmentos, cada una de las cuales corresponde con un ciclo de reloj. De
esta forma la segmentacin ejecuta las instrucciones como si fuera una
cadena de montaje, donde en cada ciclo de reloj se ejecuta una etapa de la
instruccin.
Lo importante de esta divisin en etapas es que nos permite tener varias
instrucciones ejecutndose a la vez, aunque cada una de ellas en una etapa
distinta, como si se tratase de una cadena de montaje de automviles, donde
hay varios automviles fabricndose en etapas distintas.
Aunque con variaciones dependiendo del microprocesador, las principales
etapas en que se descompone una instruccin segmentada suelen ser:

Fetch (FE). La instruccin que est en la direccin de memoria del IP


se recoge de memoria al micro. Adems incrementa el IP para que
apunte a la siguiente instruccin
Decode (DE). Decodifica la instruccin.
Dispatch (DI). Lee los operandos de los registros indicados en la
instruccin, o la direccin de memoria indicada en la instruccin, para
pasarlos a la unidad funcional que corresponda.
Execute (EX). La operacin indicada por la instruccin se ejecuta en
la unidad funcional que corresponda.
Write Back (WB). El resultado de ejecutar la instruccin se escribe
en los registros o en la memoria.

Normalmente el micro dispone de varias unidades funcionales, que son las


partes del microprocesador donde se realizan las operaciones indicadas en las
instrucciones. Aunque el nmero y tipo de unidades funcionales de un micro
dependen de la implementacin, de forma general podemos decir que un
micro dispone de los siguientes tipos de unidades funcionales:

Memory Unit. Se encarga de los accesos a memoria y de los saltos.


Fixed-Point Unit. Se encarga de las operaciones con enteros.
Floating-Point Unit. Se encarga de las operaciones con decimales.

Adems normalmente las unidades funcionales estn segmentadas con el fin


de que puede haber varias instrucciones usando la unidad funcional.
Segmentar las unidades funcionales es muy costoso, y hay microprocesadores
Pg 209

Ensamblador del PowerPC con Mac OS X

MacProgramadores

que no las segmentan, en cuyo caso esa unidad funcional slo puede ser
usada por una instruccin a la vez.
De cada uno de los tres tipos de unidades funcionales que existen, un micro
suele disponer de ms de una, con el fin de que varias instrucciones puedan
estar ejecutando en distintas unidades funcionales del mismo tipo, aunque si
la unidad funcional est segmentada, esto podra no ser tan necesario.
Visto esto podramos representar la ejecucin simultnea de instrucciones en
un micro segmentado tal como muestra la Figura B.1:
Instruccin
Instruccin
Instruccin
Instruccin
Instruccin
Instruccin

i
i+1
i+2
i+3
i+4

1
FE

2
DE
FE

3
DI
DE
FE

Ciclo de reloj
4
5
6
EX
WB
DI
EX
WB
DE
DI
EX
FE
DE
DI
FE
DE

WB
EX
DI

WB
EX

WB

Figura B.1: Ejecucin simultnea de instrucciones en un micro segmentado

En este caso suponemos que el microprocesador tiene 5 pipes, de aqu viene


el nombre de pipelines, que a veces se da a la segmentacin.
Aunque cada instruccin necesita 5 ciclos de reloj, la ejecucin simultnea de
las instrucciones nos permiten que cada instruccin tenga un tiempo medio
de ejecucin de 1 ciclo. Esto se formaliza de la siguiente forma:
Llamamos latencia, al tiempo (normalmente medido en ciclos de reloj)
necesario para ejecutar una instruccin.
Llamamos caudal (throughput) al nmero de instrucciones ejecutadas por
unidad de tiempo (tambin medido en ciclos de reloj).
Obsrvese que en el ejemplo anterior aunque la latencia de una instruccin es
de 5 ciclos, el caudal es de 1 ciclo, ya que en 5 ciclos hemos ejecutado 5
instrucciones. El lector debe de ser consciente de que en la Figura B.1 se
tardan 9 ciclos por el hecho de que el micro est arrancando y parando,
pero en circunstancias normales el micro permanece con los 5 pipes llenos.
Vemos que la segmentacin incrementa la productividad de las instrucciones,
pero no aumenta el tiempo de ejecucin de una instruccin individual, de
hecho la decrementa un poco debido a dos factores:
Por un lado la duracin de todas las etapas no es exactamente la misma, sino
que hay etapas que tardaran menos en terminarse que otras, pero el diseo
del procesador obliga a utilizar como ciclo de reloj el tiempo de la etapa ms
larga, con lo que es muy importante que las etapas estn perfectamente
Pg 210

Ensamblador del PowerPC con Mac OS X

MacProgramadores

equilibradas, pero en la prctica esto no siempre es posible y se suelen


producir reducciones en el rendimiento que no suelen superar, digamos, un
10%.
Por otro lado entre las etapas hay que dejar un pequeo tiempo de reajuste
de los cerrojos (latchs) que conectan las distintas etapas que es lo que se
llama el sesgo de reloj (clock skew).
Como ejemplo de esto ltimo vamos a estudiar la mejora de rendimiento que
conseguimos en una mquina gracias a la segmentacin. Supongamos que
tenemos una mquina no segmentada con 5 pasos por instruccin con
tiempos: 50ns, 50ns, 60ns, 50ns, 50ns. Suponer que debido al sesgo de reloj,
segmentar la mquina aade 5ns de gasto en cada etapa de la ejecucin.
Qu incremento de rendimiento se ganar con la segmentacin de esa
mquina en una mquina que disponga de 5 pipes?
La Figura B.2 (a) muestra la ejecucin de instrucciones sin segmentacin y la
Figura B.2 (b) la ejecucin de las mismas instrucciones con segmentacin.
260

260

260

50 50 60 50 50 50 50 60 50 50 50 50 60 50 50
Instruccin 1

Instruccin 2

Instruccin 3

(a) Ejecucin no segmentada


455
Instruccin 1
Instruccin 2
Instruccin 3

65 65 65 65 65
65 65 65 65 65
65 65 65 65 65

(b) Ejecucin segmentada


Figura B.2: Ejecucin de instrucciones con y sin segmentacin

Vemos que sin segmentar, el tiempo medio de ejecucin de una instruccin


es de:
50ns + 50ns + 60ns + 50ns + 50ns = 260ns
Luego 5 instrucciones se ejecutan en 5*260ns=1300ns
Mientras que en una mquina segmentada (suponiendo que no estamos
arrancando o parando) el tiempo de ejecucin de 5 instrucciones es:
5*65ns=325ns. Con lo que la mejora de rendimiento es de:
Pg 211

Ensamblador del PowerPC con Mac OS X

MacProgramadores

R=1300ns/325ns=4
Es decir se consigue un rendimiento 4 veces superior en la mquina
segmentada, y no las 5 veces tericas que veamos al principio.

2 Etapas multiciclo
No es prctico exigir que todas las etapas de una instruccin se ejecuten en
un solo ciclo de reloj, como por ejemplo en las operaciones de punto flotante.
Hacer esto significara aceptar un reloj lento.
En la prctica, una etapa de una instruccin puede duran varios ciclos de
reloj, por ejemplo las operaciones de suma y resta de entero se ejecutan en
un solo ciclo EX, mientras que la multiplicacin en coma flotante suele
consumir hasta 5 ciclos EX, y la divisin hasta 20 ciclos EX.
Luego la ejecucin de una instruccin de multiplicacin de punto flotante se
podra representar as:
FE DE DI EX EX EX EX EX WB
Obsrvese que esto hace que la unidad funcional de punto flotante
permanezca ocupada durante todos los ciclos que dura la etapa EX,
impidiendo que otra instruccin la use. Para evitarlo, se suelen aplicar dos
soluciones: Disponer de varias unidades funcionales de punto flotante, o bien,
segmentar la unidad funcional para que puedan entrar varias instrucciones de
punto flotante a tiempos distintos.
El mismo problema le encontramos en las instrucciones que acceden a
memoria, en las que cuando el dato accedido est en cach, la etapa de
lectura de memoria DI, o la de escritura en memoria WB se completan en un
solo ciclo, pero si el dato no esta en cach y hay que ir a memoria principal,
estas etapas pueden consumir ms de un ciclo.
FE DE DI DI DI EX WB
En este caso la unidad funcional de memoria tambin necesita estar duplicada
o segmentada para poder permitir a varias instrucciones trabajar en esta
unidad.

Pg 212

Ensamblador del PowerPC con Mac OS X

MacProgramadores

3 Los riesgos
Su instinto es correcto si encuentra difcil pensar que la segmentacin es tan
simple como esto, porque no lo es. En esta seccin vamos a comentar unos
problemas que surgen en la segmentacin llamados riesgos (hazards), que
impiden que se ejecute la siguiente instruccin del flujo de instrucciones
durante su ciclo de reloj designado. Los riesgos reducen el rendimiento de la
velocidad ideal lograda con la segmentacin. Hay tres tipos de riesgos:
1. Riesgos estructurales. Surgen de conflictos con los recursos
disponibles, cuando el hardware no puede soportar todas las
combinaciones posibles de instrucciones en ejecucin simultnea.
2. Riesgos por dependencia de datos. Surgen cuando una instruccin
depende de los resultados de una instruccin anterior, de forma que
una tiene que esperar al resultado de la otra.
3. Riesgos de control. Surgen de la segmentacin de los saltos y otras
instrucciones que cambian el IP.
Los riesgos en la segmentacin pueden hacer necesario detenerla. Una
detencin en una mquina segmentada requiere, con frecuencia, que
prosigan algunas instrucciones mientras que se retardan otras. Normalmente,
cuando una instruccin est detenida, todas las instrucciones posteriores a
esta instruccin tambin se detienen. Las instrucciones anteriores a la
instruccin detenida pueden continuar, pero no se cogen instrucciones nuevas
durante la detencin. Veremos algunos ejemplos de cmo operan las
detenciones en esta seccin. No se preocupe, no son tan complejas como
puede parecer!

3.1 Riesgos estructurales


Los riesgos estructurales se producen cuando diferentes instrucciones
acceden simultneamente a los mismos recursos. Para evitarlo hay que
segmentar las unidades funcionales y duplicar los recursos. Si alguna
combinacin de instrucciones no es posible ejecutarla simultneamente, se
produce un riesgo estructural, y el microprocesador detiene a la ltima
instruccin que emiti hasta que el riesgo desaparece.
Por ejemplo, un recurso que suele producir riesgos estructurales son los
puertos de memoria, muchas mquinas tienen un nico puerto de memoria
con lo que si una instruccin accede a memoria (lo cual puede llevar varios
ciclos) y otra instruccin tambin intenta acceder a memoria, sta ltima
queda detenida hasta que la primera acaba.

Pg 213

Ensamblador del PowerPC con Mac OS X

MacProgramadores

Instuccin
Instruccin
Instruccin
Instruccin
Instruccin
Instruccin

i
i+1
i+2
i+3
i+4

1
FE

2
DE
FE

3
DI
DE
FE

4
EX
DI
DE
FE

Ciclo de reloj
5
6
7
WB
EX
WB
DI
EX
WB
DE
stall DI
FE
DE

10

EX
DI

WB
EX

WB

Figura B.3: Ejemplo de stall en ejecucin segmentada

En la Figura B.3 se muestra una detencin (stall) que se produce cuando


en el sexto ciclo de reloj la instruccin i+1 est haciendo un almacenamiento
en memoria (stw) mientras que la instruccin i+3 intenta hacer una carga de
memoria (lwz), como ambas comparten el puerto de datos la segunda tiene
que esperar, lo cual retrasa un ciclo a todas las instrucciones que siguen a la
instruccin i+3.
Por qu permite el diseador riesgos estructurales?. Hay dos razones: Para
reducir el coste de fabricacin y para reducir la latencia de una unidad
funcional, ya que la segmentacin de algunas unidades funcionales aumentan
mucho su latencia porque sus etapas estn muy desequilibradas, y si la
segmentamos debemos de hacer que cada etapa dure lo que un ciclo de reloj.
Si los riesgos estructurales no se presentan con frecuencia, puede no merecer
la pena el coste de evitarlos. Adems con frecuencia merece ms la pena
disear una unidad funcional no segmentada, pero con una latencia menor.

3.2 Riesgos por dependencia de datos


Los riesgos por dependencia de datos se presentan cuando la segmentacin
cambia el orden de acceso a los operandos respecto al orden secuencial
normal que se producira si no hubiera segmentacin. Los riesgos se pueden
producir tanto durante el acceso por parte de dos instrucciones a los registros
como durante el acceso a memoria.
Considrese la ejecucin de estas dos instrucciones:
add r1,r2,r3
sub r4,r1,r5
La instruccin sub tiene como dato de entrada r1, que es el dato de salida
de la instruccin add. Como muestra la Figura B.4, la instruccin add escribe
el valor de r1 en la etapa WB, mientras que la instruccin sub lee el valor del
registro en la etapa DI.

Pg 214

Ensamblador del PowerPC con Mac OS X

Instruccin
add

MacProgramadores

Ciclo de reloj
4
5
6

FE

DE

DI

EX

WB
escri

sub

FE

DE

DI
lee

EX

WB

Figura B.4: Problema en la ejecucin segmentada de instrucciones

Luego si no hacemos nada para impedirlo, sub leer un dato errneo. En este
caso, el microprocesador tiene que detener a la instruccin sub hasta que el
dato este disponible, como muestra la siguiente Figura B.5.
Instruccin
add

Ciclo de reloj
4
5
6

FE

DE

DI

EX

WB

FE

DE

stall

stall

sub

EX

WB

escri

DI
lee

Figura B.5: Solucin para los riesgos en la ejecucin segmentada de instrucciones

Lo cual provoca una perdida de dos ciclos de reloj.


Para reducir el efecto de los riesgos de dependencia de datos, una tcnica
muy usada por los microprocesadores es el adelantamiento de datos
(forwaring o bypassing), que consiste en que el resultado de una
instruccin se enva directamente a otra instruccin sin necesidad de
almacenar ese dato el registro o memoria. De esta forma la instruccin
detenida puede leer antes este dato y perder menos ciclos de reloj.
Por ejemplo, en le caso anterior, el microprocesador se podra cablear para
que la salida de EX de la primera instruccin pasase directamente a la entrada
de DI de la segunda instruccin sin esperar a la etapa WB de la primera
instruccin, de esta forma, como muestra la Figura B.6, se ganara un ciclo de
reloj.
Instruccin
add
sub

Ciclo de reloj
4
5
6

FE

DE

DI

EX

WB

FE

DE

stall

DI lee

escri

EX

WB

Figura B.6: Adelantamiento de datos en la ejecucin segmentada

Los riesgos por dependencia de datos pueden clasificarse en tres grupos,


dependiendo del orden de los acceso de lectura/escritura en las instrucciones:

RAW (Read After Write). La instruccin j trata de leer un operando


antes de que una instruccin anterior i lo haya escrito, con lo que j
Pg 215

Ensamblador del PowerPC con Mac OS X

MacProgramadores

tomara el valor antiguo. Este es el tipo de riesgo de dependencia de


datos ms comn y es el que aparece en el ejemplo anterior.
add r1,r2,r3
sub r4,r1,r5
Para evitar este tipo de riesgos se recomienda siempre que sea posible
intercalar una instruccin sin dependencias en medio. Por ejemplo, en
nuestro ejemplo podemos intercalar una instruccin sin dependencias
as:
add r1,r2,r3
add r6,r7,r8
sub r4,r1,r5

WAW (Write After Write). La instruccin j intenta escribir un


operando antes de que sea escrito por otra instruccin anterior i. Este
riesgo es menos comn ya que implica que la instruccin i gaste ms
ciclos de reloj que la instruccin j, ya que si ambas consumieran el
mismo nmero de ciclos i siempre escribira (llegara a la etapa WB)
antes de escribir j.
Por ejemplo si tenemos:
divf fr2,fr3,fr4
addf fr2,fr5,fr6
Al ser ms rpida addf que divf, aunque addf empezase despus,
escribira en fr2 antes de que divf.
Para evitar este tipo de riesgos basta con renombrar los operandos:
divf fr2,fr3,fr4
addf fr7,fr5,fr6

WAR (Write After Read). La instruccin j intenta escribir un


operando antes de que sea ledo por una instruccin anterior i, con lo
que i leer un valor errneo.
Este es el tipo ms raro de dependencias, y para que se produzcan la
instruccin j debe de llegar a su etapa WB (escribir resultados) antes
de que la instruccin anterior i llegue a su etapa DI (leer operandos).
A las dependencia de tipo WAR tambin se las llama
antidependencias. Al igual que la dependencia WAW, las
antidependencias son falsas dependencias que no se deben a una

Pg 216

Ensamblador del PowerPC con Mac OS X

MacProgramadores

dependencia real de datos, sino a un conflicto de recursos y se puede


eliminar renombrando los registros. Por ejemplo si tenemos:
lwz r2,0(r3)
addi r3,r4,r5
Si hay un fallo de cach, la instruccin lwz se puede retrasar durante
varios ciclos, los cuales aprovecha addi para adelantarse en su
escritura.
Para solucionar la antidependencia renombramos los registros as:
lwz r2,0(r3)
addi r4,r5,r6
Es evidente que el caso RAR (Read After Read) no es un riesgo, ya que
ambas instrucciones leen el mismo dato sin modificarlo.
Afortunadamente todos los riesgos de dependencia de datos se pueden
comprobar durante la etapa DE, y si existe un riesgo la instruccin es
detenida antes de ser emitida.

3.3 Riesgos de control


Los saltos provocan retrasos en la segmentacin mayores a los que provocan
los riesgos estructurales o de dependencia de datos, ya que la direccin
efectiva de un salto no se conoce hasta la fase WB, que es la que modifica el
IP, lo cual da lugar un retraso considerable en la segmentacin tal como
muestra la Figura B.7:
Instruccin
addi
b
subi

1
FE

2
DE
FE

Ciclo de reloj
4
5
6
EX
WB
DI
EX
WB
stall
stall
stall

3
DI
DE
FE1

FE

DE

Figura B.7: Retraso producido por un salto

Obsrvesele que en 1 la instruccin de la posicin IP+4 se carga, pero al


decodificar b en la etapa DE y ver que es un salto se detiene y en el ciclo 7 se
vuelve a leer la instruccin que est en la direccin destino del salto.
Para evitar retrasos tan grandes se utiliza la tcnica del adelantamiento de
datos (vase el apartado 3.2), la cual nos permite adelantar la direccin
efectiva de salto en la etapa DE, tal como muestra la Figura B.8:

Pg 217

Ensamblador del PowerPC con Mac OS X

Instruccin
addi
b
subi

1
FE

2
DE
FE

3
DI
DE
FE1

MacProgramadores

Ciclo de reloj
4
5
6
EX
WB
DI
EX
WB
FE
DE
DI

EX

WB

Figura B.8: Ejemplo de adelantamiento de datos en los saltos

Obsrvese que con un correcto cableado para el adelantamiento de datos


podemos conseguir perder un slo ciclo en lugar de 4 ciclos.

3.4 Saltos sin resolver


Los saltos se pueden dividir en tres categoras:

Saltos incondicionales
Saltos condicionales, los cuales seleccionan la siguiente instruccin a
ejecutar entre 2 alternativas dependiendo de si se cumple o no una
condicin que se encuentra en uno de los campos del registro CR
Saltos multidestino, son saltos en los que, al igual que los
condicionales, evalan una condicin puesta en un campo de CR, pero
la direccin de destino del salto es tambin variable (estar en el
registro LR o CTR), con lo que puede haber muchos destinos.

Se dice que un salto est sin resolver (unresolved) cuando o bien la


condicin, o bien la direccin destino del salto no se conocen cuando se va a
ejecutar el salto.
Los saltos sin resolver nunca se producen en los saltos incondicionales, pero
s que se producen en los dems tipos de saltos, veamos un ejemplo:
lis r2,ha16(dato)
li r2,lo16(dato)
lwz r4,0(r2)
cmpwi cr0,r3,0
beq alla
aqui:
subi r4,r4,1
alla:
addi r4,r4,1
El orden de ejecucin de las instrucciones segmentadas es ahora el que se
muestra en la Figura B.9:

Pg 218

Ensamblador del PowerPC con Mac OS X

Instruccin
lwz
cmpwi
beq

1
FE

2
3
DE DI
FE DE
FE1

MacProgramadores

Ciclo de reloj
4
5
6
7
8
EX
WB
DI
EX
WB
stall stall FE
DE DI
stall stall stall stall FE

10

11 12

EX
DE

WB
DI EX

WB

Figura B.9: Orden de ejecucin de las instrucciones del ejemplo

Aun con adelantamientos de datos acabamos teniendo un retraso de 4 ciclos


de reloj, esto es as porque la instruccin cmpwi no calcula la condicin del
registro CR hasta la etapa WB. El primer adelantamiento evita que beq tenga
que esperar a la etapa WB de cmpwi, el segundo adelantamiento permite que
la etapa DE de beq actualice el IP para poder recoger la siguiente instruccin
ejecutar.
En definitiva, los saltos sin resolver enlentecen mucho la ejecucin de
instrucciones segmentadas, y teniendo en cuenta que entre el 11% y el 18%
de las instrucciones de un programa suelen ser saltos, el retraso global es
considerable.
A continuacin vamos a comentar varias soluciones que evitan estos
problemas.

3.5 Solucin software a los saltos sin resolver


Una primera solucin es que el programador planifique las instrucciones,
es decir, que coloque las instrucciones en un orden que evite que los saltos
estn sin resolver cuando llegue el momento de ejecutarlos.
Por ejemplo, en le programa anterior podemos adelantar la instruccin cmpwi
as:
cmpwi cr0,r3,0
lis r2,ha16(dato)
li r2,lo16(dato)
lwz r4,0(r2)
beq alla

aqui:
subi r4,r4,1
alla:
addi r4,r4,1

Ahora cuando se fuera a ejecutar la instruccin beq, el salto estara resuelto


tal como muestra la Figura B.10:

Pg 219

Ensamblador del PowerPC con Mac OS X

Instruccin
cmpwi
lis
li
lwz
beq

1
FE

2
DE
FE

3
DI
DE
FE

4
EX
DI
DE
FE

MacProgramadores

Ciclo de reloj
5
6
7
8
9
10
WB
EX WB
DI EX WB
DE DI EX WB
FE DE DI EX WB
FE1 FE DE DI EX

11

12

WB

Figura B.10: Ejecucin con salto resuelto

En este caso slo se perdera 1 ciclo de reloj en el sexto ciclo de la ltima


instruccin, en vez de perderse 4 ciclos de reloj, como pasaba cuando el salto
estaba sin resolver.
Vamos a ver ejemplos de cmo resolver el problema de los saltos sin resolver
en las estructuras de control de flujo ms conocidas.

3.5.1 Estructura if
En las estructuras if y if-else normalmente, como muestra la Figura B.11,
siempre vamos a poder intercalar instrucciones entre la comparacin y el
salto:
Salto sin resolver

Solucin

instrucciones1

cmpw cr0,r2,0
beq alla

instrucciones2

cmpw cr0,r2,0

instrucciones1

beq alla

instrucciones2

Figura B.11: Intercalar instrucciones entre la comparacin y el salto

3.5.2 Estructura while


En los bucles while (tambin llamados 0-n) la solucin no siempre es
posible, ya que pasa por intercalar instrucciones del bloque
instrucciones2 entre la operacin de comparacin y de salto, tal como
muestra la Figura B.12.
El poder adelantar estas instrucciones o no depende de los efectos laterales
que esto implique, es decir, slo podemos adelantar instrucciones que si
finalmente el salto es efectivo no modifiquen el estado de las variables del
programa, esto sera cierto si las variables o registros con los que han

Pg 220

Ensamblador del PowerPC con Mac OS X

MacProgramadores

trabajado las instrucciones son slo de uso interno al bucle. La Figura B.12
muestra un ejemplo de adelantamiento de instrucciones en un bucle while.
Salto sin resolver

instrucciones1

inicio: cmpw cr0,r2,0


beq fin

instrucciones2

b inicio
fin:

Solucin

instrucciones1

inicio: cmpw cr0,r2,0

instrucciones2

beq fin

instrucciones2

b inicio

fin:
Figura B.12: Adelantar instrucciones en un bucle while

3.5.3 Estructura do-while


En las estructuras do-while (o 1-n) la solucin pasa por adelantar la
comparacin, realizndola lo antes posible en el cuerpo del bucle, pero al
igual que antes esto no siempre es posible, ya que para poder realizar la
comparacin debemos de conocer el resultado que vamos a comparar, que
normalmente se calcula dentro del bucle. La Figura B.13 muestra un ejemplo
de adelantamiento de instrucciones en un bucle while
Salto sin resolver

Solucin

instrucciones1

inicio:

fin:

instrucciones2

cmpw cr0,r2,0
beq inicio

instrucciones1

inicio:

fin:
Figura B.13: Adelantar instrucciones en un bucle while

Pg 221

instrucciones2

cmpw cr0,r2,0

instrucciones2

beq inicio

Ensamblador del PowerPC con Mac OS X

MacProgramadores

3.5.4 Estructura for


En estas estructuras se pueden eliminar los saltos sin resolver usando saltos
condicionales en funcin del registro CTR, que son saltos que siempre estn
resueltos.

instrucciones1

mtctr r5
inicio:

instrucciones2

bdnz inicio
fin:

Esto es posible siempre que el nmero de repeticiones se conozca antes de


meternos en el bucle.
Tpicamente el contador de un bucle for no suele contar hacia atrs hasta el
0, sino que suele contar desde 1 a n, aun as podemos usar un bucle cuya
condicin de salida est en el contador, y llevar otra variable contador aparte:
li r3,1 ; Desde 1
li r4,n ; Hasta n
subi r5,r4,1
mtctr r5 ; Fijamos el contador hasta 0
inicio:

instrucciones2

add r3,r3,1
bdnz inicio
fin:

3.6 Solucin hardware a los saltos sin resolver


La planificacin de instrucciones es muy efectiva para resolver el problema de
los saltos sin resolver, pero no siempre es posible: o bien porque el
programador no la hace, o bien porque la lgica del programa no permite
hacerla. En estos casos todava podemos aprovecharnos de soluciones
hardware, como las que vamos ver.
Cuando el procesador encuentra una instruccin de salto, escanea los pipes
en ejecucin para determinar si alguna de las instrucciones que se estn
ejecutando puede modificar el estado del campo CR usado, o bien de los
registros LR y CTR si estos estn en uso por la instruccin de salto, si no es
as el salto se resuelve inmediatamente, pero si se encuentra dependencia, el
salto se considera sin resolver, y el hardware en vez de detenerse lo que hace
Pg 222

Ensamblador del PowerPC con Mac OS X

MacProgramadores

es que ejecuta especulativamente una de las ramas. Despus cuando la


condicin del salto se resuelve, si la prediccin es correcta, la ejecucin
simplemente contina, y sino el procesador debe volver al estado en el que
estaba cuando se inicio la ejecucin especulativa, y coger el otro camino.
Para evitar la penalizacin en tiempo que supone restaurar los registros
cuando el camino cogido no es el correcto los procesadores suelen usar los
llamados shadow registers, que son registros en los que se van guardando
los resultados de las instrucciones cuando se est ejecutando de forma
especulativa, de forma que si al final la prediccin es correcta su contenido se
copia a los registros reales, y sino su contenido se descarta.
Los algoritmos que usa el procesador para decidir si llevar a cabo o no el salto
se clasifican en dos grupos:
1. Algoritmos de prediccin estticos. Consisten en que el programador
codifica la instruccin de salto indicando si es ms probable que el salto sea
efectivo o si no, para ello utiliza el bit y del operando BO que veamos en el
Tema 2 y que volvemos a reproducir en la Tabla B.1:
BO
0000y
0001y
001zy
0100y
0101y
011zy
1z00y
1z01y
1z1zz

Descripcin
Decrementa el registro CTR y
es FALSE
Decrementa el registro CTR y
es FALSE
Salta si la condicin es FALSE
Decrementa el registro CTR y
es TRUE
Decrementa el registro CTR y
es TRUE
Salta si la condicin es TRUE
Decrementa el registro CTR y
Decrementa el registro CTR y
Salta siempre

despus salta si CTR0 y la condicin


despus salta si CTR=0 y la condicin
despus salta si CTR0 y la condicin
despus salta si CTR=0 y la condicin
despus salta si CTR0
despus salta si CTR=0

z Es un bit que se reserva para el futuro, y que de momento debe ser siempre 0
y Indica si es ms probable que el salto se realice a que no se realice
Tabla B.1: Configuracin del operando BO

El campo y se activa cuando el programador ve ms probable que el salto se


lleve a cabo que no, y se deja a cero para indicar que no se lleve a cabo el
salto especulativamente.
Por defecto se recomienda dejarlo a 0, ya que es ms fcil para el procesador
especular que el salto no se realizar.

Pg 223

Ensamblador del PowerPC con Mac OS X

MacProgramadores

Este bit es especialmente til a la hora de implementar bucles, ya que los


bucles tienen una mayor probabilidad de repetirse que de no hacerlo, luego si
nosotros estamos implementando un bucle podemos indicar al procesador
nuestra opinin usando este bit.
Por ejemplo para implementar el bucle do-while anterior podramos hacerlo
as:

inicio:

instrucciones1

instrucciones2

cmpw cr0,r2,0
bc 13,2,inicio

fin:
El operando BO vale 13=0b01101 donde hemos activado el bit y, ya que el
salto es ms probable que se repita. El operando BI vale 2=0b00010
indicando que queremos comprobar la igualdad a 0 del registro r2 en el
campo cr0.
Otra forma de indicar en las instrucciones de salto si creemos ms probable
que se produzcan o no es aadir al nombre de la instruccin un - (ms
probable que no se realice) o un + (ms probable que si se realice). Por
ejemplo:
bucle:
cmpwi r3,100
beq+ bucle
Indica que lo ms probable es que se realice el salto.
2. Algoritmos de prediccin dinmicos. Consisten en que es el
procesador el que decide si ejecutar especulativamente el salto o no. Aunque
inicialmente el procesador puede hacer caso al bit de prediccin depositado
por el programador, en microprocesadores ms avanzados el propio
procesador puede usar mecanismos para decidir si el salto especulativo que
va a dar es el ms correcto.
Bsicamente existen dos tcnicas de prediccin dinmica:
Branch Target Address Cache (BTAC). El procesador almacena la
direccin destino de los ltimos saltos realizados en una memoria cach, de
forma que si esa instruccin de salto se vuelve a intentar ejecutar otra vez, el
procesador busca la instruccin en su cache y mira a ver que ocurri la vez
anterior para tomar ese camino. De esta forma si el salto especulativo tiene
xito se puede conseguir una prdida de 0 ciclos.
Pg 224

Ensamblador del PowerPC con Mac OS X

MacProgramadores

Las BTAC son tablas en las que se almacena la direccin de la instruccin de


salto y su direccin de salto efectivo ms o menos de la forma que se
muestra en la Figura B.14:
Direccin de la
instruccin de
salto

Direccin a la que
salto la ltima vez

Figura B.14: Estructura de una Branch target Address Cache

Branch History Tables. El procesador mantiene un registro de las ltimas


acciones realizadas por una instruccin. Estas tablas suelen tener la forma de
la Figura B.15:
Direccin de la
instruccin de salto

Estado

Figura B.15: Estructura de una Branch History Table

Donde a cada instruccin de salto se le asocian 2 bits en el campo de estado.


Los cuatro estados de los 2 bits asociados a la instruccin de salto pueden
tomar los valores:
00
01
10
11

Strongly Taken
Weakly taken
Weakly Not taken
Strongly Not Taken

La siguiente Figura B.16 muestra la relacin entre estos 4 estados:


T
NT

Strongly
Not
Taken

NT

T
Weakly
Not
Taken

NT

Figura B.16: Estado de los bits de salto

Pg 225

T
Weakly
Taken

NT

Strongly
Taken

T - Taken NT- Not taken

Ensamblador del PowerPC con Mac OS X

MacProgramadores

Lo importante es que para que el salto pase de efectivo a no efectivo, deben


de producirse dos fallos consecutivos, lo cual se hace as porque normalmente
los bucles se llevan a cabo un nmero de veces hasta que la condicin se deja
de cumplir, pero s otro vez pasase el flujo del programa por el bucle, el bucle
seguira considerndose en el mismo estado (aunque weakly) con lo que si
ahora el bucle se repite, que es lo ms probable, el estado vuelve al estado
strongly, en el que permanece durante todas las repeticiones. De esta forma
se consigue que los saltos de los bucles se predigan siempre correctamente,
excepto cuando la condicin de repeticin se deja de cumplir.
Una ltima solucin hardware a los saltos sin resolver que estn empezando a
usar los procesadores ms avanzados es el scheduling, que consiste en que
el procesador puede pasar las instrucciones a ejecucin en orden distinto al
que estn escritas en el programa. El procesador puede decidir cambiar el
orden de ejecucin de las instrucciones en base a dos criterios: El primero es
que el procesador puede leer adelantadamente varias instrucciones en el
llamado fetch buffer y decide si pasar las instrucciones a ejecucin en el
orden que estn llegando o bien adelantar alguna de ellas si encuentra que
esa instruccin va a producir una detencin. El segundo criterio es que el
procesador puede detectar dependencias, y si las encuentra detiene una
instruccin aunque deja pasar a otras con las que no hay dependencias.

3.7 La serializacin
Para mantener al procesador y a la memoria en un estado consistente con el
modelo de ejecucin secuencial, en ciertas situaciones el procesador se ve
obligado a serializar la ejecucin de una instruccin entera, deteniendo la
ejecucin de todas las dems instrucciones hasta que esta acaba.
Esto ocurre por ejemplo cuando hay ms de una unidad funcional de punto
fijo donde recursos comunes no duplicados como el registro XER van a ser
actualizados. Por esta razn las instrucciones que modifican este registro
llevan un nombre especial como addc o addo, las cuales pueden ejecutar
considerablemente ms lento que la instruccin que no modifica este registro
(add). Lo mismo ocurre con las instrucciones con punto (.) como por
ejemplo add., que al escribir en le campo CR0 puede necesitar ejecutar
secuencialmente.
Para evitar detenciones de este tipo debido a un conflicto en el campo CR0,
es recomendable que los saltos cercanos utilicen otros campos (CR1,...CR7)
para evaluar sus condiciones.

Pg 226

Ensamblador del PowerPC con Mac OS X

MacProgramadores

4 Ms all de la segmentacin
Se denomina procesadores supersegmentados a los procesadores donde la
segmentacin es ms profunda (pueden llegar a tener 10 etapas, en lugar de
las 5 antes descritas), y en las que todas las unidades funcionales se
encuentran segmentadas.
Este trmino no debe de ser confundido con el de procesador superescalar,
que es un procesador capaz de emitir varias instrucciones en el mismo ciclo
de reloj, normalmente de 2 a 4 instrucciones sin embargo si las instrucciones
del flujo de instrucciones son dependientes, o no cumplen ciertos criterios,
slo se emitir la primera instruccin de la secuencia. La mayora de los
PowerPC actuales son superescalares.
Actualmente estn surgiendo mquinas, como por ejemplo Itanium de Intel a
las que se llama VLIW (Very Long Instruction Word) que se caracterizan
porque una instruccin est formada por la unin de varias instrucciones (3
en concreto en el caso de Itanium) las cuales se agrupan en lo que llaman un
bundle, y las 3 se emiten a la vez. Lo importante de agrupar las
instrucciones en bundles es que el compilador puede colocar en cada bundle
instrucciones que no tengan dependencias entre s con el fin de facilitar su
ejecucin simultnea sin detenciones. Esta solucin consigue mejor
rendimiento que las mquinas superescalares tradicionales, a cambio de
aumentar la complejidad de la programacin, ya que el programador tiene
que pensar en grupos de instrucciones (bundles) ms que en instrucciones
secuenciales.
Por ltimo estn las llamadas mquinas vectoriales, que usan a la vez
ambas tcnicas. Habitualmente son supersegmentadas, y tienen potentes
operaciones vectoriales que se pueden considerar equivalentes a emitir
mltiples operaciones independientes.

Pg 227

Ensamblador del PowerPC con Mac OS X

MacProgramadores

Referencias
[DEVTOOLS] Herramientas de desarrollo de Apple
http://developer.apple.com/tools/index.html
[MICROIBM] Microprocesadores de IBM
http://www-1.ibm.com/servers/eserver/
pseries/hardware/workstations/ (Workstations de 32 bits)
http://commerce.www.ibm.com/content/home/
shop_ShopIBM/en_US/eServer/pSeries/pSeries.html
(Servidores de 64 bits de alto rendimiento)
[MICROMOTOROLA] Microprocesadores de Motorola
http://www.motorola.com/SPS/PowerPC/teksupport
/teklibrary/
[UNDERFLOW] Underflow and the Reliability of Numerical Software, James
Demmel, y Combatting the effect of Underflow and Overflow in
determining Real Roots of Polynomials de S. Linnainmaa.
[WARREN] Changing Division by a constant to Multiplication in Twos
Complement Arithmetic. Warren, Henry S., Jr., IBM Research Report:
RC 18601 [1992].

Pg 228

S-ar putea să vă placă și