13.07.2015 Views

Ensamblador del PowerPC con Mac OS X

Ensamblador del PowerPC con Mac OS X

Ensamblador del PowerPC con Mac OS X

SHOW MORE
SHOW LESS
  • No tags were found...

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

2013Utvecklingen av an<strong>del</strong> specialistsjuksköterskor de senaste 15 årenAn<strong>del</strong>en sjuksköterskor som har en specialistsjuksköterskeexamen har minskat från 65 procenttill 47 procent under de senaste 15 åren. Antalet specialistsjuksköterskor har också minskatstadigt under samma period.År 1995 2000 2005 2010Antal sjuksköterskor 85 098 87 857 96 654 103 769Antal specialistsjuksköterskor 55 569 51 256 50 003 48 434An<strong>del</strong> specialistsjuksköterskor 65 % 58 % 52 % 47 %Sysselsatta inom vård och omsorg (S<strong>OS</strong> 2012)Stora pensionsavgångar och bristMe<strong>del</strong>åldern bland specialistutbildade sjuksköterskor är hög. År 2010 var 46 % av samtligasysselsatta specialistsjuksköterskor över 55 år (S<strong>OS</strong> 2012). Detta innebär att storapensionsavgångar kan förväntas under de närmaste åren. Ett av de vårdområden däravsaknaden av specialistsjuksköterskor är extra stor är äldrevården. Av de sjuksköterskor somarbetar inom särskilt boende i kommunal äldrevård har endast 1,6 % specialistutbildning medinriktning mot vård av äldre (S<strong>OS</strong> 2012).Specialistsjuksköterskans kunskapJu fler sjuksköterskor som <strong>del</strong>tar i patientnära vård och omsorg desto färre komplikationer blirdet för de personer som vårdas. Det är också i studier visat att fler sjuksköterskor med högkompetens resulterar i färre vårddagar, lägre dödlighet och lägre kostnader (SSF 2009). År2010 publicerade Royal College of Nursing (RCN) en artikel om specialistsjuksköterskor ochdess bety<strong>del</strong>se för vården. Artikeln lyfter fram direkta och indirekta för<strong>del</strong>ar medspecialistsjuksköterskor till exempel minskat antal remisser, kortare sjukhusvistelser ochminskade risker för komplikationer efter operation.Specialistsjuksköterskeutbildningen inom universitet/högskolaUtvecklingen av kunskapsmassan inom omvårdnadsämnet har ökat kraftigt under de senaste30 åren. Idag finns det över 1000 disputerade sjuksköterskor och ett 60 tal professorer. Dennautveckling har på många sätt revolutionerat vården och omvårdnadsinterventioner spelar endirekt roll för vårdens kvalitet och den enskilde patientens möjlighet till hälsa.Specialistutbildningens anknytning till högskola och akademi är nödvändig för att upprätthållaoch säkerställa denna utveckling och därmed kvaliteten inom yrket och vården. Det är ocksåav största vikt att specialistutbildningen fortsatt är meriterande för forskarutbildning.Sjuksköterskans specialistutbildning idagSjuksköterskans specialistutbildning ges vid universitet/högskola på avancerade nivå medhuvudområdet omvårdnad. Utbildningarna omfattar 60 högskolepoäng med undantag avinriktningen mot distriktssköterska, där examen uppnås efter 75 högskolepoäng.Antagningskrav till utbildning är sjuksköterskeexamen och legitimation som sjuksköterska.


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org5.5 Instrucciones lógicas <strong>con</strong> enteros ................................................ 765.6 Instrucciones de rotación y desplazamiento <strong>con</strong> enteros ............... 785.6.1 Instrucciones de desplazamiento <strong>con</strong> enteros ........................ 795.6.2 Instrucciones de rotación <strong>con</strong> enteros ................................... 805.7 Mnemonics................................................................................. 835.7.1 Mnemonics para la resta....................................................... 835.7.2 Mnemonics para las operaciones de comparación................... 845.7.3 Mnemonics para operaciones de desplazamiento y rotación.... 855.7.4 Mnemonics para acceder al registro XER ............................... 865.7.5 Otros mnemonics................................................................. 865.8 Operaciones comunes <strong>con</strong> enteros............................................... 875.8.1 Valor absoluto...................................................................... 875.8.2 Máximo y mínimo de un número sin signo ............................. 885.8.3 Máximo y mínimo de un número <strong>con</strong> signo ............................ 905.8.4 Resto de una división ........................................................... 915.8.5 División entre una <strong>con</strong>stante entera ...................................... 925.8.6 División de 64 bits en máquinas de 32 bits ............................ 966 Instrucciones de bifurcación............................................................. 1016.1 Tipos de cálculo de la dirección de salto de una instrucción......... 1016.1.1 Instrucciones de salto relativo............................................. 1026.1.2 Instrucciones de salto absoluto ........................................... 1036.1.3 Las instrucciones de salto <strong>con</strong>dicional.................................. 1046.1.4 Instrucciones <strong>con</strong>dicionales de salto relativo ........................ 1076.1.5 Instrucciones <strong>con</strong>dicionales de salto absoluto ...................... 1086.1.6 Instrucciones <strong>con</strong>dicionales de salto al Count Register.......... 1096.1.7 Instrucciones <strong>con</strong>dicionales de salto al Link Register ............ 1106.2 Mnemonics............................................................................... 1126.2.1 Mnemonics para saltos in<strong>con</strong>dicionales................................ 1126.2.2 Mnemonics para saltos <strong>con</strong>dicionales................................... 1126.2.3 Mnemonics para acceder a los registros CR, CTR y LR.......... 1166.3 Implementación en ensamblador de las sentencias de <strong>con</strong>trol deflujo más <strong>con</strong>ocidas <strong>del</strong> lenguaje C ...................................................... 1166.3.1 Condicional simple y doble.................................................. 1166.3.2 Condicional múltiple ........................................................... 1176.4 Los bucles ................................................................................ 1206.4.1 Mnemonics para bucles ...................................................... 1206.4.2 Bucle do-while ................................................................... 1216.4.3 Bucle while ........................................................................ 1226.4.4 Bucle for............................................................................ 1226.5 Operaciones lógicas <strong>con</strong> los bits <strong>del</strong> registro CR.......................... 1247 Instrucciones de trabajo <strong>con</strong> números en punto flotante.................... 1277.1 Introducción............................................................................. 1277.2 Los registros de punto flotante .................................................. 1277.3 El registro FPSCR...................................................................... 1287.3.1 Instrucciones para acceder a los bits de registro FPSCR........ 1317.3.2 Los flags de excepción........................................................ 1327.3.3 Los bits de <strong>con</strong>dición y el bit de clase.................................. 1347.3.4 Los bits de redondeo.......................................................... 136Pág. 6


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org7.4 El registro CR ........................................................................... 1367.5 Manejo de traps........................................................................ 1377.6 Instrucciones de carga y almacenamiento .................................. 1387.7 Instrucciones aritméticas........................................................... 1407.8 Instrucciones de <strong>con</strong>versión ...................................................... 1437.9 Instrucciones de comparación ................................................... 1447.10 Instrucciones de movimiento de datos.................................... 1458 Incrustar código ensamblador en un programa C .............................. 1468.1 Integración entre C y ensamblador ............................................ 1468.2 Acceso a variables C desde ensamblador.................................... 1468.3 Expresiones C como operandos de instrucciones ensamblador..... 1488.3.1 Las <strong>con</strong>straints y los modificadores ..................................... 1498.3.2 Expresiones C en gcc 3.1.................................................... 1539 Llamada a funciones........................................................................ 1549.1 Tipos de datos.......................................................................... 1549.2 Mecanismo general de llamada a procedimientos........................ 1559.3 Convención <strong>del</strong> uso de los registros ........................................... 1559.4 Estructura de la pila.................................................................. 1579.4.1 Las áreas <strong>del</strong> frame............................................................ 1589.5 Paso de <strong>con</strong>trol a un procedimiento ........................................... 1599.5.1 El prólogo y el epílogo ........................................................ 1599.5.2 Los procedimientos terminales ............................................ 1649.5.3 Paso de parámetros ........................................................... 1659.5.4 Funciones <strong>con</strong> un número variable de parámetros................ 1689.5.5 Retorno de una función ...................................................... 1699.6 Ejemplo ................................................................................... 169APÉNDICE A: Aritmética binaria1 Técnicas básicas de aritmética entera............................................... 1731.1 Números sin signo .................................................................... 1731.1.1 Suma <strong>con</strong> transmisión de acarreo ....................................... 1731.1.2 Resta <strong>con</strong> petición de acarreo ............................................. 1751.1.3 Multiplicación en base 2...................................................... 1771.1.4 División en base 2.............................................................. 1781.2 Números <strong>con</strong> signo ................................................................... 1811.2.1 Representación .................................................................. 1811.2.2 Suma y resta de números en complemento a 2.................... 1821.3 Aspectos <strong>del</strong> sistema................................................................. 1832 Introducción al punto flotante .......................................................... 1863 Formato de los datos en punto flotante ............................................ 1883.1 Números denormalizados .......................................................... 1913.2 Números especiales .................................................................. 192Rangos máximos y mínimos en los números en punto flotante .............. 1944 El problema <strong>del</strong> redondeo en punto flotante...................................... 1964.1 La precisión en punto flotante ................................................... 1964.2 Error absoluto y relativo............................................................ 1974.3 Modos de redondeo .................................................................. 1985 Las excepciones .............................................................................. 199Pág. 7


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org6 Suma en punto flotante ................................................................... 2016.1 Redondeo................................................................................. 2016.2 El algoritmo de la suma............................................................. 2027 Multiplicación en punto flotante........................................................ 2058 División y resto en punto flotante ..................................................... 2069 Comparaciones y <strong>con</strong>versiones......................................................... 207APÉNDICE B: La segmentación1 ¿Que es la segmentación?................................................................ 2092 Etapas multiciclo ............................................................................. 2123 Los riesgos...................................................................................... 2133.1 Riesgos estructurales ................................................................ 2133.2 Riesgos por dependencia de datos............................................. 2143.3 Riesgos de <strong>con</strong>trol .................................................................... 2173.4 Saltos sin resolver..................................................................... 2183.5 Solución software a los saltos sin resolver .................................. 2193.5.1 Estructura if....................................................................... 2203.5.2 Estructura while................................................................. 2203.5.3 Estructura do-while ............................................................ 2213.5.4 Estructura for .................................................................... 2223.6 Solución hardware a los saltos sin resolver ................................. 2223.7 La serialización ......................................................................... 2264 Más allá de la segmentación ............................................................ 227Pág. 8


Tema 1Introducción al <strong>PowerPC</strong>Sinopsis:Este primer tema sirve para orientar al lector sobre el <strong>con</strong>tenido <strong>del</strong> tutorial, yayuda a <strong>con</strong>cretar una serie de <strong>con</strong>ceptos básicos que serán necesario tenerclaro para leer el resto <strong>del</strong> tutorial.


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org1 La arquitectura <strong>del</strong> <strong>PowerPC</strong>A lo largo de la historia de la informática, han ido apareciendo distintasgeneraciones de ordenadores. Una parte importante de estos ordenadores hasido el microprocesador. El microprocesador introduce una diferenciadefinitiva en la forma en que trabaja un ordenador, y es a lo que nosotrosllamaremos una arquitectura. Tipos de arquitecturas de microprocesadores<strong>con</strong>ocidos a lo largo de la historia han sido, el Z80 (usado por los antiguosSpectrum), el Motorola 68000 (usado hasta hace pocos años por los<strong>Mac</strong>intosh), el microprocesador x86 de Intel (usado actualmente por los PCs),los SPARC usados en las máquinas de Sun, o el <strong>PowerPC</strong> que es el que vamosa estudiar en este tutorial. Los procesadores <strong>con</strong> una misma arquitecturaforman familias, en el sentido de que para una misma arquitectura vansurgiendo procesadores <strong>con</strong> características parecidas, pero a los que se vanañadiendo mejoras.<strong>PowerPC</strong> es una nueva arquitectura que incorpora importantes ventajas<strong>con</strong>ceptuales respecto a los anteriores.Una ventaja importante es que <strong>PowerPC</strong> es una arquitectura RISC (ReducedInstruction Set Computing), es decir, que dispone de un juego deinstrucciones reducido, frente a otras arquitecturas como x86 ó M68000 quese las <strong>con</strong>oce como CISC (Complex Instruction Set Computing) los cualesdisponen de un juego de instrucciones mucho más amplio.Aunque inicialmente los fabricantes pensaban que cuantas más instruccionestuviera su microprocesador más potente sería, estudios realizados en launiversidad de Berkeley y Stanford han demostrado que al aumentar estejuego de instrucciones aumentaba mucho la complejidad <strong>del</strong> cableado <strong>del</strong>micro, y el número de ciclos de CPU que necesitaban para ejecutar unainstrucción también aumentaba. Además observaron que el número deinstrucciones distintas que necesita un ordenador para ejecutar cualquierprograma se podía reducir a un número pequeño de primitivas, y que en lasmáquinas CISC que estaban usando en aquel entonces muchas instruccioneseran redundantes. Esto dio lugar a la aparición de las máquinas RISC de lascuales un buen ejemplo es la arquitectura SPARC o la arquitectura POWER deIBM usada por sus máquinas RS/6000, o bien, ¿cómo no?, el <strong>PowerPC</strong>, que esuna evolución de la arquitectura POWER desarrollada <strong>con</strong>juntamente por IBM,Motorola y Apple.El tiempo necesario para ejecutar un programa depende <strong>del</strong> producto de tresfactores: El número de instrucciones <strong>del</strong> programa, el número de ciclos dereloj necesarios para ejecutar una instrucción y la duración de cada ciclo(velocidad <strong>del</strong> reloj). Los programas hechos para máquinas RISC tienen unmayor número de instrucciones que su correspondiente versión CISC, pero acambio, el número de ciclos de cada instrucción disminuye. El tercer factorPág 10


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org(tiempo de cada ciclo) es un factor que depende más de la tecnología ymateriales empleados en la <strong>con</strong>strucción <strong>del</strong> micro, y que <strong>con</strong> el tiempo sesupone irá mejorando. Para coger lo mejor de ambos mundos, POWER y suevolución el <strong>PowerPC</strong>, son máquinas que no siguen una arquitectura RISCestricta (como por ejemplo SPARC), sino que incluyen instruccionesadicionales para operaciones comunes que están ahí sólo para reducir eltamaño <strong>del</strong> programa, sin por ello llegar a la complejidad de las arquitecturasCISC.<strong>PowerPC</strong> es una arquitectura diseñada para funcionar tanto en máquinas de32 bits como en máquinas de 64 bits, es decir, que los registros <strong>del</strong>microprocesador y las direcciones de memoria pueden ser o bien de 32 bits obien de 64 bits, que es a lo que se llama la palabra (word) <strong>del</strong> computador.Aun así, en ambos casos siguen el mismo mo<strong>del</strong>o, y disponen <strong>del</strong> mismojuego de instrucciones, que es el mo<strong>del</strong>o y juego de instrucciones <strong>del</strong><strong>PowerPC</strong>.Aunque esta arquitectura fue inicialmente diseñada en común, actualmente lafabricación de máquinas que siguen el mo<strong>del</strong>o <strong>del</strong> <strong>PowerPC</strong> se ha dividido endos:Por un lado Motorola está fabricando chips que siguen esta arquitectura deuso doméstico, y que aunque ha hecho algún micro de 64 bits, la mayoría <strong>del</strong>os micros de que disponen son de 32 bits.Por otro lado IBM está fabricando microprocesadores de 32 bits como de 64bits para sus máquinas y para las últimas máquinas de Apple.Apple por su parte compra los micros a Motorola (en <strong>con</strong>creto los G4disponen de micros de la serie MPC74xx de Motorola y a IBM (los G5 sonmicroprocesadores que IBM ha hecho a Apple). Podemos <strong>con</strong>sultar los microsde que dispone Motorola aquí en [MICROMOTOROLA], y los micros de IBMen [MICROIBM].Es importante también destacar que los <strong>PowerPC</strong> no sólo se usan paraordenadores de escritorio, sino que se usan en video<strong>con</strong>solas como laNintendo Gamecube, o los <strong>PowerPC</strong> de Motorola de la serie MPC4xx paradispositivos empotrados, los cuales son más baratos de fabricar aunque porejemplo carecen de unidad de punto flotante y de tablas de paginación.Nosotros nos vamos a centrar en estudiar los micros de 32 bits, que son losque utiliza el sistema operativo <strong>Mac</strong> <strong>OS</strong> X. Téngase en cuenta que aunquedispongamos de una máquina G5 <strong>con</strong> un microprocesador de 64 bits,actualmente no se utilizan sus características adicionales <strong>con</strong> el fin demantener compatibilidad. En cualquier caso pasar de un ensamblador de 32bits a uno de 64 bits resulta muy fácil ya que los juegos de instruccionesfueron pensados <strong>con</strong> el fin de que fueran similares.Pág 11


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org2 Los entornos <strong>del</strong> <strong>PowerPC</strong>Un objetivo que se fijó durante el diseño <strong>del</strong> <strong>PowerPC</strong> fue que estaarquitectura se pudiera utilizar para la fabricación de procesadores dirigidos adistintos dispositivos electrónicos, que iban desde los micros para máquinasautomáticas y sistemas empotrados hasta los microprocesadores paraworkstations y servidores de alto rendimiento.Para ello se dividió la arquitectura <strong>del</strong><strong>PowerPC</strong> en tres entornos (VéaseFigura 1.1). El fabricante tiene libertada la hora de fabricar un micro queimplemente los tres entornos, o sóloalguno de ellos. Estos entornos son:OEAVEAUISAFigura 1.1: Entornos <strong>del</strong> <strong>PowerPC</strong>User Instruction Set Architecture (UISA). Define el juego deinstrucciones de usuario de que dispone el micro (también llamado entornode resolución de problemas). Aquí se definen aspectos como los registros,tipos de datos, operaciones en punto flotante <strong>del</strong> microprocesador y formasde acceso a memoria.Virtual Environment Architecture (VEA). Define operaciones adicionalesde usuario, que normalmente escapan a lo que un programador deaplicaciones puede necesitar <strong>con</strong>trolar, como puedan ser las caches.Operating Environment Architecture (OEA). Define el juego deinstrucciones <strong>del</strong> supervisor (también llamadas operaciones privilegiadas), queson operaciones a las que normalmente sólo tiene acceso el sistemaoperativo. Como puedan ser los métodos de paginación o segmentación de lamemoria, técnicas de sincronización o gestión de excepciones (tambiénllamadas interrupciones). A estas instrucciones sólo se puede acceder si elmicro se encuentra en modo supervisor, si está en modo usuario, que esel modo normal de funcionamiento, sólo se puede acceder a las operacionesde UISA y VEA.Todos los micros deben de implementar el UISA, mientras que el VEA y OEAson opcionales, aunque si un micro implementa el OEA también debe deimplementar el VEA.Por ejemplo un micro como el MPC106 de Motorola que es un micro pequeñopensado para dispositivos empotrados puede disponer sólo de UISA, mientrasque un micro de alto rendimiento como el MPC7455 de Motorola implementalos tres entornos.Pág 12


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org3 Los registros <strong>del</strong> <strong>PowerPC</strong>En entorno UISA define el siguiente <strong>con</strong>junto de registros:o 32 registros de 32 bits de propósito general llamados GPR (GeneralPurpose Registers). Estos registros sirven para las operacionescomunes <strong>del</strong> día a día, como sumas, comparaciones, etc. En lasmáquinas de 64 bits, estos registros son de 64 bits.o 32 registros de 64 bits para operaciones en coma flotante llamadosFPR (Floating Point Registers). Estos registros nos permiten haceroperaciones matemáticas <strong>con</strong> números en representación de puntoflotante, tanto de precisión simple como doble. El tamaño de estosregistros es siempre de 64 bits, independientemente de si estamos enuna máquina de 32 bits o de 64 bits.o Otros registros diversos como son el Condition Register (CR), Floating-Point Status and Control Register (FPSCR), XER, Link Register (LR) yCount Register (CTR).El entorno VEA añade dos nuevos registros llamados TBU (Time Base Upper)y TBL (Time Base Lower), que sólo están disponibles en los micros queimplementan VEA.Por último OEA define otros muchos registros especiales llamados SPR(Special Purpose Registers), que no veremos hasta más a<strong>del</strong>ante, y a los quesólo se puede acceder en modo supervisor. Estos registros nos permiten<strong>con</strong>trolar cosas como las tablas de paginación y segmentación, la traducciónde direcciones lógicas a direcciones virtuales y reales, el manejo deexcepciones, el acceso a dispositivos, etc. Normalmente estos registros noson accedidos más que por el sistema operativo.Una característica importante de los sistemas RISC, y por tanto <strong>del</strong> <strong>PowerPC</strong>es que, a diferencia de los sistemas CISC, las únicas instrucciones quetransfieren datos entre memoria y los registros son instrucciones diseñadas<strong>con</strong> el fin de leer o escribir en memoria, y todas las demás instruccionessiempre trabajan <strong>con</strong> datos previamente cargados en registros. El hecho deque las instrucciones de los sistemas RISC sólo puedan tener como operandosregistros disminuye mucho los modos de direccionamiento de lasinstrucciones <strong>del</strong> micro, y en <strong>con</strong>secuencia la complejidad <strong>del</strong> juego deinstrucciones. Compárese esta organización <strong>con</strong> los sistemas CISC, donde lasinstrucciones pueden tener como uno de sus operadores una dirección dememoria, o bien un registro.Esto también hace que en los sistemas RISC sea muy típico que unainstrucción tenga hasta 3 operandos. Por ejemplo la instrucción de sumarecibe dos registros como origen y un tercero como destino. Esto también esuna diferencia respecto a los sistemas CISC donde las instrucciones suelenrecibir sólo dos operadores, <strong>con</strong> lo que operaciones como la de suma tienenPág 13


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgque depositar el resultado de la suma en uno de los registros origen, dandolugar a un sistema menos flexible.Como a<strong>del</strong>antamos antes, los procesadores <strong>PowerPC</strong> tienen dos niveles deprivilegio:Modo supervisor. Usado sólo por el sistema operativo para acceder a losrecursos definidos por el OEA.Modo usuario. Usado por las aplicaciones y el sistema operativo pararealizar operaciones <strong>con</strong>sideradas “no peligrosas”. Es el modo que usamospara acceder a los recursos definidos por UISA y VEA.4 Byte orderingLos bytes de la memoria se numeran empezando a <strong>con</strong>tar por 0. Cadanúmero es la dirección de memoria de un byte. En este sentido los bytes sonunidades indivisibles y no existe problema respecto a la forma de ordenar losbits de un byte en memoria. El problema surge <strong>con</strong> las variables cuyo tamañoes mayor a un byte.En este caso existen dos formas de colocar los bytes que forman una variableen memoria llamadas:Big-Endian. Donde el byte más significativo se coloca en la dirección dememoria más baja (el primero).Little-Endian. Donde el byte menos significativo se coloca el la dirección dememoria más baja (el primero).Por ejemplo, el número 617163 en binario se escribe como 1001 0110 10101100 1011. Si lo queremos guardar en memoria necesitaremos una variablede tamaño suficiente para almacenarlo.Los tamaños típicos de variables enteras (vistas desde el punto de vista de C)aparecen en la Tabla 1.1:Tipo dato TamañoRango Valores(bytes)char 1 byte -128..+127short 2 bytes -32.768..+32.767int 4 bytes -2.147.483.648..+ 2.147.483.647Tabla 1.1: Tamaños típicos de variables enterasEn nuestro caso necesitaremos una variable de tipo int. En la Figura 1.2 semuestra como se almacenaría esta variable en big-endian y en little-endian enmemoria.Pág 14


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org4.1.1.1 Big-Endian0000 0000 0000 1001 0110 1010 1100 10110 1 2 34.1.1.2 Little-Endian1100 1011 0110 1010 0000 1001 0000 00000 1 2 3Figura 1.2: Almacenamiento de variables Big-Endian y Little-Endian en memoriaEn cualquier caso, cuando apuntamos a una variable en memoria siempre seapunta al primer byte (dirección de memoria más baja) de la variable.Como veremos, la organización en big-endian tiene la ventaja de que alescribir el número lo escribimos de izquierda a derecha, tal como se lee. Elúnico in<strong>con</strong>veniente que tiene usar la organización little-endian es quedebemos de guardar los bytes <strong>del</strong> número al revés de como se lee, lo cualdificulta su lectura.Fabricantes de microprocesadores como IBM, o Sun siguen la organizaciónbig endian, por desgracia hay un microprocesador muy usado, el x86 de Intel,que usa la organización little-endian.En <strong>PowerPC</strong> por defecto se usa big-endian, aunque existen técnicas decompatibilidad que permiten acceder a los datos de memoria en little-endian.Esto es especialmente útil para mantener compatibilidad <strong>con</strong> software escritopara procesadores que usan little-endian y para poder acceder a estructurasde datos donde los datos se almacenan en formato little-endian (p.e losficheros .bmp de Windows).Obsérvese que en el caso de los registros <strong>del</strong> microprocesador no existe elproblema <strong>del</strong> orden de los bytes que lo componen, ya que los registros sonunidades indivisibles de 32 bits.Pág 15


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org5 Alineación<strong>PowerPC</strong> dispone de instrucciones que permiten transferir entre memoria ylos registros tanto bytes, como halfwords (16 bits), words (32 bits), odoublewords (64 bits). En las máquinas de 32 bits, estos últimos sólo se usanpara los datos en representación de punto flotante <strong>con</strong> precisión doble quequeramos guardar en los FPR, mientras que en los procesadores de 64 bits,los GPRs tienen 64 bits <strong>con</strong> lo que es su tamaño por defecto.Estas instrucciones de acceso a memoria funcionan más rápido si el acceso lohacemos a una dirección de memoria que sea múltiplo <strong>del</strong> tamaño de losdatos a transferir, por ejemplo si accedemos a variables de tipo int (4bytes), el acceso más rápido se <strong>con</strong>sigue cuando accedemos a una direcciónde memoria múltiplo de 4.Como regla general, debemos colocar las variables en zonas de memoria cuyadirección sea múltiplo <strong>del</strong> tamaño de la variable que estamos guardando.Si esto no se hace el microprocesador tiene que hacer dos accesos amemoria, uno para leer los cuatro primeros bytes alineados y otro para leerlos siguientes 4 bytes, para finalmente componer el valor de la variable, locual enlentece el acceso.La Tabla 1.2 muestra la alineación recomendada para cada tamaño de dato.Operando Longitud Direcciónalineadabyte 1 byte xxxxhalfword 2 bytes xxx0word 4 bytes xx00doubleword 8 bytes x000Tabla 1.2: Alinación recomendada para cada tamaño de datoUna características importante de las máquinas RISC, es que todas lasinstrucciones tienen el mismo tamaño, a diferencia de las máquinas CISCdonde las instrucciones tienen un tamaño diferente. En <strong>PowerPC</strong> todas lasinstrucciones ocupan 32 bits (tanto en arquitecturas de 32 bits como de 64bits), lo cual simplifica mucho al procesador el acceso a las instrucciones deforma <strong>con</strong>secutiva. Además en <strong>PowerPC</strong> las instrucciones siempre tienen queestar alineadas en direcciones de memoria múltiplos de 4, ya que <strong>PowerPC</strong> esliteralmente incapaz de acceder a instrucciones que no estuvierancorrectamente alineadas en memoria.Pág 16


Tema 2EMPEZANDO A PROGRAMARSinopsis:Con este tema pretendemos que el lector aprenda a manejar el juego deinstrucciones UISA, es decir, el modo usuario, que son las instruccionescomunes que tiene este microprocesador.En los siguientes temas (que actualmente estamos escribiendo) pretendemosque el lector aprenda también a manejar operaciones UISA más avanzadasasí como a manejar los demás modos.


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org1 Herramientas necesariasVamos a empezar viendo qué herramientas de programación en ensambladorexisten para <strong>Mac</strong> <strong>OS</strong> X y como se pueden usar.Los primero que vamos a necesitar es obtener las Development Tools quepodemos <strong>con</strong>seguir gratuitamente de la Apple Developer Connection (ADC) en[DEVTOOLS]:Dentro de estas herramientas en<strong>con</strong>tramos el <strong>con</strong>ocido compilador gcc deGNU, que es el que nos va a permitir compilar código C, C++, Objective-C yensamblador desde la línea de comandos.Para probar este comando podemos escribir un fichero llamado saluda.ccomo el <strong>del</strong> Listado 1.1:#include #define MENSAJE "Hola mundo\n"int main (){printf(MENSAJE);return 0;}Listado 1.1: Programa ensamblador mínimoY compilarlo desde la línea de comandos <strong>con</strong>:$ gcc saluda.c -o saluda$ ./saludaHola mundoEl proceso de generación de un ejecutable a partir de un código fuente en C yC++ tiene básicamente 4 pasos:1. Preprocesado2. Generación <strong>del</strong> código ensamblado (compilación)3. Generación <strong>del</strong> código objeto (ensamblado)4. EnlazadoEl compilador de GNU lo que hace cuando recibe un programa en lenguajeC es pasarlo a lenguaje ensamblador (segundo paso), y después pasa esecódigo a otro subsistema llamado ensamblador, que en GNU es el comandoas (tercer paso), el cual genera el código binario reubicable de ese programaen un formato especial llamado código objeto. Por último el enlazador quePág 18


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgen nuestro caso es el comando de GNU ld lo que hace es juntar todos losficheros de código objeto reubicable en otro fichero que es el ficheroejecutable (cuarto paso).Podemos pedir a gcc que realice todas o sólo alguna de estas fases.Si lo que queremos es sólo preprocesar un fichero podemos usar la opción -Easí:$ gcc -E saluda.cVemos que por la salida estándar obtenemos el código preprocesado <strong>con</strong> elfichero incluido y MENSAJE sustituido.Si lo que queremos es obtener el código ensamblador <strong>del</strong> programa C anterior(compilar), podemos usar la opción -S así:$ gcc -S saluda.cEsto genera otro fichero llamado saluda.s en el que obtendremos el códigoensamblador <strong>del</strong> programa anterior.Si queremos obtener el código objeto (fichero .o) <strong>del</strong> programa usamos laopción -c$ gcc -c saluda.cEsto genera el fichero saluda.o que después podemos enlazar junto <strong>con</strong>otros ficheros de código objeto.También podemos compilar un fichero .s (código ensamblador) para obtenersu correspondiente código objeto <strong>con</strong> esta misma opción:$ gcc -c saluda.sEn cualquier caso, para obtener el código objeto de un fichero enensamblador, gcc lo que hace es llamar al comando as. Esta herramientatambién la podemos llamar nosotros para compilar un fichero enensamblador. Es decir, podemos hacer:$ as saluda.s -oD.oDe hecho esta es la principal herramienta que vamos a usar para compilar losprogramas en ensamblador que hagamos a lo largo de este tutorial.También , antes de <strong>con</strong>tinuar, <strong>con</strong>viene comentar que las Development Toolstambién traen una herramienta visual llamada Xcode que nos permite dePág 19


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgforma más “visual” compilar programas C, C++, Objective-C, Java oensamblador, aunque internamente esta herramienta llama a lasherramientas de GNU para compilar. En este tutorial vamos a hablar siemprede los comandos y opciones de GNU, pero si el lector lo prefiere puede usaresta herramienta e indicar las opciones que aquí demos en lascorrespondientes opciones de que dispone Xcode.Por último, la Tabla 2.1 muestra las extensiones de fichero que re<strong>con</strong>oce elcompilador de GNU, y para que se utiliza cada una.Extensión Descripción Qué hace <strong>con</strong> ellos gcc.c Código fuente C Preprocesa, ensambla,compila y enlaza.cpp.cc.cxx.CCódigo fuente C++Preprocesa, ensambla,compila y enlaza.m Código fuente Objective-C Preprocesa, ensambla,compila y enlaza.h Ficheros de cabecera C, C++ oObjective-C.i Código C preprocesado (Si se lopasamos al compilador no lopreprocesa).ii Código C++ preprocesado (Si se lopasamos al compilador no lopreprocesa).s Código ensamblador que no debeser preprocesado.S Código ensamblador que debe serpreprocesado.o Archivo de código objeto Enlaza.a Librería de enlace estático Enlaza.so Librería de enlace dinámico EnlazaTabla 2.1: Extensiones de fichero que re<strong>con</strong>oce el compilador de GNUNo usados directamenteEnsambla, compila yenlazaEnsambla, compila yenlazaCompila y enlazaPreprocesa, compila yenlazaPág 20


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org2 El programa mínimoYa que sabemos cómo se usa el compilador, vamos a escribir un programamínimo para ver cómo se compila y enlaza un programa ensamblador en <strong>Mac</strong><strong>OS</strong> X.Para ello escribimos un fichero llamado basico.s de la forma:/* Descripción: Programa básico en ensamblador* Escrito por: Fernando López Hernández*/.text // Empieza la sección de código.align 2.globl _main ; Hacemos global la función main()_main:blr ;Retorna de la función mainEn primer lugar, en este programa hemos utilizado los 3 tipos de comentariosque soporta el lenguaje ensamblador, los cuales se resumen en la Tabla 2.2.Comentario Descripción/*··· */ Comentario multilínea de C// Comentario de una sola línea de C; Comentario de una sola línea propio <strong>del</strong> ensamblador asTabla 2.2: Tipos de comentarios en lenguaje ensambladorLos comentarios de C son comentarios que elimina el preprocesador, <strong>con</strong> loque cuando as va a generar el código objeto, estos comentarios ya handesaparecido. No pasa lo mismo <strong>con</strong> el tercer comentario, que es elcomentario propio de as.Todo programa debe de disponer de la directiva .text, que como veremosindica la parte <strong>del</strong> programa que corresponde al programa, y que en<strong>con</strong>secuencia es de sólo lectura. Más a<strong>del</strong>ante veremos otra directiva llamada.data que sirve para indicar el trozo <strong>del</strong> programa que corresponde a losdatos, y que será de lectura/escritura..align es otra directiva que pide al compilador que alinee la siguienteinstrucción a una dirección múltiplo de 4. El 2 lo que indica es que queremosque la dirección tenga sus últimos 2 bits a cero, es decir, de la forma xxxxxx00, o lo que es lo mismo que sea múltiplo de 2 a , siendo a la alineaciónpedida.Pág 21


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org.globl sirve para declarar como global el siguiente símbolo que aparece. Lafunción main() debe de ser un símbolo global para que <strong>Mac</strong> <strong>OS</strong> X puedaacceder a ella. Obsérvese que la función se llama _main y no main, esto esasí porque todos los símbolos sufren un name-mangling al estilo C (poner un_ <strong>del</strong>ante) antes de meterlos en la tabla de símbolos.blr es la única instrucción ensamblador que tiene el programa y que lo quehace es retornar de la llamada a la función main(). Como veremos ladirección a la que retorna esta llamada se almacena en un registro <strong>del</strong>microprocesador llamado LR (Link Register), cuyo principal uso es almacenardirecciones de retorno de las funciones.Ahora ya lo podemos compilar y ejecutar:$ gcc basico.s -o basico$ ./basicoPág 22


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org3 El lenguaje ensambladorAhora que ya sabemos cómo se hace un programa en ensamblador, vamos acomentar brevemente cuales son los principales elementos <strong>del</strong> lenguajeensamblador, así como la sintaxis de las sentencias que soporta.3.1 Sintaxis <strong>del</strong> lenguajeUn 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 dirección dememoria de la instrucción o dato que estamos compilando. Después podemosusar esta etiqueta desde otros puntos <strong>del</strong> programa para referirnos a estadirección de memoria. Por ejemplo, las instrucciones de salto indican ladirección a la que saltar dando el nombre de la etiqueta, o las instruccionesde acceso a memoria también usan etiquetas para indicar la dirección dememoria a la que acceder.La instrucción puede ser uno de estos tres elementos:o Una instrucción ensamblador, que debe ensamblar el lenguaje.o Una directiva, las cuales no generan código, si no que sirven paracambiar el comportamiento <strong>del</strong> ensamblador durante el proceso deensamblado. Aunque no generan código, sí que pueden reservarmemoria, como veremos. Una característica de las directivas es quetodas empiezan por un punto (.).o Una macro, las cuales se crean <strong>con</strong> la directiva .macro, como veremosen el Tema 3.Los operandos, son parámetros que opcionalmente reciben lasinstrucciones, bien sean instrucciones ensamblador, directivas o macros. Losoperandos a recibir dependen de la instrucción a ejecutar, y si hay más deuno se suelen separar por comas.El comentario en ensamblador se precede por ;, y, como dijimos, tambiénpodemos usar los comentarios C, aunque el preprocesador los elimina antesde pasar el fichero al ensamblador.Las distintas partes de la sentencia se pueden separar tanto por espacio comopor tabulador, pero normalmente existe la costumbre de separar por espacio,excepto en el caso de la etiqueta donde se suele poder un tabulador alPág 23


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgprincipio de línea si no existe la etiqueta, o bien poder un tabulador despuésde la etiqueta.Por ejemplo:inicio:mflr r0stwu r1,-80(r1)mr r30,r1bcl 20,31,inicioDe esta forma el programa resulta más fácil de leer.A <strong>con</strong>tinuación se muestra el ejemplo de un programa que suma dosnúmeros. Desafortunadamente, como todavía no sabemos hacer llamadas alsistema, no vamos a poder imprimir el resultado de la ejecución. Pero, aun asíeste ejemplo nos va a servir para ver algunas instrucciones elementales deacceso a registros y de suma.Al programa se llamará sumaregistros.s y aparece en el Listado 2.1:/* Descripción: Programa que suma dos números situados en* registros* Escrito por: Fernando López Hernández*/.text // Sección de código.align 2.globl _main_main:li r3,2li r4,5add r5,r3,r4blrListado 2.1: Programa que suma el <strong>con</strong>tenido de los registrosEl programa usa la instrucción li para cargar en el registro r3 un 2 y en elregistro r4 un 5, para después, <strong>con</strong> la instrucción add calcular r3+r4 yalmacenar el resultado en r5.3.2 Elementos <strong>del</strong> lenguajeEn esta sección vamos a comentar cuáles son los principales elementos quecomponen el lenguaje ensamblador.Pág 24


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org3.2.1 LiteralesUn literal es una representación escrita de un valor. Dentro de los literalesen<strong>con</strong>tramos:Los caracteres, los cuales se representan encerrados entre comillas simples.Por ejemplo: 'A', 'a', '2','?'. Cuando el compilador los encuentra lossustituye por el valor ASCII <strong>del</strong> carácter correspondiente.li r3,'A'Las cadenas de caracteres, las cuales se representan encerradas entrecomillas dobles, como por ejemplo "Hola mundo". El compilador lassustituye por los códigos ASCII de sus caracteres.Estas se utilizan sobre todo para reservar trozos de memoria <strong>con</strong> la directiva.ascii así:.ascii "Hola mundo"El compilador no pone el 0 de final de cadena, aunque si queremos que loponga podemos usar la directiva .asciz.asciz "Hola mundo"Los números enteros, los cuales se pueden representar en decimal, octal ohexadecimal.o Los números en decimal se representan en su forma natural: 4, -37.No pueden empezar por 0.o Los números en hexadecimal se representan precedidos por 0x, porejemplo: 0x45, 0xF259B4C2. Para las letras se pueden usarmayúsculas o minúsculas indistintamente, es decir podemos escribir0x3F ó 0x3fo Los números en octal empiezan por 0. Por ejemplo, 037, 041241Los números en punto flotante, se representan de una forma un pocoespecial, cuyo formato general sería:0flt_char[{+-}[dec...][.[dec...]]e[{+-}][dec...]]flt_char indica si el número es un número real de precisión simple (r) o deprecisión doble (d). El primer dec... indica la parte entera, el segundodec... la parte decimal, y por último va una e seguida de la parteexponencial <strong>del</strong> número. Con unos ejemplos seguro que queda más claro:Pág 25


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgNúmero Precisión Representación1.34 doble 0d1.34e00.00045 doble 0d45.0e-42456 float 0r2456.0e0Cuando usamos uno de estos literales <strong>con</strong> las directivas .single y .doubleque sirven para reservar memoria para un número en punto flotante deprecisión simple o doble, respectivamente, la directiva ignora el tipo <strong>del</strong>literal, y sólo se tiene en cuenta el tipo de la directiva, aun así esrecomendable indicar el tipo por claridad.Por ejemplo:F1: .single 0r2456.0e0 ; Forma recomentable de reservar; memoria para un float de; 32 bitsF2: .single 0d2456.0e0 ; También reserva 32 bitsD1: .double 0d1.34e0 ; Forma recomentable para; reservar memoria para un; double de 64 bitsD2: .double 0r1.34e0 ; También reserva 64 bits3.2.2 IdentificadoresUn identificador es un nombre que damos a uno de estos dos elementos:o Una etiqueta, que sirve para referirnos a un trozo <strong>del</strong> programa o auna variable.o Una <strong>con</strong>stante, que es un nombre al que le asociamos un literal.Cada identificador <strong>con</strong>siste en una secuencia de caracteres alfanumérica, queno puede empezar por un número, y en la que se diferencian mayúsculas deminúsculas.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 <strong>con</strong> los demás lenguajes es mejor no usar estaforma, que da lugar a <strong>con</strong>fusión <strong>con</strong> las cadenas de caracteres, y en vez deello usar guiones bajos o mayúsculas y minúsculas para separar palabras.MaximoRelativodiferencia_en_pixelesPág 26


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgLas etiquetas deben de estar precedidas por : cuando se declaran, pero nocuando se usan. Por ejemplo:inicio:········stwu r1,-80(r1) ; Declaración········bcl 20,31,inicio ; UsoRespecto al ámbito de las etiquetas, estas sólo son visibles dentro <strong>del</strong> ficheroque las declara, pero podemos hacer las etiquetas de ámbito global (parapoder acceder a ellas desde otros ficheros) <strong>con</strong> la directiva .globl:.global AA: lwi r4,5Esto hace a la etiqueta A accesible desde otros módulos. La directiva debepreceder a la etiqueta que vamos a declarar como global.También podemos usar las llamadas etiquetas numéricas, que sonetiquetas que se pueden redefinir en distintas partes de un mismo fichero.Estas etiquetas se crean <strong>con</strong> los dígitos <strong>del</strong> 0 al 9, y también deben de irprecedidas por :. Aunque puede haber muchas declaraciones de la mismaetiqueta en distintas partes <strong>del</strong> fichero, sólo la etiqueta numéricainmediatamente anterior y siguiente pueden ser accedidas desde un punto<strong>con</strong>creto <strong>del</strong> programa. Para ello usamos el nombre digitob (back) ydigitof (forward), respectivamente.Por ejemplo:1: instruccionA·················1: instruccionB·················b 1 ; Salta a instruccionBb 1b ; Salta a instruccionBb 1f ; Salta a instruccionC·················1: instruccionC3.2.3 Las expresionesLlamamos operando a cualquier identificador o literal que pueda ser usadocomo parámetro en una instrucción, directiva o macro. Ejemplos deoperandos son final, inicio, 45, 'A'Pág 27


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgLlamamos operador a un cálculo que ejecutamos sobre uno o másoperandos. El ensamblador re<strong>con</strong>oce los mismos operadores que el lenguajeC, los cuales se resumen en la Tabla 2.3:Operador Nombre Descripción- Menos unário El complemento a 2 de un número~ Negado binario Complemento a uno de un número! Negado lógico El resultado es 0 si el operando es distinto de0, y -1 en caso <strong>con</strong>trario+ Suma La suma de dos números- Resta La resta de dos números* Multiplicación El producto de dos números/ División División entera de dos números. Trunca losposibles decimales% Módulo El resto de la división entera>> Desplazamientoa la derecha Mayor que= Mayor o igualque== Igual!= DistintoTabla 2.3: Operandos que pueden aparecer en una expresión <strong>del</strong> ensambladorLas reglas de precedencia y asociatibidad de estos operadores también sonlas mismas que en el lenguaje C.Pág 28


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgVisto esto, vamos a ver que llamamos expresión a una combinación deoperandos y operadores. (p.e. 3*a+b)Las expresiones siempre se evalúan a valores de 32 bits, a pesar de que sepuedan usar operandos de distintos tamaños. Por ejemplo se podrían usarvalores declarados <strong>con</strong> las directivas .byte (8 bits) o .short (16 bits), perodespués de evaluar la expresión tendremos un valor de 32 bits.Cuando se evalúa una expresión su resultado puede ser absoluto, reubicableo externo, dependiendo de la expresión evaluada.Una expresión tiene un valor absoluto si:o Los operandos de la expresión son literales.o Los operandos de la expresión son identificadores a los que hemosasignado un valor literal.o La expresión es el resultado de la diferencia de dos operandosreubicables, y ambos operandos pertenecen a una misma sección.Una expresión tiene un valor reubicable si su valor se fija respecto a unadirección de memoria base como un offset respecto a esa dirección. Cuandoeste valor reubicable lo procesa el enlazador, se <strong>con</strong>vierte en un valorabsoluto.Un ejemplo típico de expresiones reubicables son las etiquetas, las cualestienen una dirección respecto a la base de su sección. Como veremos lamemoria está dividida en secciones, y las direcciones de memoria se suelendar respecto a la sección en la que estamos situados.A las expresiones reubicables sólo las podemos sumar y restar valores<strong>con</strong>stantes, así como hacer la resta de expresiones reubicables (pero no lasuma). Las operaciones de multiplicación y división, así como las demásoperaciones, están prohibidas en las expresiones reubicables.Por último, una expresión es externa si alguno de sus operandos no estádefinido en el fichero de la expresión, sino que es un identificador globalsituado en otro módulo.En general, se aplican las mismas restricciones a las expresiones externas,excepto que tampoco se puede hacer la resta de operandos si ambos sonexternos, es decir externo1-externo2 está prohibido si externo1 yexterno2 son identificadores externos.Pág 29


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org3.2.4 El location counterEl location counter es un símbolo que en todo momento tiene la direcciónde memoria de la instrucción que está siendo ensamblada. El símbolo usadopara referirse al location counter es el punto (.).Este resulta a veces útil como operando de una instrucción, directiva, macro oexpresión.El location counter es por naturaleza un valor reubicable.Existen dos directivas que nos permiten avanzar el valor <strong>del</strong> location counter:.align alineacion [, relleno]que nos permite avanzar el puntero a la siguiente posición en la que hayaalineacion bits <strong>con</strong> 0 a la derecha. Es decir, a la siguiente posición que seamúltiplo de 2 alineacionrelleno indica <strong>con</strong> que byte rellenar. Si no se indica rellena de ceros.Por ejemplo:.align 2Avanza el location counter hasta la siguiente posición que sea múltiplo de 4,rellenando de ceros..org avance [, relleno]Esta directiva avanza el location counter tantos bytes como diga avance,rellenando <strong>con</strong> bytes <strong>con</strong> el valor de relleno, o ceros si no se indica.Por ejemplo:.org 100, 0xFFRellena los siguientes 100 bytes <strong>con</strong> 0xFFPág 30


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org3.3 Las sentencias de asignación directaAntes comentamos que todas las sentencias en ensamblador tenían la forma:[etiqueta:] [instruccion [operandos]] [; comentario]Sólo existe una excepción que son las sentencias de asignación directa, lascuales tienen la forma:identificador = expresionLa cuales sirven para declarar <strong>con</strong>stantes que se puedan usar más a<strong>del</strong>anteen el programa.Por ejemplo, el programa <strong>del</strong> Listado 2.1 lo podríamos haber hecho comomuestra el Listado 2.2:// Sentencias de asignación directaoperando1 = 3operando2 = 5.text.align 2.globl _main_main:li r3,operando1li r4,operando2add r5,r3,r4blrListado 2.2: Programa que usa sentencias de asignación directaEl uso de las sentencias de asignación directa es equivalente al uso de ladirectiva .set, excepto que esta última requiere la asignación de expresionesabsolutas.Es decir, también podríamos haberlo hecho como muestra el Listado 2.3:Pág 31


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org// Directivas .set.set operando1,3.set operando2,5.text.align 2.globl _main_main:li r3,operando1li r4,operando2add r5,r3,r4blrListado 2.3: Programa que usa .set en lugar de identificadores3.4 Las definicionesLas sentencias de asignación directa y las directivas .set sólo nos permitenalmacenar valores literales:var1 = 3 ; Correctovar1 = r3 ; Error ensamblado.set var1 3; correcto.set var1 r3 ; Error ensambladoEn ensamblador también podemos usar definiciones (#define) que elpreprocesador sustituye <strong>con</strong>venientemente, lo cual es especialmente útil paraasignar a los registros nombres más significativos:#define dividendo r3#define divisor r4#define cociente r5divw cociente,dividiendo,divisorLas definiciones pueden aparecer en cualquier parte <strong>del</strong> programa, aunque sesuelen poner al principio, y el preprocesador las sustituye por su valor antesde pasar el programa al ensamblador.Pág 32


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org4 Acceso a memoriaEn esta sección vamos a explicar una serie de <strong>con</strong>ceptos fundamentales parapoder acceder a memoria.4.1 Segmentación <strong>del</strong> programaSabemos que el proceso de generación de un ejecutable <strong>con</strong>staprincipalmente de dos fases:1. Ensamblado. Consiste en transformar los ficheros fuente en ficheros decódigo objeto (.o). Esto se puede hacer <strong>con</strong> la opción -c de cc2. Enlazado. El enlazador (el comando ld en nuestro caso) combinatodos los ficheros objeto en un sólo fichero ejecutable.En el fichero ejecutable generado, la distribución <strong>del</strong> programa en memoria,como mínimo estará dividido en dos zonas de memoria a las que se llamasegmentos 1 :o Segmento de código. Es donde se almacenan las instrucciones <strong>del</strong>programa en sí. En <strong>con</strong>secuencia, es un segmento de sólo lectura.o Segmento de datos. Es donde se almacenan los datos <strong>con</strong> los queopera el programa, <strong>con</strong> lo que es un segmento de lectura/escritura.Aunque ya explicaremos más a<strong>del</strong>ante todo esto, cada segmento se almacenaen una página distinta, y el separar las instrucciones en un segmento apartede sólo lectura tiene tres ventajas:o Si el sistema operativo quiere descargar esta página, no tiene quealmacenarla primero en memoria secundaria (swap), ya que puedevolver a leerla <strong>del</strong> fichero <strong>del</strong> ejecutable, cosa que no pasa <strong>con</strong> elsegmento de datos, ya que éste seguramente haya cambiado respectoa su <strong>con</strong>tenido inicial.o Si el programa intenta realizar una operación de modificación de losdatos en el segmento de código, lo cual seguramente se deba a unapérdida de estabilidad <strong>del</strong> programa, se produce una excepción quepodrá tratar el sistema operativo.o Ayuda a una mejor organización modular <strong>del</strong> programa.Cuando nosotros escribimos un fichero fuente, debemos indicar el segmentoen el que estamos trabajando <strong>con</strong> las directivas .text (segmento de código)y .data (segmento de datos).1 Como veremos más a<strong>del</strong>ante existen más segmentos, pero por simplicidad vamos aempezar suponiendo que sólo existen estos dosPág 33


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org.data························.text····································Cuando el enlazador recibe los ficheros de código objeto, éste fusiona todoslos segmentos de un mismo tipo bajo un único segmento.Otro <strong>con</strong>cepto importante que va unido a los segmentos es el dereubicación. Cuando el compilador genera código objeto, éste almacenatodas las referencias a memoria como direcciones reubicables, es decir, comooffsets respecto a una dirección base 0, que es el principio <strong>del</strong> segmento.Cuando el enlazador reúne todos los ficheros objetos para generar elejecutable, tiene que asignar direcciones absolutas a las direcciones relativasque depositó el compilador, para ello simplemente <strong>con</strong>catena todos lossegmentos <strong>del</strong> mismo tipo, y luego calcula las direcciones absolutas de cadauna de las direcciones reubicables.4.2 Las seccionesCada segmento a su vez está dividido en una o más secciones que nos danun mayor nivel de precisión a la hora de indicar como tratar los datos de esasección.Vamos a comentar qué puede tener cada sección (<strong>del</strong> segmento de código y<strong>del</strong> de datos), para que sirve cada una, así como que directivas se usan para<strong>del</strong>imitar cada sección.4.2.1 Secciones <strong>del</strong> segmento de códigoLa Tabla 2.4 resume las directivas usadas para cada tipo de sección quepuede <strong>con</strong>tener el segmento de código:Directiva Sección Descripción.text (__TEXT,__text) Almacena código deprograma.<strong>con</strong>st (__TEXT,__<strong>con</strong>st) Variables <strong>con</strong>stantes.literal4(__TEXT,__literal4)Variables <strong>con</strong>stantes de 4bytesPág 34


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org.literal8.cstring.<strong>con</strong>structor.destructor.fvmlib_init0.fvmlib_init1.symbol_stub.picsymbol_stub(__TEXT,__literal8)(__TEXT,__cstring)(__TEXT,__<strong>con</strong>structor)(__TEXT,__destructor)(__TEXT,__ fvmlib_init0)(__TEXT,__fvmlib_init1)(__TEXT,__symbol_stub)(__TEXT,__picsymbol_stub)Tabla 2.4: Directivas para cada tipo de sección <strong>del</strong> segmento de códigoVariables <strong>con</strong>stantes de 8bytesCadenas de caracteres<strong>con</strong>stantesUsada sólo por los<strong>con</strong>structores de C++Usada sólo por losdestructores de C++Estas secciones las debe deusar solamente el sistema dememoria virtual de laslibrerías de enlace dinámico.Nosotros nunca debemosponer nada aquí.Usadas para llamar afunciones de librerías deenlace dinámico. Comoveremos más a<strong>del</strong>ante.text Esta directiva se usa para indicar que estamos en el segmento decódigo, y si no usamos ninguna otra directiva para especificar la sección,entonces estamos en la llamada sección de código regular, que es lasección por defecto, la cual debe <strong>con</strong>tener únicamente instruccionesensamblador..<strong>con</strong>st Esta directiva se usa para crear una sección de datos <strong>con</strong>stantes. Silos datos no van a cambiar durante la ejecución <strong>del</strong> programa se puedenguardar en el segmento de código (en vez de en el segmento de datos), <strong>con</strong>las <strong>con</strong>siguientes ventajas que aporta. Por ejemplo respecto a la paginación.El compilador de C usa esta sección para almacenar variables globalesmarcadas como <strong>con</strong>st, las tablas de salto de la sentencia switch, o losvalores de los operandos <strong>con</strong>stantes de las sentencias..literal4 Se usa para guardar sólo datos <strong>con</strong>stantes de 4 bytes, es decirenteros y variables float. Al ser sólo datos de 4 bytes siempre permanecenalineados. Durante el ensamblado el compilador reúne todas las variablesdeclaradas en esta sección que tengan el mismo valor, para que aparezcansólo una vez en memoria..literal8 Igual que antes, pero usada para guardar datos <strong>con</strong>stantes de 8bytes. Principalmente números double. Durante el ensamblado el compiladorreúne todas las variables declaradas en esta sección que tengan el mismovalor.Pág 35


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org.cstring Usada para todas las cadenas de caracteres <strong>con</strong>stantes <strong>del</strong>programa. Durante el ensamblado el compilador reúne todas las variablesdeclaradas en esta sección que tengan el mismo valor, para que aparezcansólo una vez en memoria.Estas directivas sólo indican un cambio de sección, pero no reservanmemoria. Para indicar la cantidad de memoria a reservar y valor inicial deesta memoria reservada tenemos las directivas de la Tabla 2.5:DirectivaDescripción.byte [valor] Reserva espacio para un byte, y le asigna el valordado en valor, ó 0 si no se especifica..short [valor] Reserva espacio para una variable entera de 2bytes, y le asigna el valor dado en valor, ó 0 sino se especifica..long [valor] Reserva espacio para una variable entera de 4bytes, y le asigna el valor dado en valor, ó 0 sino se especifica..single [valor] Reserva espacio para una variable de puntoflotante <strong>con</strong> precisión simple (4 bytes), y le asignael valor dado en valor, ó 0 si no se especifica..double [valor] Reserva espacio para una variable de puntoflotante <strong>con</strong> precisión doble (8 bytes), y le asignael 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..fillPone el valor dado en valor tantas veces comorepeticiones, diga repeticiones. El tamaño de la variabletamaño, valorpuede ser 1,2 ó 4 según diga tamaño.space n_bytes, Pone el valor dado en valor tantas veces como[valor]diga n_bytes, o ceros si no damos valorTabla 2.5: Directivas para indicar la cantidad de memoria a reservar y valor inicialEstas directivas se pueden usar en cualquier sección y lo que hacen esreservar la memoria indicada.Por ejemplo, podemos usar estas directivas así:.text.<strong>con</strong>stc1: .byte 'A'c2: .byte 'B'.literal4i: .long 12Pág 36


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgf: .float 0r1.34e0.literal8d: .double 0d56.e7.cstringmsg: .ascii "Hola mundo\013\000".text ; Ahora van las instrucciones en ensamblador; en una seccion de codigo regularlwz r4,0(r9)lwz r5,0(r11)Una optimización que aplica el compilador a los datos marcados como.literal4, .literal8 o .cstring es que si el mismo valor aparecevarias veces en distintos ficheros de código objeto (aunque aparezcan <strong>con</strong>distinto identificador), utiliza sólo una zona de memoria para todos loscódigos objetos que accedan a ellas.La optimización que hace el compilador al reunir todas las variables <strong>con</strong> elmismo valor en la misma dirección de memoria puede <strong>con</strong>fundir alprogramador, por ejemplo si hacemos:.literal4A1: .long 0A2: .long 0A3: .long 0A4: .long 0No estamos reservando espacio para 4 números de 32 bits sino que al tenerun mismo valor (0 en nuestro ejemplo) el compilador sólo reserva espaciopara un variable de 32 bits, y las etiquetas A1, A2, A3, A4 apuntan a lamisma dirección de memoria.Si quisiéramos reservar memoria para 4 variables de 32 bits cada unadeberíamos de haber usando .<strong>con</strong>st así:.<strong>con</strong>stA1: .long 0A2: .long 0A3: .long 0A4: .long 0Las demás directivas que aparecen en la tabla las comentaremos cuandohayamos avanzado más.Pág 37


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org4.2.2 Secciones <strong>del</strong> segmento de datosLa Tabla 2.6 resume las directivas usadas para cada tipo de sección quepuede <strong>con</strong>tener el segmento de datos:Directiva Sección Descripción.data (__DATA,__data) Sección de datos regular.static_data (__DATA,__static_data) Almacena datos estáticos.non_lazy_symbol_pointer.lazy_symbol_pointer(__DATA,__nl_symbol_pointer)(__DATA,__la_symbol_pointer)El compilador guarda enesta sección punteros asímbolos non-lazy(excepto punteros afunciones)El compilador guarda enesta sección punteros asímbolos lazy..dyld (__DATA,__dyld) Esta sección se usa parael enlazado <strong>con</strong>funciones de librerías deenlace dinámico.Nosotros no debemosusarla..<strong>con</strong>st_data (__DATA,__<strong>con</strong>st) Para almacenar datos<strong>con</strong>stantes en libreríasde enlace dinámicoTabla 2.6: Directivas usadas para cada tipo de sección <strong>del</strong> segmento de datos.data Es la sección de datos regular donde se almacenan datos variablesa no ser que se especifique otra sección..static_data Es una sección que aunque actualmente no usa elcompilador, fue puesta para que el compilador pudiera separar datos globalesy estáticos en secciones distintas.Para reservar memoria en cada una de estas secciones <strong>del</strong> segmento dedatos, además de poder usar las directivas que vimos antes para el segmentode código (.byte, .short, .long, .single, .double, .ascii, .asciz,.fill, .space), podemos usar las dos directivas de la Tabla 2.7, las cualesreservan memoria sin inicializar, cosa que no tiene sentido hacerlo en elsegmento de código por ser de sólo lectura, pero si tiene sentido en elsegmento de datos.Estas dos directivas reservan siempre memoria dentro <strong>del</strong> segmento de datos,<strong>con</strong> lo que aunque aparezcan en el segmento de código la reserva se produceen el segmento de datos regular.Pág 38


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgDirectiva.comm etiqueta, tamaño.lcomm etiqueta, tamañoDescripciónReserva tamaño bytes y crea la etiquetaglobal etiqueta que apunta a esta zonade memoria sin inicializar.Igual a .comm, sólo que la etiqueta es deámbito local, <strong>con</strong> lo que no es accesibledesde fuera <strong>del</strong> móduloTabla 2.7: Directivas para reservar memoria en las secciones <strong>del</strong> segmento de datosSi aparecen en otra sección <strong>del</strong> segmento de datos, la reserva, comonormalmente, se produce en la sección donde aparecen.Por ejemplo si hacemos:.dataA: .long 60 ; Crea una variable de 4 bytes <strong>con</strong>; un valor de 60 en la sección; (__DATA,__data).static_dataB: .long 3 ; Crea una variable de 4 bytes <strong>con</strong>; un valor de 3 en la sección; (__DATA,__static_data).comm C, 4 ; Reserva 4 bytes sin inicializar; en la sección (__DATA,__static_data).text; Ahora van las instrucciones en ensamblador; en la sección regular <strong>del</strong> segmento de código; (__TEXT,__text)lwz r4,0(r9)lwz r5,0(r11).comm D, 20 ; Reserva 20 bytes sin inicializar; en la sección (__DATA,__data); Mas instrucciones en la sección regular; <strong>del</strong> segmento de código (__TEXT,__text)mtlr r0lmw r30,-8(r1)Listado 2.4: Ejemplo de reserva de memoria4.2.3 Crear nuevas seccionesSiempre podemos pedir un cambio de sección usando la directiva .sectionPág 39


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgEsta directiva tiene el formato general:.section segmento, seccionsegmento Indica el segmento, y en principio será __TEXT o __DATA,aunque existen más segmentos que de momento no comentaremos.seccion Indica el nombre de la sección dentro <strong>del</strong> segmento.Las tablas anteriores muestran el nombre que se da a cada uno de lassecciones que hemos comentado.Obsérvese que el nombre <strong>del</strong> segmento va siempre en mayúsculas y el de lasección en minúsculas.Luego en vez de haber puesto:.<strong>con</strong>stA: .long 20Podríamos haberlo hecho <strong>con</strong> la directiva .section así:.section __TEXT,__<strong>con</strong>stA: .long 20La ventaja de esta directiva es que nos permite crear nuevos nombres desegmentos y secciones.4.2.4 Agrupar las seccionesCuando el compilador genera el código objeto, reúne todas las secciones <strong>del</strong>mismo tipo que aparezcan a lo largo <strong>del</strong> fichero fuente, de forma que elsegmento <strong>del</strong> fichero objeto tiene como mucho una sección de cada tipo.Por ejemplo si en el fichero fuente tenemos:.data····················.<strong>con</strong>st····················.text····················.<strong>con</strong>st····················Pág 40


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgEl fichero objeto correspondiente tendrá dos segmentos: de código (__TEXT)y de datos (__DATA), y el segmento de datos a su vez tendrá dos secciones:la de código regular (__TEXT,__text) y las dos secciones declaradas <strong>con</strong>.<strong>con</strong>st se reúnen en una sección de código <strong>con</strong>stante (__TEXT,__<strong>con</strong>st).Cuando el enlazador enlaza los ficheros objeto, vuelve a reunir las secciones<strong>del</strong> mismo tipo de los distintos ficheros objeto, para que sólo haya unasección de cada tipo en el segmento <strong>del</strong> ejecutable.4.3 Indireccionamiento de memoria en lasmáquinas RISCHace años, las memoria que tenían que direccionar las máquinas erarelativamente pequeña (p.e 2 8 B ó 2 16 B), <strong>con</strong> lo que las instruccionesensamblador podían incluir la dirección de memoria a la que acceder comoparte de la instrucción, llamado indireccionamiento inmediato o bienusaban un registro para almacenar la dirección a la que acceder, llamadoindireccionamiento de registro.Cuando este espacio de memoria fue creciendo, los fabricantes se dieroncuenta de que incluir direcciones de memoria tan largas en las instrucciones(indireccionamiento inmediato), aumentaba mucho el tamaño de losprogramas <strong>con</strong> lo que decidieron que las instrucciones debían de usar sóloindireccionamiento <strong>con</strong> registro.En las máquinas CISC es muy típico que la dirección de memoria a la quevayamos a acceder forme parte de la instrucción.Por ejemplo en x86 podemos usar la instrucción:movb %al,dirPara mover el byte bajo <strong>del</strong> registro AL a la dirección de memoria indicada endir.En máquinas RISC como <strong>PowerPC</strong> o SPARC sólo se permite elindireccionamiento de registro.Además, como comentamos en el Tema 1, todas las instrucciones de<strong>PowerPC</strong> ocupan 32 bits, <strong>con</strong> lo que no podemos meter una dirección dememoria (de 32 bits) dentro de la instrucción, ya que sólo la dirección dememoria ocuparía los 32 bits disponibles para codificar la instrucciónEl enfoque <strong>del</strong> indireccionamiento <strong>con</strong> registro soluciona el problema, ya queahora la instrucción ensamblador lo único que <strong>con</strong>tiene es el número dePág 41


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgregistro donde está la dirección de memoria a acceder. Los registros que seusan para indicar direcciones de memoria son los GPR, de los cuales hay 32(de r0 a r31), <strong>con</strong> lo cual la instrucción sólo gasta 5 bits (2 5 =32), en vez de32 bits.Sin embargo aquí surge un problema <strong>con</strong>ocido como el problema <strong>del</strong>bootstraping, que es el de cómo almacenamos la primera dirección dememoria de 32 bits en un registro. Es decir, ninguna instrucción <strong>del</strong> <strong>PowerPC</strong>puede permitirse el lujo de gastar 32 bits para guardar este valor quequeremos meter en un registro.La solución que se usa pasa por usar 2 instrucciones, una de ella carga los 16bits altos <strong>del</strong> registro, y la otra los 16 bits bajos.Para obtener la parte alta y la parte baja de una dirección de 32 bits (queposiblemente saquemos de una etiqueta) se usan los operadores lo16()hi16() y ha16() tal como se explica a <strong>con</strong>tinuación.o lo16(expresion) evalúa a los 16 bits bajos de expresiono hi16(expresion) evalúa a los 16 bits altos de expresióno ha16(expresion) evalúa a los 16 bits altos de expresiónincrementando 1 si el bit <strong>del</strong> signo de lo16(expresion) es 1. Comovamos a explicar en breve, esto permite cargar el valor correcto de unadirección de memoria en un registro cuando este bit vale 1.Vamos a ver cómo se cargan los 32 bits de una dirección de memoria en dospartes, cada una de las cuales carga 16 bits.En primer lugar comentar que sí hay instrucciones que pueden recibir comooperando un valor de 16 bits, que es el que luego cargan en el registro.Entre ellas en<strong>con</strong>tramos la instrucción:addis rD,(rA|0),SIMM /* ADD Immediate Shift */Esta instrucción recibe tres operandos:rD Es el registro destino de la operaciónrA Es un registro origen de la operación de suma.SIMM Es un valor de 16 bits que actúa como segundo operando. SIMMsignifica Signed IMMediate, es decir se <strong>con</strong>sidera como un número de 16 bits<strong>con</strong> signo.(rA|0) es una notación muy usada en las instrucciones <strong>del</strong> <strong>PowerPC</strong> quesignifica que aquí podemos dar uno de los 32 registros de GPR excepto r0, obien un 0, en cuyo caso significa que este operando vale 0, <strong>con</strong> lo que en rDse almacena el valor de sumar 0 a SIMM, es decir el valor de rD=0+SIMM.Pág 42


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgLa razón por la que podemos indicar cualquiera de los registros menos el r0,es que en la codificación binaria de la instrucción, el código 0 se utiliza paraindicar un 0 binario, y no el <strong>con</strong>tenido <strong>del</strong> registro r0.Luego ahora podemos usar la instrucción:addis r2,0,hi16(expr)Esta instrucción carga el valor de SIMM en r2, e inmediatamente despuésdesplaza este valor a la derecha 16 posiciones, para cargar los 16 bits altosde expr en el registro r2.A <strong>con</strong>tinuación tenemos que cargar los 16 bits bajos de expr en el registro,para lo cual podemos usar la instrucción:ori rA,rS,UIMM /* OR Immediate */rA es el destino de la operaciónrS es uno de los operandos.UIMM (Unsigned IMMediate) es el otro operando.La operación calcula el OR binario entre rS y 0000||UIMM y lo deposita enrA.Luego ahora ya podemos escribir las dos instrucciones que cargan unadirección de memoria de 32 bits en un registro.addis r2,0,hi16(expr)ori r2,r2,lo16(expr)Aún queda por ver cuándo y cómo se usa ha16(), que lo vamos a ver en elsiguiente punto.4.4 Modos de indireccionamientoLos modos de indireccionamiento son las formas en que podemos indicaruna dirección de memoria en la que las instrucciones de nuestro programaquieren leer o escribir.Como sabemos, una instrucción <strong>con</strong>sta de un campo opcode, que indica quehace la instrucción, y de unos operandos. Los operandos pueden estarcodificados directamente dentro de la instrucción, llamado operandoinmediato, o situado en memoria en cuyo caso tememos que hacer unindireccionamiento <strong>del</strong> operando.Pág 43


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgComo hemos comentado en el apartado 4.3, este indireccionamiento puedeser un indireccionamiento inmediato, cuando en el operando almacenamos ladirección de memoria a la que acceder (sólo en máquinas CISC), o unindireccionamiento de registro, cuando en el operando almacenamos elregistro que tiene la dirección de memoria a la que acceder.Es muy típico que el indireccionamiento de registro se haga sumando a elvalor <strong>del</strong> registro indireccionando una variable, lo cual permite que podamosreferirnos a direcciones de memoria <strong>con</strong>tiguas (p.e. arrays, variables de unsegmento). En este caso se llama registro base al registro a cuyo <strong>con</strong>tenidole sumamos una variable llamada índice. El índice puede ser una <strong>con</strong>stantecodificada dentro de la instrucción, en cuyo caso tenemos unindireccionamiento de registro base e índice inmediato, o bien ser unsegundo registro, en cuyo caso tenemos un indireccionamiento deregistro base y registro índice.El <strong>PowerPC</strong> dispone sólo de dos modos de indireccionamiento. Estos sonrelativamente pocos si los comparamos <strong>con</strong> la gran cantidad de modos deindireccionamiento de que suelen disponer los procesadores CICS como x86 oMotorola 68000.En principio el disponer sólo de dos modos de indireccionamiento simplifica la<strong>con</strong>strucción de programas sin penalización en el rendimiento, es más aldisponer de pocos modos de indireccionamiento se simplifica el cableado <strong>del</strong>micro, que tiene que descodificar menos instrucciones, mejorando elrendimiento.Como hemos dicho, los dos modos de indireccionamiento que existen en<strong>PowerPC</strong> son:o Indireccionamiento de registro base e índice inmediatoo Indireccionamiento de registro base y registro índice4.4.1 Indireccionamiento de registro base e índiceinmediatoLas instrucciones que usan este modo de indireccionamiento tienen codificadodentro de la instrucción un número <strong>con</strong> signo de 16 bits que actúa comoíndice. (operador d), al cual se le extiende el signo hasta los 32 bits y se lesuma <strong>con</strong> un GPR (operador rA) para generar la dirección efectiva a la queacceder.En <strong>PowerPC</strong> existe la regla de que siempre que se usan registros paraindireccionar memoria se usa la forma (rA|0), donde si rA es 0, se le suma0 a d (en vez <strong>del</strong> <strong>con</strong>tenido de r0), <strong>con</strong> lo que r0 se puede usar paraPág 44


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orginstrucciones que realizan operaciones aritméticas, pero no se puede usarnunca para indireccionar.En la Figura 2.1 se muestra cómo se genera la dirección efectiva en lasindirecciones de registro e índice inmediato.Codificación de la instrucción0 5 6 10 11 15 16 31Opcode rD/rS rA d¿rA=0?NoSí00 15 16 31Extensión de signod+GPR(rA)Direción efectivaGPR(rD/rS)StoreLoadMemoria principalFigura 2.1: Indirecciones de registro e índice inmediatoEstas instrucciones siempre reciben un operando de la forma d(rA), quesignifica 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 <strong>con</strong> signod.La Tabla 2.8 y Tabla 2.9 muestran las principales instrucciones de acceso amemoria que usan este modo de indireccionamiento:Instrucciónlbz rD,d(rA)lbzu rD,d(rA)lhz rD,d(rA)Descripción(Load Byte and Zero) El byte en la dirección efectivad(rA) se carga en el byte bajo de rD, los demásbytes de rD quedan a 0(Load Byte and Zero with Update) Igual a lbz sóloque la dirección efectiva se guarda en rA una vezrealizada la operación de carga(Load Half-word and Zero) El half-word en la direcciónefectiva d(rA)se carga en los dos bytes bajos de rD,los demás bytes de rD quedan a 0Pág 45


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orglhzu rD,d(rA)lha rD,d(rA)lhau rD,d(rA)lwz rD,d(rA)lwzu rD,d(rA)(Load Half-word and Zero with Update) Igual a lhzsólo que la dirección efectiva se guarda en rA unavez realizada la operación de carga(Load Half-word Algebraic) El half-word en la direcciónefectiva d(rA)se carga en los dos bytes bajos de rD,los demás bytes de rD se rellenan <strong>con</strong> el bit mássignificativo <strong>del</strong> half-word cargado, es decir, expandeel signo(Load Half-word Algebraic with Update) Igual a lhasólo que la dirección efectiva se guarda en rA unavez realizada la operación de carga(Load Word and Zero) El word en la dirección efectivad(rA) se carga en rD. Obsérvese que al medir unGPR 32 bits no carga 0 en el resto <strong>del</strong> registro si elGPR es de 32 bits, pero si lo haría si la instrucción seejecuta en una máquina 64 bits(Load Word and Zero with Update) Igual a lwz sóloque la dirección efectiva se guarda en rA una vezrealizada la operación de cargaTabla 2.8: Instrucciones de carga de enteros <strong>con</strong> indireccionamiento de registro base eíndice inmediatoInstrucciónstb rS,d(rA)stbu rS,d(rA)sth rS,d(rA)sthu rS,d(rA)stw rS,d(rA)stwu rS,d(rA)Descripción(STore Byte) El byte menos significativo de rS seguarda en la posición de memoria dada por d(rA)(STore Byte with Update) Igual a stb, sólo quedespués de guardar el dato en memoria, en rA seguarda la dirección efectiva calculada como d(rA)(STore Half-word) El half-word menos significativo derS se guarda en la posición de memoria dada pord(rA)(STore Half-word with Update) Igual a sth, sólo quedespués de guardar el dato en memoria, en rA seguarda la dirección efectiva calculada como d(rA)(STore Word) El valor de rS se guarda en la posiciónde memoria dada por d(rA)(STore Byte with Update) Igual a stw, sólo quedespués de guardar el dato en memoria, en rA seguarda la dirección efectiva calculada como d(rA)Tabla 2.9: Instrucciones de almacenamiento de enteros <strong>con</strong> indireccionamiento de registrobase e índice inmediatoPág 46


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org4.4.2 EjemploComo ejemplo el Listado 2.5 muestra un programa que calcula la suma dedos números almacenados en memoria, y deposita el resultado en unatercera variable de memoria./* Descripción: Programa que suma dos números* situados en memoria* Escrito por: Fernando López Hernández*/.data // Segmento de datosSD:.lcomm C,4 ; Reserva 4 bytes sin inicializar.text // Segmento de códigoSC:.<strong>con</strong>st // Sección (__TEXT,__<strong>con</strong>st)A: .long 3 ; Variable <strong>con</strong>stante <strong>con</strong> el; primer operando valiendo 3B: .long 5 ; Variable <strong>con</strong>stante <strong>con</strong> el; segundo operando valiendo 5.text // Sección (__TEXT,__text).globl _main.align 2_main:// Cargamos la dirección base <strong>del</strong> segmento// de código en r8addis r8,0,hi16(SC)ori r8,r8,lo16(SC)// Cargamos la dirección base <strong>del</strong> seg de datos en r9addis r9,0,hi16(SD)ori r9,r9,lo16(SD)// Cargamos A, B en r2 y r3lwz r2,lo16(A-SC)(r8)lwz r3,lo16(B-SC)(r8)// Calculamos la suma en r4add r4,r2,r3// Guardamos el resultado que tenemos en r4 en Cstw r4,lo16(C-SD)(r9)blrListado 2.5: Programa que calcula la suma de dos números almacenados en memoriaEl anterior programa tiene tanto un segmento de datos (.data) como unsegmento de código (.text).Pág 47


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgEl único dato que se guarda en el segmento de datos es la variable C, ya quees la única que va a ser modificada por el programa.El segmento de código tiene dos secciones:o Una es la declarada por .<strong>con</strong>st en la que declaramos las variables A yB, ya que son variables de sólo lectura, <strong>con</strong> lo que es mejor guardarlasen el segmento de código.o La otra sección es una sección de código regular, declarada al volver ausar .text, en la cual se guarda el programa en sí.Obsérvese que al principio de cada segmento (que no de cada sección)hemos puesto una etiqueta, SD (Segmento de Datos) y SC (Segmento deCódigo), las cuales nos van a ser muy útiles, ya que ahora para referirnos acualquier otra etiqueta <strong>del</strong> segmento podemos dar una dirección relativa aesta etiqueta.En <strong>con</strong>creto hemos guardado en r8 el valor de SC y en r9 el valor de SDusando el mecanismo de carga de una dirección en dos instrucciones quecomentamos antes:// Cargamos la dirección base <strong>del</strong> seg de código en r8addis r8,0,hi16(SC)ori r8,r8,lo16(SC)// Cargamos la dirección base <strong>del</strong> seg de datos en r9addis r9,0,hi16(SD)ori r9,r9,lo16(SD)Luego, cuando queramos referirnos a las demás etiquetas de un segmentosólo tendremos que dar un desplazamiento relativo respecto al principio <strong>del</strong>segmento, es decir, si queremos acceder a las variables A o B usamoslo16(A-SC)(r8) y lo16(B-SC)(r8) respectivamente. Análogamentecuando queramos acceder a C usaremos lo16(C-SD)(r9)4.4.3 Acceso a memoria <strong>con</strong> actualización de registroExiste una variante de las instrucciones de acceso a memoria porindireccionamiento de registro base e índice inmediato que son lasinstrucciones de acceso a memoria por indireccionamiento de registro base eíndice inmediato <strong>con</strong> actualización.Estas instrucciones aparecen en la Tabla 2.8 y Tabla 2.9 y se caracterizanporque son iguales a las instrucciones de acceso a memoria normales, sóloque su nombre acaba en u, por ejemplo en vez de llamarse lwz (Load Wordand Zero) se llaman lwzu (Load Word and Zero with Update).Pág 48


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgEstas instrucciones después de realizar el acceso a memoria guardan en elregistro que estamos usando para indireccionar la memoria (que suelellamarse rA), la dirección de memoria efectiva a la que han accedido. Esto esespecialmente útil a la hora de recorrer estructuras de datos como los arrays,donde los datos ocupan posiciones de memoria <strong>con</strong>secutivas.Por ejemplo si queremos leer un array de elementos de tipo half-wordpodemos hacer un bucle así:.data.lcomm A,20 ; 10 elementos de 2 bytes.text···········addis r3,0,hi16(A)ori r3,r3,lo16(A)-2DESDE 1 HASTA 10lhzu r2,2(r3); Procesamos r2FIN_DESDE4.4.4 Uso <strong>del</strong> operador ha16()Hasta ahora hemos visto que para acceder a memoria primero tenemos quecargar en un registro una dirección de memoria, para lo cual usábamos dosinstrucciones:addis r3,0,hi16(var)ori r3,r3,lo16(var)Vamos a ver ahora que usando un pequeño truco vamos a poder cargar enun registro sólo la parte alta de la dirección, y después aprovechamos elindireccionamiento de registro base e índice inmediato para indicar la partebaja de la dirección, más o menos así:addis r3,0,ha16(var)lwz r2,lo16(var)(r3)Obsérvese que ahora, para cargar la parte alta de la dirección en el registro,usamos ha16() en vez de hi16(). Como dijimos en el apartado 4.3ha16(expr) evalúa a los 16 bits altos de expresión, incrementando 1 si elbit <strong>del</strong> signo de lo16(expr) es 1.¿Por qué se hace este incremento? La razón es que si el bit de signo <strong>del</strong>o16(expr) es 1, es que este número es negativo <strong>con</strong> lo que al calcularlo16(expr)(rA), el número está restando al valor <strong>del</strong> registro, pero enrealidad para calcular la dirección efectiva debería de sumar a rA el valor <strong>del</strong>o16(expr), aunque como hemos partido el número de 32 bits de laPág 49


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgetiqueta en dos números de 16 bits, y el índice inmediato de la instruccióncodificada se interpreta como un SIMM (Signed IMMediate), la instruccióninterpreta el bit alto de lo16(expr) como un bit de signo, en vez de comoun bit de peso que es lo que es. Si sumamos uno a la parte alta de ladirección, cuando este bit vale 1, solucionamos el problema.Con un ejemplo queda más claro.Supongamos que queremos acceder a la dirección de 32 bits:dir = 01101001 01101011 10010111 00110100Si calculamos lo16(dir), hi16(dir), ha16(dir) tenemos:lo16(dir) = 10010111 00110100hi16(dir) = 01101001 01101011ha16(dir) = 01101001 01101100Es decir, como el bit alto de lo16(dir) es 1 hemos sumado 1 a ha16(dir)Ahora cuando la instrucción calcula d(rA) como la suma de la parte alta másla parte baja, si intentamos calcular la dirección efectiva dir comohi16(dir)+lo16(dir) tenemos:hi16(dir) = 01101001 01101011 00000000 00000000lo16(dir) = 11111111 11111111 10010111 00110100 +_________________________________________________dir = 01101001 01101010 10010111 00110100Que no es el valor de la dirección efectiva dir a la que queríamos acceder.Aquí, al ser el bit de signo de lo16(dir) negativo, se ha extendido el signoantes de sumar.Mientras que si la suma la hacemos de ha16(dir)+lo16(dir) siobtenemos el valor de la dirección efectiva dir:ha16(dir) = 01101001 01101100 00000000 00000000lo16(dir) = 11111111 11111111 10010111 00110100 +_________________________________________________dir = 01101001 01101011 10010111 00110100Podemos modificar el ejemplo <strong>del</strong> Listado 2.5 para que use ha16() en vez dehi16() como muestra el Listado 2.6.Pág 50


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org/* Descripción: Programa que suma dos números* situados en memoria usando ha16()* Escrito por: Fernando López Hernández*/.data // Segmento de datos.lcomm C,4 ; Reserva 4 bytes sin inicializar.text // Segmento de código.<strong>con</strong>st // Sección (__TEXT,__<strong>con</strong>st)A: .long 3 ; Variable <strong>con</strong>stante <strong>con</strong> el primer; operando valiendo 3B: .long 5 ; Variable <strong>con</strong>stante <strong>con</strong> el segundo; operando valiendo 5.text // Sección (__TEXT,__text).globl _main.align 2_main:// Cargamos A en r2addis r5,0,ha16(A)lwz r2,lo16(A)(r5)// Cargamos B en r3addis r5,0,ha16(B)lwz r2,lo16(B)(r5)// Calculamos la suma en r4add r4,r2,r3// Guardamos el resultado que tenemos en r4 en Caddis r5,0,ha16(C)stw r4,lo16(C)(r5)blrListado 2.6: Suma de números <strong>con</strong> ha16() y hi16()Ahora no usamos punteros a la base <strong>del</strong> segmento, sino que cuandoqueremos acceder a una variable, primero cargamos la parte alta de ladirección <strong>con</strong>:addis r5,0,ha16(dir)Y luego accedemos a memoria usando un indireccionamiento de registro basee índice inmediato:stw r4,lo16(dir)(r5)4.4.5 Indireccionamiento de registro base y registro índiceVamos a ver el otro tipo de indireccionamiento a memoria de que dispone el<strong>PowerPC</strong>: El indireccionamiento de registro base y registro índice.Pág 51


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgLa Figura 2.2 muestra cómo se genera la dirección efectiva en lasindirecciones de registro y registro índice.Codificación de la instrucción0 5 6 10 11 15 16 20 21 31Opcode rD/rS rA rB subopcode 0¿rA=0?NoSí00 15 16 31GPR(rB)+GPR(rA)Direción efectivaGPR(rS/rS)StoreLoadMemoria principalFigura 2.2: Indirecciones de registro y registro indiceLas instrucciones que usan este modo de indireccionamiento usan dos GPR(llamados rA y rB) para calcular la dirección efectiva como la suma de estos.A rA se le llama registro base, y a rB registro índice. En <strong>con</strong>creto secalcula como (rA|0)+rB, es decir, rA puede ser uno de los registros de r1a r31 (pero no r0), o bien 0, en cuyo caso para calcular la dirección efectivase usa sólo el valor de rB.Las Tabla 2.10 y Tabla 2.11 muestran las principales instrucciones que usaneste modo.Instrucciónlbzx rD,rA,rBlbzux rD,rA,rBlhzx rD,rA,rBDescripción(Load Byte and Zero indeXed) El byte en la direcciónefectiva (rA|0)+rB se carga en el byte bajo de rD,los demás bytes de rD quedan a 0(Load Byte and Zero with Update indeXed) Igual albzx sólo que la dirección efectiva se guarda en rAuna vez realizada la operación de carga(Load Half-word and Zero indeXed) El half-word en ladirección efectiva (rA|0)+rB se carga en los dosbytes bajos de rD, los demás bytes de rD quedan a 0Pág 52


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orglhzux rD,rA,rBlhax rD,rA,rBlhaux rD,rA,rBlwzx rD,rA,rBlwzux rD,rA,rB(Load Half-word and Zero with Update indeXed) Iguala lhzx sólo que la dirección efectiva se guarda en rAuna vez realizada la operación de carga(Load Half-word Algebraic indeXed) El half-word en ladirección efectiva (rA|0)+rB se carga en los dosbytes bajos de rD, los demás bytes de rD se rellenan<strong>con</strong> el bit más significativo <strong>del</strong> half-word cargado, esdecir, expande el signo(Load Half-word Algebraic with Update indeXed) Iguala lhax sólo que la dirección efectiva se guarda en rAuna vez realizada la operación de carga(Load Word and Zero indeXed) El word en la direcciónefectiva (rA|0)+rB se carga en rD. Obsérvese que almedir un GPR 32 bits no carga 0 en el resto <strong>del</strong>registro si el GPR es de 32 bits, pero si lo haría si es lainstrucción se ejecuta en una máquina 64 bits(Load Word and Zero with Update indeXed) Igual alwzx sólo que la dirección efectiva se guarda en rAuna vez realizada la operación de cargaTabla 2.10: Instrucciones de carga de enteros <strong>con</strong> indireccionamiento de registro base yregistro índiceInstrucciónstbx rS,rA,rBstbux rS,rA,rBsthx rS,rA,rBsthux rS,rA,rBstwx rS,rA,rBstwux rS,rA,rBDescripción(STore Byte indeXed) El byte menos significativo derS se guarda en la posición de memoria dada por(rA|0)+rB(STore Byte with Update indeXed) Igual a stbx, sóloque después de guardar el dato en memoria, en rA seguarda la dirección efectiva calculada como(rA|0)+rB(STore Half-word indeXed) El half-word menossignificativo de rS se guarda en la posición dememoria dada por (rA|0)+rB(STore Half-word with Update indeXed) Igual a sthx,sólo que después de guardar el dato en memoria, enrA se guarda la dirección efectiva calculada como(rA|0)+rB(STore Word indeXed) El valor de rS se guarda en laposición de memoria dada por (rA|0)+rB(STore Byte with Update indeXed) Igual a stwx, sóloque después de guardar el dato en memoria, en rA seguarda la dirección efectiva calculada como(rA|0)+rBTabla 2.11: Instrucciones de almacenamiento de enteros <strong>con</strong> indireccionamiento de registrobase y registro índicePág 53


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgLas instrucciones <strong>con</strong> indireccionamiento de registro base y registro índice seusan principalmente en dos <strong>con</strong>textos:o Para acceder a elementos de un array por índice. En este caso rApuede apuntar a la base <strong>del</strong> array, y rB <strong>con</strong>tener el desplazamientorespecto al principio <strong>del</strong> array.o Para mantener punteros a las variables de un segmento. En este casorA <strong>con</strong>tiene la dirección de memoria de comienzo <strong>del</strong> segmento y rB<strong>con</strong>tiene el lo16(offset) de la dirección de memoria de la variable aacceder.4.5 Carga y almacenamiento de bloques de bytes<strong>PowerPC</strong>, además de las instrucciones de carga/almacenamiento que hemosvisto, dispone de operaciones que permiten cargar/almacenar muchos bytes ala vez.Estas instrucciones lo que hacen es cargar muchos datos de memoria a losregistros indicados en la instrucción.Vamos a estudiar estas instrucciones divididas en dos grupos:1) Instrucciones de carga y almacenamiento de multiples words.Instrucciónlmw rD,d(rA)stmw rS,d(rA)Descripción(Load Multiple Word) Carga los word almacenados apartir 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 direcciónde memoria d(rA) los valores de los registros quevan desde r(S) a r(S+n) siendo n=(31-S)Tabla 2.12: Instrucciones de carga y almacenamiento de multiples wordsEstas instrucciones aparecen en la Tabla 2.12 y ambas instrucciones utilizanun indireccionamiento de registro base <strong>con</strong> índice inmediato.La instrucción lmw carga n words en los registros que van desde rD hastar31.La dirección de memoria apuntada por d(rA) debe de estar alineada a unaposición múltiplo de 4, o se producirá una excepción.Por ejemplo para cargar un array de 20 words desde memoria a registrospodemos hacer:Pág 54


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org.<strong>con</strong>stA: .long 3456 ; 20 enteros.long -565··········.long 1767.textaddis r2,0,ha16(A)lmw r11,A(r2)La instrucción carga los registros que van de r11 a r31 <strong>con</strong> los 20 números<strong>del</strong> array A.Si el registro usado para indireccionar (r2 en el ejemplo anterior) hubieraestado dentro <strong>del</strong> rango rD..r31 se sobrescribe <strong>con</strong> el valor leído dememoria.2) Instrucciones de carga y almacenamiento de múltiples bytes(caracteres)Estas instrucciones, al igual que antes, nos permiten leer un bloque dememoria, pero a diferencia de antes:o El número de bytes a leer no tiene porque ser múltiplo de 4o La dirección de memoria donde empezamos a leer no tiene porque sermúltiplo de 4Las cuatro instrucciones de que disponemos aparecen en la Tabla 2.13:Instrucciónlswi rD,rA,nstswi rS,rA,nlswx rD,rA,rBstswi rS,rA,rBDescripción(Load String Word Indirect) Carga los n primerosbytes a partir de la dirección de memoria dada por(rA|0) en los registros que van desde rD ena<strong>del</strong>ante(Store String Word Indirect) Guarda a partir de ladirección de memoria (rA|0) los n primeros bytesempezando a <strong>con</strong>tar por el byte más significativo derD en a<strong>del</strong>ante(Load String Word indeXed) Carga los n=XER[25-31]primeros bytes a partir de la dirección de memoriadada por (rA|0)+rB en los registros que van desderD en a<strong>del</strong>ante(STore String Word indeXed) Guarda a partir de ladirección de memoria (rA|0)+rB los n=XER[25-31]primeros bytes empezando a <strong>con</strong>tar por el byte mássignificativo de rS en a<strong>del</strong>anteTabla 2.13: Instrucciones de carga y almacenamiento de múltiples bytes (caracteres)Pág 55


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgEl uso <strong>del</strong> registro XER se explica en el apartado 5.2Por ejemplo, supongamos que tenemos una cadena de 12 caracteres en ladirección de memoria etiquetada saludo y la queremos copiar en la direcciónde memoria mensaje (la cual tiene un tamaño máximo de 255 caracteres).Podríamos realizar la copia rápidamente así:.cstringsaludo: .ascii "Hola mundo!\000"mensaje: .org 255.textaddis r2,0,hi16(saludo)ori r2,r2,lo16(saludo)lswi r10,r2,12 ; Rellena los registros; r10,r11,r12,r13addis r2,0,hi16(mensaje)ori r2,r2,lo16(mensaje)addi r3,0,12mtxer r3 ; En XER cargamos el número; de bytes a leerandi r3,r3,0stswi r10,r2,r3 ; Pasa r10,r11,r12,r13 a memoria4.6 MnemonicsPara simplificar algunas operaciones de programación el lenguajeensamblador de <strong>PowerPC</strong> define una serie de mnemonics 2 (palabras fácilesde recordar) que son instrucciones que equivalen realmente a otra instrucciónensamblador, pero que permiten recordar una operación cuyo nombre noevoca al propósito de la operación que queremos realizar.A lo largo <strong>del</strong> estudio de los distintos grupos de instrucciones ensamblador,vamos a acabar <strong>con</strong> una sección dedicada a los mnemonics que existen paraoperaciones comunes.El primer mnemonic que vamos a comentar es:mr rD,rS equivale a or rD,rS,rSEste mnemonic lo que hace es copiar el <strong>con</strong>tenido de rS a rD.2 Aunque en castellano se pueden traducir por mnemónicos, hemos preferido mantener eltérmino inglés para facilitar la comprensión de la documentaciónPág 56


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgUn característica de los sistemas RISC es que intentan disponer <strong>del</strong> menorjuego de instrucciones posible, <strong>con</strong> lo que si existen varias instrucciones querealizan la misma operación, sólo implementan una de ellas.<strong>PowerPC</strong> no dispone de ninguna operación de copia de datos entre registros,porque el mnemonic mr se implementa como una instrucción or.En <strong>PowerPC</strong> tampoco existe ninguna instrucción que cargue un número enregistro. De hecho, como comentamos antes sería imposible diseñar unaoperación que cargara 32 bits, ya que todas las instrucciones en <strong>PowerPC</strong>ocupaban 32 bits, pero sí que sería posible diseñar una operación que cargara16 bits, usando los otros 16 bits para codificar la instrucción.Aun así en <strong>PowerPC</strong> no existe ninguna instrucción que cargue 16 bits enregistro, sino que en vez de esto se utilizan los siguientes mnemonics:li rD,valor equivale a addi rD,0,valorlis rD,valor equivale a addis rD,0,valorVemos que están implementados como llamadas a addi (ADD Immediate) yaddis (ADD Immediate Shift). Estos mnemonics nos permiten cargar los 16bits altos y los 16 bits bajos por separado. Pero no las dos partes, vemosporqué.Por ejemplo, para cargar un número de 32 bits en el registro r2, podemoshacer:numero = 1768937;addis r2,0,ha16(numero)addi r2,r2,lo16(numero)Y si lo fuéramos a hacer <strong>con</strong> los nuevos mnemonics podríamos 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 instrucciónborra el valor <strong>del</strong> registro para cargar la parte baja.Luego, es importante recordar que la forma correcta de cargar un número de32 bits en registro no es la dada anteriormente sino esta:Pág 57


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgnumero = 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), <strong>con</strong> lo quepara cargar la parte baja usamos ori, que en vez de sumar pone los bits <strong>del</strong>a parte baja.El último mnemonic que vamos a comentar de momento, es:la rD,d(rA) equivale a addi rD,rA,dEste mnemonic se utiliza cuando en rA tenemos los 16 bits altos de ladirección de un segmento y queremos obtener la dirección de variables deese segmento como un desplazamiento d respecto a esa dirección base, porejemplo:SD:.dataA: .long 45B: .long 0C: .long 37·············.text; En r2 obtenemos la dirección base <strong>del</strong> segmentolis r2,ha16(A); Hacemos que r3 apunte a A, r4 apunte a B; y r5 apunte a Cla r3,A(r2)la r4,B(r2)la r5,C(r2)Pág 58


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org5 Instrucciones de trabajo <strong>con</strong> enterosLas instrucciones de trabajo <strong>con</strong> enteros cogen sus operandos de los GPRs ydepositan el resultado de la operación en un GPR.A no ser que se especifique lo <strong>con</strong>trario estas instrucciones tratan a losoperandos como números <strong>con</strong> signo. En caso <strong>con</strong>trario se indica en el propionombre de la instrucción, por ejemplo, mulhwu (MULtiply High WordUnsigned) o divwu (DIVide Word Unsigned) son instrucciones que trabajan<strong>con</strong> números sin signo.Para el estudio de las instrucciones de trabajo <strong>con</strong> enteros las hemos divididoen los siguientes grupos:o Instrucciones aritméticas <strong>con</strong> enteroso Instrucciones de comparación de enteroso Instrucciones lógicas <strong>con</strong> enteroso Instrucciones de desplazamiento y rotación de enterosAntes de meternos <strong>con</strong> el estudio de estas instrucciones vamos a explicar dosregistros que se usan para almacenar el resultado de ejecutar estasoperaciones: Los registros CR y XER.5.1 El registro CR (Condition Register)El registro CR sirve para reflejar el resultado de ejecutar ciertas operaciones yproporciona un mecanismo para realizar comprobaciones en el caso de lossaltos.Los bits de este registro están agrupados en campos de 4 bits llamadosCR0,CR1,...,CR7 tal como muestra la Figura 2.3:CR0 CR1 CR2 CR3 CR4 CR5 CR6 CR70 3 4 7 8 11 12 15 16 19 20 23 24 27 28 31Figura 2.3: Organización <strong>del</strong> registro CR en camposEn cualquier momento el valor de este registro puede ser leído <strong>con</strong> lainstrucción:mfcr rD /* Move From Condition register */Que copia el <strong>con</strong>tenido <strong>del</strong> registro CR en el registro rDPág 59


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgTambién podemos modificar el <strong>con</strong>tenido de cualquiera de los campos <strong>del</strong> CRusando:mtcrf mascara,rS /* MoveTo Condition Register Fields */El acceso a CR es a nivel de campo, de forma que para cada campo semodifican los 4 bits <strong>del</strong> campo o no se modifica ninguno, para ello mascaraes un número de 8 bits que actúa como máscara a la hora de indicar quecampos <strong>del</strong> CR serán afectados, de forma que los bits de mascara quetengan 1 indican que ese campo debe actualizarse <strong>con</strong> el <strong>con</strong>tenido de suscorrespondientes 4 bits <strong>del</strong> registro rS y los que tengan 0 indican que esecampo no debe modificarse.Por ejemplo, si queremos copiar todos los bits <strong>del</strong> registro r2 al registro CRharemos:mascara=255 ; 1111 1111mtcrf mascara,r2Si queremos modificar sólo los campos CR6 y CR7 de CR haríamos:mascara=3 ; 0000 0011mtcrf mascara,r2Y si sólo queremos modificar CR0 haríamos:mascara=128 ; 1000 0000mtcrf mascara,r2El principal uso de los campos de CR es almacenar el resultado de ejecutaroperaciones de comparación como por ejemplo cmp, las cuales veremos mása fondo en el apartado 5.4, y cuyos resultados se utilizan para tomardecisiones, como por ejemplo, los saltos.Las instrucción cmp tiene el formato:cmp CRF,L,rA,rBdonde CRF es el número <strong>del</strong> campo de CR donde depositar el resultado, L enlas arquitecturas de 64 bits indica si los registros se tratan como números de32 bits o de 64 bits, pero en las máquinas de 32 bits siempre debe valer 0, yrA, rB son los registros cuyos valores vamos a comparar.Luego si queremos almacenar el resultado de comparar r5 y r6 en el campoCR2 podemos hacer:cmp 2,0,r5,r6Pág 60


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgEl significado de los bits <strong>del</strong> campo destino después de realizar la operaciónes el que aparece en la Tabla 2.14.Bit Descripción0 El primer operando es menor al segundo1 El primer operando es mayor al segundo2 Los operandos son iguales3 Summary Overflow (SO). Hubo un overflow. Este bit es una copia <strong>del</strong>estado final <strong>del</strong> bit XER[SO]Tabla 2.14: Significado de los bits de los campos de CR en las instrucciones de comparaciónSi no se especifica campo de CR, por defecto va al CR0. Por desgracia elcampo L es obligatorio indicarlo, aunque para las arquitecturas de 32 bitssiempre deba valer 0.Por ejemplo, si queremos saber si es igual el <strong>con</strong>tenido de los registros r5 yr6 haríamos:cmp 0,r5,r6mfcrf 128,r2 ; Copiamos el campo CR0 a r2andi r2,4 ; Quitamos todos los bits menos el bit; que indica que que son igualesAquí guardamos el resultado de la operación de comparación en CR0(obsérvese que no hemos indicado el campo de CR, pero sí L) y despuéssacamos 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 losresultados de distintas comparaciones, cada una de ellas en un campodistinto. Además como se explica en el Apéndice B esto permite acelerar laejecución de instrucciones al reducir las dependencias entre ellas en elpipeline.Otra forma de modificar el registro CR es como resultado de ejecutar unainstrucción en la que se ha pedido reflejar el resultado de una operación <strong>con</strong>enteros. Estas instrucciones modifican el registro CR0 y se caracterizanporque 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 característica de <strong>PowerPC</strong> que no en<strong>con</strong>tramos en arquitecturas másantiguas como x86 es que la mayoría de las instrucciones no modifican losbits de <strong>con</strong>dición, <strong>con</strong> lo que se <strong>con</strong>sigue acelerar el rendimiento aldesaparecer dependencias entre instrucciones.Pág 61


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgBit Descripción0 El registro destino ha recibido un valor negativo1 El registro destino ha recibido un valor positivo2 El registro destino ha recibido un cero3 Summary Overflow (SO). Hubo un overflow. Este bit es una copia <strong>del</strong>estado final <strong>del</strong> bit XER[SO]Tabla 2.15: Significado de los bits <strong>del</strong> campo de CR0 en las instrucciones <strong>con</strong> enterosacabadas en punto (.)Como veremos en el tema de pipelines <strong>del</strong> Tema 3, estas instruccionespueden ser más lentas que sus correspondientes versiones sin punto (las queno modifican el campo CR0), <strong>con</strong> lo que sólo debemos usarlas si nos interesa<strong>con</strong>ocer este resultado.Un buen ejemplo es cuando vamos a realizar una comparación <strong>con</strong> elresultado de la operación aritmética.Por ejemplo, si queremos sumar el <strong>con</strong>tenido de los registros r5 y r6 y sabersi el resultado es un cero haríamos:addi. r7,r5,r6mfcrf 128,r2 ; Copiamos el campo CR0 a r2andi r2,4 ; Quitamos todos los bits menos el bit; que es el que indica que r7 tiene un 0Por último queda por comentar que el campo CR1 se suele utilizar parareflejar el resultado de ejecutar una operación <strong>con</strong> números en punto flotante<strong>con</strong> instrucciones de punto flotante acabadas en punto (.), como por ejemplofadd. o fabs., tal como muestra la tabla Tabla 2.16.Bit Descripción4 Floating-point eXception (FX)5 Floating-point Enabled eXception (FEX)6 Floating-point inValid eXception (VX)7 Floating-point Overflow eXception (OX)Tabla 2.16: Significado de los bits <strong>del</strong> campo de CR1 en las instrucciones en punto flotanteacabadas en punto (.)El valor de este registro, no es más que el <strong>con</strong>tendido de los bits de otroregistro FPSCR[0-3], que como veremos en el apartado 7.4 es el quealmacena los resultados de realizar operaciones en punto flotante.Pág 62


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org5.2 El registro XEREl registro XER es un registro que, al igual que CR, sirve para mostrar elresultado de ejecutar una operación <strong>con</strong> enteros, nos da información sobreposibles problemas durante la ejecución de la instrucción aritmética, así comootras informaciones asociadas a operaciones aritméticas.La Figura 2.4 muestra las partes en que se divide este registro:SO OV CA 0 0000 0000 0000 0000 0000 0 Byte Count0 1 2 24 25 31Figura 2.4: Partes <strong>del</strong> registro XERLa Tabla 2.17 describe el significado de cada uno de estos bits:Bit Nombre Descripción0 SO Summary Overflow. Este bit se activa cada vez que unainstrucción produce un overflow, y queda activo hasta quese desactiva explícitamente usando mtspr (indicando a XERcomo registro a modificar) o mcrxr1 OV Overflow. Indica que la última instrucción a producido unoverflow2 CA Carry, Indica que la última instrucción a producido unacarreo3-24 - Reservado. Siempre vale 025-31 BytecountEste campo muestra el número de bytes transferidosdurante la ejecución de una instrucción lswx (Load StringWord indeXed) o stswx (Store String Word indeXed)Tabla 2.17: significado de los bits <strong>del</strong> registro XERLo que muestra este registro es el resultado de ejecutar la instrucción en sutotalidad, no el de ejecutar alguna de sus partes, por ejemplo la instrucciónadde (ADD Extended) calcula la suma de los tres operandos y fija los bits deXER en base a la operación completa, no en base a la operación entre dos desus tres operandos.<strong>PowerPC</strong> diferencia entre acarreo y overflow, <strong>con</strong>siderando al overflow unerror mientras que al acarreo se le <strong>con</strong>sidera sólo un indicador de que a laparte alta de la suma hay que sumarle 1.Para cada operación aritmética que pueda producir un acarreo suelen existirdos instrucciones, una <strong>con</strong> indicación de acarreo y otra sin ella. Por ejemploPág 63


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgaddi no activa el bit de acarreo si se produce y addic sí que lo activa. Estoes así porque el activar el bit de acarreo puede producir retrasos en laejecución de las instrucciones siguientes <strong>del</strong> pipeline tal como se explica en elApéndice B.Lo mismo pasa <strong>con</strong> los overflow, hay una instrucción 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 <strong>con</strong>sidera un SPR (Special Purpose Register). Cuandoavancemos más veremos que existen muchos más SPR, cada uno de elloslleva un número asociado. A XER se le <strong>con</strong>sidera el SPR número 1 (SPR1) ypara leerlo/modificarlo usamos dos instrucciones que nos permiten acceder alos 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 <strong>con</strong>tenido <strong>del</strong> registro XER y pasarlo a r5haríamos:mfspr r5,1 ; 1 indica SPR1Y si ahora queremos ver si está activo el bit CA (CArry) haríamos:andis r5,r5,0x2000 ; Desactiva todos los bits menos; el bit de CAEn el apartado 5.7.4 veremos mnemonics que nos permiten acceder alregistro XER de forma más cómoda.Es importante diferenciar entre el bit OV que indica un overflow en la últimainstrucción y el bit SO que es un bit que se activa cuando alguna instrucciónproduce un overflow y se queda activo hasta que lo desactivamos (a un bitque cuando se activa ya no se desactiva en la siguiente instrucción se le llamaun bit de retención). Esto nos permite saber si a lo largo de una secuenciade operaciones aritméticas una de ellas ha producido un overflow.La forma correcta de desactivarlo sería:mfspr r3,1 ; Cogemos en r3 el valor de XERlis r4,0x7FFFF ; r4 es la máscara que desactiva; el bit SOori r4,r4,0xFFFFand r3,r3,r4 ; Aplicamos la máscaramtspr 1,r3 ; Modificamos XERmtcrxr 0 ; En CR0[CA],CR0[OV],CR0[SO] copiamos XERPág 64


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgAquí estamos usando la instrucción: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 sesincronicen <strong>con</strong> los de XER, es decir, tengan el mismo valor que los bits deXER.5.3 Instrucciones aritméticas5.3.1 Instrucciones aritméticas de sumaLa Tabla 2.18 resume las instrucciones aritméticas de suma de enteros queexisten en <strong>PowerPC</strong>:InstrucciónDescripciónaddi rD,rA,SIMM (ADD Immediate) Calcula la suma de(rA|0)+SIMM y la pone en rD.addis rD,rA,SIMM (ADD Immediate Shift) Calcula la suma de(rA|0)+(SIMM||0x0000) y la pone en rDadd rD,rA,rB (ADD) La suma rA+rB se deposita en rDadd. rD,rA,rB (ADD) Igual que add, sólo que CR0 se actualiza talcomo explicamos en el apartado 5.1addo rD,rA,rB (ADD Overflow) Igual que add, sólo que XER[OV]se pone a 1 si hay overflowaddo. rD,rA,rB (ADD Overflow) Igual que addo, sólo que CR0 seactualiza tal como explicamos en el apartado 5.1addic rD,rA,SIMM (ADD Immediate Carrying) Igual que addi sóloque XER[CA] a se pone a 1 si hay acarreoaddic. rD,rA,SIMM (ADD Immediate Carrying) Igual que addic sóloque CR0 se actualiza tal como explicamos en elapartado 5.1addc rD,rA,rB (ADD Carrying) Igual que add sólo que XER[CA]se pone a 1 si hay acarreoaddc. rD,rA,rB (ADD Carrying) Igual que addc sólo que CR0 seactualiza tal como explicamos en el apartado 5.1addco rD,rA,rB (ADD Carrying with Overflow) Igual que add sóloque si hay acarreo XER[CA] se pone a 1 yXER[OV] se pone a 1addco. rD,rA,rB (ADD Carrying with Overflow) Igual que addcosólo CR0 se actualiza tal como explicamos en elapartado 5.1adde rD,rA,rB (ADD Extended) La suma rA+rB+XER[CA] sepone en rDadde. rD,rA,rB (Add Extended) Igual que adde, sólo que CR0 seactualiza tal como explicamos en el apartado 5.1Pág 65


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgaddeo rD,rA,rB (ADD Extended with Overflow) Igual que adde,sólo que XER[OV] se pone a 1 si hay overflowaddeo. rD,rA,rB (ADD Extended with Overflow) Igual que addeo,sólo que CR0 se actualiza tal como explicamos enel apartado 5.1addme rD,rA (ADD Minus one Extended) La sumarA+XER[CA]+0xFFFFFFFF se guarda en rDaddme. rD,rA (ADD to Minus one Extended) Igual que addme,sólo que CR0 se actualiza tal como explicamos enel apartado 5.1addmeo rD,rA (ADD to Minus one Extended with Overflow) Igualque addme, sólo que XER[OV] se pone a 1 si hayoverflowaddmeo. rD,rA (ADD to Minus one Extended with Overflow) Igualque addmeo, sólo que CR0 se actualiza tal comoexplicamos en el apartado 5.1addze rD,rA(ADD to Zero Extended) La suma rA+XER[CA] sedeposita en rDaddze. rD,rA (ADD to Zero Extended) Igual que addze, sóloque CR0 se actualiza tal como explicamos en elapartado 5.1addzeo rD,rA (ADD to Zero Extended with Overflow) Igual queaddze, sólo que XER[OV] se pone a 1 si hayoverflowaddzeo. rD,rA (ADD to Zero Extended with Overflow) Igual queaddzeo, sólo que CR0 se actualiza tal comoexplicamos en el apartado 5.1SIMM ≡ Signed IMMediateUIMM ≡ Unsigned IMMediate(rA|0) ≡ El valor <strong>del</strong> registro rA o bien 0 binarioSIMM||0x0000 ≡ A SIMM se le <strong>con</strong>catena 0x0000 al final, es decir,desplazamos SIMM 16 bits a la izquierdaXER[OV] ≡ Indica que nos estamos refiriendo al bit OV <strong>del</strong> registro XERTabla 2.18: Instrucciones aritméticas de suma de enterosA todos los registros que reciben como operandos estas instrucciones se les<strong>con</strong>sidera números <strong>con</strong> signo.En el Listado 2.7 aparece un programa llamado sumalong.s 3 que suma dosnúmeros de 64 bits. Al tener los registros de <strong>PowerPC</strong> sólo 32 bits tenemosque usar dos registros para almacenar un número. Imaginemos que3 En C de GNU para <strong>PowerPC</strong> el tipo long ocupa 32 bits, debiendo usarse long long parasu correspondiente tipo de 64 bitsPág 66


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgqueremos sumar los números guardados en r2||r3 y r4||r5 y depositar lasuma en r6||r7En este caso primero tendremos que sumar <strong>con</strong> acarreo r3+r5 y si hayacarreo, pasarlo a la suma r2+r4. La suma r2+r4 no la hacemos <strong>con</strong>acarreo, ya que si hubiera acarreo este se perdería, luego en este caso vamosa <strong>con</strong>siderar al acarreo un overflow, el cual podríamos detectar para dar unmensaje de error.Para la suma <strong>con</strong> acarreo de r3+r5 vamos a usar la instrucción:addc r7,r3,r5Que pone la suma r3+r5 en r7, y activa el bit XER[CA] si hay acarreo.Después para sumar r2+r4 usamos la instrucciónaddeo r6,r2,r4Que suma r2+r4+XER[CA], y deposita la suma en r6. Además la instruccióntiene detección de overflow, que significa que activa el bit XER[OV] si seproduce desbordamiento en la suma.Este desbordamiento se podría usar después para dar un mensaje de error./* Descripción: Programa que suma dos números de 64 bits* Escrito por: Fernando López Hernández*/.data // Segmento de datos.comm C,8 ; Reserva 8 bytes sin inicializar.text // Segmento de código.<strong>con</strong>st // Seccion (__TEXT,__<strong>con</strong>st)A: .long 30 ; Parte alta de la variable A.long 0xFFFFFFFF ; Parte baja de la variable AB: .long 50 ; Parte alta de la variable B.long 0xFF ; Parte baja de la variable B.text // Sección (__TEXT,__text).globl _main_main:.align 2// Cargamos A en r2||r3lis r10,ha16(A)lwz r2,lo16(A)(r10)lwz r3,lo16(A+4)(r10)// Cargamos B en r4||r5lis r10,ha16(B)Pág 67


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orglwz r4,lo16(B)(r10)lwz r5,lo16(B+4)(r10)// Calculamos la suma en r6||r7addc r7,r3,r5addeo r6,r2,r4// Guardamos el resultado que tenemos en r6||r7 en Clis r10,ha16(C)stw r6,lo16(C)(r10)stw r7,lo16(C+4)(r10)blrListado 2.7: Programa que suma dos números de 64 bitsOtra instrucción relacionada <strong>con</strong> acarreos es:addze rD,rA /* ADD Zero extended */Que calcula la suma rA+XER[CA] y la deposita en rDEsta instrucción se utiliza para saber si la operación anterior tuvo acarreo, encuyo caso a rA se le suma 1, y si no hubo acarreo se queda valiendo lomismo.Esta instrucción se utiliza cuando vamos a sumar números de más de 64 bits.Como ejemplo, vamos a hacer ahora un programa llamado sumalong2.s(que aparece en el Listado 2.8) el cual suma números de 128 bits.Para ello vamos a guardar el primer operando en r3||r4||r5||r6 y elsegundo en r7||r8||r9||r10||r11, y vamos a calcular la suma enr12||r13||r14||r15.La Figura 2.5 muestra la forma de utilizar las instrucciones:r3 r4 r5 r6r7 r8 r9 r10addzeo r3addo r11,r3,r7addzeo r4addc r12,r4,r8addzeo r5addc r13,r5,r9addc r14,r6,r10Figura 2.5: Uso de instrucciones que suman dos números de 128 bitsPág 68


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org/* Descripción: Programa que suma dos números de 128 bits* Escrito por: Fernando López Hernández*/.data // Segmento de datos.comm C,16 ; Reserva 16 bytes sin incializar.text // Segmento de código.<strong>con</strong>st // Seccion (__TEXT,__<strong>con</strong>st)A: .long 1 ; Parte alta de la variable A.long 1; Parte alta de la variable A.long 1; Parte baja de la variable A.long 1; Parte baja de la variable AB: .long 1 ; Parte alta de la variable B.long 0xFFFFFFFF ; Parte alta de la variable B.long 0xFFFFFFFF ; Parte baja de la variable B.long 0xFFFFFFFF ; Parte baja de la variable B.text // Sección (__TEXT,__text).globl _main_main:.align 2// Cargamos A en r3||r4||r5||r6lis 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|r10lis 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||14addc r14,r6,r10addzeo r5,r5addc r13,r5,r9addzeo r4,r4addc r12,r4,r8addzeo r3,r3addo r11,r3,r7// Guardamos el resultado que tenemos// en r11||r12||r13||r14 en Clis 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)blrListado 2.8: Programa que suma números de 128 bitsPág 69


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgLa suma se va haciendo registro a registro de derecha a izquierda. Sumamosusando addc <strong>con</strong> el fin de hacer un acarreo al siguiente registro, el cual lorecoge <strong>con</strong> addzeo, la cual incrementa 1 al registro sólo si hay acarreo. Laúltima instrucción de suma (addo) es la única que no produce acarreo, sinoque en vez de esto provoca un overflow en caso de que haya acarreo. Esteoverflow se podría detectar y actuar en <strong>con</strong>secuencia.Obsérvese que hemos utilizado addzeo (ADD Zero Extended Overflow) y noaddze (ADD Zero Extended), esto es así porque otra cosa que podría pasares que el registro al que estamos pasando el acarreo (p.e. r5) este lleno, esdecir, valga 0x7FFFFFFF (todos los bits a 1 menos el de signo), en cuyo casoal sumarle 1 se produce un overflow, que el programa debería de detectar ycorregir <strong>con</strong>venientemente pasando el acarreo al siguiente registro. Nosotros,para simplificar el programa, y debido a que todavía no hemos estudiado lassentencias de bifurcación no lo vamos a hacer, aunque queda explicada lanecesidad de hacerlo.5.3.2 Instrucciones aritméticas de restaLa Tabla 2.19 resume las instrucciones aritméticas de resta de enteros queexisten en <strong>PowerPC</strong>:Instrucciónsubf rD,rA,rBsubf. rD,rA,rBsubfo rD,rA,rBsubfo. rD,rA,rBsubfc rD,rA,rBsubfc. rD,rA,rBsubfco rD,rA,rBsubfco. rD,rA,rBDescripción(SUBtract From) Calcula rB-rA y lo deposita enrD.(SUBtract From) Igual que subf, sólo que CR0 seactualiza tal como explicamos en el apartado 5.1(SUBtract From with Overflow) Igual que subf,sólo que XER[OV] se pone a 1 si hay overflow(SUBtract From with Overflow) Igual que subfo,sólo que CR0 se actualiza tal como explicamos enel apartado 5.1(SUBtract From Carring with Overflow) Calcula rBrAy lo deposita en rD, y si hay acarreo poneXER[CA] a 1(SUBtract From Carring with Overflow) Igual quesubfc, sólo que CR0 se actualiza tal comoexplicamos en el apartado 5.1(SUBtract From Carrying with Overflow) Igual quesubfc, sólo que XER[OV] se pone a 1 si hayoverflow(SUBtract From Carrying with Overflow) Igual quesubfco, sólo que CR0 se actualiza tal comoexplicamos en el apartado 5.1Pág 70


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgsubfe rD,rA,rB (SUBtract From Extended) Calcula rBrA+XER[CA]y lo deposita en rD.subfe. rD,rA,rB (SUBtract From Extended) Igual que subfe, sóloque CR0 se actualiza tal como explicamos en elapartado 5.1subfeo rD,rA,rB (SUBtract From Extended with Overflow) Igual quesubfe, sólo que XER[OV] se pone a 1 si hayoverflowsubfeo. rD,rA,rB (SUBtract From Extended with Overflow) Igual quesubfeo, sólo que CR0 se actualiza tal comoexplicamos en el apartado 5.1subfme rD,rA,rB (SUBtract From Minus one Extended) Calcula~rA+XER[CA]+0xFFFFFFFF y lo deposita en rD.subfme. rD,rA,rB (SUBtract From Minus one Extended) Igual quesubfme, sólo que CR0 se actualiza tal comoexplicamos en el apartado 5.1subfmeo rD,rA,rB (SUBtract From Minus one Extended withOverflow) Igual que subfme, sólo que XER[OV] sepone a 1 si hay overflowsubfmeo. rD,rA,rB (SUBtract From Minus one Extended withOverflow) Igual que subfmeo, sólo que CR0 seactualiza tal como explicamos en el apartado 5.1subfze rD,rA,rB (SUBtract From Zero Extended) Calcula~rA+XER[CA] y lo deposita en rD.subfze. rD,rA,rB (SUBtract From Zero Extended) Igual que subfze,sólo que CR0 se actualiza tal como explicamos enel apartado 5.1subfzeo rD,rA,rB (SUBtract From Zero Extended with Overflow)Igual que subfze, sólo que XER[OV] se pone a 1si hay overflowsubfzeo. rD,rA,rB (SUBtract From Zero Extended with Overflow)Igual que subfzeo, sólo que CR0 se actualiza talcomo explicamos en el apartado 5.1Tabla 2.19: Instrucciones aritméticas de resta de enterosAl igual que en la suma, a todos los registros que reciben como operandosestas instrucciones se les <strong>con</strong>sidera números <strong>con</strong> signo.La operación rB-rA también se puede escribir como rB+~rA+1, <strong>con</strong> lo quepodríamos implementar una resta a base de sumas.Aunque no hay ninguna operación para la resta <strong>con</strong> un operando inmediato,su efecto se puede <strong>con</strong>seguir <strong>con</strong> addi, <strong>con</strong> el operador inmediato negado.Existen mnemonics para la resta que se describen en el apartado 5.7.1.Pág 71


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org5.3.3 Instrucciones de negación aritméticaLa negación aritmética lo que obtiene es el complemento a 2 de un número,es decir el mismo número cambiado de signo. Por ejemplo el negado de 3 es-3. Formalmente la operación de complemento a 2 se define como ~rA+1La Tabla 2.20 muestra las instrucciones de negación aritmética que existen:Instrucciónneg rD,rAneg. rD,rAnego rD,rAnego. rD,rATabla 2.20: Instrucciones de negación aritmética <strong>con</strong> enterosDescripción(NEGate) Calcula el complemento a 2 de rA y lodeposita en rD, es decir, calcula ~rA+1(NEGate) Igual que neg, sólo que CR0 se actualizatal como explicamos en el apartado 5.1(NEGate with Overflow) Igual que neg, sólo queXER[OV] se pone a 1 si hay overflow(NEGate) Igual que nego, sólo que CR0 seactualiza tal como explicamos en el apartado 5.15.3.4 Instrucciones aritméticas de multiplicaciónLa Tabla 2.21 muestra las operaciones de multiplicación que existen en<strong>PowerPC</strong>.La instrucción mulli sólo debe usarse cuando estemos seguros de que los 16bits altos <strong>del</strong> registro rA estén a 0, sino se producirá una perdida de datospor desbordamiento.Para evitar este problema es preferible cargar el número SIMM en un registroy operar después <strong>con</strong> mulhw y mullw.La Figura 2.6 muestra un ejemplo de como se calcula el producto de dosnúmeros de 32 bits y como calcularlo usando las operaciones de <strong>PowerPC</strong>.Pág 72


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org01010101 10101010 01010101 10101010 (rA)x 11111111 00000000 11111111 00000000 (rB)————————————————————————————————————00000000 00000000 00000000 0000000000000000 00000000 00000000 0000000000000000 00000000 00000000 0000000000000000 00000000 00000000 0000000000000000 00000000 00000000 0000000000000000 00000000 00000000 0000000000000000 00000000 00000000 0000000000000000 00000000 00000000 0000000001010101 10101010 01010101 1010101001010101 10101010 01010101 1010101001010101 10101010 01010101 1010101001010101 10101010 01010101 1010101001010101 10101010 01010101 1010101001010101 10101010 01010101 1010101001010101 10101010 01010101 1010101001010101 10101010 01010101 1010101000000000 00000000 00000000 0000000000000000 00000000 00000000 0000000000000000 00000000 00000000 0000000000000000 00000000 00000000 0000000000000000 00000000 00000000 0000000000000000 00000000 00000000 0000000000000000 00000000 00000000 0000000000000000 00000000 00000000 0000000001010101 10101010 01010101 1010101001010101 10101010 01010101 1010101001010101 10101010 01010101 1010101001010101 10101010 01010101 1010101001010101 10101010 01010101 1010101001010101 10101010 01010101 1010101001010101 10101010 01010101 1010101001010101 10101010 01010101 10101010—————————————————————————————————————————————————————————————————————————01010101 01010101 00000000 10101001 00000001 01010100 01010110 00000000mulhw rH,rA,rBmullw rL,rA,rBFigura 2.6: Cálculo <strong>del</strong> producto de dos números de 32 bits usando instrucciones <strong>PowerPC</strong>Instrucciónmulli rD,rA,SIMMmullw rD,rA,rBmullw. rD,rA,rBmullwo rD,rA,rBDescripción(MULtiply Low Immediate) Los 32 bits bajos <strong>del</strong>producto rA*SIMM se depositan en rD.(MULtiply Low Word) Calcula los 32 bits bajos derA*rB. Esta instrucción se puede combinar <strong>con</strong>mulhw para calcular un producto completo, de 64bits(MULtiply Low Word) Igual que mullw, sólo queCR0 se actualiza tal como explicamos en elapartado 5.1(MULtiply Low Word with Overflow) Igual quemullw, sólo que XER[OV] se pone a 1 si hayoverflowPág 73


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgmullwo. rD,rA,rB (MULtiply Low Word with Overflow) Igual quemullwo, sólo que CR0 se actualiza tal comoexplicamos en el apartado 5.1mulhw rd,rA,rB (MULtiply High Word) Calcula los 32 bits altos derA*rB. Esta instrucción se puede combinar <strong>con</strong>mullw para calcular un producto completo, de 64bitsmulhw. rD,rA,rB (MULtiply High Word) Igual que mulhw, sólo queCR0 se actualiza tal como explicamos en elapartado 5.1mulhwo rD,rA,rB (MULtiply High Word with Overflow) Igual quemulhw, sólo que XER[OV] se pone a 1 si hayoverflowmulhwo. rD,rA,rB (MULtiply High Word with Overflow) Igual quemulhwo, sólo que CR0 se actualiza tal comoexplicamos en el apartado 5.1mulhwu rD,rA,rB (MULtiply High Word Unsigned) El <strong>con</strong>tenido derA y rB es <strong>con</strong>siderado como números de 32 bitssin signo y calcula los 32 bits de la parte alta <strong>del</strong>producto, depositándola en rDmulhwu. rD,rA,rB (MULtiply High Word Unsigned) Igual quemulhwu, sólo que CR0 se actualiza tal comoexplicamos en el apartado 5.1Tabla 2.21: Instrucciones aritméticas de multiplicación de enteros5.3.5 Instrucciones aritméticas de divisiónLa Tabla 2.22 muestra las instrucciones de división de enteros de que dispone<strong>PowerPC</strong>.Instruccióndivw rD,rA,rBdivw. rD,rA,rBdivwo rD,rA,rBdivwo. rD,rA,rBdivwu rD,rA,rBDescripción(DIVide Word) El dividendo es rA, el divisor es rB,y el cociente se deposita en rD. La instrucción nonos da el resto de la operación.(DIVide Word) Igual que divw, sólo que CR0 seactualiza tal como explicamos en el apartado 5.1(DIVide Word with Overflow) Igual que divw, sóloque XER[OV] se pone a 1 si hay overflow(DIVide Word with Overflow) Igual que divwo,sólo que CR0 se actualiza tal como explicamos enel apartado 5.1(DIVide Word Unsigned) Calcula la división <strong>con</strong>números sin signo. El dividendo es rA, el divisores rB, y el cociente se deposita en rD. Lainstrucción no nos d el resto de la operación.Pág 74


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgdivwu. rD,rA,rBdivwuo rD,rA,rBdivwuo. rD,rA,rBTabla 2.22: Instrucciones aritméticas de división de enterosinstrucción no nos d el resto de la operación.(DIVide Word Unsigned) Igual que divwu, sóloque CR0 se actualiza tal como explicamos en elapartado 5.1(DIVide Word Unsigned with Overflow) Igual quedivwu, sólo que XER[OV] se pone a 1 si hayoverflow(DIVide Word Unsigned with Overflow) Igual quedivwuo, sólo que CR0 se actualiza tal comoexplicamos en el apartado 5.15.4 Instrucciones de comparación de enterosEstas instrucciones comparan números y depositan el resultado de lacomparación en uno de los campos de CR.El principal uso que se da a las instrucciones de comparación es la toma dedecisiones en instrucciones de salto, las cuales estudiaremos en el apartado6.En la Tabla 2.23 se muestran las instrucciones de comparación de quedispone <strong>PowerPC</strong>. El operando CRFD es el campo de CR donde depositar elresultado de la comparación. El valor <strong>con</strong>creto que depositan en este campose explica en el apartado 5.1.Instruccióncmpi CRFD,L,rA,SIMMcmp CRFD,L,rA,rBcmpli CRFD,L,rA,UIMMcmpl CRFD,L,rA,rBDescripción(CoMPare Immediate) Compara como números<strong>con</strong> signo al número depositado en el registrorA <strong>con</strong> el número SIMM <strong>con</strong> extensión de signo.El resultado de la comparación se deposita enCRFD(CoMPare) Compara rA y rB tratándolos comonúmeros <strong>con</strong> signo y el resultado lo deposita enCRFD(Compare Logical Immediate) El númerodepositado en el registro rA se compara <strong>con</strong> elnúmero 0x0000||UIMM, tratando a losoperandos como números sin signo. El resultadode la comparación se deposita en CRFD(CoMPare Logical) Compara a los númerosdepositados en rA y rB como números sinsigno. El resultado se deposita en CRFDTabla 2.23: Instrucciones de comparación de enterosPág 75


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgLas instrucción cmpi recibe como operando un número <strong>con</strong> signo (SIMM) de16 bits sobre el que realiza una extensión <strong>del</strong> signo a 32 bits, mientras que lainstrucción cmpli recibe como operando un número sin signo (UIMM) de 16bits, sobre el que extiende los 16 bits altos rellenándolos <strong>con</strong> ceros.Esto permite usar las instrucciones que reciben números <strong>con</strong> signo (cmpi ycmp) para comparaciones aritméticas, y las instrucciones que recibennúmeros sin signo (cmpli y cmpl) para comparaciones lógicas.Todas las instrucciones de comparación permiten omitir el operando CRFD, encuyo caso el resultado se deposita en CR0. Por desgracia no podemos omitirel campo L, que en las máquinas de 32 bits siempre debe valer 0.Por ejemplo si queremos comparar como números sin signo los registros r3 yr4 y depositar el resultado de la comparación en el campo 3 de CR haríamos:cmp 3,0,r3,r4Si omitimos el campo CRFD el resultado se deposita el campo CR0:cmp 0,r3,r4Aunque L=0 lo hemos tenido que dar.5.5 Instrucciones lógicas <strong>con</strong> enterosEste grupo de instrucciones siempre <strong>con</strong>sideran a los operandos comonúmeros sin signo, luego las instrucciones que reciben operandos inmediatos,los reciben <strong>del</strong> tipo UIMM, y los extienden a 32 bits rellenando <strong>con</strong> ceros.Las instrucciones <strong>con</strong> punto (.) modifican el campo 0 de CR tal comoexplicamos en el apartado 5.1. Sin embargo, ninguna instrucción lógicamodifica los bits XER[SO,OV,CA].La Tabla 2.24, Tabla 2.25 y Tabla 2.26 muestran las instrucciones lógicas <strong>con</strong>enteros que existen en <strong>PowerPC</strong>.Instrucciónandi. rD,rA,UIMMandis. rD,rA,UIMMDescripción(AND Immediate) Realiza un and lógico entre rA y0x0000||UIMM y lo deposita en rD(AND Immediate Shifted) Realiza un and lógicoentre rA y UIMM||0x0000 y el resultado lodeposita en rDPág 76


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.organd rD,rA,rBand. rD,rA,rBandc rD,rA,rBandc. rD,rA,rBnand rD,rA,rB(AND) Realiza un and lógico entre rA y rB y elresultado se deposita en rD(AND) Igual que add, sólo que CR0 se actualizatal como explicamos en el apartado 5.1(AND with Complement) Realiza un and lógicoentre rA y ~rB (complemento a 1 de rB) y elresultado lo deposita en rD(AND with Complement) Igual que andc, sólo queCR0 se actualiza tal como explicamos en elapartado 5.1(No AND) Al resultado <strong>del</strong> and lógico entre rA yrB se le hace el complemento a 1 y se deposita enrD, es decir, en rD se guarda ~(rA&rB)Tabla 2.24: Instrucciones que realizan un and lógico <strong>con</strong> enterosEn <strong>PowerPC</strong> no existen las respectivas operaciones andi. y andis. sinpunto(.), <strong>con</strong> lo que estas operaciones siempre modifican el campo CR0.Instrucciónori rD,rA,UIMMoris rD,rA,UIMMor rD,rA,rBor. rD,rA,rBorc rD,rA,rBorc. rD,rA,rBnor rD,rA,rBDescripción(OR Immediate) Realiza un or lógico entre rA y0x0000||UIMM y lo deposita en rD(OR Immediate Shifted) Realiza or lógico entre rAy UIMM||0x0000 y el resultado lo deposita en rD(OR) Realiza un or lógico entre rA y rB y elresultado se deposita en rD(OR) Igual que or, sólo que CR0 se actualiza talcomo explicamos en el apartado 5.1(OR with complement) Realiza un or lógico entrerA y ~rB (complemento a 1 de rB) y el resultadolo deposita en rD(OR with Complement) Igual que orc, sólo queCR0 se actualiza tal como explicamos en elapartado 5.1(No OR) Al resultado <strong>del</strong> or lógico entre rA y rBse le hace el complemento a 1 y se deposita enrD, es decir, en rD se guarda ~(rA|rB)Tabla 2.25: Instrucciones que realizan un or lógico <strong>con</strong> enterosInstrucciónxori rD,rA,UIMMxoris rD,rA,UIMMDescripción(eXclusive OR Immediate) Realiza un xor lógicoentre rA y 0x0000||UIMM y lo deposita en rD(eXclusive OR Immediate Shifted) Realiza xorlógico entre rA y UIMM||0x0000 y el resultado lodeposita en rDPág 77


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgxor rD,rA,rB (eXclusive OR) Realiza un xor lógico entre rA y rBy el resultado se deposita en rDxor. rD,rA,rB (eXclusive OR) Igual que xor, sólo que CR0 seactualiza tal como explicamos en el apartado 5.1eqv rD,rA,rB (Equivalent) Realiza un xor lógico entre rA y rB yel resultado se le hace un complemento a 1 y seguarda en rD. Es decir, en rD se guarda~(rA^rB)extsb rD,rS(EXTended Sign Byte) El byte bajo de rS se copiaen el byte bajo de rD, el resto de los bits de rD serellenan <strong>con</strong> el bit de signo <strong>del</strong> byte cogido de rS,(el bit 24), es decir, se extiende el signo de bytecogido.extsb. rD,rS (EXTended Sign Byte) Igual que extsb, sólo queCR0 se actualiza tal como explicamos en elapartado 5.1extsh rD,rS(EXTended Sign Half-word) El half-word bajo derS se copia en el half-word bajo de rD, el resto <strong>del</strong>os bits de rD se rellenan <strong>con</strong> el bit de signo <strong>del</strong>half-word cogido de rS, (el bit 16), es decir, seextiende el signo de half-word cogido.extsh. rD,rS (EXTended Sign Half-word) Igual que extsh, sóloque CR0 se actualiza tal como explicamos en elapartado 5.1cntlzw rD,rS (CouNT Leading Zeros Word) La cuenta de bits 0<strong>con</strong>secutivos de rS empezando a <strong>con</strong>tar por laizquierda se guarda en rD. Esta cuenta va de 0 a32 ambos inclusive.cntlzw. rD,rS (CouNT Leading Zeros Word) Igual que cntlzw,sólo que CR0 se actualiza tal como explicamos enel apartado 5.1Tabla 2.26: Otras instrucciones lógicas <strong>con</strong> enterosA eqv se le llama la operación de equivalencia, porque comprueba que todoslos bits sean iguales en cuyo caso el resultado es 0xFFFFFFFF, en caso<strong>con</strong>trario, los bits que diverjan valen 0. El resultado sólo será 0x00000000 sitodos los bits son distintos.5.6 Instrucciones de rotación y desplazamiento<strong>con</strong> enterosLas operaciones de rotación y desplazamiento de bits son más complicadas en<strong>PowerPC</strong> que en otras arquitecturas, pero una vez que se entienden, sonespecialmente potentes.Pág 78


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgAmbas operaciones mueven los bits a izquierda o derecha, la diferencia estáen que las operaciones de desplazamiento pierden los bits que salen porun extremo, entrando ceros por el otro extremo, mientras que en lasoperaciones de rotación cuando los bits salen por un extremo, entran porel otro extremo.5.6.1 Instrucciones de desplazamiento <strong>con</strong> enterosLa Tabla 2.27 muestra las operaciones de desplazamiento de enteros queexisten:Instrucciónslw rD,rS,rCsrw rD,rS,rCsrawi rD,rS,Csrawi. rD,rS,Csraw rD,rS,rCsraw. rD,rS,rCTabla 2.27: Instrucciones de desplazamiento <strong>con</strong> enterosDescripción(Shift Left Word) Desplaza a la izquierda los bitsde rS tantas veces como diga rC (que debe serun número comprendido entre 0 y 31), elresultado se copia en rD(Shift Right Word) Desplaza a la derecha los bitsde rS tantas veces como diga rC (que debe serun número comprendido entre 0 y 31), elresultado se copia en rD(Shift Right Algebraic Word Inmediate) Desplaza ala derecha los bits de rS tantas veces como diga C(que debe ser un número comprendido entre 0 y31), al resultado se le extiende el bit de signo y secopia en rD(Shift Right Algebraic Word Inmediate) Igual quesrawi, sólo que CR0 se actualiza tal comoexplicamos en el apartado 5.1(Shift Right Algebraic Word) Desplaza a la derechalos bits de rS tantas veces como diga rC (quedebe ser un número comprendido entre 0 y 31), alresultado se le extiende el bit de signo y se copiaen rD(Shift Right Algebraic Word) Igual que sraw, sóloque CR0 se actualiza tal como explicamos en elapartado 5.1Entre las operaciones se diferencia claramente entre los desplazamientos sinsigno (slw y srw), y desplazamientos <strong>con</strong> signo o algebraicos (srawi ysraw). En los desplazamientos <strong>con</strong> signo, después de hacer eldesplazamiento se extiende el signo de forma que el bit de signo nunca semodifica, es decir, si al empezar el desplazamiento es un 0 (positivo) semantiene y por la izquierda entran ceros, y si es un 1 (negativo) se mantieney por la izquierda entran unos.Pág 79


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgPor ejemplo si hacemos:lis r3,0xFFFF ; r3=0xFFFF0000srawi r2,r3,4 ; r2=0xFFFFF000srawi r2,r3,15 ; r2=0xFFFFFFFEsrawi r2,r3,16 ; r2=0xFFFFFFFFSin embargo, en los desplazamientos sin signo el bit de signo no es distintode los demás.Por ejemplo si hacemos:lis r3,0xFFFF ; r3=0xFFFF0000li r4,4srw r2,r3,r4 ; r2=0x0FFFF000li r4,15srw r2,r3,r4 ; r2=0x0001FFFEli r4,16srw r2,r3,r4 ; r2=0x0000FFFFObsérvese que faltan las operaciones de desplazamiento a la izquierda <strong>con</strong>signo, esto es porque hay mnemonics que equivalen a estas y quedescribiremos en el apartado 5.7.3.5.6.2 Instrucciones de rotación <strong>con</strong> enterosLas operaciones de rotación reciben como operandos dos números: MB (MaskBegin) y ME (Mask End), que forman una máscara, la cual indica qué bits <strong>del</strong>os 32 bits que tiene un registro son los que nos interesan. Uno de losnúmeros indica el principio de la máscara y otro el final de la máscara, unavez que se realiza la operación de rotación, sólo obtenemos los bits que esténdentro de la máscara, los bits que caigan fuera de la máscara siempre valdrán0.P.e. si tenemos MB=4 y ME=28 la máscara sería:4 280000 1111 1111 1111 1111 1111 1111 1000A esta máscara se le hace un and binario <strong>con</strong> el resultado de ejecutar larotación y este es el valor final que se obtiene.Las operaciones de rotación de que dispone <strong>PowerPC</strong> se describen en la Tabla2.28.Pág 80


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgInstrucciónrlwinm rD,rS,N,MB,MErlwinm. rD,rS,N,MB,MErlwnm rD,rS,rN,MB,MErlwnm. rD,rS,rN,MB,MErlwimi rD,rD,N,MB,MErlwimi. rD,rD,N,MB,METabla 2.28: Instrucciones de rotación <strong>con</strong> enterosDescripción(Rotate Left Word Immediate theN and withMask) El <strong>con</strong>tenido de rS se rota a laizquierda el número de veces especificado enN. Se genera una máscara <strong>con</strong> unos desde elbit MB hasta el bit ME, y lo demás <strong>con</strong> ceros.Al resultado de la rotación se le hace un andbinario <strong>con</strong> la máscara, y el resultado sedeposita en rD(Rotate Left Word Immediate theN and withMask) Igual que rlwinm, sólo que CR0 seactualiza tal como explicamos en el apartado5.1(Rotate Left Word theN and with Mask) El<strong>con</strong>tenido de rS se rota a la izquierda elnúmero de veces especificado en los 5 bitsbajos de rN. Se genera una máscara <strong>con</strong>unos desde el bit MB hasta el bit ME, y lodemás <strong>con</strong> ceros. Al resultado de la rotaciónse le hace un and binario <strong>con</strong> la máscara, y elresultado se deposita en rD(Rotate Left Word theN and with Mask) Igualque rlwnm, sólo que CR0 se actualiza talcomo explicamos en el apartado 5.1(Rotate Left Word Immediate then MaskInsert) El <strong>con</strong>tenido de rS se rota a laizquierda tantas veces como diga N, <strong>del</strong>resultado se insertan los bits indicados por losunos de la máscara en sus respectivasposiciones <strong>del</strong> registro rD, dejando losanteriores bits <strong>con</strong> el valor anterior quetuvieran en rD(Rotate Left Word Immediate then MaskInsert) Igual que rlwimi, sólo que CR0 seactualiza tal como explicamos en el apartado5.1Obsérvese que sólo existen operaciones de rotación a la izquierda, y noexisten sus correspondientes operaciones de rotación a la derecha, esto esporque siguiendo el principio de las arquitecturas RISC de proporcionar unjuego de operaciones mínimas, las operaciones de rotación n bits a la derechase pueden <strong>con</strong>seguir haciendo 32-n rotaciones a la izquierda.Pág 81


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgUn ejemplo de cómo se utiliza rlwinm sería este: Supongamos que tenemosel registro rS <strong>con</strong> el valor:rS = 00000000 00000000 00000000 00000001Y ejecutamos las operaciones:rlwinm rD,rS,2,0,10Obtendremos 00000000 00000000 00000000 00000100, pero como lamascara <strong>del</strong>imita los valores que van desde MB=0 a ME=10, los elementosque caigan fuera de este rango valdrán 0 y en rD obtenemos todos los bits a0:rD=00000000 00000000 00000000 00000000Sin embargo si ejecutamos:rlwinm rD,rS,2,0,31Ahora la máscara va desde MB=0 hasta ME=31, es decir, abarca todos los bits<strong>del</strong> registro y en rD obtenemos:rD=00000000 00000000 00000000 00000100Por <strong>con</strong>tra, la instrucción rlwimi sí que tiene en cuenta el valor de rD, yaque sólo se cambian los bits de rD que caen bajo la máscara, dejando losdemás bits tal como están. Por ejemplo si tenemos los registros rS y rD <strong>con</strong>estos valores:rD = 11111111 11111111 11111111 11111111rS = 00000000 00000000 00000000 00000001Y hacemos:rlwimi rD,rS,2,0,10Obtenemos rD=00000000 00111111 11111111 11111111Y si hacemos:rlwimi rD,rS,2,0,31Obtenemos rD=00000000 00000000 00000000 00000100Pág 82


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org5.7 Mnemonics5.7.1 Mnemonics para la restaComo decíamos en el apartado 5.3.2, aunque no hay ninguna operación pararesta <strong>con</strong> un operando inmediato, su efecto se puede <strong>con</strong>seguir <strong>con</strong> unmnemonic que llame a addi. En la Tabla 2.29 se detallan que mnemonicshay para la resta inmediata.Mnemonicsubi rD,rA,SIMMsubi. rD,rA,SIMMsubis rD,rA,SIMMsubis. rD,rA,SIMMsubic rD,rA,SIMMsubic. rD,rA,SIMMEquivalente aaddi rD,rA,-SIMMaddi. rD,rA,-SIMMaddis rD,rA,-SIMMaddis. rD,rA,-SIMMaddic rD,rA,-SIMMaddic. rD,rA,-SIMMTabla 2.29: Mnemonic para la resta <strong>con</strong> un operando inmediatoPor otro lado las operaciones de resta reciben los operandos de una formapoco natural, ya que reciben primero el sustraendo y luego el minuendo,cuando lo normal es recibirlos al revés. Para facilitar la comprensión <strong>del</strong>programa se han creado mnemonics que reciben los operandos en el ordeninverso como muestra la Tabla 2.30.Mnemonics Equivale a Descripciónsub rD,rA,rB subf rD,rB,rA Calcula rA-rB y lo deposita enrDsub. rD,rA,rB subf. rD,rB,rA Igual que sub pero dejando elCR0 el resultado de lacomparación tal como seexplicó en el apartado 5.1subo rD,rA,rB subfo rD,rB,rA Igual que sub sólo que activael bit XER[OV] si hay overflowsubo. rD,rA,rB subfo. rD,rB,rA Igual que subo pero dejando elCR0 el resultado de lacomparación tal como seexplicó en el apartado 5.1subc rD,rA,rB subfc rD,rB,rA Calcula rA-rB y lo deposita enrD, y si hay acarreo poneXER[CA] a 1subc. rD,rA,rB subfc. rD,rB,rA Igual que sub. pero dejando elCR0 el resultado de lacomparación tal como seexplicó en el apartado 5.1Pág 83


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgsubco rD,rA,rB subfco rD,rB,rA Igual que subc sólo que activael bit XER[OV] si hay overflowsubco. rD,rA,rB subfco.Igual que subco pero dejandorD,rB,rAel CR0 el resultado de lacomparación tal como seexplicó en el apartado 5.1Tabla 2.30: Mnemonic para resta de dos registros operandos5.7.2 Mnemonics para las operaciones de comparaciónRecuérdese que las operaciones de comparación de <strong>PowerPC</strong> tienen la forma:cmp CRF,L,rA,rBTal que en arquitecturas de 32 bits L siempre debe valer 0. Para evitar tenerque pasar siempre un 0 en este operando se han diseñado los mnemonics <strong>del</strong>a Tabla 2.31:Operación Mnemonic Equivalente aCompare Wordcmpwi CRF,rA,SIMM cmpi CRF,0,rA,SIMMImmediateCompare Word cmpw CRF,rA,rB cmpi CRF,0,rA,rBCompare Logical Word cmplwicmpli CRF,0,rA,SIMMImmediateCRF,rA,SIMMCompare Logical Word cmplw CRF,rA,rB cmpli CRF,0,rA,rBTabla 2.31: Mnenonics de comparación para 32 bitsLos símbolos de la Tabla 2.32 se pueden usar en lugar de sus valoresnuméricos:Símbolo Valor Descripcióncr0 0 Campo CR0 de CRcr1 1 Campo CR1 de CRcr2 2 Campo CR2 de CRcr3 3 Campo CR3 de CRcr4 4 Campo CR4 de CRcr5 5 Campo CR5 de CRcr6 6 Campo CR6 de CRcr7 7 Campo CR7 de CRTabla 2.32: Mnemonics para símbolos numéricosPág 84


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgEstos símbolos se pueden usar en las instrucciones de comparación cmp,cmpi, cmpl y cmpli, así como en los mnemonics de comparación cmpw,cmpwi, cmplw y cmplwi. Por ejemplo, en vez de poner:cmpw 2,rA,rBPodemos poner:cmpw cr2,rA,rBQue queda mucho más claro.5.7.3 Mnemonics para operaciones de desplazamiento yrotaciónLas operaciones de desplazamiento y rotación de <strong>PowerPC</strong> proporcionan unaforma general de manipular el <strong>con</strong>tenido de los registros, pero puedenresultar difíciles de entender, o de saber cómo se utilizan.Para ayudar al programador se han creado una serie de mnemonics querealizan las operaciones más comunes que aparecen en la Tabla 2.33. En<strong>con</strong>creto estos mnemonics nos permiten realizar las siguientes operaciones:o Extract. Nos permite sacar de un registro un campo de n bitsempezando por una posición b. Estos bits se copian en un registrodestino alineados a la izquierda o a la derecha y poniendo a 0 todos losdemás bits.o Insert. Elegimos un campo de n bits <strong>del</strong> registro origen justificado a laizquierda o a la derecha, e insertamos este campo de bits en el registrodestino empezando por la posición b. Todos los demás bits <strong>del</strong> registrodestino quedan sin cambios.o Rotate. Rota el <strong>con</strong>tenido de un registro a la izquierda o a la derecha,pero sin usar máscara.o Shift. Desplazamiento lógico (sin bit de signo) <strong>del</strong> <strong>con</strong>tenido de unregistro a la izquierda o a la derecha.o Clear. Borra los n bit más a la izquierda o a la derecha de un registroo Clear left and Shift left. Borra los b bits más a la izquierda <strong>del</strong> registro,después desplaza los bits <strong>del</strong> registro n posiciones a la izquierda. Estaoperación se suele usar para escalar un valor que actúa como índice (yque sabemos que no es negativo) al ancho de un elemento <strong>del</strong> array.Todas estas instrucciones disponen de su equivalente versión <strong>con</strong> punto (.)que modifican el <strong>con</strong>tenido de CR0 como explicamos en el apartado 5.1Pág 85


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgOperación Mnemonic Equivalente aEXTract and LeftJustify WordImmediateextlwi rD,rS,n,b(n>0)rlwinm rD,rS,b,0,n-1EXTract and RightJustify WordImmediateextrwi rD,rS,n,b(n>0)rlwinm rD,rS,b+n,32-n,31INSert from LeftWord Immediateinslwi rD,rS,n,b(n>0)rlwimi rD,rS,32-b,b,(b+n)-1INSert from RightWord Immediateinsrwi rD,rS,n,b(n>0)rlwimi rD,rS,32-b+n,b,b+n-1ROTate Left Word rotlwi rD,rS,n rlwinm rD,rS,n,0,31ImmediateROTate Right Word rotrwi rD,rS,n rlwinm rD,rS,32-n,0,31ImmediateROT Left Word rotlw rD,rS,rN rlwnm rD,rS,rN,0,31Shift Left WordImmediateShift Right WordImmediateCLeaR Left WordImmediateCLeaR Right WordImmediateCLeaR Left andShift Left WordImmediateslwi rD,rS,n (n


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgnop equivale a or 0,0,0Lo que hace realmente es un or binario al <strong>con</strong>tenido de r0 <strong>con</strong>sigo mismo.Otro mnemonic nos permite hacer un complemento a 1 de los bits de unregistro:not rD,rS equivale a nor rD,rS,rS5.8 Operaciones comunes <strong>con</strong> enterosEn esta sección se comentan algunas operaciones de alto nivel no trivialesque son muy típicas de necesitar usar en un programa hecho enensamblador.5.8.1 Valor absolutoVamos a ver cómo se calcula el valor absoluto de un número sin usarsentencias <strong>con</strong>dicionales, que de hecho todavía no hemos visto.El valor absoluto de un número se puede calcular como:abs(a) = (a>=0) ? a : (0-a)Es decir, si el número es positivo sería el mismo número a, y si es negativosería 0-aEl algoritmo que vamos a explicar nos devuelve:Si (a≥0) => aSi (a complemento2(a)Para ello vamos a dar los siguientes pasos:1. Calcular b de forma que:Si (a≥0) => b = 00000000 00000000 00000000 00000000Si (a b = 11111111 11111111 11111111 111111112. Hacer un xor a a <strong>con</strong> b. De esta forma si a≥0 entonces c=a pero si a


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgSi (a≥0) => d=c-0Si (a d=c+1Obsérvese que si a d=complemento1(a)-(-1)=> d=complemento1(a)+1 => d=complemento2(a)Si esto lo pasamos a ensamblador tenemos:; r3 <strong>con</strong>tiene el valor de asrawi r4,r3,31 ; r4 = (r3r3)?r3:r4; r7 = min(r3,r4)Pág 88


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgEn <strong>con</strong>creto, los pasos <strong>del</strong> algoritmo son los siguientes:1. Calculamos la diferencia entre los números: c=b-a, la cual puede serpositiva o negativa. En la instrucción subc usamos acarreo para luego podercomprobarlo.2. Aprovechamos el acarreo de la operación anterior para calcular d, de formaque 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 lainstrucción 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-a≥0) => e=0Si (b-a e=b-aPara ello usamos la operación and entre c y d4. Calculamos el mínimo como a+e ya que:Si (b-a≥0) => min(a,b)=a+0 => min(a,b)=aSi (b-a min(a,b)=a+e => min(a,b)=a+(b-a)=bRemplazando and por andc (AND with Complement to 1) el código anteriornos permite calcular max(a,b); r3 = a; r4 = bsubc r5,r4,r3 ; r5 = r4-r3subfe r6,r4,r4 ; r6 = (r4>r3)?0:-1andc r5,r5,r6 ; r5 = (r4>r3)?(r4-r3):0add r7,r3,r5 ; r7 = (r4>r3)?r4:r3; r7 = max(r3,r4)Es decir, ahora la regla que calcula e es al revés:Si (b-a≥0) => e=b-aSi (b-a e=0Con lo que en el paso 4 obtenemos el otro número, es decir:Si (b-a≥0) => max(a,b)=a+e => min(a,b)=a+(b-a)=bSi (b-a min(a,b)=a+0 => min(a,b)=aPág 89


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org5.8.3 Máximo y mínimo de un número <strong>con</strong> signoEl algoritmo anterior sólo funciona si ambos números son positivos, si losnúmeros pueden ser positivos o negativos necesitamos aplicar un algoritmocomo el siguiente:; r3 = a; r4 = bxoris r5,r3,0x8000 ; c = a+128xoris r6,r5,0x8000 ; d = b+128; Ahora el problema es análogo al <strong>del</strong> mínimo sin signosubc r5,r6,r5 ; e = d-c = b-a+256 = b-asubfe r6,r6,r6 ; f = (d>c)?0:-1and r5,r5,r6add r5,r3,r5; g = (d>c)?0:(d-c); r5 = a+g; r5 <strong>con</strong>tendrá la soluciónObsérvese que cambiar el signo a un número <strong>con</strong> signo y interpretarle comonúmero sin signo equivale a sumar 128 al número. Por ejemplo:0000 0001 (+1) 1111 1111 (-1)1000 0001 (129) 0111 1111 (127)Teniendo en cuenta esta apreciación, este algoritmo calcula el min(a,b)<strong>con</strong>virtiendo los números <strong>con</strong> signo a y b a números sin signo, para ellocambia el bit de signo a cada número y interpreta el resultado como unnúmero sin signo.A partir de aquí el algoritmo a aplicar es el de cálculo <strong>del</strong> mínimo de númerossin signo, que vimos antes.Igual que antes, remplazando and por andc (AND with Complement to 1) elcódigo anterior nos permite calcular max(a,b); r3 = a; r4 = bxoris r5,r3,0x8000 ; c = cambio signo axoris r6 ,r5,0x8000 ; d = cambio signo b; Ahora el problema es análogo al <strong>del</strong> máximo sin signosubc r5,r6,r5 ; e = d-csubfe r6,r6,r6 ; f = (d>c)?0:-1andc r5,r5,r6add r5,r3,r5; g = (d>c)?0:(d-c); r5 = a+g; r5 <strong>con</strong>tendrá la soluciónPág 90


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org5.8.4 Resto de una divisiónLa mayoría de las computadoras y lenguajes de programación truncan elresultado de una división a la parte entera, descartando el resto.Sean n el dividendo, d el divisor, c el cociente y r el resto, la operación dedivisión en un ordenador se define como:n = d*c+rDonde:Si (n≥0) => 0≤r


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgEn las divisiones de número sin signo el algoritmo es similar, sólo que ahorase usa divwu en vez de divw:; rN Dividendo; rD Divisordivwu rT,rN,rD ; c = n/dmullw rT,rT,rD ; c*dsub rT,rN,rT ; r = n-c*d5.8.5 División entre una <strong>con</strong>stante enteraLa operación de división de enteros en <strong>PowerPC</strong> es <strong>con</strong>siderablemente máslenta que la suma, resta o multiplicación de enteros. Cuando el divisor es una<strong>con</strong>stante, podemos acelerar el proceso realizando la división mediantedesplazamientos a la derecha cuando el divisor sea múltiplo de 2, o bienmediante multiplicaciones por un “magic number”, cuando se trate de otrodivisor.El siguiente apartado describe técnicas para división de números de 32 bits.Aun así estas técnicas se pueden extender a número de 64 bits.5.8.5.1 División <strong>con</strong> signo entre una potencia de 2Si el divisor es una potencia de 2, es decir, d=2 k para 1≤k≤31, la divisiónentera se puede realizar como:srawi rC,rN,rKaddze rC,rCDonde rN <strong>con</strong>tiene el dividendo, y rC <strong>con</strong>tendrá el cociente de dividir rN/d,siendo d=2 rK .Obsérvese que si el número es positivo, el desplazamiento a la derechasiempre divide entre dos.Por ejemplo si tenemos:r3=9 00000000 00000000 00000000 00001001r3=4 00000000 00000000 00000000 00000100 srawi r3,r3,1Pero si el número es negativo entonces un desplazamiento a la derecha sólodivide entre dos si el número es par. Por ejemplo:r3=-4 11111111 11111111 11111111 11111100r3=-2 11111111 11111111 11111111 11111110 srawi r3,r3,1Pág 92


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgSi el número es impar nos sale uno más de lo esperado. Por ejemplo:r3=-5 11111111 11111111 11111111 11111011r3=-3 11111111 11111111 11111111 11111101 srawi r3,r3,1Este trozo de programa aprovecha el hecho de que la instrucción srawi de<strong>PowerPC</strong> activa el bit de acarreo si rN <strong>con</strong>tiene un número negativo e impar,y se desplazan uno o más bits, es decir, rK≥1, <strong>con</strong> lo que la instrucciónaddze <strong>del</strong> programa anterior arregla este problema.5.8.5.2 División <strong>con</strong> signo por un número que no sea potencia de 2Para todo divisor d distinto de 0, la división entre d se puede calcular comouna multiplicación y alguna de suma o desplazamiento. La idea básica esmultiplicar el dividendo n por un magic number (m) de forma que los 32bits altos <strong>del</strong> producto de dos números represente el cociente. Para lo cualusaremos la instrucción mulhw de <strong>PowerPC</strong>. Con vistas a que el resultado <strong>del</strong>a división quede en los 32 bits altos <strong>del</strong> producto el magic number debe estarcomprendido entre m=(2 32 /n) y m=(2 64 /n), ya que al multiplicar m por ntendremos un número comprendido entre C=n*(2 32 /n)=2 32 yC=n*(2 64 /n)=2 64 , que es la parte alta que nos interesa a partir de la cualcalculamos el cociente c como c=C/2 32 .Los detalles son complicados, especialmente para algunos divisores, como porejemplo el 7.En el Listado 2.9, Listado 2.10 y Listado 2.11 se muestran tres ejemplos decómo se haría la división <strong>con</strong> los divisores 3, 5 y 7, respectivamente. Estosejemplos también muestran cómo se obtendría el resto <strong>con</strong> una simple restade d*c al dividendo n.lis rM,0x5555 ; Cargamos el magic number en rMori rM,rM,0x5556; m=0x55555556 = (2 32 +2)/3mulhw rC,rM,rN ; c=floor(m*n/2 32 )srwi rT,rN,31 ; Resta 1 a c si n es negativoadd rC,rC,rT ; rC <strong>con</strong>tiene el cocientemulli rT,rC,3 ; Calcula <strong>del</strong> resto como r=n-c*3sub rT,rN,rT ; rT <strong>con</strong>tiene el restoListado 2.9: Algoritmo de la división entre 3Pág 93


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orglis rM,0x6666 ; Cargamos el magic number en rMori rM,rM,0x6667 ; m=0x66666667 = (2 33 +3)/5mulhw rC,rM,rN ; c=floor(m*n/2 32 )srawi rC,rC,1 ; c=floor(c/2)srwi rT,rN,31 ; Resta 1 a c si n es negativoadd rC,rC,rT ; rC <strong>con</strong>tiene el cocientemulli rT,rC,5 ; Calcula <strong>del</strong> resto como r=n-c*5sub rT,rN,rT ; rT <strong>con</strong>tiene el restoListado 2.10: Algoritmo de la división entre 5lis rM,0x9249 ; Cargamos el magic number en rMori rM,rM,0x2493 ; m=0x92492493 = (2 34 +5)/7 - 2 32mulhw rC,rM,rN ; c=floor(m*n/2 32 )add rC,rC,rN ; c=floor(m*n/2 32 )+nsrawi rC,rC,2 ; c=floor(c/4)srwi rT,rN,31 ; Resta 1 a c si n es negativoadd rC,rC,rT ; rC <strong>con</strong>tiene el cocientemulli rT,rC,7 ; Calcula <strong>del</strong> resto como r=n-c*7sub rT,rN,rT ; rT <strong>con</strong>tiene el restoListado 2.11: Algoritmo de la división entre 7El método general de cálculo <strong>del</strong> cociente c es:1. Multiplicar el dividendo n por el magic number m2. Obtener los 32 bits altos <strong>del</strong> producto y desplazarlo a la derecha unnúmero de veces comprendido entre 0 y 313. Añadir 1 si n es negativoEl método general siempre se reduce a uno de estos tres casos, ilustrados<strong>con</strong> la división entre 3, 5 ó 7. En el caso de la división entre 3 el multiplicadorse puede representar en 32 bits, y por eso en este caso después <strong>del</strong> mulhw eldesplazamiento a la derecha es 0. En el caso de la división entre 5, elmultiplicador también se representa <strong>con</strong> 32 bits, pero el desplazamiento a laderecha es uno. En el caso de la división entre 7, el multiplicador no se puederepresentar en 32 bits, pero los 32 bits bajos <strong>del</strong> multiplicador sonrepresentables en 32 bits. Entonces, el programa multiplica por los 32 bitsbajos <strong>del</strong> multiplicador y después corrige el producto añadiendo n*2 32 , esdecir, añade n a la parte alta <strong>del</strong> producto. Para d=7, el desplazamiento a laderecha es 2.Para la mayoría de los divisores, existe más de un multiplicador que nos danel resultado correcto <strong>con</strong> este método. En este caso, en general lo mejor esusar el multiplicador más bajo ya que este puede implicar un desplazamientode cero bits a la izquierda, ahorrándonos la instrucción srawi.Pág 94


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgEl procedimiento para dividir entre una <strong>con</strong>stante negativa es análogo. Estoes así gracias a que la división de enteros satisface la propiedad: n/(-d)=-(n/d). Con lo que para dividir entre una <strong>con</strong>stante negativa, primerodividimos entre su correspondiente <strong>con</strong>stante positiva, y luego al resultado asíobtenido le cambiamos el signo.Además, en el caso de d=-7 podemos ahorrarnos la negación si usamos elsiguiente algoritmo:lis rM,0x6DB6 ; Cargamos el magic number en rMori rM,0xDB6D ; m=0x6DB6DB6D = -(2 34 +5)/7 + 2 32mulhw rC,rM,rN ; c=floor(m*n/2 32 )sub rC,rC,rN ; c=floor(m*n/2 32 )-nsrawi rC,rC,2 ; c=floor(c/4)srwi rT,rC,31 ; Añade 1 a c si n es negativoadd rC,rC,rT ; rC <strong>con</strong>tiene el cocientemulli rT,rC,-7 ; Cálculo <strong>del</strong> resto como r=n-c*(-7)sub rT,rN,rT ; rT <strong>con</strong>tiene el restoEste programa es el mismo que el de la división entre +7, excepto que usa elmultiplicador de signo opuesto, resta en vez de añadir, y desplaza c en vezde n a la derecha 31 posiciones. (En el caso de d=+7 también podríamosdesplazar c en vez de n 31 veces a la derecha, pero habría menosparalelismo en el código).El magic number usado como multiplicador al dividir entre -d es casi siempreel negativo de magic number de d, es decir, -m (p.e. para d=7, teníamos quem=92492493, <strong>con</strong> lo que para d=-7 tenemos que m=-1*92492493=0x6DB6DB6D). Las únicas excepciones a esta regla son d=3 yd=715.827.883La Tabla 2.34 muestra los magic number y desplazamientos para los númerosmás comunes.d (decimal) m (hexadecimal) desplazamiento-5 9999 9999 1-3 5555 5555 1-2 k 7FFF FFFF k-11 - -2 k 8000 0001 k-13 5555 5556 05 6666 6666 16 2AAA AAAB 07 9249 2493 29 38E3 8E39 110 6666 6667 211 2E8B A2E9 112 2AAA AAAB 1Pág 95


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org25 51EB 851F 3125 1062 4DD3 3Tabla 2.34: Magic number y desplazamientos para los números más comunesEl algoritmo para calcular los magic numbers y desplazamientos de losdivisores está más allá de los objetivos de este tutorial. Aquel que esteinteresado en <strong>con</strong>ocerlo pude hacerlo en la web de IBM en el documento[WARREN].5.8.6 División de 64 bits en máquinas de 32 bitsAunque <strong>PowerPC</strong> dispone de instrucciones que nos permiten obtener númerosde 64 bits como el producto de números de 32 bits, no dispone de ningunainstrucción que nos permita dividir números de 64 bits. En este apartadovamos a hacer un programa que nos permite dividir números de 64 bits <strong>con</strong> osin signo. El algoritmo de división de números sin signo que vamos a usar secomenta <strong>con</strong> más detalle en el apéndice A.Una vez el lector entienda el algoritmo puede modificar el cociente y resto<strong>con</strong>venientemente para realizar divisiones de números de 64 bits <strong>con</strong> signo.En este caso es importante <strong>con</strong>templar el caso de -2 63 /(-1), donde elresultado esta indefinido.El programa lo vamos a hacer en un fichero llamado divide64.s aparece enel Listado 2.12. Para referirnos a los registros vamos a usar definiciones#define tal como explicábamos en el apartado 0, que nos permiten darnombres a los registros para recordar su utilidad más fácilmente, de acuerdoa la Tabla 2.35:identificador Registro Descripcióndvdh r3 (DiVidenDo High) 32 bits bajos <strong>del</strong> dividendodvdl r4 (DiVidenDo Low) 32 bits altos <strong>del</strong> dividendodvsh r5 (DiVideSor High) 32 bits bajos <strong>del</strong> divisordvsl r6 (DiVideSor Low) 32 bits altos <strong>del</strong> divisorcoch r7 (COCiente High) 32 bits bajos <strong>del</strong> cocientecocl r8 (COCiente Low) 32 bits altos <strong>del</strong> cocienteresh r9 (RESto High) 32 bits bajos <strong>del</strong> restoresl r10 (RESto Low) 32 bits altos <strong>del</strong> restoceros_dvd r11 Número de ceros a la izquierda <strong>del</strong> dividendoceros_dvs r12 Número de ceros a la izquierda <strong>del</strong> divisorrep r13 Repeticiones <strong>del</strong> bucle de desplazamiento a laizquierdatmp1 r14 Para cálculos temporalestmp2 r15 Para cálculos temporalestmp3 r16 Para cálculos temporalesTabla 2.35: #define <strong>del</strong> programaPág 96


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgEl dividendo se deposita en los registros dvdh:dvdl que forman el registrode 64 bits dvd. El divisor se deposita en dvsh:dvsl que forman el registrode 64 bits dvs. Al acabar el algoritmo en coch:cocl se depositara elcociente y en resh:resl el resto.La operación se realiza sobre el registro de 128 bits res:dvd. Cada iteraciónincluye los siguientes pasos:1. Desplazar la combinación res:dvd 1 bit a la izquierda. Esto carga un1 en el bit menos significativo de res cuando el bit más significativo dedvd sea 1, o un 0 en el bit menos significativo de res en caso<strong>con</strong>trario.2. Restar a res el divisor dvs. Esto calcula la resta parcial de la división.3. Si el resultado es negativo, no modificamos res e insertamos un ceroen el bit bajo de coc4. Si el resultado es positivo ponemos el resultado en res, e insertamosun uno en el bit bajo de coc5. Si el número de iteraciones es menor al ancho de dvd, volvemos alpaso 1Antes de empezar este bucle el programa desplaza dvd a la izquierda tantasveces como ceros a la izquierda tenga <strong>con</strong> el fin de evitar repeticiones debucle 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.datan: .long 2,1 ; Dividendod: .long 1,0 ; Divisor.comm c,8 ; Cociente.comm r,8 ; Resto.text.globl _mainPág 97


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org_main:// Cargamos el dividendo y divisor en los registros// Para ello usamos lswi (Load String Word// Immediate) que carga 32 bytes <strong>con</strong>secutivos en// dvdl-dvshlis r2,ha16(n)addi r2,r2,lo16(n)lswi dvdh,r2,16// Contamos el número de 0 a la izquierda// <strong>del</strong> dividendocntlzw ceros_dvd,dvdhcntlzw tmp1,dvdlcmpwi cr0,dvdh,0bne cr0,eti1 ; Si (dvdh!=0) hay ceros_dvd cerosaddi ceros_dvd,tmp1,32 ; Si (dvdh==0); hay ceros_dvd=32+tmp1 ceroseti1:// Contamos el número de 0 a la izquierda <strong>del</strong>divisorcntlzw ceros_dvs,dvshcntlzw tmp1,dvslcmpwi cr0,dvsh,0bne cr0,eti2 ; Si (dvsh!=0) hay ceros_dvs cerosaddi ceros_dvs,tmp1,32 ; Si (dvsh==0); hay ceros_dvs=32+tmp1 ceroseti2:// Determina el desplazamiento necesario para// minimizar el número de iteracionescmpw cr0,ceros_dvs,ceros_dvsbgt cr0,eti9 ; Si (dvs>dvd) cociente = 0li rep,64sub rep,rep,ceros_dvd ; Repeticiones <strong>del</strong> 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,32blt eti3// (Cuerpo if) Copiamos dvdl en dvdh// y desplazamos <strong>con</strong>venientementemr dvdh,dvdllis dvdl,0subi ceros_dvd,ceros_dvd,32slw dvdh,dvdh,ceros_dvdb eti5eti3:// (Cuerp else) Desplazamos a la izquierda; si (ceros_dvd


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgbeq eti5mtctr ceros_dvdeti4:add dvdh,dvdh,dvdhaddc dvdl,dvdl,dvdl; Fijamos el <strong>con</strong>tador <strong>del</strong>; bucle; Desplazamos uno a; izquierda sumando; Si acarrea lo pasamos; a dvdhaddze dvdh,dvdhbdnz eti4eti5:// Empezamos el bucle de desplazamientolis coch,0lis cocl,0lis resh,0lis resl,0mtctr rep; Fijamos <strong>con</strong>tador <strong>del</strong> bucleeti6:// 1. Desplazar la combinación res:dvd 1 bit// a la izquierdaaddc dvdl,dvdl,dvdladde dvdh,dvdh,dvdhadde resl,resl,resladde resh,resh,resh// 2. Restar a res el divisor dvs. Esto calcula// la resta parcial de la división.lis tmp3,0subc tmp1,resl,dvslsubfe tmp2,dvsh,reshsubfe tmp3,tmp3,tmp3cmpwi tmp3,0beq eti7 ; Si(tmp3==0) => res>=dvs// (res=dvs)//4. Si el resultado es positivo ponemos el// resultado en res y insertamos un uno en// el bit bajo de cocmr resl,tmp1mr resh,tmp2addc cocl,cocl,cocladde coch,coch,cochori cocl,cocl,1eti8:// 5. Si el número de iteraciones es menor al// ancho de dvd, volvemos al paso 1bdnz eti6b eti10eti9:// Cociente==0 (dvs>dvd)lis coch,0Pág 99


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orglis cocl,0mr resh,dvdhmr resl,dvdleti10:// Guardamos los registros en memoria// <strong>con</strong> stswi (Store String Word Immediate)lis r2,ha16(c)addi r2,r2,lo16(c)stswi coch,r2,16// RetornamosblrListado 2.12: División de 64 bits en máquinas de 32 bitsPág 100


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org6 Instrucciones de bifurcaciónEn esta sección vamos a comentar <strong>con</strong> qué instrucciones de bifurcacióncuenta <strong>PowerPC</strong>.Las instrucciones de bifurcación nos permiten alterar el flujo normal <strong>del</strong>programa. Para ello alteran el valor <strong>del</strong> <strong>con</strong>tador de programa. En <strong>PowerPC</strong>, adiferencia de otras arquitecturas, nunca se puede hacer referencia explícita aeste registro, es decir, este registro no se puede leer en <strong>PowerPC</strong>, y sólo sepuede modificar indirectamente al ejecutar instrucciones de bifurcación. Enotros sistemas es muy típico llamar a este registro PC (Program Counter) o IP(Instruction Pointer). Nosotros vamos a referirnos a el como IP, aunque esteregistro no tienen un nombre explícito en <strong>PowerPC</strong>, por no poder referirnosdiréctamenta a él.6.1 Tipos de cálculo de la dirección de salto de unainstrucciónLos saltos de las instrucciones de bifurcación pueden ser <strong>con</strong>dicionales oin<strong>con</strong>dicionales. Si son <strong>con</strong>dicionales se utiliza el registro CR para tomar ladecisión de si hacer o no el salto.Por otro lado las instrucciones de bifurcación pueden ser de salto relativo oabsoluto. Las instrucciones de bifurcación de salto absoluto especifican ladirección completa (32 bits) de la dirección de salto, obsérvese que comotodas las instrucciones de <strong>PowerPC</strong> ocupan 32 bits, la dirección absoluta desalto no se puede codificar dentro de la instrucción, sino que debe de estar enun registro.Las instrucciones de bifurcación de salto relativo son instrucciones en las quela dirección de salto se calcula respecto al IP (Instruction Pointer) actual,sumándole o restándole una determinada cantidad. Al ser esta cantidad unnúmero menor de 32 bits sí que se puede incrustar como operando inmediatoen la instrucción de salto. Como en la práctica la mayoría de los saltos sesuelen hacer a direcciones cercanas a la posición actual <strong>del</strong> IP estasinstrucciones resultan muy útiles.Recuérdese que las instrucciones de <strong>PowerPC</strong> siempre estaban alineadas altamaño de palabra, <strong>con</strong> lo que los dos últimos bits de la dirección de destinosiempre deben de valer 0. Las instrucciones de bifurcación relativasaprovechan esta característica para no tener que codificar dentro de lainstrucción estos dos últimos bits, sino que aprovechan para en su lugarcodifican otros 2 bits de más peso.Pág 101


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgComo veremos, el tamaño de esta dirección relativa puede ser de 14 bits o de24 bits, y como los últimos dos bits no es necesario almacenarlos, nospermiten dar saltos de hasta ±32.768 bytes (2 14+2-1 =32.768) y de hasta±33.554.432 bytes (2 24+2-1 =33.554.432) respectivamente, es decir, sumamos2 al exponente porque los dos últimos bits no es necesario almacenarlos <strong>con</strong>lo que podemos coger otros 2 bits de la izquierda, y le restamos 1 porque eldesplazamiento puede ser positivo o negativo.Las instrucciones de bifurcación tienen los siguientes tipos de cálculo de ladirección destino:o Salto relativoo Salto absolutoo Salto <strong>con</strong>dicional relativoo Salto <strong>con</strong>dicional absolutoo Salto <strong>con</strong>dicional al Link Registero Salto <strong>con</strong>dicional al Count RegisterA <strong>con</strong>tinuación vamos a describir como funciona cada uno de ellos.6.1.1 Instrucciones de salto relativoLas instrucciones de salto relativo generan la dirección de la siguienteinstrucción a ejecutar usando el campo LI de la instrucción. A este campo sele <strong>con</strong>catena al final dos bits <strong>con</strong> 0 y se le extiende el signo, y este valor sesuma al IP lo cual nos da la dirección efectiva de salto de la instrucción.Las instrucciones de salto relativo siempre deben tener el bit de la posición 30AA (Absolute Address) a 0, y el bit de la posición 31 LK (LinK) puede estaractivo, en cuyo caso se guarda la dirección siguiente a la instrucción de saltoen el registro LR. El uso de este registro lo explicaremos en el apartado 6.1.7.Las instrucción de salto relativo de que dispone <strong>PowerPC</strong> se resumen en laTabla 2.36:Instrucciónb Dbl DTabla 2.36: Instrucciones de salto relativoDescripción(Branch) Salta a la dirección calculada como lasuma de D más el valor actual <strong>del</strong> IP. Estainstrucción tiene AA=0 y LK=0(Branch then Link) Igual que b, sólo que en elregistro LR se almacena la dirección de lasiguiente instrucción a la instrucción de salto. Estainstrucción tiene AA=0 y LK=1La Figura 2.7 muestra el proceso de cálculo de la dirección de salto en lasinstrucciones de salto relativo:Pág 102


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org0 5 6 29 30 3118 LIAA LK(Codificación de la instrucción)0 5 6 29 30 31Exten signoLI0 00 31IP (Instruction Pointer)+0 31Dirección de saltoFigura 2.7: Cálculo de la dirección de salto en las instrucciones de salto relativo6.1.2 Instrucciones de salto absolutoLas instrucciones de salto absoluto que vamos a ver en esta sección recibencomo operando una dirección que indica la posición absoluta a la que realizarel salto.Como en una instrucción de 32 bits no se pueden codificar los 32 bits de ladirección de salto, se codifican sólo 24 bits en el campo LI, y después seextienden a 32 bits <strong>con</strong>catenando 2 bits <strong>con</strong> cero al final y rellenando los bitsque quedan <strong>del</strong>ante <strong>con</strong> ceros.0 5 6 29 30 3118 LI(Codificación de la instrucción)Exten signoLIAA LK0 5 6 29 30 310 00 31Dirección de saltoFigura 2.8: Cálculo de la dirección de salto en las instrucciones de salto absolutoPág 103


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgLa Figura 2.8 muestra el proceso de cálculo de la dirección absoluta.Obsérvese que al ser los primeros 6 bits siempre 0, esta instrucción sólo nospermite acceder a los primeros 2 26 =67.108.864 bytes <strong>del</strong> espacio de memoriade 2 32 bytes que tiene un proceso, <strong>con</strong> lo que es una instrucción poco usada.Las instrucciones de salto absoluto siempre deben tener el bit de la posición30 AA (Absolute Address) a 1, y el bit de la posición 31 LK (LinK) puede estaractivo, en cuyo caso se guarda la dirección siguiente a la instrucción de saltoen el registro LR. El uso de este registro lo explicaremos en el apartado 6.1.7.Las instrucciones de salto absoluto de que dispone <strong>PowerPC</strong> se resumen en laTabla 2.37:InstrucciónDescripciónba D (Branch Absolute) Salta a la dirección dada en D.Esta instrucción tiene AA=1 y LK=0bla D(Branch then Link Absolute) Igual que ba, sóloque en el registro LR se almacena la dirección <strong>del</strong>a siguiente instrucción a la instrucción de salto.Esta instrucción tiene AA=1 y LK=1Tabla 2.37: Instrucciones de salto absolutoEl destino de esta instrucción se indica <strong>con</strong> una etiqueta, de la cual elensamblador coge los bits de la posición 6 a la 29 y los codifica en el campoLI de la instrucción. Por ejemplo, podemos hacer:ba fin········fin: blr6.1.3 Las instrucciones de salto <strong>con</strong>dicionalLas instrucciones de salto <strong>con</strong>dicional tienen una codificación de acuerdo <strong>con</strong>la siguiente figura:0 5 6 10 11 15 16 29 30 31OpCodeBOBIAA LKFigura 2.9: Codificación de las instrucciones de salto <strong>con</strong>dicionalOpCode identifica la instrucción que vamos a codificar.BI (Branch Input) especifica los bits de CR usados como <strong>con</strong>dición a evaluarpara el salto de acuerdo a la Tabla 2.38:Pág 104


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgBIDec BinBit CRna evaluar Descripción0 00000 CR0[0] Negative (LT). El resultado de una instrucción <strong>con</strong>punto (.) es negativo1 00001 CR0[1] Positive (GT). El resultado de una instrucción <strong>con</strong>punto (.) es positivo2 00010 CR0[2] Zero (EQ). El resultado de una instrucción <strong>con</strong>punto (.) es cero3 00011 CR0[3] Summary Overflow (SO). Copia <strong>del</strong> bit XER[SO]de la anterior instrucción ejecutada4 00100 CR1[0] Copia de FPSCR[FX]5 00101 CR1[1] Copia de FPSCR[FEX]6 00110 CR1[2] Copia de FPSCR[VX]7 00111 CR1[3] Copia de FPSCR[OX]8 01000 CRn[0] Menor que:12 01100Para enteros rAfBIgual:Para enteros rA=SIMM o rA=UIMM o rA=rBPara punto flotante fA=fBSummary Overflow o floating Point UnorderedRecuérdese, que como explicamos en el apartado 5.1 el campo CR0 se sueleusar para comprobar el resultado de una operación <strong>con</strong> punto (.), como porejemplo add., de este resultado podíamos mirar si era positivo, negativo,cero, o había habido un overflow <strong>con</strong>sultando los bits de este campo.Pág 105


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgTambién, como explicamos en el apartado 5.1 el campo CR1 lo usaban lasoperaciones en punto flotante.Los demás campos (CR2 hasta CR7) se dejaban para las operaciones decomparación, aunque los resultados de las comparaciones también se puedendepositar en CR0 y CR1, sin embargo en la tabla hemos supuesto que se usanpara instrucciones <strong>con</strong> punto.En la Tabla 2.38 n se refiere a los campos de CR que van desde CR2 hastaCR7, 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 <strong>del</strong> registroCR queremos comprobar.BO (Branch Output) especifica la acción a realizar por la instrucción de saltocuando se cumpla la <strong>con</strong>dición dada por BI de acuerdo a la Tabla 2.39.BO0000y0001y001zy0100y0101y011zy1z00y1z01y1z1zzDescripciónDecrementa el registro CTR y después salta si CTR≠0 y la <strong>con</strong>diciónes FALSEDecrementa el registro CTR y después salta si CTR=0 y la <strong>con</strong>diciónes FALSESalta si la <strong>con</strong>dición es FALSEDecrementa el registro CTR y después salta si CTR≠0 y la <strong>con</strong>diciónes TRUEDecrementa el registro CTR y después salta si CTR=0 y la <strong>con</strong>diciónes TRUESalta si la <strong>con</strong>dición es TRUEDecrementa el registro CTR y después salta si CTR≠0Decrementa el registro CTR y después salta si CTR=0Salta siemprez Es un bit que se reserva para el futuro, y de momento debe ser siempre 0y Indica si es más probable que el salto se realice o que no se realice, su uso se explica en elApéndice B, en principio se puede dejar siempre a 0Tabla 2.39: Configuración <strong>del</strong> operando BOBásicamente estos 5 bits codifican 6 posibles actuaciones:o Decrementar el registro CTRo Comprobar si CRT es 0o Comprobar si CTR no es ceroo Comprobar si la <strong>con</strong>dición es verdaderao Comprobar si la <strong>con</strong>dición es falsao Predicción de salto. Se explica en el Apéndice BPág 106


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgLos otros dos campos de la instrucción codificada son:AA (Absolute Address), indica si se trata de un salto a una dirección relativa(AA=0) o absoluta (AA=1)LK (LinK), indica si antes de saltar, se copia (LK=1) o no se copia (LK=0), ladirección de la siguiente instrucción a la de salto en registro LR, esto comoveremos en el apartado 6.1.7 sirve para poder retornar de la llamada a unasubrutina.Las instrucciones de salto <strong>con</strong>dicional se dividen en cuatro tipos que vamos aexplicar detallar a <strong>con</strong>tinuación.6.1.4 Instrucciones <strong>con</strong>dicionales de salto relativoEstas instrucciones realizan un salto relativo si se cumple la <strong>con</strong>dición. Elfuncionamiento exacto de la instrucción se muestra en la Figura 2.10:0 5 6 10 11 15 16 29 30 3116 B0 BIBD AA LK(Codificación de la instrucción)¿Cumple<strong>con</strong>dición?SíNo0 31Siguiente instrucción0 15 16 29 30 31Extensión <strong>del</strong> signo+Dirección de saltoBDAA LK0 31Instruction Pointer (IP)0 31Figura 2.10: Instrucciones <strong>con</strong>dicionales de salto relativoLas instrucciones de salto <strong>con</strong>dicional relativo de que dispone <strong>PowerPC</strong> seresumen en la Tabla 2.40:Pág 107


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgInstrucciónbc BO,BI,Dbcl BO,BI,DDescripción(Branch Conditional) Si se cumplen las <strong>con</strong>diciones dadaspor BI y BO salta a la dirección calculada como la suma deD más el valor actual <strong>del</strong> IP. Esta instrucción tiene AA=0 yLK=0(Branch Conditional then Link) Igual que bc, sólo que enel registro LR se almacena la dirección de la siguienteinstrucción a la instrucción de salto. Esta instrucción tieneAA=0 y LK=1Tabla 2.40: Instrucciones <strong>con</strong>dicionales de salto relativoPor ejemplo, imaginemos que queremos hacer una operación sólo si el valor<strong>del</strong> registro r2 es menor a 5, entonces haríamos:cmpwi r2,5bc 12,0,fin; Hacemos la operación que sea······························fin: ; Otras operaciones······························Aquí BI vale 0, que significa en la comparación almacenó en CR0 un “menorque”, es decir, que r2


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgLas instrucciones <strong>con</strong>dicionales de salto absoluto que existen en <strong>PowerPC</strong> sedetallan en la Tabla 2.41.0 5 6 10 11 15 16 29 30 3116 B0 BIBD AA LK(Codificación de la instrucción)¿Cumple<strong>con</strong>dición?Sí0 15 16 29 30 310000 0000 0000 0000 BD AA LKNo0 31Siguiente instrucción0 31Dirección de saltoFigura 2.11: Instrucciones <strong>con</strong>dicionales de salto absoluto6.1.6 Instrucciones <strong>con</strong>dicionales de salto al CountRegisterCon las instrucciones de salto que <strong>con</strong>ocemos hasta ahora tenemos unproblema si queremos saltar a una dirección de memoria absoluta que estemás allá de las direcciones a las que podemos llegar <strong>con</strong> las instrucciones desalto absoluto que hemos visto.Para solucionar este problema existe otra instrucción en la que la dirección desalto se guarda en un registro llamado CTR (CounT Register).El CTR es un registro especial (SPR), en <strong>con</strong>creto el SPR9, y paraleerlo/modificarlo usamos dos instrucciones que nos permiten acceder a losSPR, 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 instrucción.Pág 109


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgUna vez puesta la dirección a la que queremos saltar en el registro CTRpodemos saltar a esta dirección <strong>con</strong> las instrucciones de <strong>PowerPC</strong> de la Tabla2.42.0 5 6 10 11 15 16 20 21 29 30 3119 B0 BI 0000528 LK(Codificación de la instrucción)¿Cumple<strong>con</strong>dición?Sí0 29CTR (CounT Register)No0 31Siguiente instrucción30 31|| 000 31Dirección de saltoFigura 2.12: Instrucciones <strong>con</strong>dicionales de salto al Count RegisterInstrucciónbcctr BO,BIbcctrl BO,BITabla 2.42: Instrucciones <strong>con</strong>dicionales de salto absolutoDescripción(Branch Conditional to CounT Register) Salta a ladirección de memoria almacenada en el CTR. Estainstrucción tiene LK=0(Branch Conditional to CounT Register then Link)Igual que bcctr sólo que almacena en el LR ladirección de la siguiente instrucción a lainstrucción de salto. Esta instrucción tiene LK=16.1.7 Instrucciones <strong>con</strong>dicionales de salto al Link RegisterAntes veíamos que las instrucciones de salto, antes de saltar, podíanalmacenar en el registro LR (Link Register) la dirección de la siguienteinstrucción a la instrucción de salto. Esto es especialmente útil para hacerllamadas a subrutinas, ya que ahora podemos retornar de esa llamadavolviendo a la dirección que dejamos almacenada en LR.Pág 110


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgQueda por ver cómo se trata otro problema, que es el problema de que unallamada a una subrutina llame a su vez a otra subrutina guardando estatambién en LR la dirección de retorno, y borrando la anterior dirección. Comoexplicaremos en el apartado 8, la solución está en guardar el valor de LR enla pila antes de llamar a otra función. Las instrucciones que vamos a verahora son las que nos permiten retornar de la llamada.La Figura 2.13 muestra el funcionamiento de este tipo de instrucciones. Éstastambién tienen el bit LK <strong>con</strong> el significado habitual de guardar el valor de lasiguiente instrucción a la de salto en LR, lo cual se hace cuando este bit estáa 1. En la práctica esta opción no se usa cuando retornamos de una subrutinaya que en ese caso no solemos guardar la dirección de la siguiente instrucciónal retorno. Sin embargo esta opción se puede usar si ponemos en LR ladirección de una subrutina a la que queremos llamar.0 5 6 10 11 15 16 20 21 29 30 3119 B0 BI 000016 LK(Codificación de la instrucción)¿Cumple<strong>con</strong>dición?Sí0 29LR (Link Register)No0 31Siguiente instrucción30 31|| 000 31Dirección de saltoFigura 2.13: Instrucciones <strong>con</strong>dicionales de salto al Link RegisterLas instrucciones <strong>con</strong>dicionales de salto al Link Register que tiene <strong>PowerPC</strong> seresumen en la Tabla 2.43.Instrucciónbclr BO,BIbclrl BO,BIDescripción(Branch Conditional to Link Register) Si secumplen las <strong>con</strong>diciones dadas por BI y BO salta ala dirección dada en el registro LR. Estainstrucción tiene LK=0(Branch Conditional to Link Register then Link)Igual que bclr, sólo que en el registro LR sealmacena la dirección de la siguiente instrucción ala instrucción de salto. Esta instrucción tiene LK=1Pág 111


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgalmacena la dirección de la siguiente instrucción ala instrucción de salto. Esta instrucción tiene LK=1Tabla 2.43: Instrucciones <strong>con</strong>dicionales de salto al Link RegisterPor último comentar que además de cargar el LR usando instrucciones <strong>con</strong> elbit LK=1, el LR es un registro especial (SPR), en <strong>con</strong>creto el SPR8 y paraleerlo/modificarlo usamos mfspr y mtspr.6.2 MnemonicsVamos a empezar <strong>con</strong> mnemonics típicos para las operaciones de bifurcación.6.2.1 Mnemonics para saltos in<strong>con</strong>dicionalesPara los saltos in<strong>con</strong>dicionales existen cuatro mnemonics que se resumen enla Tabla 2.44:Mnemonic Descripción Equivale ablr(Branch to LR) Salta a la dirección de bclr 20,0memoria almacenada en el registro LRblrl (Branch to LR and Link) Igual que blr sólo bclrl 20,0que en LR se almacena la dirección dememoria de la siguiente instrucción a lainstrucción de salto.bctr (Branch to CTR) Salta a la dirección de bcctr 20,0memoria almacenada en el registro CTRbctrl (Branch to CTR and Link) Igual que bctrsólo que en LR se almacena la dirección dememoria de la siguiente instrucción a lainstrucción de salto.bcctrl 20,0Tabla 2.44: Mnemonics de salto in<strong>con</strong>dicionalblr es un mnemonic que ya hemos usado muchas veces para retornar deuna función main().Ninguno de estos mnemonics reciben operandos ya que la dirección de saltoestará ya almacenada en los registros LR o CTR.6.2.2 Mnemonics para saltos <strong>con</strong>dicionalesDebido a la complejidad de codificar los operandos BI y BO de lasinstrucciones de salto <strong>con</strong>dicional, se han creado una serie de mnemonics quese describen en la Tabla 2.45 y Tabla 2.46:Pág 112


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgInstrucción a que equivaleCondición <strong>del</strong> salto bc bca bctr bcctrSalto si la <strong>con</strong>dición se cumple bt bta btlr btctrSalto si la <strong>con</strong>dición no secumplebf bfa bflr bfctrTabla 2.45: Mnemonics de salto <strong>con</strong>dicional sin actualización de LRInstrucción a que equivaleCondición <strong>del</strong> salto bc bca bctr bcctrSalto si la <strong>con</strong>dición se cumple btl btla btlrl btctrlSalto si la <strong>con</strong>dición no secumplebfl bfla bflrl bfctrlTabla 2.46: Mnemonics de salto <strong>con</strong>dicional <strong>con</strong> actualización de LREstos mnemonics no reciben el operando BO, pero sí que tienen que recibir 2operandos:o El operando BI <strong>con</strong> la <strong>con</strong>dición a evaluaro La dirección de salto si se cumple la <strong>con</strong>diciónEs decir, estas instrucciones tienen la forma:MNEMONIC BI, ETIQUETAPor ejemplo podemos hacer:cmpwi cr5,r3,0bf 22,finQue significa que no salte si CR5 tiene el bit de igualdad activo, es decir, si lacomparación anterior <strong>con</strong>cluyó que r3 valía 0. Véase el apartado 6.1.3 parauna mejor descripción <strong>del</strong> operando BI.Para simplificar la codificación <strong>del</strong> operando BI se han creado una serie desímbolos tal como describe la siguiente Tabla 2.47.Símbolo Valor Descripciónlt 0 Less Thangt 1 Greater Thaneq 2 EQualso 3 Summary Overflowun 3 UNorderedTabla 2.47: Símbolos para el operando BIPág 113


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgPor ejemplo en el ejemplo anterior podríamos haber hecho:cmpwi cr5,r3,0bf cr5+eq,finDonde queda mucho más claro poner cr5+eq que poner 22.En caso de que para la comparación se usara el campo CR0 no haría faltaponer cr0, es decir, podemos hacer:cmpwi cr0,r3,0bf eq,finY bf usaría el campo cr0 para comprobar la <strong>con</strong>dición.También se han hecho mnemonics que no reciben ni el operando BI, ni eloperando BO como muestra la Tabla 2.48 y Tabla 2.49:Instrucción a que equivaleCondición <strong>del</strong> salto bc bca bclr bcctrBranch if less than blt blta bltlr blrctrBranch if less than or equal ble blea blelr blectrBranch if equal beq beqa beqlr beqctrBranch if greater than or equal bge bgea bgelr bgectrBranch if greater than bgt bgta bgtlr bgctrBranch if not less than bnl bnla bnllr bnlctrBranch if not equal bne bnea bnelr bnectrBranch if not greater than bng bnga bnglr bngctrBranch if summary overflow bso bsoa bsolr bsoctrBranch if not summary overflow bns bnsa bnslr bnsctrBranch if unordered bun buna bunlr bunctrBranch if not unordered bnu bnua bnulr bnuctrTabla 2.48: Mnemonics de salto <strong>con</strong>dicional sin actualización de LRInstrucción a que equivaleCondición <strong>del</strong> salto bcl bcla bclrl bcctrlBranch if less than bltl bltla bltlrl bltctrlBranch if less than or equal blel blela blelrl blectrlBranch if equal beql beqla beqlrl beqctrlBranch if greater than or equal bgel bgela bgelrl bgectrlBranch if greater than bgtl bgtla bgtlrl bgctrlBranch if not less than bnl bnlla bnllrl bnlctrlBranch if not equal bnel bnela bnelrl bnectrlBranch if not greater than bngl bngla bnglrl bngctrlBranch if summary overflow bsol bsola bsolrl bsoctrlPág 114


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgBranch if not summary overflow bnsl bnsla bnslrl bnsctrlBranch if unordered bunl bunla bunlrl bunctrlBranch if not unordered bnul bnula bnulrl bnuctrlTabla 2.49: Mnemonics de salto <strong>con</strong>dicional <strong>con</strong> actualización de LRLa Tabla 2.50 ayuda a entender y recordar las instrucciones anteriores:Abreviatura Descripciónlt Less Thanle Less than or Equaleq EQualge Greater than or Equalgt Greater Thannl Not Lessne Not Equalng Not Greater thanso Summary Overflowns Not Summary Overflowun UNordered (para comparaciones en punto flotante)nu Not Unordered (para comparaciones en punto flotante)Tabla 2.50: Abreviaturas para los mnemonics de comparaciónObsérvese que las instrucciones que actualizan LR se escriben igual que lasque no lo actualizan, pero se las añade una l al final. La excepción esta enlas instrucciones de tipo bcla donde la l se pone antes de la última a. Porejemplo, en vez de poner bleal se pone blela.Todas estas instrucciones reciben como primer operando el campo de CR acomprobar, y como segundo operando la dirección de salto. El primero de losoperandos se puede omitir, en cuyo caso se supone que es el CR0.Es decir el formato general de estos mnemonics es:MNEMONIC [CRF,] ETIQUETAPara indicar el campo de CR a comprobar se puede usar su valor numérico obien uno de los mnemonics definidos en la tabla <strong>del</strong> apartado 5.7.2.Por ejemplo, si queremos hacer algo sólo cuando en r3 haya un númeromenor de 0 haríamos:cmpwi cr2,r3,0bge cr2,fin; Hacer algo············fin: ; Otras cosas············Pág 115


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org6.2.3 Mnemonics para acceder a los registros CR, CTR y LRCTR y LR son registros especiales (en <strong>con</strong>creto SPR9 y SPR8respectivamente), que comentamos que podíamos acceder a ellos <strong>con</strong> lasinstrucciones:mfspr rD,SPR /* Move From Special Purpose Register */mtspr SPR,rS /* Move To Special Purpose Register */Además existen mnemonics que nos permiten acceder a ellos más fácilmenteque se muestran en la Tabla 2.51:Mnemonicmfctr rDmtctr rSmflr rDmtlr rSDescripción(Move From CTR) Copia el <strong>con</strong>tenido de CTR en rD(Move to CTR) Copia el <strong>con</strong>tenido de rS en CTR(Move From LR) Copia el <strong>con</strong>tendo de LR en rD(Move To LR) Copia el <strong>con</strong>tenido de rS en CTRTabla 2.51: Mnemonics para acceso a los registro CTR y LRTambién tenemos mnemonics que nos permiten encender, apagar, copiar einvertir un determinado bit <strong>del</strong> registro CR que se resumen en la Tabla 2.52:Mnemonic Descripción Equivalente acrset B CR SET creqv B,B,Bcrclr B CR CLeaR crxor B,B,Bcrmove B1,B2 CR MOVE cror B1,B2,B2crnot B1,B2 CR NOT crnor B1,B2,B2Tabla 2.52: Mnemonics para acceder a un bit <strong>del</strong> registro CRDonde B es el bit que queremos modificar.6.3 Implementación en ensamblador de lassentencias de <strong>con</strong>trol de flujo más <strong>con</strong>ocidas<strong>del</strong> lenguaje CEn esta sección vamos a detallar como se implementarían en ensambladorcada una de la sentencias de <strong>con</strong>trol de flujo <strong>del</strong> lenguaje C.6.3.1 Condicional simple y dobleLas <strong>con</strong>dicionales simple y doble son las sentencias if e if-else de C, lascuales van a evaluar una expresión cuyo resultado se deposita en un campode CR y en función de este resultado se ejecuta una y otra parte.Pág 116


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgPor ejemplo, si queremos codificar el ensamblador la sentencia de <strong>con</strong>trol deflujo siguiente:if (a>0){// Hacer esto}else if (a


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgImaginemos que tenemos la sentencia de <strong>con</strong>trol 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 ifelseasí:lis r2,ha16(segmento) ; r2 apunta a los 16 bits; altos <strong>del</strong> segmentolwz r3,lo16(x)(r2) ; Cargamos x en r3cmpwi cr0,r3,10beq cr0,etiq10 ;if (x==10) goto etiq10cmpwi cr0,r3,11beq cr0,etiq11 ;if (x==11) goto etiq11cmpwi cr0,r3,12beq cr0,etiq12 ;if (x==12) goto etiq12cmpwi cr0,r3,13beq cr0,etiq13 ;if (x==13) goto etiq13cmpwi cr0,r3,14beq cr0,etiq14 ;if (x==14) goto etiq14cmpwi cr0,r3,15beq cr0,etiq15 ;if (x==15) goto etiq15b fueraetiq10:etiq11:etiq12:etiq13:etiq14:etiq15:;Hacer algo··············fuera:También lo podemos implementar como un test de rango así:lis r2,ha16(segmento) ; r2 base <strong>del</strong> segmentolwz r3,lo16(x)(r2) ; Cargamos x en r3subi r4,r3,10 ; r4 = r3-10cmpli cr3,r4,5 ; Comparación lógica (r4,5)Pág 118


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgbgt cr3,fuera ; if r45; 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 código.Obsérvese que cmpli comprueba tanto la <strong>con</strong>dición r45 yaque, como estamos haciendo una comparación lógica (sin signo), si secumpliera que r4


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgtabla <strong>con</strong>tiene las direcciones a las que hay que saltar en cada caso, lo cuales especialmente útil cuando todos los casos son valores <strong>con</strong>secutivos quesaltan a direcciones distintas.6.4 Los buclesRecuérdese que en el Tema 1 comentábamos que <strong>PowerPC</strong> no es unamáquina 100% RISC en el sentido de que se le habían añadido instruccionespara operaciones comunes que aunque no eran estrictamente necesarias,ayudaban a reducir el tamaño <strong>del</strong> programa y a ejecutar operacionescomunes más rápido. Una de estas son las instrucciones pensadas parabucles, especialmente los bucles <strong>con</strong> <strong>con</strong>tador, las cuales ejecutan más rápidoque si implementáramos el bucle <strong>con</strong> instrucciones <strong>con</strong>dicionales normales.En el apartado 6.1.3 vimos, aunque no usamos, que el operando BO teníaformas en las que decrementaba el registro CRT en cada comprobación, estedecremento es el que se recomienda usar en los bucles <strong>con</strong> <strong>con</strong>tador, ya quese <strong>con</strong>sigue mejor rendimiento que las operaciones de restar/comprobarnormales <strong>del</strong> <strong>PowerPC</strong>.6.4.1 Mnemonics para buclesPara las instrucciones de salto en los bucles se han creado los mnemonics quese resumen en la Tabla 2.53 y Tabla 2.54:Equivale aCondición de salto bc bca bclrDecrementa CTR y salta si CTR≠0 bdnz bdnza bdnzlrDecrementa CTR y salta si CTR≠0 y la <strong>con</strong>dición bdnzt bdnzta bdnztlres trueDecrementa CTR y salta si CTR≠0 y la <strong>con</strong>dición bdnzf bdnzfa bdnzflres falseDecrementa CTR y salta si CTR=0 bdz bdza bdzlrDecrementa CTR y salta si CTR=0 y la <strong>con</strong>dición bdzt bdzta bdztlres trueDecrementa CTR y salta si CTR=0 y la <strong>con</strong>diciónes falsebdzf bdzfa bdzflrTabla 2.53: Mnemonics para bucles sin actualización de LREquivale aCondición de salto bc bca bclrDecrementa CTR y salta si CTR≠0 bdnzl bdnzla bdnzlrlDecrementa CTR y salta si CTR≠0 y la<strong>con</strong>dición es truebdnztl bdnztla bdnztlrlPág 120


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgDecrementa CTR y salta si CTR≠0 y la bdnzfl bdnzfla bdnzflrl<strong>con</strong>dición es falseDecrementa CTR y salta si CTR=0 bdzl bdzla bdzlrlDecrementa CTR y salta si CTR=0 y la bdztl bdztla bdztlrl<strong>con</strong>dición es trueDecrementa CTR y salta si CTR=0 y la<strong>con</strong>dición es falsebdzfl bdzfla bdzflrlTabla 2.54: Mnemonics para bucles <strong>con</strong> actualización de LRLa Tabla 2.55 ayuda a recordar las abreviaturas usadas por estos mnemonics:AbreviaturatfdznzDescripciónTrueFalseDecrementZeroNot ZeroTabla 2.55: Abreviaturas de los mnemonics para buclesTodos estos mnemonics actúan sobre el registro CTR y sólo reciben comooperando la dirección a la que saltar, es decir, tienen la forma:MNEMONIC ETIQUETAA <strong>con</strong>tinuación vamos a poner ejemplos de cómo se usan estos mnemonicspara cada uno de los bucles de C.6.4.2 Bucle do-whileVamos a empezar viendo cómo se implementa un bucle do-while.Imaginemos que queremos calcular la suma de los 100 primeros números, esdecir 1+2+3+...+100. Para ellos podríamos hacer un bucle en C así:int acumulador = 0;int <strong>con</strong>tador = 1;do{acululador += <strong>con</strong>tador;<strong>con</strong>tador++;}while (<strong>con</strong>tador


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgfin:add r3,r3,1 ; r3++cmpwi r3,100ble do ; r3


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgfor (inicialización;<strong>con</strong>dición;actualización){cuerpo}Los cuales se detallan en la Figura 2.14:InicializaciónActualizaciónCondiciónNoFinSíCuerpoFigura 2.14: Estructura de la sentencia forEn caso de que el bucle deba repetirse un determinado número de veces<strong>con</strong>ocido antes de empezar el bucle podemos usar el registro CTR. Al igualque explicamos antes podemos mantener un <strong>con</strong>tador aparte en un GPR sinecesitásemos usar el <strong>con</strong>tador para los cálculos.Las sentencias break y <strong>con</strong>tinue que pudieran en<strong>con</strong>trarse en el cuerpo<strong>del</strong> bucle pueden implementarse como un salto in<strong>con</strong>dicional.Como ejemplo vamos a hacer un programa que dado un número nos dice sies primo, para ello hacemos un bucle que divida al número por todos susdivisores 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 llamadoprimo.s:Pág 123


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org.dataSD: .comm esprimo, 4 ; Aquí se deposita si es primon: .long 13 ; Número que queremos ver; si es primo.text.globl _main_main:lis r2,ha16(SD); r2 apunta a la base <strong>del</strong>; segmento de datoslwz r3,lo16(n)(r2) ; r3 es el número a comprobaraddi r4,r3,-2;mtctr r4; Inicializaciónaddi r4,r3,-1 ; r4 es el <strong>con</strong>tador; Condición. Acaba si llega a 1 el <strong>con</strong>tador; significando que es primobucle:cmpwi r4,1beq primo; Cuerpo; Dividimos y multiplicamos r3 por r4; Si es el mismo número es que es divisibledivw r5,r3,r4mullw r5,r5,r4cmpw r5,r3beq noprimo;Actualizaciónaddi r4,r4,-1bdnz bucleprimo:li r10,1b finnoprimo:li r10,0fin: stw r10,lo16(esprimo)(r2)blr; Calculamos el <strong>con</strong>tador para CTR; Fijamos el CTR6.5 Operaciones lógicas <strong>con</strong> los bits <strong>del</strong> registro CRPodemos realizar operaciones lógicas <strong>con</strong> los bits (no los campos) <strong>del</strong> registroCR, cuyo resultado podemos volver a guardar en otro campo de CR.Las operaciones de este tipo de que dispone <strong>PowerPC</strong> se muestran en laTabla 2.56:Pág 124


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgInstruccióncrand CRBD,CRBA,CRBBcror CRBD,CRBA,CRBBcrxor CRBD,CRBA,CRBBcrnand CRBD,CRBA,CRBBcrnor CRBD,CRBA,CRBBcreqv CRBD,CRBA,CRBBcrandc CRBD,CRBA,CRBBcrorc CRBD,CRBA,CRBBmcrf CRD,CRSTabla 2.56: Operaciones lógicas <strong>con</strong> campos <strong>del</strong> registro CRDescripciónAl bit de la posición CRBA se le hace un andbinario <strong>con</strong> el bit de la posición CRBB y elresultado se almacena en el bit CRBDAl bit de la posición CRBA se le hace un orbinario <strong>con</strong> el bit de la posición CRBB y elresultado se almacena en el bit CRBDAl bit de la posición CRBA se le hace un xorbinario <strong>con</strong> el bit de la posición CRBB y elresultado se almacena en el bit CRBDAl bit de la posición CRBA se le hace un nandbinario <strong>con</strong> el bit de la posición CRBB y elresultado se almacena en el bit CRBDAl bit de la posición CRBA se le hace un norbinario <strong>con</strong> el bit de la posición CRBB y elresultado se almacena en el bit CRBDAl bit de la posición CRBA se le hace un xorbinario <strong>con</strong> el bit de la posición CRBB y elcomplemento a 1 <strong>del</strong> resultado se almacenaen el bit CRBDAl bit de la posición CRBA se le hace un andbinario <strong>con</strong> el bit de la posición CRBB y elcomplemento a 1 <strong>del</strong> resultado se almacenaen el bit CRBDAl bit de la posición CRBA se le hace un orbinario <strong>con</strong> el bit de la posición CRBB y elcomplemento a 1 <strong>del</strong> resultado se almacenaen el bit CRBDLos 4 bits <strong>del</strong> campo CRS se copian en elcampo CRDLa principal utilidad de estas instrucciones es hacer operaciones lógicas <strong>con</strong>los resultados de comparaciones que aparezcan en una expresión. Porejemplo imaginemos que queremos pasar a ensamblador este trozo deprograma C:if (a>5 && b>3){// Haz algo}Podemos realizar las comparaciones relacionales <strong>con</strong> cmpwi, depositar cadaresultado en un campo distinto de CR y luego usar crand para comprobarambos resultados:Pág 125


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgcmpwi cr2,rA,5cmpwi cr3,rB,3crand 17,9,13bng cr4,fin; Haz algo·············fin: ·············Hay que tener en cuenta que crand opera a nivel de bit de CR, no a nivel decampo de CR, <strong>con</strong> lo que tenemos que decirle que bits origen leer y en quebit destino depositarlo.Como los bits de CR están ordenados como muestra la Figura 2.3, si lascomparaciones las depositamos en los campos CR2 y CR3, el bit que indica sise cumple la <strong>con</strong>dición “mayor que” es el segundo de los 4 bits <strong>del</strong> campo,luego tendremos que leer los bits 9 y 13. Para depositar el resultado en CR4debemos depositarlo también en el segundo bit de CR4 que es el bit 17.Por último, bng comprueba si cr4 <strong>con</strong>tiene la <strong>con</strong>dición “mayor que” en cuyocaso significa que cr2 y cr3 también cumplían la <strong>con</strong>dición.Pág 126


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org7 Instrucciones de trabajo <strong>con</strong> números enpunto flotanteEn este apartado vamos a estudiar las instrucciones de que dispone <strong>PowerPC</strong>para ejecutar operaciones <strong>con</strong> números en punto flotante. Durante su estudiovamos a suponer que el lector ya <strong>con</strong>oce la representación de números enpunto flotante tal como está definida en el estándar IEEE 754. Si el lector no<strong>con</strong>oce este sistema de numeración, o no lo recuerda adecuadamente, lerecomendamos que lea el apartado A antes de <strong>con</strong>tinuar.7.1 IntroducciónLa arquitectura de <strong>PowerPC</strong> dispone de un procesador de números en puntoflotante que cumple estrictamente <strong>con</strong> el estándar IEEE 754. El procesadorsoporta directamente un sub<strong>con</strong>junto de las operaciones descritas en el IEEE754 debiéndose implementar las demás operaciones por software.Respecto a los formatos de tipos de datos, <strong>PowerPC</strong> soporta sólo los tipossimple y doble. El tipo doble extendido no lo soporta <strong>PowerPC</strong> directamentedebiéndose implementar el trabajo <strong>con</strong> números en este formato porsoftware.El procesador de <strong>PowerPC</strong> tiene como tipo de dato por defecto los númerosen formato doble, lo cual significa que a no ser que se lo pidamosexplícitamente todos los cálculos y los resultados se obtienen sobre datos detipo doble. Aun así el procesador dispone de instrucciones para <strong>con</strong>vertirentre representaciones simple y doble, así como de operaciones que nospermiten trabajar directamente <strong>con</strong> datos en formatos simple.7.2 Los registros de punto flotanteEl procesador de <strong>PowerPC</strong> dispone de 32 registros destinados al trabajo <strong>con</strong>números en punto flotante llamados FPR (Floating Point Registers). Cada unode estos registros tiene 64 bits <strong>con</strong> lo que pueden almacenar un número enformato doble. Para referirnos a estos registros desde el lenguajeensamblador usaremos los nombres f0 a f31.Los registros FPR siempre trabajan <strong>con</strong> números en formato doble, aunquepodemos leer/almacenar en memoria tanto números en formato simple comoen formato doble. Las reglas que sigue <strong>PowerPC</strong> son las siguientes:o Si leemos un dato de memoria en formato doble, éste se pasadirectamente a un registro FPR, mientras que cuando leemos un datode memoria en formato simple este se transforma a formato dobleantes de almacenarse en el registro.Pág 127


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgo Cuando pasamos un dato de un registro FPR a memoria éste se puedealmacenar en memoria en formato doble directamente. Tambiénpodemos pasar un dato de un registro FPR en formato doble amemoria en formato simple, en cuyo la instrucción transforma el datode formato doble a simple antes de pasarlo a memoria.Por otro lado, el sistema de punto flotante dispone de otros dos registros quepermiten 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 de32 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 lasexcepciones <strong>del</strong> procesador.CR (Condition Register) es el mismo registro que usan las instrucciones detrabajo <strong>con</strong> enteros o las de bifurcación, y que también lo utiliza el sistema depunto flotante. El campo CR1 <strong>del</strong> registro CR se puede usar para reflejar elresultado de ejecutar operaciones de punto flotante <strong>con</strong> punto (p.e. fadd.),al igual que pasaba <strong>con</strong> el campo CR0 en las instrucciones de trabajo <strong>con</strong>enteros. También podemos usar cualquiera de los campos <strong>del</strong> registro CRpara reflejar el resultado de las comparaciones en punto flotante.7.3 El registro FPSCREl registro FPSCR (Floating Point Status and Control Register) se encuentradividido en campos de 4 bits llamados FPSCR0 hasta FPSCR7, y muchas de lasoperaciones que trabajan <strong>con</strong> él operan en estos campos. La siguiente Figura2.15 muestra los principales campos <strong>del</strong> registro FPSCR y cual es su utilidad.0 3 4 7 8 11 12 15 16 19 20 23 24 27 28 31Flags desummaryexceptionFlags deexceptionFlags deexceptioninválidaCódigos de<strong>con</strong>diciónFlags dehabilitaciónde excepciónBits deredondeoFigura 2.15: Campos <strong>del</strong> registro FPSCRLa Tabla 2.57 describe detalladamente el propósito de cada uno de los bits<strong>del</strong> registro FPSCR.Pág 128


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgCampo Bit Nombre Descripción Bitretenido0 0 FX Floating Point Exception Summary. SíCualquier excepción en punto flotante,activa implícitamente este bit.1 FEX Floating Point Enabled ExceptionNoSummary. Cualquier excepciónhabilitada que se produzca, activa estebit.2 VX Floating Point Invalid OperationException Summary. Este bit indica laocurrencia de cualquiera de las InvalidOperation Exception.No3 OX Floating Point Overflow Exception.SíActivo cuando se produce un overflow1 4 UX Floating Point Underflow Exception. SíActivo cuando se produce un underflow5 ZX Floating Point Zero Divide Exception. SíActivo cuando se produce una divisiónentre cero6 XX Floating Point Inexact Exception. Indicaque se ha tenido que hacer unredondeo.Sí7 VXSNAN Floating Point Invalid OperationSíException for Signaling NAN. Seproduce cuando uno de los operandoses un signaling NaN.2 8 VXISI Floating Point Invalid OperationSíException for Infinite Sustract Infinite.Se activa cuando pedimos calcular ∞-∞.9 VXIDI Floating Point Invalid OperationSíException for Infinite Divide Infinite. Seproduce cuando pedimos calcular ∞/∞.10 VXZDZ Floating Point Invalid OperationException for Zero Divide Zero. Seproduce cuando pedimos calcular 0/0.Sí11 VXIMZ Floating Point Invalid OperationSíException for Infinite Multiply Zero. Seproduce cuando pedimos calcular ∞*0.3 12 VXVC Floating Point Invalid OperationException for Invalid Compare. Seproduce cuando intentamos compararnúmeros sin relación de orden.SíPág 129


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org13 FR Floating Point Fraction Rounded. Se Nopone a 1 si la última instrucción deredondeo o <strong>con</strong>versión incrementó lafracción, sino se pone a 0.14 FI Floating Point Fraction Inexact. La Noúltima instrucción necesitó deredondeo.15 FPRF Floating Point Result Class Descriptor. NoLas instrucciones aritméticas, deredondeo y de <strong>con</strong>versión debenencender este bit para indicar elresultado de acuerdo a la tabla <strong>del</strong>apartado 7.3.34 16 Floaintg Point Less Than or Negative No17 Floating Point Greater Than or Positive No18 Floating Point Equal or Zero No19Floating Point Unordered or NaNNo5 20 - Reservado -21 VXSOFT Floaintg Point Invalid OperationSíException for Software Request.Permite que el programa cause unaexcepción que esté asociada a unainstrucción de punto flotante. P.e.puede ser usada por un programa quecalcula la raíz cuadrada de un número,si el operando de entrada es negativo.Esto permite emular instrucciones noimplementadas en hardware22 VXSQRT Floating Point Invalid OperationException for Invalid Square Root.Sí23 VXCVI Floating Point Invalid OperationSíException for Invalid Integer Convert6 24 VE Floating Point Invalid Operation-Exception Enable25 OE Floating Point Overflow Exception-Enable26 UE Floating Point Underflow ExceptionEnable-27 ZE Floating Point Zero Divide Exception -Enable7 28 XE Floating Point Inexact Exception Enable -Pág 130


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org29 NI Floating Point no IEEE 754 mode. Siactivamos este bit, los resultados nocumplen <strong>con</strong> el estándar IEEE 754 y losdemás bits de FPSCR pueden tenersignificados distintos a los indicadosaquí. El funcionamiento que tendría elprocesador sería dependiente <strong>del</strong>mo<strong>del</strong>o y debe <strong>con</strong>sultarse el manualde usuario <strong>del</strong> microprocesador usado.3031RNTabla 2.57: Asignación de bits en el registro FPSCRFloating Point Rounding Control:00 - Redondeo al más cercano (pordefecto)01 - Redondeo a cero10 - Redondeo a +∞11 - Redondeo a -∞--7.3.1 Instrucciones para acceder a los bits de registroFPSCRA los bits <strong>del</strong> registro de FPSCR podemos acceder a nivel de registro, a nivelde campo o a nivel de bit individual.La siguiente Tabla 2.58 resume las instrucciones de que dispone <strong>PowerPC</strong>para acceder a los bits de registro FPSCR.Instrucción Descripción Nivelaccesomffs fD(Move From FPSCR) El <strong>con</strong>tenido de Registromffs. fDFPSCR se deposita en los bits 32-63de fD. El <strong>con</strong>tenido de los bits 0-31mtfsf FM,fDmtfsf. FM,fDmtcrfs CRFD,FSde fD queda indefinido.(Move To FPSCR Fields) Los bits 32-63 <strong>del</strong> registro fD se copian alregistro FPSCR bajo el <strong>con</strong>trol de lamáscara de campos FM, la cualindica que campos se deben copiar.FM puede tener hasta 8 bits de loscuales los activos indican loscampos a copiar.(Move To CR from FPSCR) El<strong>con</strong>tenido <strong>del</strong> campo FS <strong>del</strong> registroFPSCR se copia en el campo CRFD<strong>del</strong> registro CR. Todos los bits deexcepción copiados (excepto FEX yVX) son borrados en FPSCRPág 131RegistroCampo


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgmtfsfi FD,UIMMmtfsfi. CRFD,UIMMmtfsb0 BDmtfsb0. BDmtfsb1 BDmtfsb1. BDexcepción copiados (excepto FEX yVX) son borrados en FPSCR(Move To FPSCR Field Immediate) El<strong>con</strong>tenido de UIMM se deposita en elcampo FD(Move To FPSCR Bit 0) El bit de laposición BD <strong>del</strong> registro FPSCR esborrado. Los bits FEX y VX nopueden borrarse explícitamente(Move To FPSCR Bit 1) El bit de laposición BD <strong>del</strong> registro FPSCR esencendido. Los bits FEX y VX nopueden encenderse explícitamenteTabla 2.58: Instrucciones para acceso a los bits de FPSCRCampoBitBitComo es habitual, las instrucciones de la Tabla 2.58 que llevan punto (.)producen una actualización <strong>del</strong> registro CR.7.3.2 Los flags de excepciónEl sistema de punto flotante <strong>del</strong> ensamblador <strong>del</strong> <strong>PowerPC</strong> dispone de losmismos cinco flags de excepción que recomienda el estándar IEEE 754, sóloque algunos de ellos están desdoblados en varios flags <strong>con</strong> el fin de poderprecisar mejor la causa de la excepción.En <strong>con</strong>creto estos cinco flags de excepción son:1. VX (Invalid Operation). Este flag se activa cuando se ejecuta cualquierinstrucción de punto flotante <strong>con</strong> operandos no válidos. Para <strong>con</strong>cretar más lacausa de la excepción tenemos los flags:o VXSNAN (Invalid Operation Signaling NaN). Se activa cuando uno <strong>del</strong>os operandos es un signaled NaN.o VXISI (Invalid Operation Infinite Sustract Infinite). Se activa cuandopedimos calcular ∞-∞.o VXIDI (Floating Point Invalid Operation Exception for Infinite DivideInfinite). Se produce cuando pedimos calcular ∞/∞.o VXZDZ (Floating Point Invalid Operation Exception for Zero DivideZero). Se produce cuando pedimos calcular 0/0.o VXIMZ (Floating Point Invalid Operation Exception for Infinite MultiplyZero). Se produce cuando pedimos calcular ∞*0.o VXVC (Floating Point Invalid Operation Exception for Invalid Compare).Se produce cuando intentamos comparar números sin relación deorden.Pág 132


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org2. OX (Overflow Exception). Se produce cuando el número calculado estan grande que no se puede representar en el formato utilizado y hay querepresentarlo como ∞.3. UX (Underflow Exception). Se produce cuando el número calculado estan pequeño que no se puede representar en el formato utilizado y hay querepresentarlo como 0.4. ZX (Zero Exception). Se produce cuando intentamos dividir entre 0.5. XX (Inexact Exception). Se activa cuando las últimas instrucciones depunto flotante produjeron un redondeo (es un bit de retención). Para<strong>con</strong>cretar más sobre el redondeo se usan estos otros dos flags:o FI (Fraction Inexact). Se activa cuando la última instrucción de puntoflotante produjo un redondeo (no es de retención).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 más claramente cuando se activa cada uno de los bitsde XX:¿Redondeo?FI


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgFlagVEOEUEZEXETipo de excepción que activaInvalid Operation ExceptionOverflow ExceptionUnderflow ExceptionZero Divide ExceptionInexact ExceptionTabla 2.59: Flags de habilitación de excepción7.3.2.2 Los flags de resumenAdemás de estos flags tenemos los flags de resumen (summary), loscuales se activan cuando se produce cualquier excepción, estos flags sonútiles ya que lo primero que podemos hacer es comprobar estos flags viendosi ha habido algún problema, y cuando se activan podemos llamar a unarutina que determine la causa exacta <strong>del</strong> problema.Los flags de resumen son:o FX (Floating Point Exception Summary). Cualquier excepción en puntoflotante activa implícitamente este bit.o FEX (Floating Point Enabled Exception Summary). Cualquier excepciónhabilitada que se produzca activa este bit.FX se activa aunque los flags de habilitación de excepción esténdeshabilitados, pero en este caso no se activarán los flags que indican lacausa de la excepción. FEX se activa sólo si se a producido alguna excepciónpara la que sus flags de habilitación de excepción estaban activos.7.3.3 Los bits de <strong>con</strong>dición y el bit de claseLos bits 16-19 indican el resultado de una comparación, la cual debe activarsólo uno de los cuatro bits < (menor que), > (mayor que), = (igual) ó ? (sinrelación de orden).Los bits 16-19 combinados <strong>con</strong> el bit 15 (bit de clase) nos pueden servir parasaber a que clase pertenece el resultado de una instrucción de punto flotante(número normalizado, número denormalizado, cero, NaN o infinito).La Tabla 2.60 muestra cómo se deben interpretar estos bits.Pág 134


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgResult Flags(Bits 15-19)C < > = ?Resultado parauna comparaciónResultado paraotra operación0 0 0 0 1 Sin relación de No aplicableorden0 0 0 1 0 == (Igual) +00 0 1 0 0 > (Mayor que) Número normalizado positivo0 0 1 0 1 No aplicable +∞0 1 0 0 0 < (Menor que) Número normalizado negativo0 1 0 0 1 No aplicable -∞1 0 0 0 1 Sin relación de Quiet NaNorden1 0 0 1 0 == (Igual) -01 0 1 0 0 > (Mayor que) Número denormalizadopositivo1 1 0 0 0 < (Menor que) Número denormalizadonegativoTabla 2.60: Floating Point Result Flags FPSCR[FPRF]Por ejemplo, para saber de qué tipo es el número que obtenemos comoresultado de una suma en punto flotante podríamos hacer un programa talque así:fadd f0,f1,f2 ; Fija los valores de FPSCR[15-19]; de acuerdo al tipo de f0mcrfs 2,3 ; Copia los bits FPSCR[12-15] a CR2mcrfs 3,4 ; Copia los bits FPSCR[16-19] a CR3bun 3,infinito ; Si el bit 3 de CR3 es 1; el resultado es infitito o NaNbeq 3,cero ; Si CR3[2]=1b normal ; Es un número normalizado; o denormalizadoinfinito:bt 11,NaN; Si BI=11, es decir, CR2[3]=1; (Summary Overflow o Floating Point; Unordered) f0 es un Quiet NaN; f0 es infinitoNaN:; f0 es NaNcero:; f0 es 0normal:bt 11,denormal ; Si BI=11, es decir, CR2[3]=1; (Summary Overflow o Floating Point; Unordered) indica que f0; es un número denormalizado; f0 es un número normalizadoPág 135


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgdenormal:; f0 es un número denormalizadoEn el programa pasamos los bits FPSCR[15-19] al registro CR para comprobarsu valor y decidir la clase <strong>del</strong> resultado de la suma de acuerdo a la tablaanterior.7.3.4 Los bits de redondeoLos bits 30 y 31 de FPSCR sirven para indicar el modo de redondeo a aplicarde acuerdo a la Tabla 2.61:7.4 El registro CRBit Bit 31 Modo redondeo300 0 Al más cercano0 1 A cero1 0 A +∞1 1 A -∞Tabla 2.61: Modo de redondeoSi usamos las instrucciones <strong>con</strong> punto (.), el resultado de su ejecuciónademás de almacenarse en el registro FPSCR se almacena en el campo CR1<strong>del</strong> registro CR. Después podemos comprobar este campo para obtenerinformación sobre el valor obtenido.La Tabla 2.62 muestra cuáles son los bits <strong>del</strong> registro FPSCR que se copian alregistro CR en caso de usar instrucciones <strong>con</strong> punto.Bit Descripción4 Contiene el valor <strong>del</strong> bit FX <strong>del</strong> registro FPSCR que indica que algunaexcepción se ha producido5 Contiene el valor <strong>del</strong> bit FEX <strong>del</strong> registro FPSCR que indica quealguna excepción para la que su flag de habilitación de excepciónestaba encendido se ha producido6 Contiene el valor <strong>del</strong> bit VX <strong>del</strong> registro FPSCR que indica que algunainvalid exception se ha producido7 Contiene el valor <strong>del</strong> bit OX <strong>del</strong> registro FPSCR que indica que se haproducido un desbordamientoTabla 2.62: Bits <strong>del</strong> registro FPSCR copiados al registro CREl valor <strong>del</strong> campo CR1 <strong>del</strong> registro CR se puede <strong>con</strong>sultar tras ejecutar unainstrucción para ver si se ha producido una excepción de la siguiente manera:Pág 136


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgfadd. f0,f1,f2bt 5,excepcion ; Si FEX está activo; No ha habido excepcion··························excepcion:mcrfs 2,1 ; Copia FPSCR[4-7] a CR2bt 6,invalid ; Miramos los bits de CR para ver quebt 7,overflow ; tipo de excepción se ha producidobt 8,underflowbt 9,divbyzerobt 10,inexactinvalid:mcrfs 2,2 ; Copia FPSCR[8-11] a CR2mcrfs 3,3 ; Copia FPSCR[12-15] a CR3mcrfs 4,5 ; Copia FPSCR[20-23] a CR4; Ahora podemos saber el tipo exacto de invalid; operation en base al flag de excepción invalid; operation que esté activooverflow:; Se ha producido un overflowunderflow:; Se ha producido un underflowdivbyzero:; Se ha intentado dividr entre ceroinexact:; Redondeo inexacto7.5 Manejo de traps<strong>PowerPC</strong> permite tanto usar flags de habilitación de traps, como usar flags dehabilitación de excepción, será el diseñador <strong>del</strong> sistema operativo quien debatomar esta decisión.Por defecto <strong>Mac</strong> <strong>OS</strong> X usa la opción de los flags de habilitación de excepciónque se <strong>con</strong>sidera la más adecuada, pero si el diseñador de un sistema lo<strong>con</strong>sidera oportuno (p.e. por razones de compatibilidad hacia atrás como pasaen Linux) puede usar traps. Para ello debe encender los registros FE0 y FE1<strong>del</strong> registro MSR, que es un registro de superusuario que comentaremos en elTema [pendiente], <strong>con</strong> lo cual sólo puede ser modificado por el sistemaoperativo.La Tabla 2.63 describe los valores que pueden tomar los flags FE0 y FE1:Pág 137


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgFE0 FE1 Descripción0 0 Ignore Exceptions Mode. Las excepciones en punto flotante noinvocan a un handle de traps0 1 Imprecise Nonrecoverable Mode. Cuando se produce unaexcepción de punto flotante, se llama al handle de traps de laexcepción. Podría no ser posible identificar la instrucción o datoque causó la excepción porque los datos de la instrucción queprovocó la excepción pueden ser usados por otras instruccionesde punto flotante que se estén ejecutando.1 0 Imprecise Recoverable Mode. Cuando se produce una excepciónde punto flotante, se llama al handle de traps de la excepción.Siempre es posible saber la instrucción y dato que produjo lainstrucción porque los datos de la instrucción que provocó laexcepción no pueden ser usados por otras instrucciones de puntoflotante que se estén ejecutando.1 1 Precise Mode. El sistema nunca ejecuta <strong>con</strong>currentemente dosinstrucciones de punto flotante, <strong>con</strong> lo que siempre es posiblesaber la instrucción que produjo la excepción. Este modo sólodebe ser usado en depuración ya que puede degradar mucho elrendimiento <strong>del</strong> sistema.Tabla 2.63: Valores que pueden tomar los flags FE0 y FE1El uso de traps lo veremos en el Tema [pendiente], el resto <strong>del</strong> temasupondremos que los traps están desactivados.7.6 Instrucciones de carga y almacenamientoAntes de que <strong>PowerPC</strong> pueda operar <strong>con</strong> un dato en punto flotante situado enmemoria, debe de cargarlo en alguno de los FPR. Análogamente <strong>PowerPC</strong>puede depositar los datos en memoria una vez que acaba de trabajar <strong>con</strong>ellos.Como se explicó en el aparatado 7.2, los registros FPR siempre trabajan <strong>con</strong>números en formato doble, aunque podemos leer/almacenar en memoriatanto números en formato simple como en formato doble.Las instrucciones de acceso a memoria para punto flotante (al igual quepasaba <strong>con</strong> las de acceso a memoria <strong>con</strong> enteros) se pueden dividir en dostipos:o Instrucciones de acceso <strong>con</strong> indireccionamiento de registro base e índiceinmediatoo Instrucciones de acceso <strong>con</strong> indireccionamiento de registro base y registroíndicePág 138


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgVéase el apartado 4.4 para una mejor descripción de estos modos deindireccionamiento.En <strong>con</strong>creto las instrucciones de acceso <strong>con</strong> indireccionamiento de registrobase e índice inmediato aparecen en la Tabla 2.64 y Tabla 2.65:Instrucciónlfs fD,d(rA)lfsu fD,d(rA)lfd fD,d(rA)lfdu fD,d(rA)Descripción(Load Floating-point Single) El word en la dirección dememoria d(rA) se interpreta como un número enpunto flotante de precisión simple, y se carga en fD<strong>con</strong>vertido a punto flotante de precisión doble(Load Floating-point Single with Update) Igual a lfs,sólo que rA se actualiza <strong>con</strong> el valor de d(rA)después de leer la memoria(Load Floating-point Double) El doble-word en ladirección de memoria d(rA) se carga en fD(Load Floating-point Double with Update) Igual alfd, sólo que rA se actualiza <strong>con</strong> el valor de d(rA)después de leer la memoriaTabla 2.64: Instrucciones de carga de números en punto flotante <strong>con</strong> indireccionamiento deregistro base e índice inmediatoInstrucciónsfs fD,d(rA)sfsu fD,d(rA)sfd fD,d(rA)sfdu fD,d(rA)Descripción(Store Floating-point Single) El <strong>con</strong>tenido de fD se<strong>con</strong>vierte a precisión simple y se guarda en el word <strong>del</strong>a dirección de memoria apuntada por d(rA)(Store Floating-point Single with Update) Igual a sfs,sólo que rA se actualiza <strong>con</strong> el valor de d(rA)después de escribir la memoria(Store Floating-point Double) El <strong>con</strong>tenido de fD seguarda en memoria, en el doble-word apuntado pord(rA)(Store Floating-point Double with Update) Igual asfd, sólo que rA se actualiza <strong>con</strong> el valor de d(rA)después de escribir la memoriaTabla 2.65: Instrucciones de almacenamiento de números en punto flotante <strong>con</strong>indireccionamiento de registro base e índice inmediatoY las instrucciones de acceso <strong>con</strong> indireccionamiento de registro base yregistro índice aparecen en la Tabla 2.66 y Tabla 2.67:Instrucciónlfsx fD,rA,rBDescripción(Load Floating-point Single indeXed) El word en ladirección de memoria (rA|0)+rB se interpreta comoun número en punto flotante de precisión simple, y secarga en fD <strong>con</strong>vertido a punto flotante de precisióndoblePág 139


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orglfsux fD,rA,rBlfdx fD,rA,rBlfdux fD,rA,rBcarga en fD <strong>con</strong>vertido a punto flotante de precisióndoble(Load Floating-point Single with Update indeXed) Iguala lfsx, sólo que rA se actualiza <strong>con</strong> el valor de(rA|0)+rB después de leer la memoria(Load Floating-point Double indeXed) El doble-word enla dirección de memoria (rA|0)+rB se carga en fD(Load Floating-point Double with Update indeXed)Igual a lfdx, sólo que rA se actualiza <strong>con</strong> el valor de(rA|0)+rB después de leer la memoriaTabla 2.66: Instrucciones de carga de números en punto flotante <strong>con</strong> indireccionamiento deregistro base y registro índiceInstrucciónsfsx fD,rA,rBsfsux fD,rA,rBsfdx fD,rA,rBsfdux fD,rA,rBDescripción(Store Floating-point Single indeXed) El <strong>con</strong>tenido defD se <strong>con</strong>vierte a precisión simple y se guarda en elword de la dirección de memoria apuntada por(rA|0)+rB(Store Floating-point Single with Update indeXed)Igual a sfsx, sólo que rA se actualiza <strong>con</strong> el valor de(rA|0)+rB después de escribir la memoria(Store Floating-point Double indeXed) El <strong>con</strong>tenido defD se guarda en memoria, en el doble-word apuntadopor (rA|0)+rB(Store Floating-point Double with Update indeXed)Igual a sfdx, sólo que rA se actualiza <strong>con</strong> el valor de(rA|0)+rB después de escribir la memoriaTabla 2.67: Instrucciones de almacenamiento de números en punto flotante <strong>con</strong>indireccionamiento de registro base y registro índice7.7 Instrucciones aritméticas<strong>PowerPC</strong> dispone de las operaciones aritméticas que propone el estándarIEEE 754:o Sumao Restao Multiplicacióno Multiplicación-sumao Divisióno Raíz cuadrada (opcional)o Redondeo a entero (opcional)Pág 140


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgLas dos últimas son operaciones opcionales, lo que significa que no todos losmicros las poseen, debemos de <strong>con</strong>sultar el manual <strong>del</strong> microprocesador paraver si la soporta.La operación de multiplicación-suma se proporciona <strong>con</strong> el fin de poderrealizar operaciones de multiplicación seguidas de una suma <strong>con</strong> un únicoredondeo, lo cual proporciona más precisión que hacer dos redondeos.La Tabla 2.68 describe más <strong>con</strong>cretamente las instrucciones:Instrucción Descripción Precisiónfadd fD,fA,fB(Floating Add) En fD obtenemos la Doblefadd. fD,fA,fB suma fA+fBfadds fD,fA,fB (Floating Add Single) En fDSimplefadds. fD,fA,fB obtenemos la suma fA+fBfsub fD,fA,fB(Floating Substract) En fD obtenemos Doblefsub. fD,fA,fB el valor de fA-fBfsubs fD,fA,fB (Floating Sustract Single) En fD Simplefsubs. fD,fA,fB obtenemos el valor de fA-fBfmul fD,fA,fB(Floating Multiply) En fD obtenemos Doblefmul. fD,fA,fB el producto fA*fBfmuls fD,fA,fB (Floating Multiply Single) En fD Simplefmuls. fD,fA,fB obtenemos el producto fA*fBfmadd fD,fA,fB,fC (Floating Multiply-Add) En fD Doblefmadd. fD,fA,fB,fC obtenemos fA*fB+fCfmadds fD,fA,fB,fC (Floating Multiply-Add Single) En fD Simplefmadds. fD,fA,fB,fC obtenemos fA*fB+fCfmsub fD,fA,fB,fC (Floating Multiply-Substract) En fD Doblefmsub. fD,fA,fB,fC obtenemos fA*fB-fCfmsubs fD,fA,fB,fC (Floating Multiply-Subtract Single) En Simplefmsubs. fD,fA,fB,fC fD obtenemos fA*fB-fCfnmadd fD,fA,fB,fC (Floating Negative Multiply-Add) En Doblefnmadd. fD,fA,fB,fC fD obtenemos -(fA*fB+fC)fnmadds fD,fA,fB,fC (Floating Negative Multiply-Add Simplefnmadds. fD,fA,fB,fC Single) En fD obtenemos -(fA*fB+fC)fnmsub fD,fA,fB,fC (Floating Negative Multiply-Substract) Doblefnmsub. fD,fA,fB,fC En fD obtenemos -(fA*fB-fC)fnmsubs fD,fA,fB,fC (Floating Negative Multiply-Subtract Simplefnmsubs. fD,fA,fB,fC Single) En fD obtenemos -(fA*fBfC)fdiv fD,fA,fB(Floating Divide) en fD obtenemos el Doblefdiv. fD,fA,fB resultado de dividir fA/fB.fdivs fD,fA,fB (Floating Divide Single) en fD Simplefdivs. fD,fA,fB obtenemos el resultado de dividirfA/fBPág 141


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgfsqrt fD,fSfsqrt. fD,fSfsqrts fD,fSfsqrts. fD,fSfres fD,fSfres. fD,fSfrsqrte fD,fSfrsqrte. fD,fSfsel fD,fA,fB,fCfsel. fD,fA,fB,fCTabla 2.68: Instrucciones aritméticasfA/fB(Floating SQuare RooT) en fDobtenemos la raíz cuadrada de fS.Esta operación es opcional(Floating SQuare RooT Single) En fDobtenemos la raíz cuadrada de fS.Esta operación es opcional(Floating Reciprocal Estimate Simple)En fD obtenemos 1/fS. Estaoperación es opcional. No existe sucorrespondiente operación paranúmeros de precisión doble(Floating Reciprocal SQuare RootEstimate) En fD obtenemos1/sqrt(fS). Esta operación esopcional. No existe sucorrespondiente operación paranúmeros <strong>con</strong> precisión simple(Floating Select) El valor de fA secompara <strong>con</strong> 0. Si fA es mayor oigual que 0, fB se deposita en fD,sino fC se deposita en fD. Lacomparación ignora el signo de 0 (+0ó -0). Esta operación es opcional.DobleSimpleSimpleDobleDobleTodas ellas disponen de una versión <strong>con</strong> punto (.) que actualiza el registroCR.Casi todas las operaciones se proporcionan tanto para precisión simple comopara precisión doble. Las instrucciones de precisión simple se diferencianporque tienen una s al final de su nombre.En la división decimal no se desperdicia el resto como pasa en la divisiónentera, es decir, si hacemos:; f1 = 7.0; f2 = 2.0fdiv f0,f1,f2 ; f3 = 3.5La operación fsel se utiliza para <strong>con</strong>seguir el mismo efecto que el operador?: <strong>del</strong> lenguaje C, donde asignamos un valor u otro a fD en función de una<strong>con</strong>dición sin hacer saltos, los cuales como se explica en el Apéndice B,degradan más el rendimiento <strong>del</strong> programa.Pág 142


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org7.8 Instrucciones de <strong>con</strong>versiónIEEE 754 requiere que el sistema de numeración en punto flotante dispongade las siguientes operaciones de <strong>con</strong>versión:o De punto flotante a enteroo De entero a punto flotanteo De punto flotante a entero, <strong>con</strong> el resultado en punto flotanteo Entre todos los formatos de punto flotante que existano Entre punto flotante binario y punto flotante decimalEn ensamblador de <strong>PowerPC</strong> dispone de algunas de estas <strong>con</strong>versiones,debiéndose implementar las demás <strong>con</strong>versiones por software.<strong>PowerPC</strong> dispone de tres instrucciones de <strong>con</strong>versión que aparecen en laTabla 2.69:Instrucciónfrsp fD,fSfrsp. fD,fSfctiw fD,fSfctiw. fD,fSfctiwz fD,fSfctiwz. fD,fSDescripción(Floating Round to Single Precision) Redondea eldato almacenado en fS al número más cercano quepueda ser representado en formato simple, y losguarda en fD (en formato doble)(Floating Convert To Integer Word) El númeroalmacenado en fD lo <strong>con</strong>vierte a entero de 32 bits,usando el modo de redondeo activo, y lo deposita enlos bits fD[32-63], quedando los bits fD[0-31]indefinidos.(Floating Convert To Integer Word round towardZero) El número almacenado en fD lo <strong>con</strong>vierte aentero de 32 bits eliminando los decimales, y lodeposita en los bits fD[32-63], quedando los bitsfD[0-31] indefinidos.Tabla 2.69: Instrucciones de <strong>con</strong>versiónAdemás de estas tres instrucciones, podemos realizar <strong>con</strong>versiones entreformatos simple y doble utilizando las operaciones de carga/almacenamientode datos en memoria. En <strong>con</strong>creto para <strong>con</strong>vertir de simple a doble podemosusar la instrucción lfs (Load Floating-point Single) que carga un dato quetengamos en formato simple en memoria en un dato de formato doble enregistro. Para <strong>con</strong>vertir de doble a simple podemos usar la instrucción stfs(STore Floating-point Single) que almacena un dato que tengamos en formatodoble en un registro a formato simple en memoria.Pág 143


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org7.9 Instrucciones de comparaciónLas operaciones de comparación en punto flotante comparan el <strong>con</strong>tenido dedos registros FPR (esta comparación <strong>con</strong>sidera que +0=-0).La comparación puede ser de dos tipos:o Con relación de orden. Si uno de los operandos es un quiet NaN seactiva el flag de excepción VXVC (suponiendo que el flag dehabilitación de excepción VE esté activo).o Sin relación de orden. Si uno de los operandos es un quiet NaN noactiva ningún flag de excepción.Sea la comparación <strong>con</strong> o sin relación de orden, si se encuentra un signalingNaN se activa el bit VXSNAN (suponiendo que el flag de habilitación deexcepción VE esté activo).En cualquier caso, en el campo de CR que hayamos especificado a lainstrucción, se activarán los bits <strong>del</strong> campo de acuerdo a la Tabla 2.70:Bit Significado0 fA < fB1 fA > fB2 fA = fB3 fA ? fB (unordered)Tabla 2.70: Reglas de activación de los campos <strong>del</strong> registro CRAdemás de los bits <strong>del</strong> campo CR que especifiquemos, los bits FPSCR[16-19]también se activan <strong>con</strong>venientemente.Las instrucciones de comparación de que dispone <strong>PowerPC</strong> se detallan en laTabla 2.71:Instrucciónfcmpo CRFD,fA,fBfcmpu CRFD,fA,fBDescripción(Floating CoMPare Ordered) Compara fA <strong>con</strong> fB,produciendo una VXVC si alguno de los operandos esun NaN. El resultado se deposita en el campo de CRdado por CRFD.(Floating CoMPare Unordered) Compara fA <strong>con</strong> fB,pudiendo ser alguno de los operandos en un NaN. Elresultado se deposita en el campo de CR dado porCRFD.Tabla 2.71: Instrucciones de comparaciónPág 144


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgLa diferencia entre estas dos instrucciones es que fcmpo se usa cuando noesperamos en<strong>con</strong>trar un NaN, mientras que fcmpu se usa cuando queremos<strong>con</strong>templar esta posibilidad.7.10 Instrucciones de movimiento de datosLas instrucciones de movimiento de datos nos permiten copiar el <strong>con</strong>tenido deun registro FPR a otro, permitiéndonos modificar el signo durante la copia.Estas instrucciones no alteran el registro FPSCR, y sólo las que tienen punto(.) alteran el registro CR y se detallan en la Tabla 2.72.Instrucciónfmr fD,fSfmr. fD,fSfneg fD,fSfneg. fD,fSfabs fD,fSfabs. fD,fSfnabs fD,fSfnabs. fD,fSDescripción(Floating Move Register) Copia el <strong>con</strong>tenido de fS afD(Floating Negate) Copia el <strong>con</strong>tenido de fS a fD ycambia el signo durante la copia(Floating ABSolute value) Copia el <strong>con</strong>tenido de fS afD y pone el bit de signo a 0 durante la copia(Floating Negate ABSolute value) Copia el <strong>con</strong>tenidode fS a fD y pone el bit de signo a 1 durante la copiaTabla 2.72: Instrucciones de movimiento de datosPág 145


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org8 Incrustar código ensamblador en unprograma C8.1 Integración entre C y ensambladorEn esta sección vamos a comentar varias técnicas que permiten incrustarinstrucciones ensamblador dentro de un programa C. Para ello tenemos ladirectiva asm, un ejemplo de su uso sería el siguiente:#include 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 ensamblejunto <strong>con</strong> el resto <strong>del</strong> programa. Obsérvese que las instrucciones se separanpor \n, que es la forma de indicar un retorno de carro.Si ahora hiciésemos:$ gcc -S cyasm.cSiendo cyasm.c el programa anterior, veríamos que las instrucciones dentrode la directiva asm aparecen en el programa ensamblador correspondiente.8.2 Acceso a variables C desde ensambladorSi usamos la directiva asm, un problema que acabaremos en<strong>con</strong>trándonos, esel de cómo acceder desde ensamblador a las variables C de nuestroprograma. Para ello tenemos que <strong>con</strong>ocer el name-mangling que utiliza Cpara sus variables. En C a todas las variables globales y funciones se lesasigna una etiqueta global que corresponde <strong>con</strong> el nombre de la función ovariable precedida por un guión bajo (_).Cuando nos refiramos a las variables C desde ensamblador tendremos queusar este nombre. Por ejemplo:#include 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)" );Pág 146


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgprintf("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, <strong>con</strong> lo que tenemos que usarotras técnicas para acceder a ellas desde ensamblador, como veremos enbreve.C++ utiliza un name-mangling distinto sobre todo a la hora de referirse a lasfunciones, ya que al poder estar las funciones sobrecargadas, C++ almacena,además <strong>del</strong> nombre de la función, los tipos de sus parámetros.Por ejemplo si declaramos la función:int suma(int a, int b);El nombre que le da C es _sumaSin 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 símbolos C++ podemos usar elcomando nm (Name Mangling), que recibe como argumento un fichero .o, oun fichero ejecutable (<strong>con</strong> información de depuración), y nos muestra lossímbolos que <strong>con</strong>tiene:$ nm cyasm.o0000007c D _G000000a0 s ___FRAME_BEGIN__00000000 T _mainU _printfU _suma__FiiU _suma__FiiiU dyld_stub_binding_helperPág 147


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org8.3 Expresiones C como operandos deinstrucciones ensambladorDesde las instrucciones ensamblador puestas en la directiva asm podemosusar expresiones C como operandos de las instrucciones ensamblador. Estopermite una mejor integración entre C y ensamblador, ya que podemosacceder a variables C que estén guardadas en registros directamente, en vezde tener que leer un dato de memoria y pasarlo a un registro o viceversa.El siguiente ejemplo muestra cómo podemos dividir dos números usando lainstrucción ensamblador divw:#include 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 división es %i",cociente);return 0;}Aquí después de la instrucción ensamblador se ponen los operandos de salida,y los operandos de entrada separados por dos puntos (:). Si hay más de unoperando se pueden separar por comas. Si no hay operandos de salida sedebe de poner dos veces el símbolo de dos puntos. "=r" y "r" son lo que sellama <strong>con</strong>straints, y las explicaremos en el siguiente apartado. La r significaque queremos trabajar <strong>con</strong> un registro GPR, y en los operandos de salida esobligatorio usar el símbolo = para indicar que es un operando de salida.Después de las <strong>con</strong>straints se pone entre paréntesis la expresión C quequeremos asociar al operando. Aquí decimos expresión C, y no variableporque dentro <strong>del</strong> paréntesis se pueden poner expresiones C arbitrarias comopor ejemplo 2*a+b, y no sólo el nombre de una variable. El compilador ya seencargará de buscar el registro que <strong>con</strong>tiene el resultado de evaluar estaexpresión. Una restricción importante es que los operandos de salida sólopueden <strong>con</strong>tener expresiones Lvalues (y el compilador comprueba que seaasí), mientras que los operandos de entrada pueden <strong>con</strong>tener cualquierexpresión.Dentro de la instrucción, a los operandos nos referimos usando los nombres%0 a %9, <strong>con</strong> lo que el máximo número de operandos está limitado a 10.Pág 148


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org8.3.1 Las <strong>con</strong>straints y los modificadoresCada operando lleva asociadas unas <strong>con</strong>straints que indican el tipo <strong>del</strong>operando según la Tabla 2.73:ConstraintrbfmiFXSignificadoRegistro GPRRegistro GPR distinto de r0Registro FPRReferencia a memoriaOperando inmediato entero. Son literales cuyo valor es<strong>con</strong>ocido en tiempo de compilaciónOperando inmediato en punto flotante de doble precisión. Sonliterales cuyo valor es <strong>con</strong>ocido en tiempo de compilaciónSe acepta un operando de cualquier tipo: registro, dirección dememoria o operando inmediato.Tabla 2.73: Constraints de una expresión CLo posibles modificadores que pueden acompañar a una <strong>con</strong>straint están enla Tabla 2.74:Modificador Significado= Operando de sólo escritura. No se garantiza que <strong>con</strong>tenga elvalor previo de la variable+ Operando de lectura/escritura. Antes de usarse va a <strong>con</strong>tenerel valor de la variable o expresión, y después de ejecutarse lasinstrucciones ensamblador su valor se guardaráapropiadamente& No asignar el mismo registro al operando de entrada y desalidaTabla 2.74: Modificadores de una <strong>con</strong>straintEstos modificadores siempre se aplican al operando de salida. En caso deusarlos se colocan <strong>del</strong>ante de la <strong>con</strong>straint. P.e. "+r"Como vimos, en <strong>PowerPC</strong> había instrucciones como:addi rD,(rA|0),SIMMEn la que el segundo operando podía recibir o bien un 0, o bien un GPR der1 a r31, pero no el registro r0. De esta forma podíamos sumar 0 a SIMM yalmacenar el resultado en rD.Esto puede producir problemas si intentamos compilar instrucciones como:asm ( "addi %0,%1,1" : "=r" (H) : "r" (G));Pág 149


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgYa que si el compilador tiene la variable G en el registro r0, al compilartenemos:addi r3,r0,1Y como acabamos de decir, r0 no puede ser usado como segundo operando.En este caso debemos de usar la <strong>con</strong>straint b, que significa usar uno de losregistros de r1 a r31. Con lo que el problema no se producirá. Es decir laforma correcta de codificar la instrucción anterior es:asm ( "addi %0,%1,1" : "=r" (H) : "b" (G));La r <strong>del</strong> primer operando no hace falta cambiarla por b, ya que esteoperando puede usar al registro r0, es el segundo operando el que no puede.Además de poder referirnos a registros podemos referirnos a direcciones dememoria, en cuyo caso usamos la <strong>con</strong>straint 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 direcciónde memoria de N y nos hace un indireccionamiento de registro base e índiceinmediato a la variable N.Los operandos marcados <strong>con</strong> la <strong>con</strong>straint = son operandos de sólo salida ydeben de usarse sólo para escritura, es decir, nunca debe usarse un operandopara lectura/escritura.Por ejemplo este programa compilaría correctamente, pero al ejecutarlo noda el resultado esperado:#include int N=4;int main () {asm ( " addi %0,%0,1 " : "=r" (N) );printf("N incrementada vale %i",N);return 0;}Pág 150


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgLa razón de fallo es que el compilador <strong>con</strong>sidera a %0 un parámetro de salida,<strong>con</strong> lo que no lo carga de memoria, y el resultado <strong>del</strong> registro está indefinido.Si queremos que un operando de salida disponga <strong>del</strong> valor correcto de laentrada debemos marcarlo <strong>con</strong> la <strong>con</strong>straint + como muestra el siguienteejemplo:#include int N=4;int main () {asm ( " addi %0,%0,1 " : "+r" (N) );printf("N incrementada vale %i",N);return 0;}Ahora el programa si funcionaría correctamente, ya que en el registroasignado a %0 estará el valor correcto de N el cual luego será sobrescrito.Otra forma, más compleja pero igual de válida, de resolver este problema esdeclarar dos operandos, uno de lectura y otro de escritura. La <strong>con</strong>exión entreestos debe de expresarse <strong>con</strong> <strong>con</strong>straints que indican que ambos deben deestar en el mismo registro cuando la instrucción se ejecute.En <strong>con</strong>creto, la forma correcta de hacerlo sería esta:#include int N=4;int main () {asm ( " addi %0,%1,1 " : "=r" (N) :"0" (N) );printf("N incrementada vale %i",N);return 0;}La <strong>con</strong>straint "0" puesta en el registro de entrada garantiza que el registrode entrada y de salida sean el mismo, aunque, carga de memoria el valor <strong>del</strong>operando antes de ejecutar la instrucción (y lo guarda después de ejecutarla).Curiosamente para la expresión que representa el operando de entrada y desalida podemos usar la misma expresión o expresiones distintas. La<strong>con</strong>straints "0" se encarga de que el registro que usemos sea el mismo. Losdígitos como <strong>con</strong>straints sólo se permiten como operandos de entrada, ydeben de referirse a operandos de salida.Sólo este tipo de <strong>con</strong>straints garantizan que un operando esté en el mismolugar que otro, el mero hecho de que dos operandos usen la mismaexpresión C (N en nuestro caso), no es suficiente para garantizar que nosPág 151


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgrefiramos al mismo registro en el código ensamblador. Es decir, el siguienteprograma podría 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 seproducirían si el programa C estuviese usando uno de los registros queusamos desde ensamblador. Por ejemplo, esta instrucción daría problemas siel 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 instrucción modificael registro r3, usando la llamada lista de registros modificados, que sepone 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 sunombre entre comillas y separándolos por comas.También si nuestro programa ensamblador modifica el registro CR debemosde 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" );Además si nuestro programa ensamblador modifica la memoria de una formaimpredecible, debemos añadir "memory" a la lista de registros modificados.En principio, el compilador de C puede asignar el mismo registro a unoperando de entrada y de salida, y suponer que el dato de entrada será<strong>con</strong>sumido antes de producir la salida. Esto normalmente es cierto, pero si elprograma ensamblador está formado por varias instrucciones esto podría noser cierto, ya que una instrucción posterior podría intentar leer un registroque una instrucción anterior haya modificado. En este caso debemos de poneral operando de salida la <strong>con</strong>straint "&" para evitar que se le asigne el mismoregistro que use un operando de entrada.Por último debemos comentar que la directiva asm supone que lasinstrucciones que estamos ejecutando no tienen más efectos laterales que elde modificar los operandos de salida. Esto no significa que no podamos usarinstrucciones <strong>con</strong> efectos laterales, sino que debemos tener cuidado <strong>con</strong> lasoptimizaciones que pudiera hacer el compilador, ya que si los operandos desalida no se usan en ningún punto <strong>del</strong> programa el optimizador <strong>del</strong>compilador podría eliminar nuestras instrucciones ensamblador. Tambiénpodría aplicar otras optimizaciones como sacarlas fuera de un bucle,Pág 152


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgremplazar dos instrucciones que calculan una subexpresión por una solaguardando el operando de salida en un registro y ejecutar la instrucción unasola vez.Podemos prevenir el que el compilador aplique estas optimizaciones usando elmodificador volative:asm volatile ( "lwz r3,%0":/*sin salida*/:"m" (N) );8.3.2 Expresiones C en gcc 3.1A partir de la versión 3.1 de gcc es posible especificar los operandos deentrada y de salida usando nombres simbólicos, los cuales podemos usarluego dentro <strong>del</strong> código ensamblador. Estos nombres se ponen entrecorchetes <strong>del</strong>ante de la <strong>con</strong>straint <strong>del</strong> operando y nos podemos referir a ellosdesde dentro <strong>del</strong> código ensamblador como %[nombre], en vez de usar %nsiendo n el número <strong>del</strong> parámetro. Es decir, podemos hacer cosas como:#include 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 división es %i",cociente);return 0;}Los nombres simbólicos que damos a los operandos no tienen por quécoincidir <strong>con</strong> los nombres de las variables C a las que los asociamos.Pág 153


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org9 Llamada a funcionesVamos a ver ahora cuál es el mecanismo de llamada a funciones en <strong>Mac</strong> <strong>OS</strong>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 funcionesescritas en ensamblador desde C.9.1 Tipos de datos<strong>Mac</strong> <strong>OS</strong> X define los tipos de datos de la Tabla 2.75:Tipo C o C++Tamaño Rango Valores(en bytes)unsigned char 1 0 a 255charsigned char1 -128 a 127unsigned short 2 0 a 65.535shortsigned short2 -32.768 a 32.767unsigned intunsigned long4 0 a 4.294.967.295intsigned int4 -2.147..483.648 a 2.147.483.647longsigned longbool 4 0 (falso) 1-4.294.967.295 (true)unsigned long long 8 0 a 18.446.744.073.709.551.615long long8 -9.223.372.036.854.775.808 a9.223.372.036.854.775.807signed long longfloat 4 Ver Apéndice Adouble 8 Ver Apéndice Along double 16 Ver Apéndice Apuntero 4 0 a 0xFFFFFFFFTabla 2.75: Tipos de datos de <strong>Mac</strong> <strong>OS</strong> XAdemás de estos tipos la Tabla 2.76 muestra los tipos de datos para AltiVec.Tipo C o C++vector unsignedcharvector charvector signed charvector unsignedshortTamaño(en bytes)16 (1 bytecada)16 (1 bytecada)16 (2 bytescada)Rango Valores0 a 255-128 a 1270 a 65.535Pág 154


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgvector signed shortvector unsigned intvector intvector signed intvector bool charvector bool shortvector bool intvector floatvector pixelTabla 2.76: Tipos de datos de AltiVec16 (2 bytescada)16 (4 bytescada)16 (4 bytescada)16 (1 bytecada)16 (2 bytescada)16 (4 bytescada)16 (4 bytescada)16 (3 bytescada)-32.768 a 32.7670 a 4.294.967.295-2.147..483.648 a 2.147.483.6470 (falso) 1-255(true)0 (falso) 1-65.535 (true)0 (falso) 1-4.294.967.295(true)Ver Apéndice Aformato de pixel 1/5/59.2 Mecanismo general de llamada aprocedimientosLa interfaz entre dos procedimientos se define en términos de unprocedimiento que llama (caller) y un procedimiento llamado(callee). El caller computa los parámetros que debe recibir el callee, losdeposita en la pila, y pasa el <strong>con</strong>trol al callee. El callee recoge los parámetros,realiza unas operaciones y calcula un valor (o quizá no), y retorna el <strong>con</strong>trol ala siguiente sentencia a la sentencia que le llamó.9.3 Convención <strong>del</strong> uso de los registrosLos registros <strong>del</strong> procesador se clasifican en dedicados, volátiles y novolátiles: Los registros dedicados tienen asignado un uso especifico quenosotros no deberíamos de usar para otros propósitos. Los registrosvolátiles (también llamados de scratch) se pueden usar para hacer cualquiercálculo en ellos y su <strong>con</strong>tenido no se garantiza que se mantenga tras llamar auna subrutina, <strong>con</strong> lo que nosotros tampoco tendremos que preocuparnos desalvaguardar su valor. A estos registros también se les llama caller-saveregisters, porque el procedimiento que llama es el que debe encargarse deguardar su valor (si le interesa) antes de llamar a otro procedimiento. Porúltimo, los registros no volátiles son registros que podemos usar encualquier momento, pero su <strong>con</strong>tenido debe de ser guardado antes demodificarlos en el <strong>con</strong>texto <strong>del</strong> procedimiento local, y restaurados antes deabandonar el procedimiento. A estos procedimientos también se les llamacallee-save registers porque es el procedimiento llamado quien debe deguardar su valor antes de modificarlos.Pág 155


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgLa Tabla 2.77 describe cual es la <strong>con</strong>vención <strong>del</strong> uso de registros en <strong>Mac</strong> <strong>OS</strong> XGrupo Registro Tipo UsoregistroGPR GPR0 Volátil Usado normalmente para almacenar elLR de retorno de la funciónGPR1 Dedicado Puntero a la cima de la pilaGPR2 Volátil En <strong>Mac</strong> <strong>OS</strong> Classic era un registrodedicado que se usaba como punteroa la TOC (Table Of Content) o a laGOT (Global Offset Table). <strong>Mac</strong> <strong>OS</strong> Xusa un esquema de direccionamientodiferente y este registro es un registrode propósito general como otrocualquiera.GPR3-GPR10 Volátil Estos 8 registros se usan para pasarlos parámetros de las llamadas afunciones. Una vez recibimos losparámetros se pueden usar parascratch si se deseaGPR11 VolátilGPR12 Volátil Contiene la dirección de salto cuandollamamos a funciones de enlacedinámico. Si no estamos llamando auna función de enlace dinámico seusa como un registro másGPR13-GPR31 No volátil Sus valores se <strong>con</strong>servan entrellamadas a procedimientosFPR FPR0 Volátil Registro de scratchFPR1-FPR13 Volátil Usado para paso de parámetros enpunto flotante. Una vez recibimos losparámetros se pueden usar parascratch si se deseaFPR14-FPR31 No volátil Sus valores se <strong>con</strong>servan entrellamadas a procedimientosAltiVec v0-v2 Volátil Registros de scratchv3-v13 Volátil Usado para el paso de parámetros deeste tipov14-v19 Volátil Registros de scratchv20-v31 No volátil Sus valores se <strong>con</strong>servan entrellamadas a procedimientosvrsave No volátil Indica los vectores que deben serguardados en un cambio de <strong>con</strong>textoSPR LR No volátil Almacena la dirección de retorno de larutina llamadaCTR Volátil Usado en bucles y saltosPág 156


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgCRXER Volátil Excepciones de punto fijoFPSCR Volátil Excepciones de punto flotanteCR0-CR1 Volátil Para <strong>con</strong>sultar el resultado de unaoperación aritmética o paracomparacionesCR2-CR4 No volátil Para comparacionesCR5-CR7 Volátil Para comparacionesTabla 2.77: Convención de uso de los registros de <strong>Mac</strong> <strong>OS</strong> X9.4 Estructura de la pilaEl mo<strong>del</strong>o de programación de <strong>Mac</strong> <strong>OS</strong> X define que un proceso <strong>con</strong>sta de unsegmento de código, un segmento de datos donde se depositan las variablesglobales, y un segmento de pila por cada hilo activo donde se depositan lasvariables locales al hilo y <strong>con</strong> el que se lleva el <strong>con</strong>trol de las llamadas afunciones que haga el hilo.La pila crece avanzando de direcciones altas a direcciones bajas, y paragestionarla se usa un único puntero a la cima de la pila (stack pointer)almacenado, por <strong>con</strong>venio, en el registro GPR1.GPR1La pila crece hacia abajoÁrea de parámetrosÁrea de enlaceCallerNuevoframeGPR1Área de parámetrosÁrea de enlaceRegistros guardadosVariables localesÁrea de parámetrosÁrea de enlaceCallerCalleeFigura 2.17: Creación de un frame en la pilaCada vez que una función llama a otra se crea en la pila un nuevo frame, elcual almacena toda la información que necesita el procedimiento para susautogestión.Pág 157


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgLa Figura 2.17 muestra la creación de un frame en la pila tras llamar a unprocedimiento. Como vamos a ver, GPR1 en todo momento apunta a la cimade la pila <strong>con</strong> la que estamos trabajando.9.4.1 Las áreas <strong>del</strong> frameEl frame está dividido en las cuatro áreas que vamos a comentar a<strong>con</strong>tinuación:El área de parámetros. Se trata de un trozo de memoria donde el callerdeposita los parámetros que va a pasar al callee, es decir, en el frame de unprocedimiento no están sus parámetros sino los parámetros <strong>del</strong> procedimientoal que va a llamar. Después, el procedimiento al que llame deberáapañárselas para acceder a los parámetros que están en el frame <strong>del</strong> que leha llamado.Como un procedimiento puede llamar a varios procedimientos, este áreadeberá tener un tamaño suficiente como para acoger la lista de parámetrosmás larga de todos los procedimientos a los que vaya a llamar.A esta área se la <strong>con</strong>sidera volátil en el sentido de que una vez que llamamosa un procedimiento, éste si quiere puede modificar el valor de los parámetrosaquí depositados, esto se hace, por ejemplo, cuando una función como partede un cálculo que está llevando a cabo, modifica el valor de sus parámetros,depositando en ellos valores intermedios que necesita para calcular un valorfinal.El área de enlace está formado por 3 palabras y tiene un offset relativo a laposición <strong>del</strong> puntero a pila antes de llamar al procedimiento.Los valores de este área lo fija en parte el caller (al que pertenece el área deenlace) y en parte el callee, en cada llamada que le hagamos. En <strong>con</strong>cretoaquí en<strong>con</strong>tramos:o Offset 0: Back chain. El caller (el dueño <strong>del</strong> área) guarda aquí el valor<strong>del</strong> puntero a pila antes de que el callee lo decremente para crear unnuevo frame.o Offset 4: El callee guarda aquí el valor <strong>del</strong> registro CR. Este valor sólotiene que guardarlo el callee si modifica algún campo no volátil de CR(CR2-CR4 son los no volátiles) durante su ejecución.o Offset 8: El callee guarda aquí la dirección de retorno al caller, es decir,el valor <strong>del</strong> registro LR. Este valor lo guarda el callee sólo si el calleemodifica el valor de este registro (llama a otro procedimiento), sino nohace falta guardarlo.Pág 158


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgObsérvese que el área de enlace está en una posición fija que el callee puede<strong>con</strong>ocer (a un determinado offset de la posición <strong>del</strong> puntero a la cima <strong>del</strong>frame <strong>del</strong> caller). Esto es necesario para que el callee pueda acceder a lainformación <strong>del</strong> área de enlace, así como al área de parámetros, que estáinmediatamente después <strong>del</strong> área de enlace. A estos datos debe de acceder elcallee antes de decrementar el puntero a pila (crear su frame), es decir, elcallee debe recoger los parámetros y fijar los valores <strong>del</strong> área de enlace,antes de crear su frame.El área de registros guardados es donde un procedimiento debealmacenar el valor de todos los registros no volátiles que vaya a usar. En casode que el procedimiento sólo use registros volátiles (que es lo habitual) estaárea medirá 0 bytes. La forma en que el procedimiento almacene los registrosse deja a elección <strong>del</strong> programador.El área de variables locales es un área adicional de memoria que puedereservar el procedimiento si éste va a almacenar variables locales enmemoria. Si todas las variables locales se almacenan en registro esta áreamedirá 0 bytes.9.5 Paso de <strong>con</strong>trol a un procedimientoCuando un procedimiento (caller) quiere pasar el <strong>con</strong>trol a otro (callee), enprincipio lo único que tiene que hacer es usando la instrucción bl (Brach thenLink), o alguna de sus variantes, saltar a la dirección en la que se encuentrael procedimiento que queremos ejecutar. Esta instrucción deposita en elregistro LR la dirección de la siguiente instrucción a la instrucción de salto,que es lo que llamamos la dirección de retorno.9.5.1 El prólogo y el epílogoCada procedimiento va a ser el responsable de crear y destruir su propioframe. Esta acción se lleva a cabo por un trozo de programa llamadoprólogo, que se deposita antes <strong>del</strong> cuerpo de la rutina, y por otro llamadoepílogo, que se encarga de destruir el frame y que se pone después <strong>del</strong>cuerpo de la rutina.Vamos a comentar qué acciones son las que se realizan en el prólogo yepílogo de la llamada a una función.Antes de nada debemos comentar que el orden <strong>con</strong>creto en que se ejecutanlas acciones <strong>del</strong> prólogo y epílogo, no vienen dados por las especificacionesde <strong>Mac</strong> <strong>OS</strong> X, sino que la especificaciones se limitan a decir qué acciones hayque llevar a cabo y no en qué orden deben de ejecutarse.Pág 159


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgEl prólogo es el que se encarga de crear en la pila un nuevo frame y deguardar todos los valores que deban ser preservados. En <strong>con</strong>creto susresponsabilidades son:o Si el registro LR va a ser modificado por una futura llamada aprocedimiento, éste debe ser guardado en el área de enlace de sucaller.o Si los campos no volátiles <strong>del</strong> registro CR (CR2-CR4) van a sermodificados, el callee debe guardar el registro CR en el área de enlacede su callero Decrementar el puntero a pila para crear su nuevo frame. Laespecificación dice que el puntero a frame siempre debe apuntar adirecciones múltiplos de 16, <strong>con</strong> lo que durante el decremento si esnecesario se deja un padding <strong>con</strong> el fin de cumplir esta <strong>con</strong>dición.o El callee guarda en su área de enlace el valor <strong>del</strong> puntero a pila talcomo se lo dió el caller.o Guardar el valor de los registros no volátiles que vayan a sermodificados en el área de registros guardados.Obsérvese que un procedimiento puede saber en tiempo de compilación cuáles el tamaño de su frame, para lo cual calcula la suma de cada una de lasáreas que forman el frame, tamaños que son todos <strong>con</strong>ocidos en tiempo decompilación.En la especificación se recomienda que el guardar el puntero a pila ydecrementarlo se haga en un sólo paso usando la instrucción:stwu r1,-tamanoFrame(r1)La cual guarda el valor <strong>del</strong> registro r1 en la dirección apuntada por-tamanoFrame(r1) y después decrementa el valor de r1.A <strong>con</strong>tinuación se muestra un ejemplo de cómo se implementaría el prólogo..set tamanoFrame,16miFuncion:; Prólogomflr r0stw r0,8(r1)mfcr r0stw r0,4(r1); Tamaño <strong>del</strong> frame; Recoge en r0 el LR; Guarda el LR en el área de enlace; <strong>del</strong> caller; Recoge en r0 el CR; Guarda el CR en el área de enlace; <strong>del</strong> callerstwu r1,-tamanoFrame(r1) ; Crea su frame··················Pág 160


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgEn este ejemplo suponemos que no existen variables locales ni hay queguardar registros no volátiles luego necesitamos crear un frame de 12 bytespara el área de enlace, pero como la especificación dice que los framessiempre deben de tener un tamaño múltiplo de 16, creamos un frame de 16bytes <strong>con</strong> un padding de 4 bytes.Al final de ejecutar la función el epílogo destruye el frame y retorna el <strong>con</strong>trolal caller. En <strong>con</strong>creto las responsabilidades <strong>del</strong> epílogo son:o Restaurar el valor de los registros no volátiles guardados.o Restaurar el valor <strong>del</strong> puntero a pila.o Si se modificaron los campos no volátiles <strong>del</strong> registro CR, restaurarlo.o Si se modificó el valor <strong>del</strong> registro LR, restaurarlo.o Retornar a la dirección almacenada en LR.A <strong>con</strong>tinuación se muestra un ejemplo de cómo implementar el epílogo..set tamanoFrame,16miFuncion:··················; Epílogolwz r1,0(r1)lwz r0,4(r1); Tamaño <strong>del</strong> frame; Recoge el puntero a pila de su; área de enlace <strong>con</strong> lo que el; frame queda destruido; Recoge el CR <strong>del</strong> área de enlace; <strong>del</strong> callermtcrf 255,r0 ; Recupera el valor <strong>del</strong> CRlwz r0,8(r1) ; Recoge el LR <strong>del</strong> área de enlace; <strong>del</strong> callermtlr r0; Fija la dirección de retornoblr; RetornaLo primero que hace el epílogo es destruir el frame <strong>del</strong> callee recuperando elvalor de r1, que tiene almacenado en el área de enlace <strong>del</strong> callee, y despuésrecupera los valores de CR y LR para finalmente retornar.Por último vamos a ver que realmente el compilador gcc de <strong>Mac</strong> <strong>OS</strong> X actúacomo aquí hemos explicado. Para ello vamos a crear un fichero llamadollamadas.c que aparece en el Listado 2.13:void funcion_b(void){}void funcion_a(){funcion_b();Pág 161


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org}int main (){funcion_a();return 0;}Listado 2.13: Ejemplo de funcionesY lo vamos a compilar para generar su correspondiente código ensamblador<strong>con</strong> el comando:$ gcc -S llamadas.sUsando la versión 2.95.2 <strong>del</strong> compilador obtenemos una salida como la <strong>del</strong>Listado 2.14 (la cual puede variar ligeramente en otra versión <strong>del</strong>compilador):.text.align 2.globl _funcion_b_funcion_b:; Prologostmw r30,-8(r1) ; Guarda r30 y r31 en su área de; registro guardadosstwu r1,-48(r1) ; Crea su frame de 48 bytes; (3*16 bytes)mr r30,r1 ; Pone el puntero a pila en r30L6:; Epílogolwz r1,0(r1) ; Recoge el puntero a pila <strong>del</strong>; área de enlace <strong>del</strong> callerlmw r30,-8(r1) ; Recupera los valores de r30 y r31blr; Retorna.align 2.globl _funcion_a_funcion_a:; Prólogomflr r0; Recoge en r0 el LRstmw r30,-8(r1) ; Guarda r30 y r31 en su área de; registro guardadosstw r0,8(r1) ; Guarda el LR en el área de enlace; <strong>del</strong> callerstwu r1,-80(r1) ; Crea su frame de 80 bytes; (5*16 bytes)mr r30,r1 ; Pone el puntero a pila en r30; Llamadabl _funcion_bL7:Pág 162


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org; Epílogolwz r1,0(r1) ; Recoge el puntero a pila <strong>del</strong>; área de enlace <strong>del</strong> callerlwz r0,8(r1) ; Recoge el LR <strong>del</strong> área de enlace; <strong>del</strong> callermtlr r0; Fija la dirección de retornolmw r30,-8(r1) ; Recupera los valores de r30 y r31blr; Retorna.align 2.globl _main_main:; Prólogomflr r0stmw r30,-8(r1) ; Guarda r30 y r31 en su área de; registros guardadosstw r0,8(r1) ; Guarda LR en el área de enlace; <strong>del</strong> callerstwu r1,-80(r1) ; Crea su frame de 80 bytes; (5*16 bytes)mr r30,r1 ; Pone el puntero a pila en r30; Llamadabl _funcion_a; Epílogoli r3,0; Pone un 0 en el retorno de lamain()b L8L8:lwz r1,0(r1) ; Recupera el puntero a pila <strong>del</strong>; área de enlace de su callerlwz r0,8(r1) ; Recupera el LR <strong>del</strong> área de enlace; de su callermtlr r0lmw r30,-8(r1) ; Restaura los registros r30 y r31blr; RetornaListado 2.14: Código ensamblador generado por gccHemos comentado el código ensamblador generado para facilitar sucomprensión.Vemos que el funcionamiento <strong>del</strong> compilador es básicamente el que hemosestudiado, aunque en este caso vemos una pequeña desoptimización debida aque el registro r30 y r31 son <strong>con</strong>tinuamente guardados y recuperados encada llamada a función sin razón aparente. De hecho podríamos eliminar lasinstrucciones que manejan estos registros y el programa seguiría funcionandoexactamente igual.Estas desoptimizaciones se deben a que no hemos pedido a gcc ningunaoptimización, el lector puede ejecutar ahora el compilador <strong>con</strong> optimizaciónasí:Pág 163


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org$ gcc -S -O3 llamadas.cObteniendo el código <strong>del</strong> 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 r0stw r0,8(r1)stwu r1,-64(r1)bl _funcion_ali r3,0lwz r0,72(r1)la r1,64(r1)mtlr r0blrListado 2.15: Código ensamblador generado por gcc optimizadoQue como se puede apreciar a simple vista es un programa mucho máspequeño y optimizado.9.5.2 Los procedimientos terminalesRecuérdese que al estar el puntero a pila situado en la cima de la pila (ycrecer la pila en direcciones decrecientes de memoria) un procedimientosiempre accede a direcciones <strong>con</strong> offset positivo respecto al puntero a pila.Esto aunque habitual no es obligatorio, ya que las posiciones que están másallá <strong>del</strong> puntero a pila, que es lo que se llama la zona vacía (véase Figura2.18), están sin usar y si el procedimiento lo desea también puede usarlas.Esto es lo que hacen los llamados procedimientos terminales, que sonaquellos que no llaman a ningún otro procedimiento. En este caso, muchasveces, estos procedimientos no crean un nuevo frame para ellos, sino quemantienen el puntero a pila en la posición que lo tenía el caller, y si necesitantrabajar <strong>con</strong> variables locales en memoria lo que hacen es usar la zona vacía.Pág 164


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgEl procedimiento terminal también guardaríael valor <strong>del</strong> CR en el área de enlace <strong>del</strong>caller (si fuese necesario), pero al no tenerque fijar un nuevo frame el trabajo realizadopor el prólogo y el epílogo es mínimo.9.5.3 Paso de parámetrosGPR1Área de parámetrosÁrea de enlaceCallerEl procedimiento de paso de parámetrosque vamos a ver es el que define <strong>Mac</strong> <strong>OS</strong> Xpara C. Para C++ y Objective-C estosmecanismos varían ligeramente.ZonavacíaLos parámetros se pasan depositando elprocedimiento que llama los parámetros enFigura 2.18: Zona vacía enlos procedimientos terminalessu área de parámetros y recogiéndolos el procedimiento llamado <strong>del</strong> área deparámetros de su caller.Como el caller puede llamar a varias funciones durante su ejecución, eltamaño <strong>del</strong> área de parámetros <strong>del</strong> caller debe ser el mayor de los tamañosque va a necesitar para llamar a cada una de las funciones que llama (opuede llamar). Este es un tamaño que siempre se puede saber en tiempo decompilación mirando el prototipo de cada una de las funciones que llama.Los parámetros se colocan en el área de parámetros <strong>con</strong> una alineación de 4bytes, en <strong>con</strong>creto:o Si el parámetro mide 4 bytes se coloca a <strong>con</strong>tinuación sin más.o Si el parámetro es menor a 4 bytes (p.e. char o short), se alinea a 4bytes ocupando el parámetro la parte baja de la palabra de 4 bytes. El<strong>con</strong>tenido de los bytes más significativos queda sin definir.o Si el parámetro es mayor a 4 bytes (p.e. un struct o un array) serellenan a la derecha (posiciones altas) <strong>con</strong> un padding para ocupar untamaño múltiplo de 4 bytes.Por ejemplo <strong>con</strong>sideremos una rutina <strong>con</strong> 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 cómo se colocan estos bytes en el área de parámetros, primero<strong>con</strong>vertimos los parámetros en una estructura tal que así:Pág 165


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgstruct Parametros{int pi1;float pf2;double pd3;short ps4;double pd5;char pc6;short ps7;float pf8;short ps9;};Esta estructura sirve como plantillapara <strong>con</strong>struir el área de parámetrosde la pila. El elemento que acaba enla dirección de memoria más baja espi1, y a partir de ahí van ocupandodirecciones de memoria positivas a lolargo <strong>del</strong> área de memoria,respetando las reglas de padding quehemos dado. Luego la organizaciónexacta de los parámetros sería la <strong>del</strong>a Figura 2.19.+44+40+36+32+28+20+16+8+40pf8pd5pd3pf2pi1Zona vacíaps9ps7ps4pc6Figura 2.19: Ejemplo de organizaciónde parámetros en la pilaEn principio esta sería la forma que tendría el área de parámetros, pero laespecificación define una optimización muy importante que dice que:"Las 8 primeras palabras de los parámetros no se pasan en la pila, sino quese usan los registros para pasar los parámetros”.Esta optimización es muy importante porque la mayoría de las funcionestienen pocos parámetros y así evitamos tener que acceder a memoria parahacer el paso de parámetros.Sin embargo, la especificación es un poco caprichosa respecto a la formacorrecta de pasar estos parámetros en registros. Veamos que diceexactamente.En primer lugar la especificación dice que los parámetros correspondientes alas 8 primeras palabras se pasan en los registros GPR3 al GPR10. Aun así, elespacio <strong>del</strong> área de parámetros que ocuparían estos parámetros en el área deparámetros (y que no ocupan por pasarse en registros) debe quedarreservado (a pesar de no <strong>con</strong>tener los datos). Esto se hace por variasrazones:Pág 166


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgo Proporciona un espacio de memoria al callee para guardar el valor <strong>del</strong>os registros si este tuviera que usar los registros <strong>con</strong> otros fines (p.e.para pasar parámetros a una subrutina).o Para simplificar la depuración algunos compiladores escriben losparámetros en el área de parámetros de la memoria, esto permite aldepurador ver el valor de los parámetros <strong>con</strong> sólo leer de memoria.o Las rutinas <strong>con</strong> un número variable de parámetros nunca usan losregistros sino que guardan los parámetros en memoria.Otra peculiaridad es que si los parámetros son de tipo float o double sepasan en los registros FPR1 a FPR13, aunque los registros que hubieranocupado si los hubiéramos guardado en GPRs quedan reservados, pero sin<strong>con</strong>tener el valor, es decir, no se pueden usar para pasar parámetros de tiposescalares. Esta regla en principio no tiene ninguna utilidad práctica, y sólo dalugar a un desperdicio, pero la regla se mantiene por compatibilidad <strong>con</strong> otrossistemas programables en <strong>PowerPC</strong>, como puedan ser AIX de IBM.+44+40+36+32+28+20+16+8+40ps9pf8ps7pc6pd5ps4pd3pf2pi1Zona vacíaGPR10GPR9GPR8GPR7GPR6GPR5GPR4GPR3FPR4FPR3FPR2FPR1Figura 2.20: Ejemplo de organización real de parámetros en la pilaPor último respecto a los parámetros que sean vectores (AltiVec) estos sepasan en los registros v2 a v13, y en el caso de los vectores, su presencia noafecta a los registros GPR ni FPR. El caller no debe reservar espacio en el áreade parámetros de la pila a no ser que su número exceda el número deparámetros que podemos pasar en los registros de AltiVec.Pág 167


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgEn el ejemplo anterior tenemos que cambiar la distribución de los parámetrospara que se pasen de acuerdo a la regla que hemos visto, <strong>con</strong> lo que ahora ladistribución de parámetros quedaría como muestra la Figura 2.20.Vemos que los parámetros pi1 a pc6 no se guardan realmente el memoriasino en registros. También observamos como parámetros como pf2, pd3 ópd5 producen un <strong>con</strong>sumo de GPRs a pesar de que su valor no se almacenaen estos registros, sino en FPRs.9.5.4 Funciones <strong>con</strong> un número variable de parámetrosEn C podemos crear funciones que reciban un número variable deparámetros. Estas funciones denotan la parte variable <strong>con</strong> una elipsis (...) alfinal de la lista de parámetros. La función puede tener un número fijo deparámetros al principio, los cuales suelen dar información sobre losparámetros que van después.Un ejemplo de función de este tipo sería: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 ejecutaríamos así:double s = suma(3,4.5,6.7,3.2);En este caso todos los parámetros variables se almacenan en sucorrespondiente posición <strong>del</strong> área de parámetros de la memoria, esto permiteque recojamos estos parámetros accediendo mediante un puntero a la zonade memoria que ocupan. En el ejemplo anterior el puntero p se calculacomo:double* p = (double*)(&n+1);Una vez tenemos el puntero al área de parámetros ya podemos leerlos.Pág 168


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org9.5.5 Retorno de una funciónCuando una función retorna un valor, la forma de devolverlo depende <strong>del</strong> tipo<strong>del</strong> valor retornado:o Si es un valor escalar de 4 bytes se retorna en el registro GPR3 sinmás.o Si es un valor menor de 4 bytes (p.e. char o short) se retorna en laparte baja <strong>del</strong> registro GPR3. El <strong>con</strong>tenido de los bytes mássignificativos queda sin definir.o Los valores de tipo long long (8 bytes) se devuelven en GPR3:GPR4<strong>con</strong>teniendo GPR3 los bytes más 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 losregistros FPR1:FPR2 siendo la parte alta la que se coloca en FPR1.o Los datos compuestos (p.e. estructuras y arrays) se almacenan enmemoria gestionada por el caller, y en la llamada el caller debe deindicar la dirección de memoria donde desea obtener el retorno,poniendo en GPR3 un puntero a esta zona de memoria. Al ser<strong>con</strong>siderado GPR3 como un parámetro no se garantiza su valor en elretorno. En <strong>con</strong>secuencia en ese tipo de funciones GPR4 <strong>con</strong>tendrá elprimer parámetro de la función.9.6 EjemploPara acabar este apartado vamos a hacer un ejemplo de como seimplementaría una función recursiva que calcula el factorial de un número enensamblador.Esta función ensamblador la vamos a poner en un fichero llamadofactorial.s que aparece en el Listado 2.16, y la vamos a llamar desde unprograma C que vamos a hacer en el fichero factorial.c que aparece enel Listado 2.17..set tamanoFrame,16.text.align 2.globl _factorial_factorial:; Prólogomflr r0; Recoge en r0 el LRstw r0,8(r1); Guarda el LR en el área; de enlace <strong>del</strong> callerstwu r1,-tamanoFrame(r1) ; Crea su framePág 169


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org; Cuerpo de la funcióncmpwi r3,1; Si (n>1)bgt sigueli r3,1 ; Retorna 1b epilogosigue:stw r3,tamanoFrame+12(r1) ; Guarda r3 en el área de; parámetros <strong>del</strong> padre; para poder hacer otra; llamada recursivasubi r3,r3,1; Decrementa nbl _factorial; Llama a factorialmr r4,r3; Recoge el retorno y; lo guarda en r4lwz r3,tamanoFrame+12(r1) ; Recupera el parámetro; <strong>del</strong> área de enlace; <strong>del</strong> padremulhw r5,r3,r4; Calcula n*factorial(n-1)cmpwi r5,0; Si hay acarreobne acarreo ; devolvemos 0mullw r3,r3,r4b epilogoacarreo:li r3,0epilogo:; Epílogolwz r1,0(r1)lwz r0,8(r1)mtlr r0blrListado 2.16: Llamada a una función C; r3 = n*factorial(n-1); Recoge el puntero a pila; de su área de enlace; <strong>con</strong> lo que destruye; el frame; Recoge el LR <strong>del</strong> área de; enlace <strong>del</strong> caller; Fija la dirección de; retorno; RetornaComo la función se vuelve a llamar a sí misma tiene que guardar el parámetropasado en el registro r3 en el área de parámetros <strong>del</strong> caller antes <strong>del</strong>lamarse recursivamente, y cuando retorna de la llamada vuelve a ir amemoria a recuperar el parámetro guardado para poder calcularn*factorial(n-1).La función comprueba si durante la multiplicación hay acarreo, es decir, simulhw da un número distinto de cero, en cuyo caso es que el númerocalculado no cabe en un registro de 32 bits y retorna 0 indicando que no sepudo calcular.Pág 170


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org#include 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: Función llamada desde ensambladorPág 171


Apéndice AAritmética binariaSinopsis:En este apéndice se pretende hacer un repaso a todos los <strong>con</strong>ceptosrelacionados <strong>con</strong> la representación de números, tanto en punto fijo como enpunto flotante 4 , así como los temas relacionados <strong>con</strong> la aritmética binaria.Aunque, como se dijo en el prólogo, este libro presupone que el lector estáfamiliarizado <strong>con</strong> la representación binaria y su aritmética, un repaso podríaayudar a un lector que llevase algún tiempo sin tocar este tema.4 En castellano muchas veces se les llama coma fija y coma flotante, ya que en castellano el<strong>del</strong>imitador de la parte fraccionaria es la coma y no el punto


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org1 Técnicas básicas de aritmética entera1.1 Números sin signoVamos a empezar viendo la aritmética <strong>con</strong> números binarios sin signo y en elsiguiente apartado comentaremos los aspectos de los números binarios <strong>con</strong>signo.1.1.1 Suma <strong>con</strong> transmisión de acarreoLa suma de números binarios se realiza sumando los dígitos de la mismamagnitud de acuerdo a la Tabla A.1:a i b i c i s i c i+10 0 0 0 00 1 0 1 01 0 0 1 01 1 0 0 10 0 1 1 00 1 1 0 11 0 1 0 11 1 1 1 1Tabla A.1: Proceso de suma de números binariosa (a n-1 ...a 1 a 0 ) y b (b n-1 ...b 1 b 0 ) son los dígitos a sumar, s (s n-1 ...s 1 s 0 )es la suma y c (c n-1 ...c 1 c 0 ) el acarreo. Si hay acarreo en el nivel i, elacarreo se pasa al nivel i+1.Por ejemplo para sumar 23 y 56, primero los pasamos a binario, y despuésaplicando 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, aligual que en el sexto bit, y éste se ha llevado hasta el séptimo bit.Si queremos hacer un sumador hardware que pueda calcular la suma denúmeros de n bits: a n-1 ...a 1 a 0 y b n-1 ...b 1 b 0 necesitamos unoscomponentes llamados semisumadores, y otros llamados sumadorescompletos.Pág 173


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgEl semisumador toma dos bits a i y b i como entrada, y produce como salidaun bit de suma s i y un bit de acarreo c i+1 . Como ecuaciones lógicas:s i =a i *(~b i ) + (~a i )*b ic i+1 =a i *b i .Al semisumador también se le denomina sumador (2,2), ya que toma 2entradas y produce 2 salidas. El sumador completo es un sumador (3,2) y sedefine por las ecuaciones lógicas:s i = a i *(~b i )*(~c i ) + (~a i )*b i *(~c i ) + (~a i )*(~b i )*c i+ a i *b i *c ic i+1 = a i b i + a i c i + b i c iA la entrada al sumador c i se le denomina el acarreo de entrada, mientrasque la salida <strong>del</strong> sumador c i+1 es el acarreo de salida.El problema principal a la hora de <strong>con</strong>struir un sumador para números de nbits es propagar los acarreos. La forma más obvia de resolver esto es <strong>con</strong> unsumador de transmisión de acarreo (ripple-carry adder), que <strong>con</strong>stade n sumadores completos tal como muestra la Figura A.1:a n-1b n-1a n-2b n-2a 1b 1a ob o0SumadorcompletoSumadorcompletoSumadorcompletoSumadorcompletoc ns n-1c n-1s n-2c ns n-1 c 1Figura A.1: Sumador de transmisión de acarreoEl bit menos significativo entra por el sumador más a la derecha. Vemos quela salida <strong>del</strong> i-ésimo sumador alimenta el acarreo <strong>del</strong> sumador (i+1)-ésimo.Como el acarreo de orden inferior es 0, el primer sumador basta <strong>con</strong> que seaun semisumador. Sin embargo, más tarde veremos que inicializar el bit deacarreo de orden inferior a 1, es útil para realizar la resta.Pág 174


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org1.1.2 Resta <strong>con</strong> petición de acarreoLa resta actúa de forma parecida a la suma, sólo que ahora cuando el bit <strong>del</strong>minuendo es 0 y el bit de sustraendo es 1, en vez de “pasar” un bit al dígitode mayor peso, se le “pide” un bit.Según esto el proceso de resta de números binarios sería el de la Tabla A.2:a i b i c i s i c i+10 0 0 0 00 1 0 1 11 0 0 1 01 1 0 0 00 0 1 1 10 1 1 0 11 0 1 0 01 1 1 1 1Tabla A.2: Proceso de resta de números binariosPor ejemplo para calcular 56-23, primero los pasamos a binario, y despuésaplicando la regla anterior tenemos:0011 1000 (56)0001 0111 (23) -–––––––––––––––––0010 0001 (33)Ya en el bit más a la derecha vemos que hemos tenido que pedir al nivelsuperior, y el acarreo de petición se ha mantenido hasta el cuarto bitempezando a <strong>con</strong>tar por la derecha.a n-1b n-1a n-2b n-2a 1b 1a ob o1SumadorcompletoSumadorcompletoSumadorcompletoSumadorcompletoc ns n-1c n-1s n-2c ns n-1 c 1Figura A.2: Circuito restadorPág 175


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgLo más curioso de todo es que si quisiéramos hacer un restador hardware,bastaría <strong>con</strong> aprovechar el circuito <strong>del</strong> sumador, invirtiendo las entradas <strong>del</strong>sustraendo y poniendo a 1 el bit de acarreo de más a la derecha comomuestra 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:(minuendo) 14 1111(sustraendo) 7 - 0111 -⎯⎯⎯⎯⎯(diferencia) 7 01111. Pasamos el sustraendo a complemento a 2Binario Complemento a 1 Complemento a 20111 1000 10012. Sumar el minuendo al sustraendo en complemento a 21110 (minuendo)+ 1001 (sustraendo en complemento a 2)⎯⎯⎯⎯101113. Descartar el overflow1110 (minuendo)+ 1001 (sustraendo en complemento a 2)⎯⎯⎯⎯101110 - Suma1 - Restaa n-1b n-1a n-2b n-2a 1b 1A 0b 0xorxorxorxorSumadorcompletoSumadorcompletoSumadorcompletoSumadorcompletoc ns c n-1s n-2n-1c ns n-1 c 1Figura A.3: Circuito sumador-restadorPág 176


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgLa razón por la cual el circuito anterior funciona como restador puedeentenderse mejor ahora. Los cuatro inversores <strong>con</strong>vierten el sustraendobinario en su forma en complemento a 1 y el acarreo <strong>con</strong> su bit de entradapuesto a 1 <strong>con</strong>vierte el sustraendo en complemento a 2.Ahora podríamos <strong>con</strong>struir un circuito sumador-restador como el de la FiguraA.3. El circuito sumador-restador tiene una entrada adicional de <strong>con</strong>trol. Siesta entrada está a 0, significa que queremos sumar, y las puertas XOR dejanpasar la misma entrada que reciben. Si la entrada de <strong>con</strong>trol está a 1,significa que queremos restar, <strong>con</strong> lo que las puertas XOR invierten la entraday se activa el bit de acarreo.1.1.3 Multiplicación en base 2La multiplicación binaria es muy parecida a la multiplicación decimal, secolocan multiplicando y multiplicador de forma que el multiplicando semultiplica por cada uno de los bits <strong>del</strong> multiplicador <strong>con</strong>venientementedesplazado, y al final se suman.Por ejemplo, para calcular 34*67 en binario, haríamos:00100010 (34)x 01000011 (67)————————0010001000100010000000000000000000000000000000000010001000000000———————————————000100011100110El multiplicador hardware más sencillo opera sobre dos números sin signoproduciendo cada vez un bit como muestra la Figura A.4. Los números quevamos a multiplicar son a n-1 ...a 1 a 0 y b n-1 ...b 1 b 0 los cuales se colocan enlos registros A y B (<strong>con</strong> el bit menos significativo a la derecha, como eshabitual). El registro P se pone inicialmente a cero:Pág 177


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgDesplazamientoPA∑B1 bitn bitsFigura A.4: Circuito multiplicadorEl algoritmo repite los siguientes dos pasos:1. Si el bit menos significativo de A es 1, entonces el registro B se suma<strong>con</strong> el registro P; en caso <strong>con</strong>trario, el registro P se mantiene comoestá.2. Los registros A y P se desplazan un bit a la derecha de forma que el bitmenos significativo de P se pasa al bit más significativo de A, y el bitmenos significativo de A, que no se vuelve a usar más en el algoritmo,se pierde.Después de n pasos el producto aparece en los registros P:A, <strong>con</strong>teniendo Alos bits menos significativos.1.1.4 División en base 2Este algoritmo se puede implementar fácilmente en hardware usando tresregistros tal como muestra la Figura A.5:DesplazamientoPA∑B1 bitn bitsFigura A.5: Circuito divisorPág 178


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgPara calcular la división a/b el algoritmo más sencillo procede de la siguienteforma:Se pone el dividendo a en el registro A, y el divisor b en el registro B.Después se habilita un tercer registro P que inicialmente se pone a 0.Al final de la ejecución <strong>del</strong> algoritmo A <strong>con</strong>tendrá el cociente, y P el resto <strong>del</strong>a división.El algoritmo <strong>con</strong>siste en repetir n veces los siguientes pasos (n es el númerode bits de los registros <strong>con</strong> los que estamos trabajando):1. Desplazar la combinación P:A 1 bit a la izquierda. Esto carga un 1 en elbit menos significativo de P cuando el bit más significativo de A sea 1,o un 0 en el bit menos significativo de P en caso <strong>con</strong>trario.2. Restar a P el divisor B. Esto calcula la resta parcial de la división.3. Si el resultado es negativo, no modificamos P e insertamos un cero enel bit bajo de A4. Si el resultado es positivo ponemos el resultado en P, y insertamos un1 en el bit bajo de A5. Si el número de iteraciones es menor a n, volvemos al paso 1A <strong>con</strong>tinuación se muestra un ejemplo de como se ejecutaría la división:65/15 usando registros de 16 bits.Inicialmente tendremos:A= 00000000 01000001 (65)B= 00000000 00001111 (15)P= 00000000 00000000 (0)Pasos 1-9:Como los 9 bits más a la izquierda de A son ceros, P recibirá 9 bits 0 y P-Bsiempre será negativo <strong>con</strong> lo que el programa se limitará a desplazar losceros a la izquierda obteniendo:A= 10000010 00000000 (65)B= 00000000 00001111 (15)P= 00000000 00000000 (0)Luego los registros P:A acaban teniendo:P:A= 00000000 00000000 10000010 00000000Las últimas 7 repeticiones son las que van depositando en A el cociente de ladivisión, y en P el resto.Pág 179


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org10º paso:DesplazamosP:A= 00000000 00000001 00000100 00000000B= 00000000 00001111B>P y no hacemos nada más.11º paso:DesplazamosP:A= 00000000 00000010 00001000 00000000B= 00000000 00001111B>P y no hacemos nada más.12º paso:DesplazamosP:A= 00000000 00000100 00010000 00000000B= 00000000 00001111B>P y no hacemos nada más.13º paso:DesplazamosP:A= 00000000 00001000 00100000 00000000B= 00000000 00001111B>P y no hacemos nada más.14º paso:DesplazamosP:A= 00000000 00010000 01000000 00000000B= 00000000 00001111En este desplazamiento finalmente (P>B) <strong>con</strong> lo que calculamos P-B y loguardamos en P. Además ponemos un 1 en A.Luego acabamos teniendo:Pág 180


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgP:A= 00000000 00000001 01000000 00000001B= 00000000 0000111115º paso:DesplazamosP:A= 00000000 00000010 10000000 00000010B= 00000000 00001111B>P y no hacemos nada más.16º paso:DesplazamosP:A= 00000000 00000101 00000000 00000100B= 00000000 00001111B>P y finalmente hemos acabado.Ahora tenemos que el cociente es A=4 y que el resto está en P=5.Obsérvese 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 laderecha cuando se multiplica y a la izquierda cuando se divide. Si permitimosque el par de registros P:A se puedan desplazar a la izquierda y a la derechaindistintamente, podemos aprovechar el mismo hardware para hacer unmultiplicador-divisor.1.2 Números <strong>con</strong> signo1.2.1 RepresentaciónHay cuatro métodos para representar números <strong>con</strong> signo: signo-magnitud,complemento a dos, complemento a uno y polarizado (biased). En el sistemade signo-magnitud el bit de orden superior es el bit de signo, y los n-1 bitsinferiores son la magnitud <strong>del</strong> número. En el sistema de complemento ados, un número y su negativo suman 2 n . En el complemento a uno, elnegativo de un número se obtiene negando cada bit. En el sistemapolarizado, se toma una polarización fija de forma que la suma de lapolarización y el número que se está representando sea siempre no negativo.Un número se representa primero sumándolo a la polarización y dicha sumase codifica como un número ordinario sin signo.Pág 181


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgEjemplo: ¿Cuánto es -3 representado en cada uno de estos formatos?La representación binaria de 3 es 0011. En signo-magnitud -3 sería 1011. Encomplemento a dos 0011+1101=10000, luego sería 1101. En complemento auno negamos todos los bits y tenemos 1100. Usando una polarización de 8, 3se representa como 0011+1000=1011, es decir 3+8=11, y -3 se representacomo 0101 ya que-3+8=5.Negar un número en complemento a 2 es fácil, sólo hay que pasarlo acomplemento a 1 (negar todos sus bits) y luego sumarle 1.Por ejemplo si queremos negar el 27 hacemos:00011011 (27)11100100 (complemento a 1)1 +————————11100101 (-27)Si ahora lo queremos volver a negar aplicamos el mismo procedimiento:11100101 (-27)00011010 (complemento a 1)1 +————————00011011 (27)1.2.2 Suma y resta de números en complemento a 2La gran ventaja que tiene representar los números en complemento a 2 esque para hacer una suma basta <strong>con</strong> sumarlos como si fueran números sinsigno. Por ejemplo si queremos calcular 34+(-17), primero los representamosen complemento a 2 y luego sumamos.Primero empezamos calculando la representación de -17:00010001 (17)11101110 (complemento a 1)1 +————————11101111 (-17)Y luego los sumamos:00100010 (34)11101111 (-17) +————————100010001 (17)Pág 182


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgVemos que la suma produce un acarreo en el bit de orden superior quesimplemente se descarta.La resta de números en complemento a 2 también se hace como la resta denúmeros sin signo:Por ejemplo para calcular 34-(-17) hacemos:00100010 (+34)11101111 (-17) -————————100110011 (+51)El desbordamiento (overflow) se produce cuando el resultado de laoperación no cabe en la representación que se está utilizando. Para númerossin signo detectar el desbordamiento es fácil: se presenta justo cuando hayun acarreo de salida <strong>del</strong> bit más significativo. Para el complemento a dos lascosas son más complicadas: el desbordamiento se presenta, exactamente,cuando el acarreo de entrada <strong>del</strong> bit de orden superior es diferente <strong>del</strong>acarreo de salida (que es descartado) <strong>del</strong> bit de orden superior. En el ejemplode la suma 34+(-17) anterior el acarreo de entrada <strong>del</strong> bit de orden superiores 1 y el acarreo de salida también 1, <strong>con</strong> lo que no hay desbordamiento,pero si calculamos:(-80)+(-120) tendremos:10110000 (-80)10001000 (-120) +————————100111000 (56)Ahora el acarreo de entrada <strong>del</strong> bit más significativo es 0, mientras que elacarreo de salida <strong>del</strong> bit más significativo es 1, al ser distintos indica que hahabido un desbordamiento.1.3 Aspectos <strong>del</strong> sistemaCuando se diseña un repertorio de instrucciones, hay una serie de cuestionesrelativas a la aritmética entera que es necesario aclarar:Primero, ¿qué debe hacerse cuando hay un desbordamiento de enteros?Antes de nada aclarar que no debe <strong>con</strong>fundirse el desbordamiento (overflow)<strong>con</strong> el acarreo. Cuando sumamos o restamos números en complemento a 2,es normal que se produzca un acarreo en el último bit, que simplemente sedescarta. El desbordamiento es distinto, se debe a que el número obtenido noes correcto ya que no se puede representar en un registro <strong>del</strong> tamaño usado.Pág 183


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgP.e. 34+(-17) producía un acarreo que se descartaba sin más. (-80)+(-120)produce un desbordamiento que hace que el resultado de la suma obtenidoen el registro no sea el correcto.El problema <strong>del</strong> desbordamiento se complica por el hecho de que detectar eldesbordamiento es diferente dependiendo de si los operandos son enteros<strong>con</strong> o sin signo.Consideremos primero la aritmética sin signo. Hay tres enfoques: poner a 1un bit de desbordamiento, causar un trap en caso de desbordamiento, o nohacer nada <strong>con</strong> el desbordamiento. En el último caso el software tiene quecomprobar si se va a producir o no desbordamiento, <strong>con</strong> lo que es la soluciónmenos apropiada y de hecho sólo se usó en las máquinas MIPS.En <strong>PowerPC</strong> el enfoque que se ha seguido es el de que las instrucciones noproducen un trap, sino que activan un flag que indica que la excepción se haproducido. En las instrucciones de punto fijo existen tres flag, que se detallanen la Tabla A.3, en el registro XER que indican que la excepción se haproducido:FlagSOOVCADescripción(Summary Overflow) Se activa cuando hay un overflow y quedaactivo hasta que lo desactivamos explícitamente <strong>con</strong> mtxer. Es útilpara saber si durante la ejecución de una serie de instruccioneshubo un overflow(OVerflow) Indica si la última operación aritmética produjooverflow(Carry) Indica si la última operación aritmética produjo acarreoTabla A.3: Flags de excepción en <strong>PowerPC</strong>Después <strong>PowerPC</strong> dispone de varias operaciones, unas en las que no sedetecta nada (addi y add), otras en las que sólo se detecta el acarreo (addcy adde) y otras en las que se activa el overflow (addco, addeo, addmeo yaddzeo).¿Qué ocurre en el caso de la aritmética <strong>con</strong> signo?. Obsérvese que mientrasque el la aritmética sin signo el acarreo implica overflow, aquí puede serdeseable ignorarlo, como pasa en el caso de la suma de números encomplemento a 2, donde el acarreo simplemente se ignora. Esta es la razónde que existan instrucciones como addi o add que lo ignoran. Además elignorar el acarreo puede ser útil en circunstancias en las que por la lógica <strong>del</strong>programa sabemos que no se va a producir, porque acelera la ejecución deinstrucciones tal como se explica en el Apéndice B.Una segunda cuestión está relacionada <strong>con</strong> la multiplicación. El resultado <strong>del</strong>a multiplicación de dos números de n bits ¿deberá ser de 2n bits, o deberáPág 184


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgdevolver los n bits de orden inferior, señalando desbordamiento si el resultadosobrepasa los n bits?.El argumento en favor de un resultado de n bits es que, virtualmente entodos los lenguajes de alto nivel, la multiplicación es una operación cuyosargumentos son variables enteras y cuyo resultado es una variable entera <strong>del</strong>mismo tipo. Por tanto no hay forma de generar código que utilice unresultado de doble precisión. El argumento a favor de 2n bits es que lo puedautilizar una rutina, en lenguaje ensamblador, para acelerar sustancialmente lamultiplicación de enteros en múltiple precisión.En <strong>PowerPC</strong> se ha buscado una solución intermedia y para multiplicarnúmeros de 32 bits usamos las instrucciones mullw (MULtiply Low Word)mulhw (MULtiply High Word) que nos proporcionan la parte alta y baja de los64 bits resultados <strong>del</strong> producto. Si sólo nos interesa la parte baja (como eshabitual) usamos sólo mullw.Pág 185


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org2 Introducción al punto flotanteSe han inventado varias formas de representar números no enteros. Una deellas es utilizar punto fijo, es decir, utilizar aritmética entera e imaginar elpunto binario en algún sitio en medio <strong>del</strong> número. Sumar dos de talesnúmeros suele hacerse mediante una suma entera, mientras que lamultiplicación requiere algún desplazamiento extra.Sin embargo sólo hay una representación no entera cuyo uso se ha extendidoampliamente, y es la representación en punto flotante. En este sistema, larepresentación de un número se divide en tres partes: un signo, unexponente y una mantisa. Y el valor <strong>del</strong> número así representado secalcula como:n = (signo) mantisa * 2 exponenteAunque ésta es la fórmula que se usa para guardar un número en unordenador, a la que llamaremos punto flotante binario, nosotros tambiénusaremos en nuestros ejemplos otra representación a la que llamaremospunto flotante decimal:n = (signo) mantisa * 10 exponenteAunque esta fórmula no vale para calcular números en binario, si que nosserá útil en los ejemplos ya que las personas estamos más familiarizadas <strong>con</strong>números en base 10.Un ejemplo de representación en punto flotante decimal sería un número<strong>con</strong> un signo negativo, una mantisa de 1,5 y un exponente de -2, lo cual estárepresentando el número: -1,5*10 -2 =-0,015.Un ejemplo de representación en punto flotante binario sería un número<strong>con</strong> signo positivo, una mantisa de 1.01b y un exponente de +10b, quepasado a decimal 1,01b es el número 1,25d y +10b pasado a decimal es el+2, luego sería el número 1,25*2 2 =5Obsérvese que la mantisa nunca tiene signo, ya que el signo se separa aparteen el campo destinado a tal propósito, sin embargo el exponente siempre esun número <strong>con</strong> signo.Obsérvese también que un mismo número en punto flotante puede tenermuchas representaciones. P.e. -1,5*10 -2 =-0,15*10 -1 =-0,015*10 0 =-0,00015*10 1Para simplificar la representación se a creado el <strong>con</strong>cepto de número enpunto flotante normalizado, donde decimos que un número estáPág 186


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgnormalizado si la mantisa tiene un sólo dígito a la izquierda de la coma. P.e. -7,5*10 3 está normalizado, -75*10 2 no. En binario también se normalizan losnúmeros. Por ejemplo 1,0110*2 -11 está normalizado, pero 1011,0*2 -110 no loestá.Pág 187


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org3 Formato de los datos en punto flotanteEl estándar IEEE 754 especifica cuatro formatos para almacenar números ennotación de punto flotante: simple, doble, simple extendido, dobleextendido. Todos los formatos tienen los tres campos que explicábamosantes, sólo que cada uno de ellos tiene un tamaño mayor o menor que les damás o menos precisión.A la hora de almacenar un número en punto flotante, a éste se le hace unamodificación llamada empaquetamiento que <strong>con</strong>siste en:o Normalizar la mantisa de forma que a la izquierda <strong>del</strong> punto binarioaparezca un sólo 1 y coger de ésta sólo los bits que están a la derecha<strong>del</strong> punto binario, que es a lo que se llama la fracción.o Al exponente se le polariza (véase el apartado 1.2) <strong>con</strong> el fin dealmacenar el número como un número sin signo. A esto es a lo que sellama el exponente polarizado, en <strong>con</strong>traposición al exponente quetenemos cuando desempaquetamos el número que se llamaexponente no polarizado. Como polarización se utiliza 2 n-1 siendo nel número de bits <strong>del</strong> campo destinado a almacenar el exponente.Ejemplo: Los números de precisión simple utilizan 1 bit para el signo, 23para la fracción y 8 para el exponente polarizado ¿Cómo se empaquetaría elnúmero en punto flotante 150*2 -9 ?Primero debemos de pasar la mantisa a notación binaria, <strong>con</strong> lo que tenemos:mantisa = 150 = 10010110Ahora debemos normalizar la mantisa para lo que transformamos en elnúmero: 1,0010110 * 2 -2 , es decir, al mover la coma binaria 7 posiciones a laizquierda el exponente aumenta en 7 unidades.Ahora ya podemos representar mantisa y exponente en binario:mantisa = 1,0010110exponente = 11111110 (-2)Por último empaquetamos el número, para lo cual, la fracción se calcula comolos dígitos a la derecha de la coma y el exponente polarizado se calcula comoel exponente no polarizado más 2 n-1 =2 7 =128, es decir el exponentepolarizado será -2+128=126:fracción = 0010110 00000000 00000000 00000000exponente polarizado = 01111110Pág 188


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgComo el signo es positivo valdrá 0, <strong>con</strong> lo que la representación <strong>del</strong> númeroempaquetado en una variable de tipo simple será la que se muestra en laFigura A.6:Signo Exponente polarizadoFracción00111 1110 0010110 00000000 000000001b 8b 23bFigura A.6: Representación de un número simpleDe los cuatro formatos definidos por el IEEE 754, sólo el formato simple esobligatorio de implementar, el formato doble es recomendado y todas lasimplementaciones de IEEE 754 existentes lo implementan. Por último losformatos simple extendido y doble extendido sólo los tienen algunasimplementaciones. <strong>PowerPC</strong> implementa los formatos simple, doble y dobleextendido, pero no el simple extendido.En lenguaje C estos formatos están representados por los tipos de datos de laTabla A.4:Formato IEEE 754SimpleDobleDoble extendidoTipo Cfloatdoublelong doubleTabla A.4: Tipos de datos C para números un punto flotanteEl tamaño de los campos para los formatos simple y doble está estandarizadopor el IEEE 754 y son los que se muestran el la Tabla A.5, pero el tamaño <strong>del</strong>os campos para los formatos simple extendido y doble extendido no estánestandarizados por el IEEE 754, sino que el IEEE754 sólo da unos tamañosmínimos para cada campo.Formato Signo Exponente Fracciónsimple 1 8 23doble 1 11 52simple1 ≥10 ≥32extendidodoble extendido 1 ≥16 ≥64Tabla A.5: Tamaños de los campos de cada uno de los formatos <strong>del</strong> IEEE 754El formato simple extendido actualmente no lo implementa nadie, pero eldoble extendido si que está implementado, tanto por Intel, como porPág 189


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org<strong>PowerPC</strong> y SPARC, aunque la forma en que lo implementan varía de unmicroprocesador a otro.Vamos a ver más detenidamente como lo implementa cada uno: Tanto<strong>PowerPC</strong> como SPARC lo implementan en un número de 128 bits (16 Bytes)como muestra la Figura A.7:Signo ExponenteFracción1b 15b 112b16 BFigura A.7: Representación de los double extendidos en <strong>PowerPC</strong> y SPARCIntel, sin embargo, lo implementa en un número de 96 bits (12 bytes) comoel que muestra la siguiente figura:ExplicitSin usar Signo Exponente leadingFracción16b 1b 15b 1b 63b12 BFigura A.8: Representación de los double extendidos por IntelLa especificación de Intel dice que de los 12 bytes sólo se usan 10 bytesdejando 2 bytes vacíos. El bit explicit leading almacena el 1 que hay a laizquierda de la fracción, que aunque normalmente es implícito, aquí se haceexplícito. Esto será útil cuando veamos los números desnormalizados en elapartado 3.1 donde veremos que aquí puede ir un 0.Por último comentar que los exponentes <strong>con</strong> valor máximo y mínimo (0 y 255en el caso <strong>del</strong> formato simple) se utilizan <strong>con</strong> valores especiales, comomuestra la Tabla A.6, y que comentaremos en los siguientes apartados.Valor especial Signo Exponente Fracción0 0 ó 1 0 0Número denormalizado 0 ó 1 0 cualquiera+∞ 0 máximo 0-∞ 1 máximo 0NaN 0 ó 1 máximo !=0Tabla A.6: Representación de valores especialesPág 190


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgEl número 0 es uno de estos valores especiales y se representa poniendotodos los bits a cero, salvo quizá el de signo que se puede activar pararepresentar el -0. A efectos prácticos 0 y -0 son idénticos, pero existendeterminadas ocasiones en las que se comportan de forma diferente, porejemplo al calcular 1/-0 = -∞. en principio el lector no debería de darle másimportancia, salvo para recordar que el cero en notación de punto flotante sepuede representar de dos formas distintas.3.1 Números denormalizadosAntes comentamos que la mantisa era igual a la fracción <strong>con</strong> un 1 <strong>del</strong>ante <strong>del</strong>a coma binaria. Esto nos limita el número más pequeño que podemosrepresentar. Por ejemplo en notación simple donde el exponente tiene 8 bits yla fracción tiene 23 bits, el número más pequeño que podemos representar esel ±1*2 -127 , que en decimal nos viene a dar el número ±5,8*10 -39 .Una característica <strong>del</strong> estándar IEEE 754 es que permite representar númerospor debajo de este umbral, a los que llaman números denormalizados,para ello lo que hacemos es dejar el exponente polarizado a 0 de forma queahora la parte fraccionaria se interpreta como si a la izquierda de la comahubiera un 0 en vez de un 1.Por ejemplo, si en<strong>con</strong>tramos el número simple empaquetado que muestra laFigura A.9:Signo ExponenteFracción0 0000 00000010000 00000000 000000001b 8b 23bFigura A.9: Ejemplo de número denormalizadoEste número se interpreta como 0,001*2 -128Cuando un número es tan pequeño que ya no se puede representar como unnúmero normalizado se dice que el número de ha degradado (underflow).¿Por qué el estándar permite almacenar números denormalizados en vez desimplemente redondearlos a 0?, una razón es que de esta forma elprogramador puede saber que se está acercando a un número“peligrosamente pequeño”, lo cual es especialmente útil en el cálculo dealgunos valores matemáticos como los límites. Si por ejemplo nosotroshacemos un programa que busca calcular:lim 1/xx->∞Pág 191


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgEl programa podría determinar que hemos entrado en un númerodenormalizado y detener un supuesto bucle. Esto es a lo que se llama eldegradamiento gradual a cero.Para una discusión matemática más a fondo sobre este tema puede <strong>con</strong>sultar[UNDERFLOW].3.2 Números especialesOtra peculiaridad <strong>del</strong> estándar IEEE 754 es que nos permite representar losvalores +∞ y -∞, para ello utiliza los patrones de bits especiales de la FiguraA.10:+ ∝ 1111 11110000000 00000000 00000000- ∝ 1111 11111000000 00000000 00000000Figura A.10: Representación de +∝ y -∝Es decir, el exponente se pone al máximo valor, la fracción se pone a cero yel bit de signo indica si es +∞ ó -∞.Cuando el resultado de un cálculo es tan grande que no se puede representaren el formato utilizado se usa esta forma de devolver infinito.Por último la otra gran peculiaridad <strong>del</strong> estándar IEEE 754 es que puederepresentar números no válidos que se obtienen en cálculos especiales comopor ejemplo 0/0, ∞+(-∞), o la raíz de un número negativo. Estos son valoresindefinidos en el campo de los números reales y se representan <strong>con</strong> el valorespecial NaN (Not a Number). Este valor se codifica dejando el exponentea su valor máximo y dejando una fracción distinta de cero tal como muestrala Figura A.11, <strong>con</strong> lo que más que haber un número NaN, hay una familiacompleta de NaN.NaN 0 1111 1111xxxxxxx xxxxxxxx xxxxxxxxFigura A.11: Representación de NaNEl valor NaN se propaga entre las operaciones aritméticas, de forma que siuno de los operandos de una operación aritmética es NaN, el resultado de laoperación también será NaN.Pág 192


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgLos NaN pueden ser de dos tipos: quiet NaN y signaling NaN. Cuando unsignaling NaN se encuentra en una operación aritmética, si está activo eltratamiento de excepciones se produce una excepción. Cuando se encuentraun quiet NaN no se produce la excepción.Los signaling NaN no tienen por qué ser producidos por operacionesaritméticas no válidas, nosotros mismos podemos crearlos manualmente, porejemplo para rellenar un área de memoria sin inicializar, de forma que si elprograma encuentra un número de estos podemos saber que el programa aaccedido a un trozo de memoria sin inicializar.Cuando realizamos una operación aritmética que produce un resultado noválido obtenemos un signaling NaN. Si usamos este valor para ejecutar otraoperación aritmética este produce un quiet NaN. Esto es útil porque si hay unproblema de cálculo, la excepción sólo se producirá una vez.Los NaN toman distintos valores en su parte fraccionaria indicando la causa<strong>del</strong> error. La Tabla A.7 muestra los valores que puede tomar el campo de lafracción:Decimal Hexadecimal Significado1 0x01 Raíz cuadrada invalida (p.e. raíz de -1)2 0x02 Suma invalida (p.e. (+∞)-(-∞))4 0x04 División inválida (p.e. 0/0)8 0x08 Multiplicación inválida (p.e. 0*∞)9 0x09 Resto inválido (p.e. x%0)17 0x11 Intento de <strong>con</strong>vertir cadena ASCII inválida21 0x15 Intento de crear un NaN <strong>con</strong> código cero33 0x21 Parámetro inválido para una funcióntrigonométrica (p.e. sin(), cos(), tan())34 0x22 Parámetro inválido para una funcióntrigonométrica inversa (p.e. acos(), asin(),atan())36 0x24 Parámetro inválido para una función logarítmica(p.e. log() o ln())37 0x25 Parámetro inválido para una función exponencial(p.e. exp())38 0x26 Parámetro inválido para una función financiera40 0x28 Parámetro inválido para una función hiperbólicainversa (p.e. acosh() o asinh())42 0x2A Parámetro inválido para una función gamma (p.e.gamma() o lgamma())Tabla A.7: Significado de la parte fraccionaria de un NaNPág 193


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgPara indicar si el número es un signaling NaN o un quiet NaN se usa el bitmás significativo de la fracción. Para indicar la causa <strong>del</strong> NaN se usan losvalores de la tabla anterior puestos a la derecha de la fracción y desplazados8 posiciones a la izquierda tal como muestra la Figura A.12:Signaling NaN 0 1111 1111000000 xxxxxxxx 00000000Quiet NaN 1 1111 1111100000 xxxxxxxx 00000000Figura A.12: Representación signaling NaN y quiet NaN3.3 Rangos máximos y mínimos en los números enpunto flotantePara acabar de ver el formato de los números en punto flotante vamos ahacer un estudio de cuáles son los rangos de los números máximos y mínimosque podemos representar <strong>con</strong> cada formato.Los rangos exactos se describen en la Tabla A.8:FormatoMínimoMínimoMáximodenormalizado normalizadoSimple 3,5*10 -46 5,8*10 -39 1,7*10 38Doble 1,2*10 -324 1,1*10 -308 8,9*10 307Doble extendido 1,6*10 -4966 1,6*10 -4932 5,9*10 4931Tabla A.8: Rangos de los distintos tipos de datos en punto flotanteVamos a explicar cómo se calculan estos rangos. Sólo vamos a ver cómo secalcularían para el formato simple, aunque el mismo razonamiento se puedeaplicar para los demás tipos.El número máximo representable en formato simple sería aquel que tieneactivos todos los bits de la fracción y el exponente toma el valor máximo+126, ya que +127 se usa para representar los infinitos, luego este númerosería:1,1111111 11111111 11111111 * 2 126 ≈ 2 127 = 1,7*10 38Para calcular el número mínimo normalizado sería aquel que tiene el 1 de laizquierda de la coma de la mantisa, pero toda la parte fraccionaria a 0 y comoexponente -127 (-128 se usa para representar el cero y los númerosdenormalizados), luego sería:Pág 194


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org1,0000000 00000000 00000000*2 -127 = 5,8*10 -39Por último el número denormalizado más pequeño que se puede representaren formato simple sería aquel que tiene el exponente a -128 y la mantisa <strong>con</strong>un cero a la izquierda de la coma, y la fracción <strong>con</strong> todo ceros excepto el bitmenos significativo que estará a 1.0,0000000 00000000 00000001*2 -128 = 2 -151 = 3,5*10 -46Pág 195


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org4 El problema <strong>del</strong> redondeo en punto flotante4.1 La precisión en punto flotanteUn hecho evidente <strong>con</strong> el que nos vamos a en<strong>con</strong>trar cuando trabajamos <strong>con</strong>números en punto flotante es que tenemos que representar infinitos númerosreales usando sólo un <strong>con</strong>junto finito (aunque muy grande) de númerosbinarios en notación de punto flotante. Para afrontar este problema vamos autilizar redondeos, donde lo que hacemos es representar un número realusando el número en punto flotante más cercano a él.Un caso claro donde se aprecian los problemas de redondeo es en el hechode que los números en punto flotante decimal y punto flotante binario serepresentan de forma distinta. Por ejemplo el número 183234,373 tiene unarepresentación exacta en punto flotante decimal, pero si lo intentamos pasara notación de punto flotante binaria obtenemos un número periódico:1,0110010 11110000 10011000...Esto provoca que al almacenar este número en formato simple (float) en unordenador y luego recuperarlo, en vez de volver a obtener el 183234,373obtengamos el 183234,3729999... Este problema se acentúa más cuando másgrande es el número.Un hecho importante que <strong>con</strong>viene resaltar es el de que los números enpunto flotante se encuentran desigualmente distribuidos, de forma que losnúmeros pequeños (los más cercanos a 0) están más juntos entre sí que losnúmeros más grandes (los más cercanos a ±∞).Para ver este hecho podemos dibujar los números en una línea decoordenadas suponiendo que tenemos números en notación de punto flotantebinario <strong>con</strong> una parte fraccionaria de 3 bits. En este caso se cumple la reglade que entre 2 n-1 y 2 n habrá un total de 8 números uniformementedistribuidos. Esta regla será cierta para cualquier n, aunque la distancia sedobla cada vez que incrementamos n tal como observamos en la Figura A.13.0 2 -1 2 0 2 1 2 2 2 3 2 4Figura A.13: Distribución de los números en punto flotantePág 196


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgO sea, el número de elementos entre cada par 2 n-1 y 2 n es <strong>con</strong>stante, aunqueno su separación, lo cual produce el efecto indicado.Esto implica que la precisión que <strong>con</strong>siguen los redondeos cuando estamostrabajando <strong>con</strong> números pequeños sea mucho mayor que la que se <strong>con</strong>siguecuando estemos trabajando <strong>con</strong> números grandes. Obsérvese que en parteesto es normal, ya que no es la misma la precisión <strong>con</strong> la que trabaja, porejemplo, un microscopio, en la que una micra puede echar a perder todos loscálculos, que la precisión que necesita un astrónomo al calcular la distanciade la tierra al sol, o la distancia entre galaxias, donde unos miles de metrosmás o menos son inapreciables.4.2 Error absoluto y relativoYa que los errores de redondeo son inherentes a los números en puntoflotante, es importante buscar un método para medirlos. Consideremos comoejemplo un sistema de representación de números en punto flotante decimaly <strong>con</strong> una fracción de 3 dígitos. Si el resultado de un cálculo en punto flotantenos da 3,12*10 -2 , y el cálculo <strong>con</strong> una precisión infinita es 0,0314, es claroque el error es de dos unidades en el último dígito. Del mismo modo, si elnúmero real 0,0314159 se representa en nuestro sistema de punto flotantecomo 3,14*10 -2 , entonces el error es de 0,159 unidades <strong>del</strong> último dígito. Unmétodo muy usado para medir los errores es medir el error usando comomagnitud las unidades en el último dígito (uud), en el ejemplo anteriorlos errores serian respectivamente 0,2 uud y 0,159 uud.Se sabe que si un sistema de cálculo en punto flotante calcula correctamentelos valores (<strong>con</strong> precisión infinita), el error máximo que puede cometer es de0,5 uud. Esto se debe a que después de calcular un valor (<strong>con</strong> precisióninfinita) debe representarlo en punto flotante, <strong>con</strong> lo que el redondeo produceuna perdida de precisión máxima de 0,5 uud.En general se busca que los sistemas aritméticos que diseñemos tengan unerror máximo de 0,5 uud, en cuyo caso al sistema aritmético se le <strong>con</strong>sideracorrecto.Téngase en cuenta que éste es un sistema de medición de errores relativo yaque si por ejemplo un número que estamos calculando <strong>con</strong> precisión infinitavale 4,56323*10 20 y el sistema de punto flotante nos devuelve el número4,56*10 20 , aunque el error es de 0,323 uud, el error absoluto es de323*10 17 =32.300.000.000.000.000.000 unidades. Sin embargo, los errores deredondeo que se pueden producir en números pequeños son tambiénpequeños. Por ejemplo en precisión simple si intentamos representar unnúmero <strong>con</strong> exponente 0 el error máximo que podemos cometer durante elredondeo es de 0,5 uud, es decir 2 -23 /2=5,9*10 -9 , que es un número bastantepequeño.Pág 197


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org4.3 Modos de redondeoEl estándar IEEE 754 define 4 modos de redondeo, los cuales indican cómorealizar un redondeo cuando un número real no se puede representarexactamente en la notación de punto flotante utilizada.El modo por defecto es el modo de redondeo al más cercano, queredondea a un número par en caso de empate. Por ejemplo si tenemos unafracción de 3 dígitos 1,4015 se redondearía a 1,402Los otros modos de redondeo son redondeo hacia cero, redondeo hacia+∞ y redondeo hacia -∞. Todo sistema de numeración en punto flotanteque siga el estándar IEEE 754 debe disponer de un mecanismo que nospermita cambiar este modo de redondeo. En el caso de <strong>PowerPC</strong> se usa el losflag RN <strong>del</strong> registro FPSCR para indicar el tipo de redondeo de acuerdo a laTabla A.9.Flags RN Modo de redondeo00 Redondeo al más cercano01 Redondeo a 010 Redondeo a +∞11 Redondeo a -∞Tabla A.9: Modos de redondeoPág 198


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org5 Las excepcionesCuando se produce una situación anómala en la ejecución de instrucciones depunto flotante se produce una excepción. IEEE 754 recomienda que existanflags asociados a las excepciones, en el caso de <strong>PowerPC</strong> estos flags están enel registro FPSCR. Al empezar un programa su ejecución todos los flag deexcepción están apagados. Cuando se produce una excepción se activa elflag apropiado, pero la aplicación se <strong>con</strong>tinúa ejecutando. Después laaplicación puede <strong>con</strong>sultar los flag de excepción o bien modificarlos.El estándar también recomienda que para cada tipo de excepción haya unflag de habilitación de trap de excepción, de forma que si hay unaexcepción <strong>con</strong> su flag de trap habilitado se llame al manejador de trap.Además recomienda el uso <strong>del</strong> flag de habilitación de excepción, quecuando están activos indican que si una excepción se produce se encienda sucorrespondiente flag de excepción. Si están apagados, el flag de excepciónno se encenderá a pesar de que se produzca la excepción. Losmicroprocesadores que sólo disponen de flags de habilitación de excepción nopermite que el sistema operativo pueda reaccionar ante una excepción, sinoque es el propio programa el que, tras ejecutar una instrucción, debe decomprobar si se ha encendido algún flag de excepción.El usar los flags de habilitación de excepción se <strong>con</strong>sidera mejor que el uso detraps, ya que a la hora de ejecutar instrucciones como:fdiv f0,f1,f2fadd f2,f3,f4En un sistema segmentado (ver Apéndice B para una descripción de lossistemas segmentados) se podrían intentar ejecutar las dos instrucciones<strong>con</strong>currentemente, donde la instrucción fdiv tarda más que la instrucciónfadd, y si ahora se produjese una excepción en una de ellas el gestor detraps tendría problemas para saber cual de ellas ha producido la excepción.<strong>PowerPC</strong> permite tanto usar flags de habilitación de traps como usar flags dehabilitación de excepción, será el diseñador <strong>del</strong> sistema operativo quien debatomar esta decisión.IEEE 754 define cinco tipos de excepciones que vamos a detallar. Lasimplementaciones son libres de disponer de más flags de excepción si lo<strong>con</strong>sideran apropiado, tal como pasa en <strong>PowerPC</strong> que dispone de una grancantidad de flags de excepción, aunque básicamente las excepciones sepueden resumir en estas cinco.Pág 199


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgAdemás estos flag pueden ser flags retenidos (sticky), no serlo, o bienexistir un flag de retenido y su correspondiente de no retenido, a elección <strong>del</strong>a implementación.Las cinco excepciones que define IEEE 754 son:1. Invalid Operation. Ocurre si algún operando es inválido para laoperación que estamos realizando. Esto ocurre siempre que un operando seaun NaN. También ocurre en los casos descritos en la Tabla A.10:Operación Invalid OperationSuma o resta Suma o resta de infinitos. P.e. (+∞)+(-∞)Multiplicación 0*∞División 0/0 ó ∞/∞Restox%y si y=0 ó x=±∞Raíz cuadrada Con un operando negativoComparación Cuando los operandos son ±∞ o NaNTabla A.10: Causas de una Invalid Operation2. Underflow. Ocurre cuando el resultado de la operación es demasiadopequeño para ser almacenado en el formato utilizado. En este caso el númerotoma el valor 0 y activa el flag de excepción.3. Overflow. Ocurre cuando el número obtenido es demasiado grande paraser almacenado en el formato utilizado. En este caso el número toma el valor±∞ y activa el flag de excepción.4. Divide-by-zero. Ocurre cuando dividimos un número entre cero. Tambiénocurre cuando intentamos calcular el logaritmo de 0 que es -∞.5. Inexact. Ocurre siempre que hay que redondear un número por no existiruna representación exacta de ese número en punto flotante. Se usa porque elprograma puede estar interesado en saber si ha habido redondeo, los cualesse vuelven especialmente perjudiciales cuando hay una acumulación deoperaciones <strong>con</strong> redondeo.Pág 200


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org6 Suma en punto flotanteHay dos diferencias entre la aritmética en punto flotante y la aritméticaentera: Debemos mantener un campo para el signo, otro para exponente yotro para la parte fraccionaria, y el resultado de una operación en puntoflotante, habitualmente, se ha de redondear al número más cercanorepresentable en el formato utilizado.6.1 RedondeoCon el fin de poder desarrollar software que se pueda ejecutar de la formamás homogénea posible en distintas plataformas, el estándar <strong>del</strong> IEEE 754 hadefinido una regla respecto a cómo deben de realizarse las operacionesaritméticas entre números en punto flotante:El resultado de una operación aritmética entre dos números en puntoflotante, ha de ser el mismo que si primero se realizase la operación <strong>con</strong>precisión infinita, y después se redondease ese resultado a un númerorepresentable en el formato que estemos utilizando, usando el método deredondeo que esté actualmente activo.Esta regla que en principio parece difícil de cumplir, por la dificultad que tieneun ordenador para realizar cálculos <strong>con</strong> precisión infinita, no es tan difícilcomo parece, de hecho, veremos que podemos obtener los resultados quepide la regla, <strong>con</strong> sólo un poco más de esfuerzo.En el caso de la suma, para obtener el resultado de la forma pedida lo únicoque tenemos que hacer es añadir dos bits de guarda al final de los registrossumadores, y un bit de retención (stricky bit). Veamos cómo se haceesto.Para facilitar el estudio vamos a suponer que tenemos un sistema de puntoflotante decimal <strong>con</strong> tres bit para la mantisa. Hay dos formas de redondeoque se pueden presentar durante la suma:El primer caso requiere redondeo debido al acarreo de salida a la izquierda.Por ejemplo:2,34*10 28,51*10 2 +––––––––10,85*10 2 ––––> Redondea a 10,8*10 2El segundo caso requiere redondeo debido a exponentes desiguales, Porejemplo:Pág 201


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org2,34*10 22,56*10 0 +––––––––2,3656*10 2 ––––> Redondea a 2,37*10 2De hecho es posible que se den a la vez ambas formas:9,51*10 26,42*10 1 +––––––––10,152*10 2 ––––> Redondea a 10,2*10 2En cada uno de estos casos la suma se debe calcular <strong>con</strong> más dígitos <strong>con</strong> elfin de realizar correctamente el redondeo. Se ha demostrado que para que elresultado de una suma en punto flotante sea el mismo que si redondeásemosel resultado de una suma <strong>con</strong> precisión infinita, basta <strong>con</strong> disponer de dos bitsadicionales a la derecha de los registros <strong>del</strong> sumador, llamados bits deguarda.La situación peor sería una situación como esta:4,5674*10 02,5001*10 -4 +–––––––––4,56765001*10 0 ––––> Redondea a 4,5677*10 0Aunque aquí pudiera parecer que se necesita mantener doble número dedígitos para realizar un redondeo correcto, ya que el 1 más a la derecha de2,5001 determina si el resultado es 4,5676 ó 4,5677, después de unapequeña reflexión se puede ver que sólo es necesario saber si hay o no másdígitos distintos de cero pasadas las posiciones de guarda, esta informaciónse puede almacenar en un sólo bit llamado bit de retención (stricky bit), quese implementa examinando cada dígito que está despreciado debido a undesplazamiento. Tan pronto como aparece un dígito distinto de cero, el bit deretención se pone a 1 y permanece <strong>con</strong> este valor. Para implementar elredondeo al par más cercano simplemente añadimos el bit de retención a laderecha <strong>del</strong> dígito más a la derecha justo antes de redondear.6.2 El algoritmo de la sumaLas notaciones e i y m i se utilizan aquí para referirnos al exponente y lamantisa desempaquetados <strong>del</strong> número en punto flotante a i . Suponiendo quelos números en punto flotante a 1 y a 2 no <strong>con</strong>tengan valores especiales, elprocedimiento básico para sumarlos <strong>con</strong>sta de cinco pasos:Pág 202


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org1. Si e 1


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgVemos que el resultado es el mismo que si hubiéramos usado un sumador deprecisión infinita y luego hubiéramos redondeado, <strong>con</strong> lo que el resultado escorrecto.El paso 4 involucra la suma de números <strong>con</strong> signo y magnitud, y en sí mismotiene tres pasos:a. Convertir cualquier número negativo en su complemento a dosb. Realizar una suma de |m|+4 bits en complemento a dos: |m|+3bits de magnitud y 1 bit de signoc. Si el resultado es negativo, realizar otra complementación a dospara volver a poner el resultado en la forma de signo y magnitud.Pág 204


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org7 Multiplicación en punto flotanteVamos a ver cómo se haría la multiplicación en punto flotante suponiendo quelos operandos de entrada no <strong>con</strong>tienen valores especiales.La multiplicación en punto flotante es parecida a la multiplicación entera quevimos en el apartado 1.1.3. Debido a que los números en punto flotante sealmacenan en forma de signo-magnitud, el multiplicador sólo necesita tratar<strong>con</strong> números sin signo. Si las mantisas son números sin signo de |m| bits,entonces el producto puede tener hasta 2|m| bits y se debe redondear a unnúmero de |m| bits. Además de multiplicar las mantisas se deben de sumarlos exponentes.Sean a 1 y a 2 los números a multiplicar de los cuales hemos desempaquetadolas mantisas m 1 y m 2 y los exponentes e 1 y e 2 , el algoritmo que nos permiterealizar la multiplicación de números en punto flotante sería:1. Usando el multiplicador <strong>del</strong> apartado 1.1.3 multiplicar las dos mantisasm 1 y m 2 para obtener un producto de 2|m| bits en los registros P:A.Además los bits que se pierden por la derecha de A según avanza elalgoritmo, se les debe de hacer un or binario <strong>con</strong> el bit de retención.2. Al acabar el algoritmo se suma el bit de retención 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| bitsusando el modo de redondeo que esté activo obteniendo así la nuevamantisa m 3 .4. Para calcular el exponente resultado e 3 , se calcula como la suma de losexponentes de los operandos de entrada e 1 y e 2 .Ejemplo: Multiplicar los números en punto flotante decimal a 1 =67,45*10 2 ya 2 =34,98*10 0 usando una mantisa de |m|=4 bitsPrimero multiplicamos las mantisas obteniendo el resultado en un registro de8 bits:67,45x 34,98––––––––––2359,4010Ahora redondeamos el número obteniendo la mantisa resultado m 3 =2359El exponente resultado se obtiene como la suma de los exponentes deentrada e 1 e 2 , luego e 3 =2+0=2Finalmente tenemos que el producto 67,45*10 2 *34,98*10 0 =2359*10 2Pág 205


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org8 División y resto en punto flotantePodemos obtener el algoritmo de la división en punto flotante a partir <strong>del</strong>algoritmo de la división de enteros que vimos en el apartado 1.1.4 de formasimilar a como hemos obtenido el algoritmo de multiplicación en puntoflotante a partir <strong>del</strong> algoritmo de multiplicación de enteros. Además estealgoritmo nos proporciona el resto de la división el cual es útil a la hora dehacer los redondeos.Sea a 1 el dividendo y a 2 el divisor desempaquetados sus respectivas mantisasm 1 y m 2 y sus exponentes e 1 y e 2 . El algoritmo para calcular a 3 =a 1 /a 2 sería elsiguiente:1. Usando el divisor de enteros <strong>del</strong> apartado 1.1.4 dividir las dos mantisasm 1 y m 2 para obtener un cociente de |m| bits en el registro A y unresto en el registro P.2. Si el resto r 3 así obtenido es mayor a la mitad <strong>del</strong> divisor entonces alcociente se le suma uno, si no se deja igual, es decir, si 2*r 3 >a 2entonces a2=a2+1, si 2*r3=a2 se aplica el método de redondeo queesté activo, si no a2 se deja como está.3. Para calcular el exponente resultado e 3 , se calcula como e 3 =e 1 -e 2 .Ejemplo: Dados los números en punto flotante decimal a 1 =23,52*10 2a 2 =12,75*10 0 calcular a 1 /a 2 usando una mantisa de |m|=4 bits.yPrimero dividimos las mantisas:Dividendo=2352Divisor=1275Obteniendo:Cociente = 1844Resto = 900Ahora como el resto es mayor a 1/2 cociente debemos sumar uno al cocienteobteniendo:Cociente = 1845Resto = 900Por último calculamos el exponente e 3 =e 1 -e 2 =2-0=2, <strong>con</strong> lo que finalmentetenemos que el resultado de la división es:(23,52*10 2 ) / (12,75*10 0 ) = 18,45*10 2Pág 206


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org9 Comparaciones y <strong>con</strong>versionesIEEE 754 define que un sistema en punto flotante debe de disponer deoperaciones que permitan comparar números en punto flotante. La tricotomíacomparativa usual de los números reales se extiende en el estándar para quesólo una de estas cuatro comparaciones sea cierta:o abo a=bo a y b no mantienen relación de ordenSi a ó b valen NaN, entonces se dice que a no mantiene una relación deorden respecto a b, en caso <strong>con</strong>trario se cumple una de las otras tres<strong>con</strong>diciones: ,=IEEE 754 también requiere que el sistema de numeración en punto flotantedisponga de las siguientes operaciones de <strong>con</strong>versión:o De punto flotante a enteroo De entero a punto flotanteo De punto flotante a entero, <strong>con</strong> el resultado en punto flotanteo Entre todos los formatos de punto flotante que existano Entre punto flotante binario y punto flotante decimalEstas <strong>con</strong>versiones puede proporcionarlas el propio sistema hardware(ensamblador) o bien proporcionarse por software (librerías numéricas en C).Pág 207


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgApéndice BLa segmentaciónSinopsis:Este apéndice está pensado para lectores que des<strong>con</strong>ozcan en que <strong>con</strong>siste lasegmentación, la cual se menciona repetidamente en distintos <strong>con</strong>textos <strong>del</strong>os temas anteriores.Actualmente todos los microprocesadores de alto rendimiento que se fabricanson segmentados. A <strong>con</strong>tinuación vamos a ver en que <strong>con</strong>siste lasegmentación y las ventajas de rendimiento que introduce.Pág 208


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org1 ¿Que es la segmentación?La segmentación (pipelines) es un técnica usada por losmicroprocesadores más avanzados (la mayoría de los procesadores actuales:Pentium, SPARC, <strong>PowerPC</strong>, Alpha,...) por la cual se solapa la ejecución devarias instrucciones.En las máquinas segmentadas una instrucción se divide en varias etapas osegmentos, cada una de las cuales corresponde <strong>con</strong> un ciclo de reloj. Deesta forma la segmentación ejecuta las instrucciones como si fuera unacadena de montaje, donde en cada ciclo de reloj se ejecuta una etapa de lainstrucción.Lo importante de esta división en etapas es que nos permite tener variasinstrucciones ejecutándose a la vez, aunque cada una de ellas en una etapadistinta, como si se tratase de una cadena de montaje de automóviles, dondehay varios automóviles fabricándose en etapas distintas.Aunque <strong>con</strong> variaciones dependiendo <strong>del</strong> microprocesador, las principalesetapas en que se descompone una instrucción segmentada suelen ser:• Fetch (FE). La instrucción que está en la dirección de memoria <strong>del</strong> IPse recoge de memoria al micro. Además incrementa el IP para queapunte a la siguiente instrucción• Decode (DE). Decodifica la instrucción.• Dispatch (DI). Lee los operandos de los registros indicados en lainstrucción, o la dirección de memoria indicada en la instrucción, parapasarlos a la unidad funcional que corresponda.• Execute (EX). La operación indicada por la instrucción se ejecuta enla unidad funcional que corresponda.• Write Back (WB). El resultado de ejecutar la instrucción se escribeen los registros o en la memoria.Normalmente el micro dispone de varias unidades funcionales, que son laspartes <strong>del</strong> microprocesador donde se realizan las operaciones indicadas en lasinstrucciones. Aunque el número y tipo de unidades funcionales de un microdependen de la implementación, de forma general podemos decir que unmicro 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 <strong>con</strong> enteros.• Floating-Point Unit. Se encarga de las operaciones <strong>con</strong> decimales.Además normalmente las unidades funcionales están segmentadas <strong>con</strong> el finde que puede haber varias instrucciones usando la unidad funcional.Segmentar las unidades funcionales es muy costoso, y hay microprocesadoresPág 209


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgque no las segmentan, en cuyo caso esa unidad funcional sólo puede serusada por una instrucción a la vez.De cada uno de los tres tipos de unidades funcionales que existen, un microsuele disponer de más de una, <strong>con</strong> el fin de que varias instrucciones puedanestar ejecutando en distintas unidades funcionales <strong>del</strong> mismo tipo, aunque sila unidad funcional está segmentada, esto podría no ser tan necesario.Visto esto podríamos representar la ejecución simultánea de instrucciones enun micro segmentado tal como muestra la Figura B.1:InstrucciónCiclo de reloj1 2 3 4 5 6 7 8 9Instrucción i FE DE DI EX WBInstrucción i+1 FE DE DI EX WBInstrucción i+2 FE DE DI EX WBInstrucción i+3 FE DE DI EX WBInstrucción i+4 FE DE DI EX WBFigura B.1: Ejecución simultánea de instrucciones en un micro segmentadoEn este caso suponemos que el microprocesador tiene 5 pipes, de aquí vieneel nombre de pipelines, que a veces se da a la segmentación.Aunque cada instrucción necesita 5 ciclos de reloj, la ejecución simultánea <strong>del</strong>as instrucciones nos permiten que cada instrucción tenga un tiempo mediode ejecución de 1 ciclo. Esto se formaliza de la siguiente forma:Llamamos latencia, al tiempo (normalmente medido en ciclos de reloj)necesario para ejecutar una instrucción.Llamamos caudal (throughput) al número de instrucciones ejecutadas porunidad de tiempo (también medido en ciclos de reloj).Obsérvese que en el ejemplo anterior aunque la latencia de una instrucción esde 5 ciclos, el caudal es de 1 ciclo, ya que en 5 ciclos hemos ejecutado 5instrucciones. El lector debe de ser <strong>con</strong>sciente de que en la Figura B.1 setardan 9 ciclos por el hecho de que el micro está “arrancando” y “parando”,pero en circunstancias normales el micro permanece <strong>con</strong> los 5 pipes llenos.Vemos que la segmentación incrementa la productividad de las instrucciones,pero no aumenta el tiempo de ejecución de una instrucción individual, dehecho la decrementa un poco debido a dos factores:Por un lado la duración de todas las etapas no es exactamente la misma, sinoque hay etapas que tardarían menos en terminarse que otras, pero el diseño<strong>del</strong> procesador obliga a utilizar como ciclo de reloj el tiempo de la etapa máslarga, <strong>con</strong> lo que es muy importante que las etapas estén perfectamentePág 210


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgequilibradas, pero en la práctica esto no siempre es posible y se suelenproducir reducciones en el rendimiento que no suelen superar, digamos, un10%.Por otro lado entre las etapas hay que dejar un pequeño tiempo de reajustede los cerrojos (latchs) que <strong>con</strong>ectan las distintas etapas que es lo que sellama el sesgo de reloj (clock skew).Como ejemplo de esto último vamos a estudiar la mejora de rendimiento que<strong>con</strong>seguimos en una máquina gracias a la segmentación. Supongamos quetenemos una máquina no segmentada <strong>con</strong> 5 pasos por instrucción <strong>con</strong>tiempos: 50ns, 50ns, 60ns, 50ns, 50ns. Suponer que debido al sesgo de reloj,segmentar la máquina añade 5ns de gasto en cada etapa de la ejecución.¿Qué incremento de rendimiento se ganará <strong>con</strong> la segmentación de esamáquina en una máquina que disponga de 5 pipes?La Figura B.2 (a) muestra la ejecución de instrucciones sin segmentación y laFigura B.2 (b) la ejecución de las mismas instrucciones <strong>con</strong> segmentación.260 260 26050 50 60 50 50 50 50 60 50 50 50 50 60 50 50Instrucción 1 Instrucción 2 Instrucción 3(a) Ejecución no segmentada455Instrucción 1Instrucción 2Instrucción 365 65 65 65 6565 65 65 65 6565 65 65 65 65(b) Ejecución segmentadaFigura B.2: Ejecución de instrucciones <strong>con</strong> y sin segmentaciónVemos que sin segmentar, el tiempo medio de ejecución de una instrucciónes de:50ns + 50ns + 60ns + 50ns + 50ns = 260nsLuego 5 instrucciones se ejecutan en 5*260ns=1300nsMientras que en una máquina segmentada (suponiendo que no estamosarrancando o parando) el tiempo de ejecución de 5 instrucciones es:5*65ns=325ns. Con lo que la mejora de rendimiento es de:Pág 211


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgR=1300ns/325ns=4Es decir se <strong>con</strong>sigue un rendimiento 4 veces superior en la máquinasegmentada, y no las 5 veces teóricas que veíamos al principio.2 Etapas multicicloNo es práctico exigir que todas las etapas de una instrucción se ejecuten enun solo ciclo de reloj, como por ejemplo en las operaciones de punto flotante.Hacer esto significaría aceptar un reloj lento.En la práctica, una etapa de una instrucción puede duran varios ciclos dereloj, por ejemplo las operaciones de suma y resta de entero se ejecutan enun solo ciclo EX, mientras que la multiplicación en coma flotante suele<strong>con</strong>sumir hasta 5 ciclos EX, y la división hasta 20 ciclos EX.Luego la ejecución de una instrucción de multiplicación de punto flotante sepodría representar así:FE DE DI EX EX EX EX EX WBObsérvese que esto hace que la unidad funcional de punto flotantepermanezca ocupada durante todos los ciclos que dura la etapa EX,impidiendo que otra instrucción la use. Para evitarlo, se suelen aplicar dossoluciones: Disponer de varias unidades funcionales de punto flotante, o bien,segmentar la unidad funcional para que puedan entrar varias instrucciones depunto flotante a tiempos distintos.El mismo problema le en<strong>con</strong>tramos en las instrucciones que acceden amemoria, en las que cuando el dato accedido está en caché, la etapa <strong>del</strong>ectura de memoria DI, o la de escritura en memoria WB se completan en unsolo ciclo, pero si el dato no esta en caché y hay que ir a memoria principal,estas etapas pueden <strong>con</strong>sumir más de un ciclo.FE DE DI DI DI EX WBEn este caso la unidad funcional de memoria también necesita estar duplicadao segmentada para poder permitir a varias instrucciones trabajar en estaunidad.Pág 212


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org3 Los riesgosSu instinto es correcto si encuentra difícil pensar que la segmentación es tansimple como esto, porque no lo es. En esta sección vamos a comentar unosproblemas que surgen en la segmentación llamados riesgos (hazards), queimpiden que se ejecute la siguiente instrucción <strong>del</strong> flujo de instruccionesdurante su ciclo de reloj designado. Los riesgos reducen el rendimiento de lavelocidad ideal lograda <strong>con</strong> la segmentación. Hay tres tipos de riesgos:1. Riesgos estructurales. Surgen de <strong>con</strong>flictos <strong>con</strong> los recursosdisponibles, cuando el hardware no puede soportar todas lascombinaciones posibles de instrucciones en ejecución simultánea.2. Riesgos por dependencia de datos. Surgen cuando una instruccióndepende de los resultados de una instrucción anterior, de forma queuna tiene que esperar al resultado de la otra.3. Riesgos de <strong>con</strong>trol. Surgen de la segmentación de los saltos y otrasinstrucciones que cambian el IP.Los riesgos en la segmentación pueden hacer necesario detenerla. Unadetención en una máquina segmentada requiere, <strong>con</strong> frecuencia, queprosigan algunas instrucciones mientras que se retardan otras. Normalmente,cuando una instrucción está detenida, todas las instrucciones posteriores aesta instrucción también se detienen. Las instrucciones anteriores a lainstrucción detenida pueden <strong>con</strong>tinuar, pero no se cogen instrucciones nuevasdurante la detención. Veremos algunos ejemplos de cómo operan lasdetenciones en esta sección. ¡No se preocupe, no son tan complejas comopuede parecer!3.1 Riesgos estructuralesLos riesgos estructurales se producen cuando diferentes instruccionesacceden simultáneamente a los mismos recursos. Para evitarlo hay quesegmentar las unidades funcionales y duplicar los recursos. Si algunacombinación de instrucciones no es posible ejecutarla simultáneamente, seproduce un riesgo estructural, y el microprocesador detiene a la últimainstrucción que emitió hasta que el riesgo desaparece.Por ejemplo, un recurso que suele producir riesgos estructurales son lospuertos de memoria, muchas máquinas tienen un único puerto de memoria<strong>con</strong> lo que si una instrucción accede a memoria (lo cual puede llevar variosciclos) y otra instrucción también intenta acceder a memoria, ésta últimaqueda detenida hasta que la primera acaba.Pág 213


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgInstucciónCiclo de reloj1 2 3 4 5 6 7 8 9 10Instrucción i FE DE DI EX WBInstrucción i+1 FE DE DI EX WBInstrucción i+2 FE DE DI EX WBInstrucción i+3 FE DE stall DI EX WBInstrucción i+4 FE DE DI EX WBFigura B.3: Ejemplo de stall en ejecución segmentadaEn la Figura B.3 se muestra una detención (stall) que se produce cuandoen el sexto ciclo de reloj la instrucción i+1 está haciendo un almacenamientoen memoria (stw) mientras que la instrucción i+3 intenta hacer una carga dememoria (lwz), como ambas comparten el puerto de datos la segunda tieneque esperar, lo cual retrasa un ciclo a todas las instrucciones que siguen a lainstrucción i+3.¿Por qué permite el diseñador riesgos estructurales?. Hay dos razones: Parareducir el coste de fabricación y para reducir la latencia de una unidadfuncional, ya que la segmentación de algunas unidades funcionales aumentanmucho su latencia porque sus etapas están muy desequilibradas, y si lasegmentamos debemos de hacer que cada etapa dure lo que un ciclo de reloj.Si los riesgos estructurales no se presentan <strong>con</strong> frecuencia, puede no merecerla pena el coste de evitarlos. Además <strong>con</strong> frecuencia merece más la penadiseñar una unidad funcional no segmentada, pero <strong>con</strong> una latencia menor.3.2 Riesgos por dependencia de datosLos riesgos por dependencia de datos se presentan cuando la segmentacióncambia el orden de acceso a los operandos respecto al orden secuencialnormal que se produciría si no hubiera segmentación. Los riesgos se puedenproducir tanto durante el acceso por parte de dos instrucciones a los registroscomo durante el acceso a memoria.Considérese la ejecución de estas dos instrucciones:add r1,r2,r3sub r4,r1,r5La instrucción sub tiene como dato de entrada r1, que es el dato de salidade la instrucción add. Como muestra la Figura B.4, la instrucción add escribeel valor de r1 en la etapa WB, mientras que la instrucción sub lee el valor <strong>del</strong>registro en la etapa DI.Pág 214


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgInstrucciónCiclo de reloj1 2 3 4 5 6 7 8add FE DE DI EX WBescrisub FE DE DIleeEX WBFigura B.4: Problema en la ejecución segmentada de instruccionesLuego si no hacemos nada para impedirlo, sub leerá un dato erróneo. En estecaso, el microprocesador tiene que detener a la instrucción sub hasta que eldato este disponible, como muestra la siguiente Figura B.5.InstrucciónCiclo de reloj1 2 3 4 5 6 7 8add FE DE DI EX WBescrisub FE DE stall stall DIleeEX WBFigura B.5: Solución para los riesgos en la ejecución segmentada de instruccionesLo cual provoca una perdida de dos ciclos de reloj.Para reducir el efecto de los riesgos de dependencia de datos, una técnicamuy usada por los microprocesadores es el a<strong>del</strong>antamiento de datos(forwaring o bypassing), que <strong>con</strong>siste en que el resultado de unainstrucción se envía directamente a otra instrucción sin necesidad dealmacenar ese dato el registro o memoria. De esta forma la instruccióndetenida puede leer antes este dato y perder menos ciclos de reloj.Por ejemplo, en le caso anterior, el microprocesador se podría cablear paraque la salida de EX de la primera instrucción pasase directamente a la entradade DI de la segunda instrucción sin esperar a la etapa WB de la primerainstrucción, de esta forma, como muestra la Figura B.6, se ganaría un ciclo dereloj.InstrucciónCiclo de reloj1 2 3 4 5 6 7 8add FE DE DI EX WBescrisub FE DE stall DI lee EX WBFigura B.6: A<strong>del</strong>antamiento de datos en la ejecución segmentadaLos riesgos por dependencia de datos pueden clasificarse en tres grupos,dependiendo <strong>del</strong> orden de los acceso de lectura/escritura en las instrucciones:• RAW (Read After Write). La instrucción j trata de leer un operandoantes de que una instrucción anterior i lo haya escrito, <strong>con</strong> lo que jPág 215


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgtomaría el valor antiguo. Este es el tipo de riesgo de dependencia dedatos más común y es el que aparece en el ejemplo anterior.add r1,r2,r3sub r4,r1,r5Para evitar este tipo de riesgos se recomienda siempre que sea posibleintercalar una instrucción sin dependencias en medio. Por ejemplo, ennuestro ejemplo podemos intercalar una instrucción sin dependenciasasí:add r1,r2,r3add r6,r7,r8sub r4,r1,r5• WAW (Write After Write). La instrucción j intenta escribir unoperando antes de que sea escrito por otra instrucción anterior i. Esteriesgo es menos común ya que implica que la instrucción i gaste másciclos de reloj que la instrucción j, ya que si ambas <strong>con</strong>sumieran elmismo número de ciclos i siempre escribiría (llegaría a la etapa WB)antes de escribir j.Por ejemplo si tenemos:divf fr2,fr3,fr4addf fr2,fr5,fr6Al ser más rápida addf que divf, aunque addf empezase después,escribiría en fr2 antes de que divf.Para evitar este tipo de riesgos basta <strong>con</strong> renombrar los operandos:divf fr2,fr3,fr4addf fr7,fr5,fr6• WAR (Write After Read). La instrucción j intenta escribir unoperando antes de que sea leído por una instrucción anterior i, <strong>con</strong> loque i leerá un valor erróneo.Este es el tipo más raro de dependencias, y para que se produzcan lainstrucción j debe de llegar a su etapa WB (escribir resultados) antesde que la instrucción anterior i llegue a su etapa DI (leer operandos).A las dependencia de tipo WAR también se las llamaantidependencias. Al igual que la dependencia WAW, lasantidependencias son falsas dependencias que no se deben a unaPág 216


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgdependencia real de datos, sino a un <strong>con</strong>flicto de recursos y se puedeeliminar renombrando los registros. Por ejemplo si tenemos:lwz r2,0(r3)addi r3,r4,r5Si hay un fallo de caché, la instrucción lwz se puede retrasar durantevarios ciclos, los cuales aprovecha addi para a<strong>del</strong>antarse en suescritura.Para solucionar la antidependencia renombramos los registros así:lwz r2,0(r3)addi r4,r5,r6Es evidente que el caso RAR (Read After Read) no es un riesgo, ya queambas instrucciones leen el mismo dato sin modificarlo.Afortunadamente todos los riesgos de dependencia de datos se puedencomprobar durante la etapa DE, y si existe un riesgo la instrucción esdetenida antes de ser emitida.3.3 Riesgos de <strong>con</strong>trolLos saltos provocan retrasos en la segmentación mayores a los que provocanlos riesgos estructurales o de dependencia de datos, ya que la direcciónefectiva de un salto no se <strong>con</strong>oce hasta la fase WB, que es la que modifica elIP, lo cual da lugar un retraso <strong>con</strong>siderable en la segmentación tal comomuestra la Figura B.7:InstrucciónCiclo de reloj1 2 3 4 5 6 7 8addi FE DE DI EX WBb FE DE DI EX WBsubi FE 1 stall stall stall FE DEFigura B.7: Retraso producido por un saltoObsérvesele que en 1 la instrucción de la posición IP+4 se carga, pero aldecodificar b en la etapa DE y ver que es un salto se detiene y en el ciclo 7 sevuelve a leer la instrucción que está en la dirección destino <strong>del</strong> salto.Para evitar retrasos tan grandes se utiliza la técnica <strong>del</strong> a<strong>del</strong>antamiento dedatos (véase el apartado 3.2), la cual nos permite a<strong>del</strong>antar la direcciónefectiva de salto en la etapa DE, tal como muestra la Figura B.8:Pág 217


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgInstrucciónCiclo de reloj1 2 3 4 5 6 7 8addi FE DE DI EX WBb FE DE DI EX WBsubi FE 1 FE DE DI EX WBFigura B.8: Ejemplo de a<strong>del</strong>antamiento de datos en los saltosObsérvese que <strong>con</strong> un correcto cableado para el a<strong>del</strong>antamiento de datospodemos <strong>con</strong>seguir perder un sólo ciclo en lugar de 4 ciclos.3.4 Saltos sin resolverLos saltos se pueden dividir en tres categorías:• Saltos in<strong>con</strong>dicionales• Saltos <strong>con</strong>dicionales, los cuales seleccionan la siguiente instrucción aejecutar entre 2 alternativas dependiendo de si se cumple o no una<strong>con</strong>dición que se encuentra en uno de los campos <strong>del</strong> registro CR• Saltos multidestino, son saltos en los que, al igual que los<strong>con</strong>dicionales, evalúan una <strong>con</strong>dición puesta en un campo de CR, perola dirección de destino <strong>del</strong> salto es también variable (estará en elregistro LR o CTR), <strong>con</strong> lo que puede haber muchos destinos.Se dice que un salto está sin resolver (unresolved) cuando o bien la<strong>con</strong>dición, o bien la dirección destino <strong>del</strong> salto no se <strong>con</strong>ocen cuando se va aejecutar el salto.Los saltos sin resolver nunca se producen en los saltos in<strong>con</strong>dicionales, perosí que se producen en los demás tipos de saltos, veamos un ejemplo:lis r2,ha16(dato)li r2,lo16(dato)lwz r4,0(r2)cmpwi cr0,r3,0beq allaaqui:subi r4,r4,1alla:addi r4,r4,1El orden de ejecución de las instrucciones segmentadas es ahora el que semuestra en la Figura B.9:Pág 218


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgInstrucciónCiclo de reloj1 2 3 4 5 6 7 8 9 10 11 12lwz FE DE DI EX WBcmpwi FE DE DI EX WBbeq FE 1 stall stall FE DE DI EX WBstall stall stall stall FE DE DI EX WBFigura B.9: Orden de ejecución de las instrucciones <strong>del</strong> ejemploAun <strong>con</strong> a<strong>del</strong>antamientos de datos acabamos teniendo un retraso de 4 ciclosde reloj, esto es así porque la instrucción cmpwi no calcula la <strong>con</strong>dición <strong>del</strong>registro CR hasta la etapa WB. El primer a<strong>del</strong>antamiento evita que beq tengaque esperar a la etapa WB de cmpwi, el segundo a<strong>del</strong>antamiento permite quela etapa DE de beq actualice el IP para poder recoger la siguiente instrucciónejecutar.En definitiva, los saltos sin resolver enlentecen mucho la ejecución deinstrucciones 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<strong>con</strong>siderable.A <strong>con</strong>tinuación vamos a comentar varias soluciones que evitan estosproblemas.3.5 Solución software a los saltos sin resolverUna primera solución es que el programador planifique las instrucciones,es decir, que coloque las instrucciones en un orden que evite que los saltosestén sin resolver cuando llegue el momento de ejecutarlos.Por ejemplo, en le programa anterior podemos a<strong>del</strong>antar la instrucción cmpwiasí:cmpwi cr0,r3,0lis r2,ha16(dato)li r2,lo16(dato)lwz r4,0(r2)beq allaaqui:subi r4,r4,1alla:addi r4,r4,1Ahora cuando se fuera a ejecutar la instrucción beq, el salto estaría resueltotal como muestra la Figura B.10:Pág 219


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgInstrucciónCiclo de reloj1 2 3 4 5 6 7 8 9 10 11 12cmpwi FE DE DI EX WBlis FE DE DI EX WBli FE DE DI EX WBlwz FE DE DI EX WBbeq FE DE DI EX WBFE 1 FE DE DI EX WBFigura B.10: Ejecución <strong>con</strong> salto resueltoEn este caso sólo se perdería 1 ciclo de reloj en el sexto ciclo de la últimainstrucción, en vez de perderse 4 ciclos de reloj, como pasaba cuando el saltoestaba sin resolver.Vamos a ver ejemplos de cómo resolver el problema de los saltos sin resolveren las estructuras de <strong>con</strong>trol de flujo más <strong>con</strong>ocidas.3.5.1 Estructura ifEn las estructuras if y if-else normalmente, como muestra la Figura B.11,siempre vamos a poder intercalar instrucciones entre la comparación y elsalto:Salto sin resolver·············instrucciones1·············cmpw cr0,r2,0beq alla·············instrucciones2·············Solucióncmpw cr0,r2,0·············instrucciones1·············beq alla·············instrucciones2·············Figura B.11: Intercalar instrucciones entre la comparación y el salto3.5.2 Estructura whileEn los bucles while (también llamados 0-n) la solución no siempre esposible, ya que pasa por intercalar instrucciones <strong>del</strong> bloqueinstrucciones2 entre la operación de comparación y de salto, tal comomuestra la Figura B.12.El poder a<strong>del</strong>antar estas instrucciones o no depende de los efectos lateralesque esto implique, es decir, sólo podemos a<strong>del</strong>antar instrucciones que sifinalmente el salto es efectivo no modifiquen el estado de las variables <strong>del</strong>programa, esto sería cierto si las variables o registros <strong>con</strong> los que hanPág 220


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgtrabajado las instrucciones son sólo de uso interno al bucle. La Figura B.12muestra un ejemplo de a<strong>del</strong>antamiento de instrucciones en un bucle while.Salto sin resolver·············instrucciones1·············inicio: cmpw cr0,r2,0beq fin·············instrucciones2·············b iniciofin:Solución·············instrucciones1·············inicio: cmpw cr0,r2,0·············instrucciones2·············beq fin·············instrucciones2·············b iniciofin:Figura B.12: A<strong>del</strong>antar instrucciones en un bucle while3.5.3 Estructura do-whileEn las estructuras do-while (o 1-n) la solución pasa por a<strong>del</strong>antar lacomparación, realizándola lo antes posible en el cuerpo <strong>del</strong> bucle, pero aligual que antes esto no siempre es posible, ya que para poder realizar lacomparación debemos de <strong>con</strong>ocer el resultado que vamos a comparar, quenormalmente se calcula dentro <strong>del</strong> bucle. La Figura B.13 muestra un ejemplode a<strong>del</strong>antamiento de instrucciones en un bucle whileinicio:fin:Salto sin resolver·············instrucciones1··························instrucciones2·············cmpw cr0,r2,0beq inicioinicio:fin:Solución·············instrucciones1··························instrucciones2·············cmpw cr0,r2,0·············instrucciones2·············beq inicioFigura B.13: A<strong>del</strong>antar instrucciones en un bucle whilePág 221


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org3.5.4 Estructura forEn estas estructuras se pueden eliminar los saltos sin resolver usando saltos<strong>con</strong>dicionales en función <strong>del</strong> registro CTR, que son saltos que siempre estánresueltos.inicio:fin:·············instrucciones1·············mtctr r5·············instrucciones2·············bdnz inicioEsto es posible siempre que el número de repeticiones se <strong>con</strong>ozca antes demeternos en el bucle.Típicamente el <strong>con</strong>tador de un bucle for no suele <strong>con</strong>tar hacia atrás hasta el0, sino que suele <strong>con</strong>tar desde 1 a n, aun así podemos usar un bucle cuya<strong>con</strong>dición de salida esté en el <strong>con</strong>tador, y llevar otra variable <strong>con</strong>tador aparte:inicio:fin:li r3,1 ; Desde 1li r4,n ; Hasta nsubi r5,r4,1mtctr r5 ; Fijamos el <strong>con</strong>tador hasta 0·············instrucciones2·············add r3,r3,1bdnz inicio3.6 Solución hardware a los saltos sin resolverLa planificación de instrucciones es muy efectiva para resolver el problema <strong>del</strong>os saltos sin resolver, pero no siempre es posible: o bien porque elprogramador no la hace, o bien porque la lógica <strong>del</strong> programa no permitehacerla. En estos casos todavía podemos aprovecharnos de solucioneshardware, como las que vamos ver.Cuando el procesador encuentra una instrucción de salto, escanea los pipesen ejecución para determinar si alguna de las instrucciones que se estánejecutando puede modificar el estado <strong>del</strong> campo CR usado, o bien de losregistros LR y CTR si estos están en uso por la instrucción de salto, si no esasí el salto se resuelve inmediatamente, pero si se encuentra dependencia, elsalto se <strong>con</strong>sidera sin resolver, y el hardware en vez de detenerse lo que hacePág 222


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orges que ejecuta especulativamente una de las ramas. Después cuando la<strong>con</strong>dición <strong>del</strong> salto se resuelve, si la predicción es correcta, la ejecuciónsimplemente <strong>con</strong>tinúa, y sino el procesador debe volver al estado en el queestaba cuando se inicio la ejecución especulativa, y coger el otro camino.Para evitar la penalización en tiempo que supone restaurar los registroscuando el camino cogido no es el correcto los procesadores suelen usar losllamados shadow registers, que son registros en los que se van guardandolos resultados de las instrucciones cuando se está ejecutando de formaespeculativa, de forma que si al final la predicción es correcta su <strong>con</strong>tenido secopia a los registros reales, y sino su <strong>con</strong>tenido se descarta.Los algoritmos que usa el procesador para decidir si llevar a cabo o no el saltose clasifican en dos grupos:1. Algoritmos de predicción estáticos. Consisten en que el programadorcodifica la instrucción de salto indicando si es más probable que el salto seaefectivo o si no, para ello utiliza el bit y <strong>del</strong> operando BO que veíamos en elTema 2 y que volvemos a reproducir en la Tabla B.1:BO0000y0001y001zy0100y0101y011zy1z00y1z01y1z1zzDescripciónDecrementa el registro CTR y después salta si CTR≠0 y la <strong>con</strong>diciónes FALSEDecrementa el registro CTR y después salta si CTR=0 y la <strong>con</strong>diciónes FALSESalta si la <strong>con</strong>dición es FALSEDecrementa el registro CTR y después salta si CTR≠0 y la <strong>con</strong>diciónes TRUEDecrementa el registro CTR y después salta si CTR=0 y la <strong>con</strong>diciónes TRUESalta si la <strong>con</strong>dición es TRUEDecrementa el registro CTR y después salta si CTR≠0Decrementa el registro CTR y después salta si CTR=0Salta siemprez Es un bit que se reserva para el futuro, y que de momento debe ser siempre 0y Indica si es más probable que el salto se realice a que no se realiceTabla B.1: Configuración <strong>del</strong> operando BOEl campo y se activa cuando el programador ve más probable que el salto selleve a cabo que no, y se deja a cero para indicar que no se lleve a cabo elsalto especulativamente.Por defecto se recomienda dejarlo a 0, ya que es más fácil para el procesadorespecular que el salto no se realizará.Pág 223


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgEste bit es especialmente útil a la hora de implementar bucles, ya que losbucles tienen una mayor probabilidad de repetirse que de no hacerlo, luego sinosotros estamos implementando un bucle podemos indicar al procesadornuestra opinión usando este bit.Por ejemplo para implementar el bucle do-while anterior podríamos hacerloasí:inicio:fin:·············instrucciones1··························instrucciones2·············cmpw cr0,r2,0bc 13,2,inicioEl operando BO vale 13=0b01101 donde hemos activado el bit y, ya que elsalto es más probable que se repita. El operando BI vale 2=0b00010indicando que queremos comprobar la igualdad a 0 <strong>del</strong> registro r2 en elcampo cr0.Otra forma de indicar en las instrucciones de salto si creemos más probableque se produzcan o no es añadir al nombre de la instrucción un - (másprobable que no se realice) o un + (más probable que si se realice). Porejemplo:bucle:cmpwi r3,100beq+ bucleIndica que lo más probable es que se realice el salto.2. Algoritmos de predicción dinámicos. Consisten en que es elprocesador el que decide si ejecutar especulativamente el salto o no. Aunqueinicialmente el procesador puede hacer caso al bit de predicción depositadopor el programador, en microprocesadores más avanzados el propioprocesador puede usar mecanismos para decidir si el salto especulativo queva a dar es el más correcto.Básicamente existen dos técnicas de predicción dinámica:Branch Target Address Cache (BTAC). El procesador almacena ladirección destino de los últimos saltos realizados en una memoria caché, deforma que si esa instrucción de salto se vuelve a intentar ejecutar otra vez, elprocesador busca la instrucción en su cache y mira a ver que ocurrió la vezanterior para tomar ese camino. De esta forma si el salto especulativo tieneéxito se puede <strong>con</strong>seguir una pérdida de 0 ciclos.Pág 224


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgLas BTAC son tablas en las que se almacena la dirección de la instrucción desalto y su dirección de salto efectivo más o menos de la forma que semuestra en la Figura B.14:Dirección de lainstrucción desaltoDirección a la quesalto la última vezFigura B.14: Estructura de una Branch target Address CacheBranch History Tables. El procesador mantiene un registro de las últimasacciones realizadas por una instrucción. Estas tablas suelen tener la forma <strong>del</strong>a Figura B.15:Dirección de lainstrucción de saltoEstadoFigura B.15: Estructura de una Branch History TableDonde a cada instrucción de salto se le asocian 2 bits en el campo de estado.Los cuatro estados de los 2 bits asociados a la instrucción de salto puedentomar los valores:00 - Strongly Taken01 - Weakly taken10 - Weakly Not taken11 - Strongly Not TakenLa siguiente Figura B.16 muestra la relación entre estos 4 estados:NTStronglyNotTakenTNTWeaklyNotTakenTNTWeaklyTakenTNTStronglyTakenTFigura B.16: Estado de los bits de saltoT - Taken NT- Not takenPág 225


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgLo importante es que para que el salto pase de efectivo a no efectivo, debende producirse dos fallos <strong>con</strong>secutivos, lo cual se hace así porque normalmentelos bucles se llevan a cabo un número de veces hasta que la <strong>con</strong>dición se dejade cumplir, pero sí otro vez pasase el flujo <strong>del</strong> programa por el bucle, el bucleseguiría <strong>con</strong>siderándose en el mismo estado (aunque weakly) <strong>con</strong> lo que siahora el bucle se repite, que es lo más probable, el estado vuelve al estadostrongly, en el que permanece durante todas las repeticiones. De esta formase <strong>con</strong>sigue que los saltos de los bucles se predigan siempre correctamente,excepto cuando la <strong>con</strong>dición de repetición se deja de cumplir.Una última solución hardware a los saltos sin resolver que están empezando ausar los procesadores más avanzados es el scheduling, que <strong>con</strong>siste en queel procesador puede pasar las instrucciones a ejecución en orden distinto alque están escritas en el programa. El procesador puede decidir cambiar elorden de ejecución de las instrucciones en base a dos criterios: El primero esque el procesador puede leer a<strong>del</strong>antadamente varias instrucciones en elllamado fetch buffer y decide si pasar las instrucciones a ejecución en elorden que están llegando o bien a<strong>del</strong>antar alguna de ellas si encuentra queesa instrucción va a producir una detención. El segundo criterio es que elprocesador puede detectar dependencias, y si las encuentra detiene unainstrucción aunque deja pasar a otras <strong>con</strong> las que no hay dependencias.3.7 La serializaciónPara mantener al procesador y a la memoria en un estado <strong>con</strong>sistente <strong>con</strong> elmo<strong>del</strong>o de ejecución secuencial, en ciertas situaciones el procesador se veobligado a serializar la ejecución de una instrucción entera, deteniendo laejecución de todas las demás instrucciones hasta que esta acaba.Esto ocurre por ejemplo cuando hay más de una unidad funcional de puntofijo donde recursos comunes no duplicados como el registro XER van a seractualizados. Por esta razón las instrucciones que modifican este registrollevan un nombre especial como addc o addo, las cuales pueden ejecutar<strong>con</strong>siderablemente más lento que la instrucción que no modifica este registro(add). Lo mismo ocurre <strong>con</strong> las instrucciones <strong>con</strong> punto (.) como porejemplo add., que al escribir en le campo CR0 puede necesitar ejecutarsecuencialmente.Para evitar detenciones de este tipo debido a un <strong>con</strong>flicto en el campo CR0,es recomendable que los saltos cercanos utilicen otros campos (CR1,...CR7)para evaluar sus <strong>con</strong>diciones.Pág 226


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.org4 Más allá de la segmentaciónSe denomina procesadores supersegmentados a los procesadores donde lasegmentación es más profunda (pueden llegar a tener 10 etapas, en lugar <strong>del</strong>as 5 antes descritas), y en las que todas las unidades funcionales seencuentran segmentadas.Este término no debe de ser <strong>con</strong>fundido <strong>con</strong> el de procesador superescalar,que es un procesador capaz de emitir varias instrucciones en el mismo ciclode reloj, normalmente de 2 a 4 instrucciones sin embargo si las instrucciones<strong>del</strong> flujo de instrucciones son dependientes, o no cumplen ciertos criterios,sólo se emitirá la primera instrucción de la secuencia. La mayoría de los<strong>PowerPC</strong> actuales son superescalares.Actualmente están surgiendo máquinas, como por ejemplo Itanium de Intel alas que se llama VLIW (Very Long Instruction Word) que se caracterizanporque una instrucción está formada por la unión de varias instrucciones (3en <strong>con</strong>creto en el caso de Itanium) las cuales se agrupan en lo que llaman unbundle, y las 3 se emiten a la vez. Lo importante de agrupar lasinstrucciones en bundles es que el compilador puede colocar en cada bundleinstrucciones que no tengan dependencias entre sí <strong>con</strong> el fin de facilitar suejecución simultánea sin detenciones. Esta solución <strong>con</strong>sigue mejorrendimiento que las máquinas superescalares tradicionales, a cambio deaumentar la complejidad de la programación, ya que el programador tieneque pensar en grupos de instrucciones (bundles) más que en instruccionessecuenciales.Por último están las llamadas máquinas vectoriales, que usan a la vezambas técnicas. Habitualmente son supersegmentadas, y tienen potentesoperaciones vectoriales que se pueden <strong>con</strong>siderar equivalentes a emitirmúltiples operaciones independientes.Pág 227


<strong>Ensamblador</strong> <strong>del</strong> <strong>PowerPC</strong> <strong>con</strong> <strong>Mac</strong> <strong>OS</strong> Xmacprogramadores.orgReferencias[DEVTOOLS] Herramientas de desarrollo de Applehttp://developer.apple.com/tools/index.html[MICROIBM] Microprocesadores de IBMhttp://www-1.ibm.com/servers/eserver/pseries/hardware/workstations/ (Workstations de 32 bits)http://commerce.www.ibm.com/<strong>con</strong>tent/home/shop_ShopIBM/en_US/eServer/pSeries/pSeries.html(Servidores de 64 bits de alto rendimiento)[MICROMOTOROLA] Microprocesadores de Motorolahttp://www.motorola.com/SPS/<strong>PowerPC</strong>/teksupport/teklibrary/[UNDERFLOW] “Underflow and the Reliability of Numerical Software”, JamesDemmel, y “Combatting the effect of Underflow and Overflow indetermining Real Roots of Polynomials” de S. Linnainmaa.[WARREN] Changing Division by a <strong>con</strong>stant to Multiplication in Two’sComplement Arithmetic. Warren, Henry S., Jr., IBM Research Report:RC 18601 [1992].Pág 228

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!