Bus -- el «sistema de carreteras» interno de la computadora
Los componentes internos de la computadora necesitan intercambiar información constantemente. La CPU debe tomar instrucciones de la memoria y leer/escribir datos, ¿cómo se transmite esta información? La respuesta es—Bus。
Un bus es un conjunto de líneas de comunicación compartidas que conectan dispositivos como la CPU, la memoria, el disco duro y la tarjeta gráfica, igual que el sistema de carreteras de una ciudad—con vías principales y ramales, cada uno con un propósito claro.
Esta lección te ayudará a comprender la división de tareas de los tres buses y a usar Python para simular una operación completa de lectura de memoria.
Analogía del sistema de carreteras: tres tipos de vías, tres propósitos
Imagina que repartes paquetes en una gran ciudad. El repartidor necesita saber tres cosas:A dónde entregar、Qué entregar、Si el destinatario debe firmar o no。
Dentro de la computadora también hay tres «carreteras» muy similares:
| Tipo de bus | Función | Dirección de transmisión | Analogía cotidiana |
|---|---|---|---|
| Bus de direcciones (Address Bus) | Transmite la dirección de memoria a la que se quiere acceder | CPU → Memoria (unidireccional) | El «número de casa» en la nota de entrega—le dice al receptor «busco esta dirección» |
| Bus de datos (Data Bus) | Transmite el contenido real de los datos | Bidireccional | El «paquete» que lleva el repartidor—el objeto en sí, puede enviarse o recibirse |
| Bus de control (Control Bus) | Transmite señales de control como lectura/escritura e interrupciones | CPU ↔ varios componentes (bidireccional) | El «comprobante de entrega»—indica a la otra parte si es recogida o entrega, y si la transmisión ha terminado |
El ancho del bus de direcciones determina cuánta memoria puede acceder la CPU. Un bus de direcciones de 32 bits puede acceder a 2^32 = 4GB de espacio de memoria, y un bus de direcciones de 64 bits puede acceder teóricamente a 2^64 bytes (aproximadamente 16EB). Por eso un sistema operativo de 32 bits solo puede usar como máximo 4GB de memoria.
Proceso completo de una operación de lectura de memoria
Supón que la CPU necesita leer un dato de la dirección de memoria 100. Todo el proceso se divide en 4 pasos, con los tres buses trabajando en conjunto:
Desglose de pasos
- La CPU coloca la dirección: La CPU pone el valor de dirección 100 en elbus de direcciones. En este momento, la memoria ha recibido el número de casa.
- La CPU envía la señal: La CPU emite la señal de «lectura» (READ) en elbus de control. La memoria sabe que la otra parte quiere retirar algo.
- La memoria coloca los datos: Tras recibir la dirección y la señal de lectura, la memoria encuentra el dato almacenado en la dirección 100 y lo coloca en elbus de datos.
- La CPU recibe los datos: La CPU lee el dato del bus de datos y lo guarda en un registro interno. La transmisión se completa.
Diagrama de tiempos
A continuación se muestra un diagrama de tiempos en ASCII que ilustra los cambios de estado del bus durante la ejecución de esta instrucción:
时间 | 地址总线 控制总线 数据总线 ------|------------------------------------------ T0 | 100 IDLE XXXX ← CPU 放上地址 T1 | 100 READ XXXX ← CPU 发出读信号 T2 | 100 READ 0x2A ← 内存放上数据 T3 | XXXX IDLE 0x2A ← CPU 取走数据 ------|------------------------------------------ 结果: CPU 从地址 100 读到了数据 0x2A
Demostración de código: simular el proceso de interacción del bus con Python
El siguiente código Python simula por completo el proceso de cooperación entre el bus de direcciones, el bus de datos y el bus de control en una operación de lectura de memoria.
Ejemplo
Simulación de interacción del bus - una operación completa de lectura de memoria (demo de ejemplo)
Este programa simula el proceso completo en el que la CPU lee datos de la memoria a través de los tres buses:
1. Bus de direcciones: la CPU emite la dirección de memoria a la que quiere acceder
2. Bus de control: la CPU emite las señales de control de lectura/escritura
3. Bus de datos: la memoria devuelve/recibe los datos
Cada cambio de estado del bus imprime un registro detallado, lo que facilita observar el trabajo coordinado de los tres buses.
"""
import time
class AddressBus:
"""Bus de direcciones - unidireccional: la CPU envía la dirección a la memoria"""
def __init__(self):
self.value = None # Valor de dirección actual en el bus
self.width = 16 # Bus de direcciones de 16 bits, puede direccionar 64KB
def set_address(self, addr):
"""La CPU coloca la dirección en el bus de direcciones"""
self.value = addr
print(f" [Bus de direcciones] La CPU colocó la dirección: {addr} (0x{addr:04X})")
return addr
def clear(self):
"""Limpiar el bus"""
self.value = None
print(f" [Bus de direcciones] Bus limpiado, entrando en estado inactivo")
class DataBus:
"""Bus de datos - bidireccional: tanto la CPU como la memoria pueden enviar y recibir datos"""
def __init__(self):
self.value = None # Valor de datos actual en el bus
self.width = 8 # Bus de datos de 8 bits, transfiere un byte a la vez
self.direction = None # 'TO_CPU' o 'TO_MEMORY'
def send_from_cpu(self, data):
"""La CPU envía datos al bus"""
self.value = data
self.direction = 'TO_MEMORY'
print(f" [Bus de datos] CPU → bus, datos: {data} (0x{data:02X})")
return data
def send_from_memory(self, data):
"""La memoria envía datos al bus"""
self.value = data
self.direction = 'TO_CPU'
print(f" [Bus de datos] Memoria → bus, datos: {data} (0x{data:02X})")
return data
def read_to_cpu(self):
"""La CPU lee datos del bus de datos"""
data = self.value
print(f" [Bus de datos] La CPU lee datos del bus: {data} (0x{data:02X})")
self.clear()
return data
def read_to_memory(self):
"""La memoria lee datos del bus de datos (se usa en operaciones de escritura)"""
data = self.value
print(f" [Bus de datos] La memoria lee datos del bus: {data} (0x{data:02X})")
self.clear()
return data
def clear(self):
"""Limpiar el bus"""
self.value = None
self.direction = None
print(f" [Bus de datos] Bus limpiado, entrando en estado inactivo")
class ControlBus:
"""Bus de control - bidireccional: transmite señales de lectura/escritura, señales de interrupción, etc."""
# Tipo de señal de control
READ = 'MEM_READ' # Señal de lectura de memoria
WRITE = 'MEM_WRITE' # Señal de escritura de memoria
IDLE = 'IDLE' # Inactivo
def __init__(self):
self.signal = self.IDLE
def set_signal(self, signal):
"""Establecer la señal de control"""
self.signal = signal
signal_name = {
self.READ: 'Lectura de memoria (MEM_READ)',
self.WRITE: 'Escritura de memoria (MEM_WRITE)',
self.IDLE: 'Inactivo (IDLE)'
}
print(f" [Bus de control] La CPU envía la señal: {signal_name.get(signal, signal)}")
def clear(self):
"""Limpiar la señal"""
self.signal = self.IDLE
print(f" [Bus de control] Señal limpiada, entrando en estado inactivo")
class SimpleMemory:
"""Módulo de memoria simplificado - espacio de almacenamiento de 256 bytes"""
def __init__(self, size=256):
self.size = size
self.data = {}
# Inicializar algunos datos de demostración
for i in range(size):
self.data[i] = i % 256 # La dirección i almacena el valor i % 256
# Colocar algunos valores especiales en direcciones específicas como demostración
self.data[100] = 42 # Dirección 100: almacenar 42 (0x2A)
self.data[200] = 0xAB # Dirección 200: almacenar 0xAB (171)
self.data[50] = ord('R') # Dirección 50: almacenar el código ASCII de la letra 'R'
self.data[51] = ord('U')
self.data[52] = ord('N')
self.data[53] = ord('O')
self.data[54] = ord('O')
self.data[55] = ord('B')
def read(self, addr):
"""Leer datos de la dirección especificada"""
if 0 <= addr < self.size:
return self.data.get(addr, 0)
else:
raise ValueError(f"Dirección {addr} fuera del rango de memoria (0-{self.size-1})")
def write(self, addr, data):
"""Escribir datos en la dirección especificada"""
if 0 <= addr < self.size:
self.data[addr] = data
else:
raise ValueError(f"Dirección {addr} fuera del rango de memoria (0-{self.size-1})")
class CPU:
"""CPU simplificada - interactúa con la memoria a través del bus"""
def __init__(self, addr_bus, data_bus, ctrl_bus, memory):
self.addr_bus = addr_bus # Bus de direcciones
self.data_bus = data_bus # Bus de datos
self.ctrl_bus = ctrl_bus # Bus de control
self.memory = memory # Memoria
# Registros internos de la CPU
self.mdr = 0 # Registro de datos (Memory Data Register)
self.mar = 0 # Registro de direcciones (Memory Address Register)
def memory_read(self, addr):
"""
Ejecutar una operación completa de lectura de memoria
Flujo:
T0: MAR ← addr (preparación interna)
T1: Bus de direcciones ← addr, Bus de control ← READ
T2: La memoria lee los datos, Bus de datos ← data
T3: MDR ← Bus de datos, todos los buses se limpian
Retorno: el valor de dato leído
"""
print(f"\n{'='*55}")
print(f"Inicio de la operación: la CPU lee datos de la dirección de memoria {addr}")
print(f"{'='*55}")
# T0: preparación interna de la CPU—cargar la dirección en MAR
self.mar = addr
print(f"\n[T0 - preparación interna de la CPU])
print(f" [CPU interno] MAR (Registro de dirección de memoria) ← {addr}")
# T1: La CPU coloca la dirección en el bus de direcciones y, al mismo tiempo, envía la señal de lectura en el bus de control
print(f"\n[T1 - Enviar dirección y señal de lectura]")
self.addr_bus.set_address(addr)
self.ctrl_bus.set_signal(ControlBus.READ)
# Simular retardo de transmisión de señal
time.sleep(0.001)
# T2: La memoria responde: encuentra los datos según la dirección en el bus de direcciones y los coloca en el bus de datos
print(f"\n[T2 - Respuesta de la memoria]")
data = self.memory.read(addr)
self.data_bus.send_from_memory(data)
# Simular retardo de transmisión de señal
time.sleep(0.001)
# T3: La CPU lee los datos del bus de datos y los guarda en MDR. Se limpian todos los buses
print(f"\n[T3 - La CPU recibe datos]")
self.mdr = self.data_bus.read_to_cpu()
self.ctrl_bus.clear()
self.addr_bus.clear()
# Mostrar resultado
print(f"\n{'='*55}")
print(f"Operación completada: se leyeron los datos {self.mdr} (0x{self.mdr:02X}) desde la dirección {addr} (0x{addr:04X})")
print(f"{'='*55}")
return self.mdr
def memory_write(self, addr, data):
"""
Ejecutar una operación completa de escritura en memoria
Proceso:
T0: MAR ← addr, MDR ← data
T1: bus de direcciones ← addr, bus de datos ← data, bus de control ← WRITE
T2: La memoria toma los datos del bus de datos y los escribe en la dirección addr
T3: Se limpian todos los buses
"""
print(f"\n{'='*55}")
print(f"Operación iniciada: la CPU escribe los datos {data} en la dirección de memoria {addr}")
print(f"{'='*55}")
# T0: Preparación interna de la CPU
self.mar = addr
self.mdr = data
print(f"\n[T0 - Preparación interna de la CPU]")
print(f" [CPU interno] MAR ← {addr}, MDR ← {data}")
# T1: La CPU coloca la dirección y los datos en el bus y emite la señal de escritura
print(f"\n[T1 - Enviar dirección, datos y señal de escritura]")
self.addr_bus.set_address(addr)
self.data_bus.send_from_cpu(data)
self.ctrl_bus.set_signal(ControlBus.WRITE)
time.sleep(0.001)
# T2: La memoria toma los datos del bus de datos y los escribe
print(f"\n[T2 - Escritura en memoria]")
received = self.data_bus.read_to_memory()
self.memory.write(addr, received)
print(f" [Memoria interna] Dirección {addr} (0x{addr:04X}) ← {received} (0x{received:02X})")
time.sleep(0.001)
# T3: Se limpian todos los buses
print(f"\n[T3 - Limpiar buses]")
self.ctrl_bus.clear()
self.addr_bus.clear()
print(f"\n{'='*55}")
print(f"Operación completada: {data} se ha escrito en la dirección {addr}")
print(f"{'='*55}")
# ===== Programa principal: ejecutar demostración =====
if __name__ == "__main__":
print("=" * 60)
print(" Simulación de interacción de buses —— Demostración de principios de organización de computadoras EJEMPLO")
print("=" * 60)
print()
# 1. Inicializar buses
print("【Inicialización del sistema】Crear bus de direcciones, bus de datos, bus de control y módulo de memoria")
addr_bus = AddressBus()
data_bus = DataBus()
ctrl_bus = ControlBus()
memory = SimpleMemory()
print()
# 2. Ver estado inicial de la memoria
print("【Estado inicial de la memoria】Vista previa de los datos en direcciones clave:")
for addr in [50, 51, 52, 53, 54, 55, 100, 200]:
ch = chr(memory.data[addr]) if 32 <= memory.data[addr] < 127 else '?'
print(f" Dirección {addr} (0x{addr:04X}): {memory.data[addr]:3d} (0x{memory.data[addr]:02X}) '{ch}'")
print()
# 3. Inicializar CPU
cpu = CPU(addr_bus, data_bus, ctrl_bus, memory)
# 4. Demostración: leer datos de la memoria
print("\n" + "▼" * 60)
print("Demostración 1: Leer datos de la dirección de memoria 100")
print("▼" * 60)
val1 = cpu.memory_read(100)
print("\n" + "▼" * 60)
print("Demostración 2: Leer datos de la dirección de memoria 200")
print("▼" * 60)
val2 = cpu.memory_read(200)
print("\n" + "▼" * 60)
print("Demostración 3: Leer consecutivamente de las direcciones de memoria 50-55 y formar los caracteres (EJEMPLO)")
print("▼" * 60)
chars = []
for addr in range(50, 56):
val = cpu.memory_read(addr)
chars.append(chr(val))
print(f"\n"Cadena formada: {''.join(chars)}")
# 5. Demostración: escribir datos en la memoria
print("\n" + "▼" * 60)
print("Demostración 4: Escribir el dato 77 en la dirección de memoria 10")
print("▼" * 60)
cpu.memory_write(10, 77)
# 6. Verificar el resultado de la escritura
print("\n" + "▼" * 60)
print("Demostración 5: Verificar la escritura — leer el dato de la dirección 10")
print("▼" * 60)
val3 = cpu.memory_read(10)
print(f"\n"Verificación: escritura 77, lectura {val3}, {'éxito' if val3 == 77 else 'fallo'}")
print("\n" + "=" * 60)
print(" ¡Todas las demostraciones completadas!")
print("=" * 60)
Ancho del bus y rendimiento real
El ancho del bus de direcciones determina «cuánta memoria puede gestionar»
Cada línea del bus de direcciones transmite un bit binario. N líneas de direcciones pueden representar 2^N direcciones diferentes.
| Ancho del bus de direcciones | Espacio direccionable | CPU típica |
|---|---|---|
| 16 bits | 2^16 = 64 KB | Intel 8086 (1978) |
| 20 bits | 2^20 = 1 MB | Intel 8088 (IBM PC, 1981) |
| 24 bits | 2^24 = 16 MB | Intel 80286 (1982) |
| 32 bits | 2^32 = 4 GB | Intel 80386 (1985) |
| 64 bits | 2^64 = aproximadamente 16 EB | Procesadores x86-64 modernos |
Nota: Los CPUs modernos de 64 bits suelen tener menos de 64 líneas de dirección reales (por ejemplo, 48), porque 2^64 bytes superan con creces las necesidades reales de la memoria física actual. Con 48 líneas de dirección ya se pueden direccionar 256 TB, suficiente para el uso actual.
El ancho del bus de datos determina «cuántos datos se pueden transferir de una sola vez»
Un bus de datos de 8 bits transmite 1 byte a la vez; un bus de datos de 64 bits transmite 8 bytes a la vez. Por eso, para la misma tarea, un sistema de 64 bits suele ser más rápido que uno de 32 bits: la cantidad de datos transmitidos de una sola vez se duplica.
Tipos de señales del bus de control
El bus de control no es tan uniforme como los buses de direcciones y datos. Es un conjunto de diversas líneas de señal, que incluyen:
- MEM_READ / MEM_WRITESeñal de habilitación de lectura/escritura de memoria
- IO_READ / IO_WRITESeñal de lectura/escritura de puertos de E/S
- INTERRUPTSeñal de solicitud de interrupción: la forma en que los dispositivos externos notifican a la CPU
- CLOCKSeñal de reloj: el «latido» que impulsa el trabajo sincronizado de todo el sistema
- RESETSeñal de reinicio: devuelve la CPU a su estado inicial
Resumen y verificación
Resumen en una frase:El bus de direcciones se encarga de «a dónde ir», el bus de datos de «qué transportar», y el bus de control de «qué hacer»: los tres buses cumplen sus respectivas funciones y cooperan para completar cada transferencia de datos.
Preguntas de autoevaluación
- Cuando la CPU va a leer un dato de la memoria, ¿quién coloca la información en el bus de direcciones? ¿Y quién coloca la información en el bus de datos?
- Si el bus de direcciones de una computadora solo tiene 16 líneas, ¿cuánta memoria puede gestionar como máximo?
- ¿Cuál es la mayor diferencia entre el bus de control y los buses de direcciones y datos? (Pista: piensa en la «composición» del bus de control).
Respuestas de referenciaReferencia: 1. La dirección la coloca la CPU, y los datos los coloca la memoria. 2. 2^16 = 65536 bytes = 64 KB. 3. Los buses de direcciones y datos transmiten señales digitales uniformes (valor de dirección/valor de datos), mientras que el bus de control es un conjunto de líneas de señal discretas y diferentes entre sí, cada una con su propia función independiente.
Otras extensiones