Introducción.
Una computadora digital es una máquina que puede resolver problemas ejecutando una secuencia de instrucciones dadas. Se llama programa a una secuencia de instrucciones que describe paso a paso como ejecutar cierta tarea. Los circuitos electrónicos de cada computadora pueden reconocer y ejecutar directamente un conjunto limitado de instrucciones simples. Todos los programas que se desean ejecutar en una computadora deben convertirse previamente en una secuencia de estas instrucciones simples. Estas instrucciones básicas pocas veces rebasan la complejidad de:
-
Sumar
dos números.
-
Comprobar
si un número es cero.
-
Mover
datos de una parte de la memoria a otra.
El conjunto de instrucciones primitivas de una
computadora forma el lenguaje con el cual podemos comunicarnos con ella. Dicho
lenguaje se llama leguaje de máquina. Normalmente intentan hacer las
instrucciones primitivas lo más simple posible, siempre que estén de acuerdo
con el uso para el que se ha proyectado la computadora y el rendimiento
requerido, a fin de reducir la complejidad y el costo de la electrónica que se
necesite. Debido a que la mayoría de los lenguajes de máquina son demasiado
elementales, es difícil y tedioso utilizarlos.
Hay dos formas de atacar este problema; ambas
incluyen el diseño de un nuevo conjunto de instrucciones, más convenientes para
las personas que el conjunto de instrucciones propias de la máquina. Estas
instrucciones, en conjunto forman un nuevo lenguaje que llamaremos L2, de
manera semejante al que forman las nuevas instrucciones propias de la máquina,
que llamaremos L1. Las dos aproximaciones difieren en el modo en que los
programas escritos en L2 son ejecutados por la computadora, ya que, después de
todo, sólo puede ejecutar programas escritos en su lenguaje de máquina L1.
Un método para ejecutar un programa escrito en
L2 consiste en sustituir primero cada instrucción por una secuencia equivalente
de instrucciones L1. El resultado es un nuevo programa escrito totalmente con
instrucciones en L1. La computadora ejecutará entonces el nuevo programa en L1
y no el anterior en L2. Esta técnica se denomina traducción o compilación.
La otra técnica es escribir un programa en L1
que tome programas escritos en L2 como datos de entrada y los lleve a cabo
examinando una instrucción a la vez y ejecutando directamente la secuencia
equivalente de instrucciones en L1. Esta técnica, que no requiere la generación
previa de un nuevo programa en L1 se llama interpretación y el programa que la
lleva a cabo, interprete.
La traducción y la interpretación son bastantes
similares. En ambos métodos, las instrucciones L2 se llevan a cabo al ejecutar
secuencias equivalentes de instrucciones en L1. La diferencia radica en que, en
la traducción todo programa en L2 se convierte en un programa en L1 (código
objeto), el programa en L2 se desecha y entonces se ejecuta el programa
generado en L1. En la interpretación se ejecuta cada instrucción en L2
inmediatamente después de examinarla y decodificarla. No se genera ningún
programa traducido. Ambos métodos se usan ampliamente.
En vez de pensar en términos de traducción o
interpretación, a menudo conviene imaginar la existencia de una computadora
hipotética o máquina virtual cuyo lenguaje sea L2.
La invención de toda una serie de lenguajes,
cada uno más conveniente que sus predecesores, puede continuar indefinidamente
hasta que se consiga una adecuado. Cada lenguaje usa a su predecesor como base,
de manera que una computadora que usa esta técnica puede considerarse como una
serie de capas o niveles, uno por encima del otro. El lenguaje de alto niveles
el más simple, y el de más bajo nivel el más complejo.
Lenguajes, Niveles y Máquinas virtuales.
Existe una relación importante entre un
lenguaje y una máquina virtual. Cada máquina tiene algún lenguaje de máquina,
que consiste en todas las instrucciones que puede ejecutar. De hecho, una
máquina define un lenguaje. En forma similar, un lenguaje define una máquina:
la que puede ejecutar todos los programas escritos en ese lenguaje.
Una máquina con n niveles puede verse como n
máquinas virtuales diferentes, cada una de las cuales tiene un lenguaje de
máquina especial. Solo los programas escritos en L1 pueden ser ejecutados
directamente por los circuitos electrónicos sin que se tenga que utilizar la traducción ni la
interpretación. Los programas escritos en L2, L3, ..., Ln deben interpretarse
por un intérprete en un nivel inferior o traducidos a otro lenguaje correspondiente
a un nivel inferior.
Una persona cuyo trabajo sea escribir programas
para la máquina virtual de nivel n no necesita conocer los interpretes ni los
traductores subyacentes.
Máquinas Multinivel actuales.
La mayoría de las computadoras modernas constan
de dos o más niveles. En el nivel 0, el más inferior, es realmente el hardware
de la máquina. Sus circuitos ejecutan los programas en el lenguaje de máquina
de nivel 1.
En el nivel más bajo, el nivel de lógica
digital, los objetos que nos interesan se denominan compuertas. Si bien se construyen
a partir de componentes analógicos, tales como transistores, las compuertas
pueden modelarse con precisión como dispositivos digitales. Cada compuerta
tiene una o más entradas digitales (señales que se representan con 0 o 1) y
calcula alguna función simple de estas entradas, como las funciones lógicas
AND, OR y EXOR. La tabla de verdad de estas compuertas es.
AND
OR EXOR
x
y f x y f x y
f
0
0 0 0 0 0 0 0
0
0
1 0 0 1 1 0 1
1
1
0 0 1 0 1 1 0 1
1
1 1 1 1 1 1 1
0
El siguiente nivel por encima es el nivel 1,
que conforma el verdadero nivel de lenguaje de máquina. En contraste con el
nivel 0, donde no existe el concepto de programa como conjunto de instrucciones
a realizar, en el nivel 1 existe ya un programa llamado microprograma, cuya
función es interpretar las instrucciones del nivel 2. Llamaremos al nivel 1 el
nivel de microprogramación.
Es preciso señalar que algunas computadoras no
tienen un nivel de micro computación. En estas máquinas las instrucciones del
nivel de máquina convencional son realizadas directamente por los circuitos
electrónicos (nivel 0), sin ningún intérprete que intervenga. En consecuencia,
el nivel de máquina convencional es el 1 no el 2. De todos modos, continuaremos
llamando al nivel de máquina convencional “nivel 2”.
El tercer nivel normalmente es un nivel
híbrido. La mayoría de las instrucciones de su lenguaje están también en el lenguaje
2. Además existe un nuevo conjunto de instrucciones, una diferente organización
de la memoria y la posibilidad de ejecutar dos o más programas en paralelo,
entre otras cosas.
Las nuevas posibilidades que se añaden al nivel
tres las lleva a cabo un intérprete que
actúa en el nivel 2 al que tradicionalmente se llama sistema operativo. Las
instrucciones idénticas a las del nivel 2 las lleva directamente a cabo el
microprograma en lugar de ejecutarlas el sistema operativo. En otras palabras,
algunas de las instrucciones del nivel 3 las interpreta el sistema operativo y
otras las interpreta el microprograma, de ahí lo híbrido.
En el nivel 4 se encuentra los leguajes de
nivel intermedio como el C y en el nivel 5 los lenguajes de alto nivel como C++
y Java.
Hardware, Software y máquinas multinivel.
El hardware esta constituido por los circuitos
electrónicos, junto con la memoria y los dispositivos de entrada y salida.
El Software consta de las instrucciones detalladas
que dicen como hacer algo, es decir los programas. Los programas pueden
representarse en tarjetas perforadas, cinta magnética, película fotográfica y
otros medios.
Cualquier operación realizada por el software
puede ser implementada con el hardware y cualquier instrucción ejecutada por
hardware puede ser simulada por software.
Cronología histórica de la arquitectura de
computadoras.
La generación 0, computadoras mecánicas (1642 –
1945)
La primera generación, bulbos (1945 – 1955)
La segunda generación, transistores (1955 –
1965)
La tercer generación, circuitos integrados
(1965 – 1980)
La cuarta generación, computadoras personales e
integración a alta escala (1980 – 20??)
Organización de computadoras.
En la figura 1 se muestra la organización de
una computadora con un solo bus. La unidad central de procesamiento (CPU) es el
cerebro de la computadora. Su función es ejecutar programas almacenados en la
memoria central tomando sus instrucciones, examinándolas y luego ejecutándolas
una tras otra. La CPU se compone de varias partes. La unidad de control se
encarga de traer las instrucciones de la memoria principal y de determinar su
tipo. La unidad aritmética y lógica realiza operaciones como la suma o la
función booleana AND, necesarias para llevar a cabo las instrucciones.
La CPU también contiene una pequeña memoria de
alta velocidad utilizada para almacenar resultados intermedios y cierta
información de control. Esta memoria consta de varios registros, cada uno de
los cuales tiene cierta función. El registro más importante es el Contador de
programa (CP), que indica la próxima instrucción que debe ejecutarse. También
es importante el registro de instrucción (RI), que contiene la instrucción que
se está ejecutando.
Figura 1
Ejecución
de las instrucciones.
La CPU
ejecuta instrucciones en una serie de pequeños pasos:
1.- Extrae
de la memoria la siguiente instrucción y la lleva al registro de instrucción.
2.- Cambia
el contador de programa de modo que señale la siguiente instrucción.
3.-
Determina el tipo de instrucción que acaba de extraer.
4.-
Verifica si la instrucción requiere datos de la memoria y, si así es, determina
donde están situados.
5.- Extrae
los datos, si los hay, y los carga en los registros internos del CPU.
6.- Ejecuta
la instrucción.
7.-
Almacena los datos en el lugar apropiado.
8.- Va al paso
1 para empezar la ejecución de la siguiente instrucción.
Códigos.
Binario.
El código binario es una representación de los números decimales en binario. Es muy utilizado por la computadoras ya que es el lenguaje que entiende. En binario tendremos la siguiente ponderación dependiendo de la posición de los dígitos.
wn.... w7 w6 w5 w4 w3 w2 w1 w0 w-1 w-2 w-3 w-4
2n ... 128 64 32 16
8 4 2 1 ½
¼ 1/8 1/16
y el número en decimal lo calculamos como
La ecuación
anterior nos sirve para hacer la conversión de binario a decimal, y para hacer
la conversión de decimal a binario hacemos:
Para hacer
Hexadecimal.
El código Hexadecimal es un sistema de numeración que utiliza 16 dígitos, con los siguientes valores
dígito |
valor binario |
valor decimal |
0 |
0000 |
0 |
1 |
0001 |
1 |
2 |
0010 |
2 |
3 |
0011 |
3 |
4 |
0100 |
4 |
5 |
0101 |
5 |
6 |
0110 |
6 |
7 |
0111 |
7 |
8 |
1000 |
8 |
9 |
1001 |
9 |
A |
1010 |
10 |
B |
1011 |
11 |
C |
1100 |
12 |
D |
1101 |
13 |
E |
1110 |
14 |
F |
1111 |
15 |
La ponderación que se da a cada dígito
hexadecimal es
... w7 w6 w5 w4 w3 w2 w1 w0 w-1 w-2 w-3 w-4
…
... 167 166 165 164 163 162 161 160 16-1
16-2 16-3 16-4 ...
y el número en decimal lo calculamos como
HEX |
DEC |
CHR |
CTRL |
|
HEX |
DEC |
CHR |
|
HEX |
DEC |
CHR |
|
HEX |
DEC |
CHR |
00 |
0 |
NUL |
^@ |
|
20 |
32 |
SP |
|
40 |
64 |
@ |
|
60 |
96 |
` |
01 |
1 |
SOH |
^A |
|
21 |
33 |
! |
|
41 |
65 |
A |
|
61 |
97 |
a |
02 |
2 |
STX |
^B |
|
22 |
34 |
" |
|
42 |
66 |
B |
|
62 |
98 |
b |
03 |
3 |
ETX |
^C |
|
23 |
35 |
# |
|
43 |
67 |
C |
|
63 |
99 |
c |
04 |
4 |
EOT |
^D |
|
24 |
36 |
$ |
|
44 |
68 |
D |
|
64 |
100 |
d |
05 |
5 |
ENQ |
^E |
|
25 |
37 |
% |
|
45 |
69 |
E |
|
65 |
101 |
e |
06 |
6 |
ACK |
^F |
|
26 |
38 |
& |
|
46 |
70 |
F |
|
66 |
102 |
f |
07 |
7 |
BEL |
^G |
|
27 |
39 |
' |
|
47 |
71 |
G |
|
67 |
103 |
g |
08 |
8 |
BS |
^H |
|
28 |
40 |
( |
|
48 |
72 |
H |
|
68 |
104 |
h |
09 |
9 |
HT |
^I |
|
29 |
41 |
) |
|
49 |
73 |
I |
|
69 |
105 |
i |
0A |
10 |
LF |
^J |
|
2A |
42 |
* |
|
4A |
74 |
J |
|
6A |
106 |
j |
0B |
11 |
VT |
^K |
|
2B |
43 |
+ |
|
4B |
75 |
K |
|
6B |
107 |
k |
0C |
12 |
FF |
^L |
|
2C |
44 |
, |
|
4C |
76 |
L |
|
6C |
108 |
l |
0D |
13 |
CR |
^M |
|
2D |
45 |
- |
|
4D |
77 |
M |
|
6D |
109 |
m |
0E |
14 |
SO |
^N |
|
2E |
46 |
. |
|
4E |
78 |
N |
|
6E |
100 |
n |
0F |
15 |
SI |
^O |
|
2F |
47 |
/ |
|
4F |
79 |
O |
|
6F |
111 |
o |
10 |
16 |
DLE |
^P |
|
30 |
48 |
0 |
|
50 |
80 |
P |
|
70 |
112 |
p |
11 |
17 |
DC1 |
^Q |
|
31 |
49 |
1 |
|
51 |
81 |
Q |
|
71 |
113 |
q |
12 |
18 |
DC2 |
^R |
|
32 |
50 |
2 |
|
52 |
82 |
R |
|
72 |
114 |
r |
13 |
19 |
DC3 |
^S |
|
33 |
51 |
3 |
|
53 |
83 |
S |
|
73 |
115 |
s |
14 |
20 |
DC4 |
^T |
|
34 |
52 |
4 |
|
54 |
84 |
T |
|
74 |
116 |
t |
15 |
21 |
NAK |
^U |
|
35 |
53 |
5 |
|
55 |
85 |
U |
|
75 |
117 |
u |
16 |
22 |
SYN |
^V |
|
36 |
54 |
6 |
|
56 |
86 |
V |
|
76 |
118 |
v |
17 |
23 |
ETB |
^W |
|
37 |
55 |
7 |
|
57 |
87 |
W |
|
77 |
119 |
w |
18 |
24 |
CAN |
^X |
|
38 |
56 |
8 |
|
58 |
88 |
X |
|
78 |
120 |
x |
19 |
25 |
EM |
^Y |
|
39 |
57 |
9 |
|
59 |
89 |
Y |
|
79 |
121 |
y |
1A |
26 |
SUB |
^Z |
|
3A |
58 |
: |
|
5A |
90 |
Z |
|
7A |
122 |
z |
1B |
27 |
ESC |
|
|
3B |
59 |
; |
|
5B |
91 |
[ |
|
7B |
123 |
{ |
1C |
28 |
FS |
|
|
3C |
60 |
< |
|
5C |
92 |
\ |
|
7C |
124 |
| |
1D |
29 |
GS |
|
|
3D |
61 |
= |
|
5D |
93 |
] |
|
7D |
125 |
} |
1E |
30 |
RS |
|
|
3E |
62 |
> |
|
5E |
94 |
^ |
|
7E |
126 |
~ |
1F |
31 |
US |
|
|
3F |
63 |
? |
|
5F |
95 |
_ |
|
7F |
127 |
DEL |
El
IEEE (Institute of Electrical and Electronics Engineers) ha creado un código
estándar para representar números flotantes. Este estándar especifica como
deben ser representados números en precisión simple de 32 bits y de doble
precisión en 64 bits.
La representación
estándar IEEE para números flotantes requiere de una palabra de 32, la cual
debe ser numerada del 0 a 31, izquierda a derecha. El primer bit S, es un bit
de signo, los siguientes 8 bits son el exponente del número 'E', y los 23 bits
restantes son la mantisa 'F':
S EEEEEEEE FFFFFFFFFFFFFFFFFFFFFFF
0 1 8 9 31
El valor V representado por la palabra
debe determinarse como sigue:
En particular,
0 00000000 00000000000000000000000 = 0
1 00000000 00000000000000000000000 = -0
0 11111111 00000000000000000000000 = Infinity
1 11111111 00000000000000000000000 = -Infinity
0 11111111 00000100000000000000000 = NaN
1 11111111 00100010001001010101010 = NaN
0 10000000 00000000000000000000000 = +1 * 2**(128-127) * 1.0 = 2
0 10000001 10100000000000000000000 = +1 * 2**(129-127) * 1.101 = 6.5
1 10000001 10100000000000000000000 = -1 * 2**(129-127) * 1.101 = -6.5
0 00000001 00000000000000000000000 = +1 * 2**(1-127) * 1.0 = 2**(-126)
0 00000000 10000000000000000000000 = +1 * 2**(-126) * 0.1 = 2**(-127)
0 00000000 00000000000000000000001 = +1 * 2**(-126) *
0.00000000000000000000001 =
2**(-149) (valor mas pequeño posible)