0% encontró este documento útil (0 votos)
34 vistas36 páginas

Universidad Nacional de Ucayali

Este documento describe diferentes conceptos relacionados con el lenguaje ensamblador como instrucciones CISC y RISC, registros, arquitecturas Harvard, Von Neumann y modificada Harvard, así como el ciclo de fetch. También explica cómo compilar programas con el ensamblador NASM en Linux y Windows.
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como DOCX, PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
34 vistas36 páginas

Universidad Nacional de Ucayali

Este documento describe diferentes conceptos relacionados con el lenguaje ensamblador como instrucciones CISC y RISC, registros, arquitecturas Harvard, Von Neumann y modificada Harvard, así como el ciclo de fetch. También explica cómo compilar programas con el ensamblador NASM en Linux y Windows.
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como DOCX, PDF, TXT o lee en línea desde Scribd
Está en la página 1/ 36

UNIVERSIDAD NACIONAL DE UCAYALI

Facultad de ingeniería de sistemas e ingeniería civil


Escuela profesional de ingeniería de sistemas

TRABAJO 01 - SO

Integrantes:
- Alexander Efrain Coral Pinedo
- Leslie Lizeth Pinedo Zumaeta
- Darwin Diaz Paima
- Hernández Gallegos Jesús
Asignatura:
Sistemas Operativos
Docente:
Ing. Msc. Euclides Panduro Padilla
Ciclo.
VII– Grupo A

Pucallpa – Perú
2024
Índice
El Lenguaje Ensamblador...................................................................................................................1
Instrucciones......................................................................................................................................3
CISC (Complex Instruction Set Computing).....................................................................................3
RISC (Reduced Instruction Set Computing).....................................................................................5
Registros.............................................................................................................................................8
Arquitectura Harvard........................................................................................................................12
Arquitectura Von Newman...............................................................................................................14
Arquitectura Harvard Modificado....................................................................................................17
Ciclo De Fetch...................................................................................................................................19
La unidad de control.....................................................................................................................21
Tipos de instrucciones..................................................................................................................22
Ensamblador NASM.........................................................................................................................23
¿Cómo compilar con NASM en Linux?..........................................................................................30
Etapa 1 - Crear un fichero fuente..............................................................................................30
Etapa 2 - Ensamblar el fichero fuente.......................................................................................30
Etapa 3 - Creación del ejecutable|............................................................................................31
Etapa 4: Ejecución del programa..............................................................................................31
¿Cómo compilar con NASM en Windows?...................................................................................31
Etapa 1 - Instalar los programas necesarios..............................................................................32
Etapa 2 - Crear un fichero fuente..............................................................................................32
Etapa 3 - Ensamblar el fichero fuente.......................................................................................32
Etapa 4 - Creación y ejecución del programa...........................................................................33
Bibliografía.......................................................................................................................................33
El Lenguaje Ensamblador

El lenguaje ensamblador es el lenguaje de programación utilizado para escribir programas


informáticos de bajo nivel, y constituye la representación más directa del código máquina
específico para cada arquitectura de computadoras legible por un programador. Implementa
una representación simbólica de los códigos de máquina binarios y otras constantes
necesarias para programar una arquitectura de procesador.

Cada arquitectura de procesador tiene su propio lenguaje ensamblador que usualmente es


definida por el fabricante de hardware, y está basada en los mnemónicos que simbolizan los
pasos de procesamiento (las instrucciones), los registros del procesador, las posiciones de
memoria y otras características del lenguaje. Un lenguaje ensamblador es por lo tanto
específico de cierta arquitectura de computador física (o virtual). Esto está en contraste con
la mayoría de los lenguajes de programación de alto nivel, que idealmente son portátiles.

Un programa utilitario llamado ensamblador es usado para traducir sentencias del lenguaje
ensamblador al código de máquina del computador objetivo. El ensamblador realiza una
traducción más o menos isomorfa (un mapeo de uno a uno) desde las sentencias
mnemónicas a las instrucciones y datos de máquina.

Esto está en contraste con los lenguajes de alto nivel, en los cuales una sola declaración
generalmente da lugar a muchas instrucciones de máquina. Muchos sofisticados
ensambladores ofrecen mecanismos adicionales para facilitar el desarrollo del programa,
controlar el proceso de ensamblaje, y la ayuda de depuración. Particularmente, la mayoría
de los ensambladores modernos incluyen una facilidad de macro (descrita más abajo), y se
llaman macro ensambladores.

Fue usado principalmente en los inicios del desarrollo de software, cuando aún no se
contaba con potentes lenguajes de alto nivel y los recursos eran limitados. Actualmente se
utiliza con frecuencia en ambientes académicos y de investigación, especialmente cuando
se requiere la manipulación directa de hardware, alto rendimiento, o un uso de recursos
controlado y reducido.

También es utilizado en el desarrollo de controladores de dispositivo (en inglés, device


drivers) y en el desarrollo de sistemas operativos, debido a la necesidad del acceso directo a
las instrucciones de la máquina. Muchos dispositivos programables (como los
microcontroladores) aún cuentan con el ensamblador como la única manera de ser
manipulados.

Ventajas:

1. Ejecución más rápida: Al trabajar directamente con el microprocesador, las


instrucciones se ejecutan más rápidamente que en lenguajes de alto nivel.

2. Eficiencia en el uso de memoria: Los programas escritos en ensamblador ocupan


menos espacio en memoria, ya que no necesitan cargar bibliotecas u otros recursos
adicionales como lo hacen los lenguajes de alto nivel.

3. Flexibilidad: Permite aprovechar al máximo los recursos de la máquina, ya que


cualquier tarea que pueda realizarse en ella puede ser expresada en ensamblador.

Desventajas:

1. Mayor tiempo de programación: Debido a su naturaleza de bajo nivel, se


requieren más instrucciones para realizar tareas simples en comparación con los
lenguajes de alto nivel. Además, los errores son más propensos y pueden ser más
difíciles de detectar.

2. Programas fuente grandes: Los programas escritos en ensamblador tienden a ser


más extensos debido a la cantidad de instrucciones necesarias, lo que dificulta el
mantenimiento y reduce la productividad del programador.

3. Riesgo de afectar recursos inesperadamente: Los errores de programación


pueden tener consecuencias graves, como bloquear o reiniciar la máquina, debido a
que es posible ejecutar secuencias de instrucciones inválidas con relativa facilidad.

4. Falta de portabilidad: Cada máquina tiene su propio conjunto de instrucciones en


lenguaje ensamblador, lo que dificulta llevar programas de un sistema a otro sin
modificarlos significativamente.
Instrucciones

CISC (Complex Instruction Set Computing)

En la arquitectura computacional, CISC (complex instruction set computer) es un modelo


de arquitectura de computadora. Los microprocesadores CISC tienen un conjunto de
instrucciones que se caracteriza por ser muy amplio y permitir operaciones complejas entre
operandos situados en la memoria o en los registros internos, en contraposición a la
arquitectura RISC. Este tipo de arquitectura dificulta el paralelismo entre instrucciones, por
lo que, en la actualidad, la mayoría de los sistemas CISC de alto rendimiento implementan
un sistema que convierte dichas instrucciones complejas en varias instrucciones simples del
tipo RISC, llamadas generalmente microinstrucciones. Los CISC pertenecen a la primera
corriente de construcción de procesadores, antes del desarrollo de los RISC. Ejemplos de
ellos son: Motorola 68000, Zilog Z80 y toda la familia Intel x86 usada en la mayoría de las
computadoras personales actuales.

Ventajas De Los Procesadores CISC

 Para el compilador se requiere de poco esfuerzo para traducir programas de alto


nivel o lenguajes de instrucciones a lenguaje ensamblador o máquina

 El tamaño del código es corto, reduciendo los requisitos de memoria

 Almacenar las instrucciones CISC requieren de menos cantidad de memoria


RAM

 Genera procesos de administración de uso de energía que permiten ajustar la


velocidad y el voltaje del reloj

 Requiere de menos instrucciones configuradas para realizar la misma instrucción


que la arquitectura RISC

Desventajas De Los Procesadores CISC

 Pueden requerir de varios ciclos de reloj para completar una instrucción de un


software

 El rendimiento del equipo sufre un descenso debido a la velocidad del reloj


 La ejecución mediante canalización en procesadores CISC puede ser
realmente complicado

 Este diseño de procesadores requiere muchos más transistores que la


arquitectura RISC

 Utilizan sobre el 20% de las instrucciones existentes en un evento de


programación

 Tienen un diseño mucho mayor que la arquitectura RISC, lo cual conlleva más
generación de temperatura, mayor consumo y mayor requisito de espacio físico

Ejemplo de Instrucciones CISC:

Intel x86 (CISC):

; Ejemplo de instrucción MOV (mover)

MOV AX, BX ; Mueve el contenido de BX al registro AX

; Ejemplo de instrucción ADD (sumar)

ADD AX, 10 ; Suma 10 al valor en el registro AX

; Ejemplo de instrucción MUL (multiplicar)

MUL CX ; Multiplica el contenido del registro CX por AX, resultado en DX:AX

Motorola 68k (CISC):

; Ejemplo de instrucción MOVE (mover)

MOVE.L D1, D2 ; Mueve el contenido del registro D1 al registro D2

; Ejemplo de instrucción ADDQ (sumar con incremento rápido)

ADDQ.W #5, D3 ; Suma 5 al contenido del registro D3 con extensión de palabra

; Ejemplo de instrucción MULS (multiplicar con signo)

MULS.W D5, D6 ; Multiplica el contenido del registro D6 por el contenido del


registro D5 con extensión de palabra, resultado en registro D6
RISC (Reduced Instruction Set Computing)

En la arquitectura computacional, RISC (del inglés reduced instruction set computer) es un


tipo de microprocesador con las siguientes características fundamentales:  Instrucciones de
tamaño fijo y presentadas en un reducido número de formatos.  Sólo las instrucciones de
carga y almacenamiento acceden a la memoria de datos. El objetivo de diseñar máquinas
con esta arquitectura es posibilitar la segmentación y el paralelismo en la ejecución de
instrucciones y reducir los accesos a memoria. Las máquinas RISC protagonizan la
tendencia actual de construcción de microprocesadores. PowerPC, DEC Alpha, MIPS,
ARM, SPARC… son ejemplos de algunos de ellos. RISC es una filosofía de diseño de CPU
para computadora que está a favor de conjuntos de instrucciones pequeñas y simples que
toman menor tiempo para ejecutarse.

Ventajas de los procesadores RISC

 Tienen la capacidad de ofrecer un mejor rendimiento gracias al menor número


de instrucciones y la simplicidad de las mismas

 Requieren de menos transistores, lo cual los hace más económicos de diseñar y


producir

 Permiten crear procesadores con «espacio» libre para añadir otros circuitos o
reducir sencillamente el encapsulado

 Este diseño requiere de menos consumo de energía y generan menos calor que
los procesadores RISC

Desventajas de los procesadores RISC

 El rendimiento del procesador puede variar dependiendo del código que se


ejecuta, ya que las instrucciones posteriores que se ejecuten pueden depender de
una instrucción anterior

 Actualmente la mayoría de software y compiladores hacen uso de instrucciones


complejas
 Necesitan de memorias muy rápidas para almacenar diferentes cantidades de
instrucciones, que requieren de una gran cantidad de memoria caché para responder
a la instrucción en el menor tiempo posible

Ejemplo de Instrucciones RISC:

ARM (RISC):

; Ejemplo de instrucción MOV (mover)

MOV R1, R2 ; Mueve el contenido del registro R1 al registro R2

; Ejemplo de instrucción ADD (sumar)

ADD R3, R4, R5 ; Suma el contenido de los registros R3 y R4, y guarda el resultado
en R5

; Ejemplo de instrucción MUL (multiplicar)

MUL R6, R7, R8 ; Multiplica el contenido de los registros R6 y R7, y guarda el


resultado en R8

MIPS (RISC):
; Ejemplo de instrucción ADD (sumar)

ADD $t0, $t1, $t2 ; Suma el contenido de los registros $t1 y $t2, y guarda el
resultado en $t0

; Ejemplo de instrucción SUB (restar)

SUB $s0, $s1, $s2 ; Resta el contenido de los registros $s1 y $s2, y guarda el
resultado en $s0

; Ejemplo de instrucción MULT (multiplicar)

MULT $a0, $a1 ; Multiplica el contenido de los registros $a0 y $a1, y guarda el
resultado en un registro de 64 bits
Registros

Los registros en lenguaje ensamblador son áreas de almacenamiento de datos de alta


velocidad ubicadas dentro del procesador de la computadora. Cada registro tiene un tamaño
fijo y se utiliza para realizar operaciones aritméticas, lógicas y de transferencia de datos.
La Unidad Central de Proceso (CPU, por sus siglas en inglés) tiene 14 registros internos
cada uno de 16 bits. Los primeros cuatro, AX, BX, CX y DX, son de uso general y se
pueden usar también como registros de 8 bits. Es decir, AX se puede dividir en AH y AL
(AH es el byte alto, high, y AL es el byte bajo, low) Lo mismo es aplicable a los otros tres
(BX en BH y BL, CX en CH y CL y DX en DH y DL).
Estos son los únicos registros que pueden usarse de modo dual (en 8 o 16 bits) Los registros
de la CPU son conocidos por sus nombres propios, que son: ·

 AX (acumulador).

 BX (registro base).

 CX (registro contador).

 DX (registro de datos).

 DS (registro del segmento de datos).

 ES (registro del segmento extra).

 SS (registro del segmento de pila).

 CS (registro del segmento de código).

 BP (registro de apuntadores base).

 SI (registro índice fuente).

 DI (registro índice destino).

 SP (registro del apuntador de pila).

 IP (registro del apuntador de siguiente instrucción).

 F (registro de banderas).
El registro AX se usa para almacenar resultados, lectura o escritura desde o hacia los
puertos. El BX sirve como apuntador base o índice. El CX se utiliza en operaciones de
iteración, como un contador que automáticamente se incrementa o decrementa de acuerdo
con el tipo de instrucción usada. El DX se usa como puente para el acceso de datos.

El DS es un registro de segmento cuya función es actuar como policía donde se encuentran


los datos. Cualquier dato, ya sea una variable inicializada o no, debe estar dentro de este
segmento. La única excepción es cuando tenemos programas del tipo *.com, ya que en
éstos sólo puede existir un segmento. El registro ES tiene el propósito general de permitir
operaciones sobre cadenas, pero también puede ser una extensión del DS.

El SS tiene la tarea exclusiva de manejar la posición de memoria donde se encuentra la pila


(stack) Esta es una estructura usada para almacenar datos en forma temporal, tanto de un
programa como de las operaciones internas de la computadora personal (PC, por sus siglas
en inglés) En términos de operación interna, la CPU usa este segmento para almacenar las
direcciones de retorno de las llamadas a rutinas. El registro de segmentos más importante es
el CS o segmento de código. Es aquí donde se encuentra el código ejecutable de cada
programa, el cual está directamente ligado a los diferentes modelos de memoria.

El registro BP (base pointer) se usa para manipular la pila sin afectar al registro de
segmentos SS. Es útil cuando se usa interfaz entre lenguajes de alto nivel y el ensamblador.
Puesto que dicha interfaz se basa en el concepto de la pila BP, nos permite acceder
parámetros pasados sin alterar el registro de segmento SS. Los registros SI y DI son útiles
para manejar bloques de cadenas en memoria, siendo el primero el índice fuente y el
segundo el índice destino. En otras palabras, SI representa la dirección donde se encuentra
la cadena y DI la dirección donde será copiada.

El registro SP apunta a un área específica de memoria que sirve para almacenar datos bajo
la estructura LIFO (último en entrar, primero en salir), conocida como pila (stack) El
registro IP (instruction pointer) apunta a la siguiente instrucción que será ejecutada en
memoria.

A continuación, se describe el significado de cada bit del registro F (banderas).


Todas las banderas apagadas:
NV UP DI PL NZ NA PO NC
Todas las banderas prendidas:
OV DN EI NG ZR AC PE CY

Significado de los bits:


Overflow NV = no hay desbordamiento
OV = Sí lo hay

Direction UP = hacia adelante


DN = hacia atrás

Interrupts DI = desactivadas
EI = activadas

Sign PL = positivo
NG = negativo

Zero NZ = no es cero
ZR = sí lo es

Auxiliary Carry NA = no hay acarreo auxiliar


AC = hay acarreo auxiliar

Parity PO = paridad non


PE = paridad par

Carry NC = no hay acarreo


CY = sí lo hay

Aquí hay una descripción general de los registros comunes en diferentes arquitecturas:
x86 (CISC):
1. Registros de propósito general:
 EAX, EBX, ECX, EDX
 Son utilizados para almacenar datos generales, direcciones de memoria,
resultados de operaciones aritméticas, etc.
2. Registros de segmento:
 CS (Código), DS (Datos), SS (Stack), ES (Extra)
 Controlan el acceso a diferentes segmentos de memoria.
3. Registros de índice:
 ESI (Source Index), EDI (Destination Index)
 A menudo se utilizan en operaciones de cadenas y transferencias de datos.
4. Registro de apuntador de pila:
 ESP (Stack Pointer)
 Indica la posición actual en la pila de llamadas.
5. Registro de puntero de base:
 EBP (Base Pointer)
 Se utiliza para acceder a parámetros y variables locales en funciones.
6. Registro de contador de instrucciones:
 EIP (Instruction Pointer)
 Contiene la dirección de la próxima instrucción a ejecutar.
ARM (RISC):
1. Registros de propósito general:
 R0 a R15
 Se utilizan para almacenar datos y resultados de operaciones.
2. Registros de estado:
 CPSR (Current Program Status Register)
 Almacena el estado actual del procesador, incluyendo el modo de operación
y las banderas de condición.
3. Registros de apuntador de pila:
 SP (Stack Pointer)
 Indica la posición actual en la pila de llamadas.
4. Registros de enlace:
 LR (Link Register)
 Almacena la dirección de retorno después de una llamada a una función.
MIPS (RISC):
1. Registros de propósito general:
 $0 a $31
 Utilizados para almacenar datos y resultados de operaciones.
2. Registro de apuntador de pila:
 $sp (Stack Pointer)
 Indica la posición actual en la pila de llamadas.
3. Registros de retorno:
 $ra (Return Address)
 Almacena la dirección de retorno después de una llamada a una función.

Arquitectura Harvard

La arquitectura Harvard es un diseño de computadora que separa la memoria y la unidad de


procesamiento, con pistas de almacenamiento y de señal físicamente separadas para las
instrucciones y para los datos. Esto significa que los datos y las instrucciones se almacenan
en memorias diferentes y se acceden de manera independiente. El término proviene de la
computadora Harvard Mark I basada en relés, que almacenaba las instrucciones sobre
cintas perforadas (de 24 bits de ancho) y los datos en interruptores electromecánicos. Estas
primeras máquinas tenían almacenamiento de datos totalmente contenido dentro la unidad
central de proceso, y no proporcionaban acceso al almacenamiento de instrucciones como
datos. Los programas necesitaban ser cargados por un operador; el procesador no podría
arrancar por sí mismo. Este modelo de arquitectura se contrapone al modelo de von
Neumann, que no distingue físicamente la memoria y procesamiento del código y de los
datos, lo cual genera cuellos de botella en el acceso a la memoria.
 Estructura: En la arquitectura Harvard, la CPU (Unidad Central de Procesamiento) y la
memoria principal (RAM) son físicamente separadas. Tienen buses de direcciones y
datos independientes.
 Memoria: En esta arquitectura, la memoria se divide en dos: una para almacenar
instrucciones (Program Memory o Memoria de Programa) y otra para almacenar datos
(Data Memory o Memoria de Datos). Esto permite que la CPU acceda simultáneamente
a instrucciones y datos, lo que mejora la eficiencia y tiempos de respuesta.
 Acceso a la Memoria: Debido a la separación de los buses de direcciones y datos, la
CPU puede acceder a la memoria de programa y de datos de forma independiente y
simultánea, lo que puede mejorar el rendimiento en ciertos casos.
 Ventajas:
 Tiene mayor ancho de banda: Al tener buses independientes, la CPU puede leer
instrucciones y datos al mismo tiempo, lo que aumenta el rendimiento en
comparación con la arquitectura von Neumann.
 Se accede más rápido a la memoria de instrucciones: Como la memoria de
programa es independiente, la CPU puede acceder a las instrucciones sin esperar a
que se completen las operaciones de acceso a la memoria de datos.
 Seguridad: La separación física de la memoria de instrucciones y datos puede
ayudar a prevenir ciertos tipos de ataques de seguridad, como los desbordamientos
de búfer.
 Desventajas:
 Costo: La implementación de buses separados y la gestión de dos tipos de memoria
pueden aumentar el costo de diseño y fabricación.
 Complejidad: La gestión de dos tipos de memoria y los buses independientes
pueden complicar el diseño del sistema y el desarrollo de software.
 Ejemplos de Uso: La arquitectura Harvard se utiliza en una variedad de dispositivos,
como microcontroladores, sistemas embebidos y algunos tipos de DSP (Procesadores
de Señales Digitales).
Es el componente principal de los DSP (procesamiento de señales digitales),
normalmente para productos de transformación de audio y vídeo.
Los microcontroladores se caracterizan por tener pequeñas cantidades de programa
(memoria flash) y memoria de datos (SRAM), sin cache, y aprovechan la arquitectura
de Harvard para acelerar el procesamiento de la instrucción simultánea y el acceso a
datos.
En resumen, la arquitectura Harvard es una estructura de procesamiento que utiliza buses
independientes para datos e instrucciones. Esto permite una ejecución más eficiente de
programas y ayuda a evitar cuellos de botella. ofrece ventajas en términos de rendimiento y
seguridad debido a la separación física de la memoria de instrucciones y datos, aunque
puede aumentar la complejidad y el costo del diseño.

Arquitectura Von Newman

La arquitectura von Neumann es un diseño de computadora teórico para que una


computadora pueda tener un programa almacenado de manera interna, sirviendo como base
para casi todas las computadoras que actualmente se realizan. fundamental que sigue los
principios establecidos por el matemático y físico John von Neumann a mediados del siglo
XX, que, en el año de 1945, después de la Segunda Guerra Mundial, dos científicos
plantearon de forma autónoma cómo construir una computadora más maleable, el
matemático Alan Turing y el científico de igual talento John Von Neumann.
El británico Alan Turing había estado involucrado en descifrar el código Enigma en
Bletchley Park, usando la computadora ‘Coloso’. Por otro lado, el estadounidense John
Von Neumann había estado trabajando en el Proyecto Manhattan para construir la primera
bomba atómica, que necesitaba una gran cantidad de cálculos manuales.
Hasta ese momento, las computadoras en tiempo de guerra se “programaban” más o menos
reconectando toda la máquina para poder llevar a cabo una tarea diferente. Por ejemplo, la
primera computadora llamada ENIAC tardaba tres semanas en reconectarse para realizar un
cálculo diferente.
El nuevo concepto consistía en que en una memoria no solo debían almacenarse los datos,
sino que también el programa que procesaba esos datos debería estar almacenado en la
misma memoria.
Esta arquitectura con el programa almacenado internamente se conoce comúnmente como
arquitectura ‘Von Neumann’.
Esta novedosa idea significaba que una computadora con esta arquitectura sería mucho más
fácil de reprogramar. Efectivamente, el programa en sí mismo se trataría igual que los
datos.
 Estructura: En la arquitectura von Neumann, tanto las instrucciones como los datos se
almacenan en la misma memoria y son tratados de la misma manera, lo que significa
que las instrucciones y los datos son direccionales. La CPU accede secuencialmente a la
memoria para leer instrucciones y datos.
Funciona usando cuatro simples pasos: buscar, decodificar, ejecutar, almacenar,
llamado el “Ciclo de la máquina”.
Las instrucciones son obtenidas por la CPU desde la memoria. La CPU luego
decodifica y ejecuta estas instrucciones. El resultado es almacenado de nuevo en la
memoria luego que se complete el ciclo de ejecución de las instrucciones.
- Buscar: En este paso se obtienen las instrucciones desde la RAM y se las coloca en la
memoria caché para que la unidad de control acceda a ellas.
- Decodificar: La unidad de control decodifica las instrucciones de tal manera que la
unidad aritmética lógica pueda comprenderlas, y luego las envía a la unidad aritmética
lógica.
- Ejecutar: La unidad lógica aritmética ejecuta las instrucciones y envía el resultado de
nuevo a la memoria caché.
- Almacenar: Una vez que el contador del programa indica detenerse, se descarga el
resultado final a la memoria principal.
 Memoria: En esta arquitectura, la memoria es unitaria, es decir, no se diferencia entre la
memoria que almacena programas (instrucciones) y la que almacena datos. Toda la
información se almacena en la misma memoria, y tanto las instrucciones como los datos
se representan de manera binaria.
 Acceso a la Memoria: La CPU accede a la memoria de forma secuencial, leyendo
instrucciones y datos uno tras otro a través de un único bus de datos y un único bus de
direcciones.
 Ventajas:
 Simplicidad: La arquitectura von Neumann es más simple de implementar y
entender que otras arquitecturas más complejas, lo que la hace adecuada para una
amplia gama de aplicaciones, ya que la unidad de control recupera los datos y las
instrucciones de la misma manera desde la memoria. Por tanto, el diseño y
desarrollo de la unidad de control está simplificado, siendo más barato y más
rápido.
 Flexibilidad: La capacidad de almacenar tanto instrucciones como datos en la
misma memoria permite una mayor flexibilidad en la programación y ejecución de
programas.
La organización de la memoria es realizada por los programadores, lo que permite
utilizar toda la capacidad de la memoria.
 Desventajas:
 Cuello de Botella de la Memoria: Debido a que la CPU accede a la memoria de
forma secuencial, puede producirse un cuello de botella cuando se necesita acceder
repetidamente a la memoria para leer instrucciones y datos. Como la CPU es mucho
más rápida que el bus de datos, esto significa que a menudo permanezca inactiva.
Por el procesamiento secuencial de las instrucciones no se permite la
implementación paralela del programa.
 Seguridad: La falta de separación entre la memoria de programa y la de datos puede
hacer que el sistema sea más vulnerable a ciertos tipos de ataques, como los
desbordamientos de búfer.
 Ejemplos de Uso: La arquitectura von Neumann se utiliza en una amplia variedad de
sistemas informáticos, desde computadoras personales y servidores hasta sistemas
embebidos y dispositivos móviles.
En resumen, la arquitectura von Neumann ofrece simplicidad y flexibilidad, pero puede
enfrentar limitaciones en términos de rendimiento y seguridad debido a su diseño de
memoria unitaria y acceso secuencial. Sin embargo, sigue siendo uno de los diseños más
utilizados en la actualidad debido a su eficacia y versatilidad.

Arquitectura Harvard Modificado

La arquitectura Harvard modificada es una variante de la arquitectura Harvard tradicional


que combina características de la arquitectura Harvard y la arquitectura von Neumann, que
permite que los contenidos de la memoria de instrucciones sean accedidos como si fuesen
datos.
En consecuencia, algunas máquinas Harvard puras son productos especiales. En cambio, la
mayoría de las computadoras modernas implementan una arquitectura Harvard modificada.
Esas modificaciones son varias formas de aflojar la separación estricta entre el código y los
datos, al mismo tiempo que se sigue admitiendo el acceso simultáneo de datos e
instrucciones de mayor rendimiento de la arquitectura de Harvard.
 Estructura: Similar a la arquitectura Harvard tradicional, la arquitectura Harvard
modificada mantiene la separación física entre la memoria de programa (instrucciones)
y la memoria de datos. Sin embargo, a diferencia de la arquitectura Harvard pura,
permite la ejecución de instrucciones almacenadas en la memoria de datos.
 Memoria: Al igual que en la arquitectura Harvard tradicional, en la versión modificada,
la memoria se divide en dos partes: una para almacenar instrucciones (Memoria de
Programa) y otra para almacenar datos (Memoria de Datos). Esta separación permite un
acceso independiente y simultáneo a instrucciones y datos.
 Acceso a la Memoria: La CPU puede acceder simultáneamente a la memoria de
programa y de datos, lo que puede mejorar el rendimiento al permitir la ejecución de
instrucciones mientras se accede a los datos. Sin embargo, a diferencia de la
arquitectura Harvard pura, la CPU también puede ejecutar instrucciones almacenadas
en la memoria de datos.
 Ventajas:
 Mayor Flexibilidad: La capacidad de ejecutar instrucciones desde la memoria de
datos aumenta la flexibilidad del sistema y puede simplificar el diseño del software.
 Rendimiento Mejorado: Al permitir la ejecución de instrucciones desde ambas
memorias de manera simultánea, se puede lograr un mejor rendimiento en
comparación con la arquitectura Harvard pura en ciertos casos.
 Seguridad: La separación física entre la memoria de programa y la memoria de
datos puede proporcionar cierto nivel de seguridad al prevenir ciertos tipos de
ataques, como los desbordamientos de búfer.
 Desventajas:
 Complejidad: La combinación de características de las arquitecturas Harvard y von
Neumann puede aumentar la complejidad del diseño del sistema y del software.
Los problemas con la protección del espacio ejecutable, que aumentan los riesgos
de malware y defectos de software. Además, en estos sistemas es notoriamente
difícil documentar el flujo de código y también puede dificultar mucho más la
depuración.
 Costo: La implementación de características adicionales puede aumentar el costo de
diseño y fabricación en comparación con la arquitectura Harvard pura.
 Ejemplos de Uso: La arquitectura Harvard modificada se utiliza en una variedad de
sistemas embebidos, microcontroladores y algunos procesadores especializados donde
se requiere un equilibrio entre el rendimiento y la flexibilidad.
 Características
Tres características se suelen utilizar para distinguir una máquina con arquitectura
Harvard modificada de una máquina con arquitectura Von Neumann o Harvard.
- La memoria de instrucciones y datos ocupan diferente espacio de direcciones.
- La memoria de instrucciones y datos tienen caminos hardware separados de la unidad
central de proceso (CPU).
- La memoria de instrucciones y datos pueden ser accedidas de diferente manera.
En resumen, la arquitectura Harvard modificada ofrece ventajas en términos de flexibilidad,
rendimiento y seguridad, en comparación con la arquitectura Harvard pura, que este tiene
mayor ancho de banda y se accede más rápido a la memoria de instrucciones, aunque puede
enfrentar desafíos adicionales en términos de complejidad y costo de diseño.

Ciclo De Fetch
El ‘’Ciclo de Fetch’’ es una parte fundamentar de la Arquitectura de una computadora
moderna, un ciclo de instrucción, que también es llamado como ciclo de ‘’fetch-and-
execute’’ o ‘’ciclo de ‘’Fetch-decode-execute’’ en inglés. El ‘’Ciclo de Fetch’’ es el periodo
de tiempo que tarda la unidad central del proceso (CPU) en ejecutar una instrucción de
lenguaje máquina. Un Ciclo de Instrucción o Ciclo de Fetch está formado por uno o más
ciclos máquina, para que cualquier sistema de proceso de datos basado en microprocesador
(una computadora) o microcontrolador (un reproductor de MP3) para que pueda cumplir
con una tarea debe de buscar cada instrucción en la memoria principal y luego ejecutarla.

Fase completa del Ciclo:

 Buscar la instrucción en la memoria principal

o Se vuelca el valor del contador de programa sobre el bus de direcciones.


Entonces la CPU pasa la instrucción de la memoria principal a través del bus
de datos al Registro de Dirección de Memoria (MAR). A continuación, el
valor del MAR es colocado en el Registro de Instrucción Actual (CIR), un
circuito que guarda la instrucción temporalmente de manera que pueda ser
decodificada y ejecutada.
 Decodificar la instrucción
o El decodificador de instrucción interpreta e implementa la instrucción. El
registro de instrucción (IR) mantiene la instrucción en curso mientras el
contador de programa (PC, program counter) guarda la dirección de
memoria de la siguiente instrucción a ser ejecutada.

 Recogida de datos desde la memoria principal

 Se accede al banco de registros por los operandos (solo si es


necesario)

 Se calcula el valor del operando inmediato con extensión de signo


(solo si es necesario)

o También se lee la dirección efectiva de la memoria principal si la instrucción


tiene una dirección indirecta, y se recogen los datos requeridos de la
memoria principal para ser procesados y colocados en los registros de datos.

 Ejecutar la instrucción
o A partir del registro de instrucción, los datos que forman la instrucción son
decodificados por la unidad de control. Ésta interpreta la información como
una secuencia de señales de control que son enviadas a las unidades
funcionales relevantes de la CPU para realizar la operación requerida por la
instrucción poder terminarla y seguir así.
 Almacenar o guardar resultados
o El resultado generado por la operación es almacenado en la memoria
principal o enviado a un dispositivo de salida dependiendo de la instrucción.
Basándose en los resultados de la operación, el contador de programa se
incrementa para apuntar a la siguiente instrucción o se actualiza con una
dirección diferente donde la próxima instrucción será recogida.
Estas 4 sub-etapas ocurren en todos los procesadores sea cual sea su utilidad, arquitectura y
compatibilidad binaria o lo que llamamos ISA. Por lo que es aplicable a prácticamente
cualquier modelo que os podáis encontrar en el mercado. Eso sí, en muchos casos variarán las
tecnologías utilizadas u otros componentes que entran a formar parte de este proceso para
agilizar trabajos mucho más específicos.

La unidad de control

La unidad de control es la pieza más compleja que existe en un procesador y sus tareas son las
siguientes que se detalla aquí debajo. Como en todos los casos, se trata de un conjunto de
mínimos, que son esenciales:
 Se encarga de coordinar el movimiento y el orden en que de los datos que se mueven
dentro y fuera del procesador, así de las diferentes subunidades que se encargan de
ello.

 En general se considera que las unidades de la etapa de captación o Fetch forman parte
del hardware que llamamos unidad de control y dicho hardware es llamado también el
Front-End de un procesador.

 Interpreta las instrucciones y las envía a las diferentes unidades de ejecución a las que
está conectado.

 Está comunicado a las diferentes ALUs y unidades de ejecución del procesador que
actúan

 Se encarga de captar y descodificar las instrucciones, sino también de escribir los


resultados en los registros, caches o en la dirección correspondiente de la RAM.

La unidad de control lo que hace es descodificar las instrucciones y esto lo hace porque cada
instrucción en realidad no deja de ser una especie de oración en donde primero va el verbo y
luego el objeto directo u objeto sobre el que se hace la acción. El sujeto se acaba eliminando
en este lenguaje interno de los ordenadores por el hecho que se sobrentiende que es el propio
ordenador el que lo ejecuta, así pues, cada cantidad de bits es una oración donde los primeros
1 y 0 corresponden a la acción y los que vienen a continuación es el dato o la localización del
dato que se quiere manipular.

Tipos de instrucciones

Las instrucciones que intervienen durante las fases del ciclo se pueden clasificarse en:

 Instrucciones de cálculo (aritmético y lógico).


 Instrucciones de transferencia de datos.
 Instrucciones de ruptura de secuencia.

De acuerdo a su formato y número de operandos se clasifican en:

 Instrucciones de tres operandos.


 Instrucciones de dos operandos.
 Instrucciones sin operando

Ensamblador NASM

Introducción

El lenguaje ensamblador, también conocido como assembler, es un lenguaje de bajo nivel


que permite escribir programas directamente en instrucciones de máquina. NASM
(Netwide Assembler) es uno de los ensambladores más populares y ampliamente utilizados
en sistemas operativos basados en arquitecturas x86 y x86-64.

Aquí veremos los fundamentos del ensamblador NASM, su sintaxis, estructuras de control,
manipulación de datos, acceso a memoria y otros aspectos clave que lo convierten en una
herramienta esencial para programadores de sistemas y desarrolladores de software.

Historia y Desarrollo

NASM fue creado por Simon Tatham y Julian Hall en 1996 como un proyecto de código
abierto. Desde entonces, ha experimentado múltiples versiones y revisiones, convirtiéndose
en una de las opciones más confiables y poderosas para la programación en ensamblador en
plataformas x86 y x86-64. NASM se caracteriza por su portabilidad, rendimiento y su
amplio conjunto de características que lo hacen adecuado para una variedad de
aplicaciones, desde la programación de sistemas operativos hasta la optimización de código
de bajo nivel.
Características Principales

NASM ofrece una serie de características que lo distinguen como una herramienta poderosa
para programadores de ensamblador:

1. Sintaxis Clara y Flexible: NASM utiliza una sintaxis clara y flexible que facilita la
escritura y comprensión del código ensamblador. Su sintaxis está inspirada en la
convención Intel, lo que la hace familiar para muchos programadores.

2. Portabilidad: NASM es altamente portátil y es compatible con una amplia gama de


plataformas, incluyendo sistemas operativos como Windows, Linux y macOS, así como
diversas arquitecturas x86 y x86-64.

3. Amplia Documentación: NASM cuenta con una extensa documentación que cubre
todos los aspectos del ensamblador, incluyendo guías de referencia, tutoriales y ejemplos de
código.

4. Optimización de Código: NASM permite escribir código altamente optimizado, lo que


lo hace ideal para aplicaciones donde el rendimiento es crítico, como los sistemas
operativos y los controladores de dispositivo.

5. Soporte para Macros: NASM soporta macros, lo que permite la creación de código
modular y reutilizable. Las macros facilitan la escritura de código más legible y mantenible.

Estructura del Código NASM

Un programa NASM típico consta de varias secciones, cada una con un propósito
específico:

1. Sección de Datos: En esta sección se definen las variables y constantes utilizadas por el
programa.
2. Sección de Código: Aquí se encuentra el código ensamblador real, que consiste en
instrucciones y directivas NASM.

3. Sección de Texto: Esta sección puede contener cadenas de texto y datos similares
utilizados por el programa.

4. Sección de BSS (Block Started by Symbol): Esta sección se utiliza para reservar
espacio para variables no inicializadas.
Sintaxis Básica

La sintaxis de NASM se compone de instrucciones, directivas y comentarios. Las


instrucciones son las operaciones reales que realiza el procesador, las directivas son
comandos especiales que controlan el ensamblado del código y los comentarios son notas
para el programador y no afectan al programa ensamblado.

Un ejemplo de código NASM básico que imprime "Hola, mundo" en la consola puede ser:

Manipulación de Datos y Control de Flujo

NASM ofrece una variedad de instrucciones para manipular datos y controlar el flujo de
ejecución del programa. Algunas de las instrucciones más comunes incluyen:
- Movimiento de Datos: `mov`, que mueve datos entre registros y memoria.

- Operaciones Aritméticas: `add`, `sub`, `mul`, `div`, que realizan operaciones aritméticas.

- Operaciones Lógicas: `and`, `or`, `xor`, que realizan operaciones lógicas a nivel de bits.

- Control de Flujo: `jmp`, `cmp`, `je`, `jne`, `jg`, `jl`, que controlan el flujo de ejecución
del programa mediante saltos condicionales e incondicionales.

Acceso a Memoria

NASM proporciona varias instrucciones para acceder a la memoria, incluyendo:

- Movimiento de Datos entre Registros y Memoria: `mov`, que se utiliza para cargar
datos desde la memoria en registros y viceversa.
- Acceso Directo a la Memoria: `mov`, `push`, `pop`, que se utilizan para acceder
directamente a la memoria sin utilizar registros intermedios.
- Instrucciones de Carga y Almacenamiento: `movsb`, `movsw`, `movsd`, que se utilizan
para transferir bloques de datos de un lugar a otro en la memoria.

Registros de propósito general:

Se utilizan comúnmente para almacenar datos temporales, direcciones de memoria y otros


valores durante la ejecución de un programa. Cada uno de estos registros tiene un propósito
específico, más comunes en arquitecturas x86 y x86-64:

 EAX (AX en 16 bits): Registro acumulador. Se utiliza para operaciones aritméticas


y lógicas, así como para almacenar los resultados de operaciones.
 EBX (BX en 16 bits): Registro base. Se utiliza comúnmente como un puntero a
datos en la memoria o como un contador en bucles.
 ECX (CX en 16 bits): Registro contador. Se utiliza frecuentemente como un
contador en bucles y en ciertas operaciones de cadena y gráficos.
 EDX (DX en 16 bits): Registro de datos extendido. Se utiliza para almacenar datos
temporales y para algunas operaciones aritméticas que requieren registros
adicionales.
 ESI (SI en 16 bits): Índice de origen. Se utiliza principalmente como un puntero a
datos en operaciones de cadena y en estructuras de datos que requieren acceso
secuencial.
 EDI (DI en 16 bits): Índice de destino. Similar a ESI, se utiliza como un puntero a
datos en operaciones de cadena y en estructuras de datos que requieren acceso
secuencial, pero generalmente se usa para apuntar al destino de las operaciones.

EJEMPLO

Calcular suma de dos enteros:

Un ejemplo básico de un programa en ensamblador NASM que calcula la suma de dos


números enteros y muestra el resultado en la consola:
Este programa comienza con la sección .data, donde se definen las variables num1 y num2,
que representan los dos números que se sumarán. En la sección .text, se realiza la suma de
los dos números y se imprime el resultado en la consola utilizando llamadas al sistema.
Finalmente, el programa sale del sistema operativo.
¿Cómo compilar con NASM en Linux?

Etapa 1 - Crear un fichero fuente

No es necesario un editor específico para crear un fichero fuente en lenguaje ensamblador.


Podemos elegir entre Gedit, Kwrite, Xemacs, etc. A la hora de guardarlo deberás ponerle la
extensión .asm.

Etapa 2 - Ensamblar el fichero fuente

 Para esta etapa, necesitaremos que el programa NASM esté instalado en nuestra
computadora. Si tienes Debian o Ubuntu, simplemente escribe el comando:

sudo apt-get install nasm

 Si utilizas otra distribución Linux, deberás utilizar el gestor de paquetes de tu


distribución (por ejemplo urpmi, yum, emerge...).

 Pasemos ahora al ensamblado del fichero fuente. Dirígete desde la línea de


comandos a la carpeta donde se encuentra. En este ejemplo lo hemos llamado
"test.asm". Escribimos:

nasm -f elf test.asm

 Esto creará un fichero llamado "test.o" en el directorio actual. Este aún no es


ejecutable, únicamente es un fichero objeto. Es necesario leerlo con las bibliotecas
de las que depende como, por ejemplo, la biblioteca standard libc.

Etapa 3 - Creación del ejecutable

Ahora que ya tenemos nuestro fichero objeto llamado "test.o" vamos a crear nuestro
ejecutable. Aquí se dan dos casos:
 El programa inicia con un procedimiento llamado “_start”. Esto significa que el
programa posee su propio punto de entrada sin utilizar la función main. Esto no
cambia mucho, sin embargo necesitarás utilizar el comando ld para crear el
ejecutable:

ld test.o -o test

 El programa inicia con un procedimiento llamado “main”. Entonces necesitarás


utilizar gcc para crear el ejecutable:

gcc test.o -o test

Etapa 4: Ejecución del programa

 Para ejecutar nuestro programa llamado “test”, basta con escribir este comando:

./test

 También podemos utilizar un depurador para observar la ejecución. Podemos


utilizar gdb, que se utiliza en línea de comandos. Si deseas un depurador visual
existen interfaces gráficas que utilizan gdb en segundo plano, como por ejemplo
Insight.

¿Cómo compilar con NASM en Windows?

En Windows cambia la manera en la que se llama a los parámetros, la función llamada debe
limpiar ella misma la pila. Además, si tu punto de entrada es "_start" o "main", deberás
cambiarlo a "_WinMain@16" y sustituir “ret” por "ret 16". A continuación, un ejemplo
de un fichero fuente correcto utilizado en Windows:
section .text
global _WinMain@16
_WinMain@16:
mov eax, 0
ret 16

Etapa 1 - Instalar los programas necesarios

En primer lugar tendrás que instalar NASM y MinGW, si todavía no dispones de ellos en
tu ordenador. Una vez hecho esto, vamos a insertar NASM en el entorno de desarrollo
MingW. Descomprime el fichero NASM y deberías encontrar una carpeta que contiene un
archivo llamado nasm.exe. Copia este fichero en la carpeta C:\MinGW\bin.

Etapa 2 - Crear un fichero fuente

Al igual que en Linux, no es necesario utilizar un editor específico para crear un fichero
fuente. Podemos utilizar, por ejemplo, el bloc de notas. Eso sí, debemos tener cuidado con
la extensión .txt. No se recomienda utilizar procesadores de texto como Word o WordPad
que pueden guardar el fichero en un formato no deseado. También puedes emplear un
editor que utiliza la coloración sintáctica para la sintaxis de NASM como NasmEdit IDE
(gratuito). En todos los casos se recomienda poner la extensión .asm.

Etapa 3 - Ensamblar el fichero fuente

Abre el intérprete de comandos de Windows (escribe cmd.exe en “Ejecutar” del menú


Inicio o directamente cmd en la barra de búsqueda). Aquí, debes ir a la carpeta que
contiene tu fichero fuente utilizando el comando cd. Una vez hecho esto, ensambla el
fichero fuente (llamémoslo test.asm) con este comando:

nasm -f win32 test.asm -o test.o


Etapa 4 - Creación y ejecución del programa

 Para crear el ejecutable, escribe en la ventana DOS la siguiente línea de código:

ld test.o -o test.exe

 Para testar el ejecutable, simplemente escribe “test” en la ventana DOS. Si


deseas un depurador para visualizar mejor lo que sucede, utiliza OllyDbg, un
excelente depurador.
Bibliografía

Hall, Julian, et al. "The NASM Manual." Netwide Assembler (NASM) - A Portable
Assembler. Consultado en enero de 2022. https://www.nasm.us/doc/ .
Tatham, Simon. "Netwide Assembler (NASM)." GitHub Repository. Consultado en enero
de 2022. https://github.com/netwide-assembler/nasm .
Intel Corporation. "Intel® 64 and IA-32 Architectures Software Developer's Manual."
Consultado en enero de 2022.
https://software.intel.com/content/www/us/en/develop/articles/intel-sdm.html .
Muñoz, Alejandro. "Programación en Ensamblador." Consultado en enero de 2022.
https://es.wikipedia.org/wiki/Programaci%C3%B3n_en_ensamblador .
Irene, Burn “Ensamblador NASM: qué es y cómo utilizar en Linux y Windows”. 17/05/22
14:33 https://es.ccm.net/ordenadores/programacion/2206-compilar-un-programa-
ensamblador-con-nasm/ .
MIA J. Rafael Rojano C. “Introducción al NASM”
https://www.uv.mx/rrojano/arquitectura_dos/intro-nasm.pdf .
Peñalver, E. (2024, 26 abril). Esto es lo que Qualcomm no nos ha contado de sus CPU
Snapdragon X. HardZone. https://hardzone.es/noticias/procesadores/cpu-
snapdragon-x-qualcomm/
Salgado, F. (s. f.). Qué es un Ciclo Fetch. Scribd.
https://es.scribd.com/document/526415610/Que-es-un-Ciclo-Fetch?
doc_id=526415610&download=true&order=633541747
Celestino, N. (2017, 1 mayo). GoConqr - Ciclo Fetch. GoConqr.
https://www.goconqr.com/es/diapositiva/8735265/ciclo-fetch
González, A. H. (2017). Lenguaje ensamblador.
Ksolano. (s. f.). Ciclo de Fetch. Scribd. https://es.scribd.com/doc/22376834/Ciclo-de-Fetch
https://academia-lab.com/enciclopedia/arquitectura-de-harvard/
https://www.lifeder.com/arquitectura-von-neumann/
https://www.wikiwand.com/es/Arquitectura_Harvard_modificada
https://www.profesionalreview.com/2021/07/18/risc-vs-cisc/
https://yesenializbethguerrerogarcia.blogspot.com/2017/03/registros-de-lenguaje-
ensamblador.html

También podría gustarte