CT14: Buses: medio compartido - Obijuan/Cuadernos-tecnicos-FPGAs-libres GitHub Wiki

Descripción

Ejemplos y bloques para la organización de circuitos que comparten información a través de un BUS. Creación de buses UNIDIRECCIONALES y BIDIRECCIONALES

  • Icestudio: Todos los ejemplos se han probado con Icestudio 0.12. Usa esta versión o superior
  • Colecciones:
    • iceBus: Elementos para la creación y el acceso a Buses
  • Ejemplos: Todos los ejemplos de este cuaderno técnico están accesibles en su repositorio en github

Historial

  • 2023-Enero-17: Version inicial del cuaderno técnico
  • 2024-Mayo-24: Ejemplos adaptados a la nueva toolchain: apio-0.9.4. Eliminado el error en la verificación. Probados con icestudio 0.12. Los pantallazos de los ejemplos no se han actualizado todavía

Contenido

Introducción

En general, los circuitos están formados por unidades funcionales (bloques) interconectados entre sí mediante grupos de cables llamados buses

Un ejemplo es un computador básico, formado por los siguientes tres elementos: la unidad central de proceso (CPU), la memoria principal y el controlador de entrada/salida. En este diagrama se muestra su modelo estructural:


NOTA: Este dibujo está tomado de la lección 1 (Símplez) del libro "Conceptos básicos de arquitectura y sistemas operativos" por Gregorio Fernández. En él se describe el modelo estructural de un computador simplificado, denominado Símplez. Este libro me marcó mucho cuando estudié por primera vez la asinagura de Fundamentos de los computadores en la Universidad. Y además, tuve el enorme privilegio de tener como profesor a su autor 🙂️


En este esquema simplificado aparecen 3 unidades funcionales: la CPU, la memoria principal y el controlador de E/S. Están unidos mediante 3 buses, llamados Bus A, Bus C y Bus D. El Bus A transporta las direcciones, el Bus D los datos y el Bus C las señales de control (microórdenes)

En general, cada unidad de los circuitos genera una información de salida y recibe una información de entrada. A las unidades que generan datos las llamaremos productoras y a las que reciben datos consumidoras. Una unidad puede ser productora, consumidora o ambas

En un circuito siempre habrá uno o varios consumidores (es indifierentes). Sin embargo, el número de productores nos permite establecer la siguiente clasificación:

  • Circuitos con un único productor

  • Circuitos con múltiples productores

Compartiendo recursos

Un caso muy frecuente es cuando tenemos varios productores y un único consumidor. Por ejemplo cuando el consumidor es una unidad de salida, como por ejemplo un puerto serie, un LCD, o simplemente unos LEDs. Los productores envían sus datos a la salida (consumidor), a través del bus, para mostrársela al usuario

Como el recurso es único y compartido, ambos productores NO PUEDEN USARLO A LA VEZ. Tiene que existor otro elemento (que llamamos unidad de control, o controlador central) que sea el que decida en cada momento qué productor envía los datos al consumidor

Además, en electrónica digital NO SE PUEDEN CONECTAR DOS SALIDAS al mismo cable, o de lo contrario se produce un cortocircuito. Es necesario añadir un elemento para acceder al bus

Para entender estos conceptos de una manera empírica, vamos a definir un sistema mínimo, en el que usaremos el bus más pequeño posible: un bus de un bit. Nuestro consumidor será un simple LED. Y los productores serán circuitos que generan una secuencia en el LED

Ejemplo 1: Un LED parpadeante

Comenzamos por un ejemplo cuyo funcionamiento ya conocemos,y hemos usado muchas veces: un circuito que hace parpadear un LED. Pero ahora lo vamos a analizar desde otra perspectiva

El LED es el recurso a usar, que es un consumidor: El bit recibido se muestra por el LED. Hay una unidad productora, que es la que genera el parpadeo, que se transmite por el bus de 1 bit al LED

(01-LED-parpadeante.ice)

Es un circuito con un productor y con un consumidor

El LED parpadea a la frecuencia de 1 Hz indefinidamente

Compartiendo el bus

Si ahora queremos compartir el LED con otro circuito productor hay que añadir un elemento nuevo que nos permite acceder al bus. Este elemento es un multiplexor 2 a 1

Cuando la señal sel del multiplexor está a 0 (en reposo), es la entrada 0 la que llega al LED. El productor conectado a la entrada 0 es el que tiene acceso al recurso. Cuando sel se pone a 1, es el otro productor, el conectado a la entrada 1, el que tiene acceso al recurso

Esta entrada de selección la maneja el controlador, que es el circuito que decide qué productor tiene acceso al LED a través del bus en cada momento

Ejemplo 2: LED apagado y parpadeante

En este circuito de ejemplo ampliamos el ejemplo para permitir que el LED esté en dos estados diferentes: Bien parpadeando, cuando el corazón (productor) tiene el BUS, o apagado, cuando el bit 0 está en el bus

El bit a 0 es el productor por defecto: Tiene el bus cuando ningún otro productor está accediendo

(02-LED-apagado-parpadeante.ice)

El controlador es manual: un pulsador. Cuando No está apretado, el LED está apagado. Cuando se aprieta, el LED parpadea: el corazón accede al BUS y toma el control del LED

Al apretar el botón se genera la microorden blink, que es la que hace parpadear el LED (inyectando la salida del corazón en el bus)

Ejemplo 3: LED en tres estados

Ampliamos el ejemplo anterior para hacer que el LED parpadee a dos velocidades. Al apretar el pulsador SW1 el LED parpadea a 1 Hz, al apretar el pulsador SW2 lo hace a 4 Hz y si no se aprieta ninguna el LED permanece apagado

Ahora el controlador, que sigue siendo manual, genera 2 microórdenes: blink1 y blink4. Cada una de estas señales da acceso al bus al productor corresponiente: al corazón de 1Hz y de 4Hz

(03-LED-tres-estados.ice)

Observamos que los multiplexores están conectados en cascada. El bus lo forma el cable que entra por las entradas 0 de los multiplexores. Los productores se conectan por las entradas 1, y vuelcan su información al bus cuando se activa la microorden correspondiente

Esta forma de acceso al bus tiene una ventaja: tiene prioridad. En caso de activarse las dos microórdenes a la vez, el LED parpadea a 1Hz. El multiplexor más cercano al recurso es el que define la prioridad. Cuando más cerca está el productor del recurso, más prioridad tiene. El bit a 0 es el de menor prioridad: sólo tiene el bus si no hay microórdenes activadas

Esta estructura tiene otra ventaja: es escalable. Si ahora quisiéramos añadir más productores, basta con conectarlos a través de su multiplexor de acceso corresopndiente

Clasificación de los buses

Los buses que vamos a ver en este cuaderno técnicos los clasificamos de la siguiente forma:

  • Bus unidireccional
  • Bus unidireccional con Feedback
  • Bus bidireccional

Bus unidireccional

Es el bus más simple, y uno de los que más usaremos. Está formado por un único recurso (consumidor) compartido por varios productores. El caso de uso más sencillo es el emplear LEDs para mostrar información de salida. Todos los circuitos que precisen mostrar información en los LEDs, lo harán a través de un BUS Unidireccional

En esta figura se muestra un ejemplo de un bus unidireccional de N bits en el que hay dos circuitos productores y un consumidor. Además está el productor por defecto que define el valor que tiene el bus cuando no hay otro circuito accediendo a él

El sentido de la información es en una única dirección: de los productores al consuidor. El consumidor se sitúa en el extremo derecho, y los productores en la izquierda

El bus es el cable azul, que une el productor por defecto con el consumidor. Este cable atraviesa los elementos de acceso al bus, que normalmente son "transparentes"

Cuando un productor necesita enviar algo al consumidor, activa su señal de acceso al bus oe y su dato (de N bits) entra en el bus y llega al consumidor

Este bus tiene prioridad: El productor situado más a la derecha tiene una prioridad más alta

En este bus NO HAY ARBITRAJE. El controlador que genera las microórdenes de acceso es el que decide qué productor accede al BUS y qué otros productores no. Este bus está pensado para aplicaciones de control en bucle abierto

Bloque de acceso al bus

Para acceder al bus se utiliza el bloque Unibus-access, que se encuentra en la colección iceBus

El bus de N bits se introduce por la izquierda y sale por la derecha para conectarlo con el resto de elementos. Por defecto, el bus atraviesa el componente (es un componente transparente)

Por la entrada dat el productor introduce el dato de N bits a inyectar en el bus. La señal de control oe se usa para inyectar el dato. Cuando oe es 0, el componente funciona en modo transparente. Cuando oe es 1, el dato de N bits que está en la entrada dat se inyecta en el bus

Este bloque de acceso se implementa mediante un multiplexor, como hemos visto en las secciones anteriores. En esta figura se muestra la implementación de un bloque de acceso a un bus de 2-bits:

Se utiliza un bloque nuevo, en vez de directamente el multiplexor, para aportar información semántica: Este bloque es para inyectar datos en el bus. Da igual cómo esté implementando. De esta forma, los diseños quedan más claros, y los buses creados son más legibles

Ejemplo 4: UNIBUS: Parpadeo del LED a diferentes velocidades

Para familiarizarnos con este bus, veremos diferentes ejemplos, comenzando por el más sencillo de todos: un bus de 1 bit. En este ejemplo se crea un bus de 1-bit con el valor por defecto 0. Hay dos productores que inyectan en el bus señales de 2Hz y 10Hz al apretar los botones sw1y sw2 respectivamente

(04-UNIBUS-LED-tres-estados.ice)

El valor por defecto está en la izquierda. Mediante dos bloques de acceso los productores 1 y 2 inyectan sus valores en el bus cuando se activan las microórdenes blink1 y blink2 respectivamente

La prioridad la tiene el productor 1 (Corazón de 2Hz). Si se activan a la vez las dos microórdenes, el productor 1 será el que tenga el LED

En este ejemplo vemos cómo ahora podemos definir buses para compartir recursos (en este ejemplo el LED) y cómo los circuitos que los usan (productores) están desacoplados. Añadir nuevos productores es sencillo, así como modificar los existentes. Al estar desacoplados los podemos modificar sin influir en el resto de los circuitos conectados al bus

Ejemplo 5: UNIBUS: tocando dos tonos

En este ejemplo el recurso a compartir es un zumbador. Hay dos circuitos productores que emiten tonos de 1Khz y 2Khz respectivamente. El valor por defecto del bus es 0 (Silencio)

Se emiten secuencialmente un tono de 1Khz, luego de 2Khz, luego un silencio y se vuelve a repetir cíclicamente, a la velocidad de 10 Hz

(05-UNIBUS-tocando-dos-tonos.ice)

El controlador usado es un anillo de 3 biestables D, en los que hay un bit a 1 que se mueve cíclicamente. Al pasar por dos de los biestables se generan las microórdenes tone1 y tone2

Ejemplo 6: UNIBUS: Mostrando números en los LEDs

En este ejemplo se muestran 3 números distintos en 8 LEDs. Para ello se utiliza un bus de 8 bits. El controlador es manual, construido a partir de 4 biestables D en anillo. Cada vez que se aprieta el pulsador SW1 se desplaza el bit y se genera la siguiente microorden

(06-UNIBUS-mostrando-numeros-LEDs.ice)

En los LEDs se muestra la secuencia 0x00, 0x55, 0xAA y 0xFF

Bus de datos y bus de control

Los controladores tienen una entrada para los datos y una o varias para las señales de control. Para poder compartir estos controladores, lo que hacemos es que creamos dos buses, una para llevar los datos y otro para las señales de control. Y reciben los nombres de bus de datos y bus de control

El productor que quiere acceder al controlador deberá escribir los datos en el bus de datos y activar las señales necesarias del bus de control

En la siguiente figura se muestra esta idea, usando dos productores y un consumidor

Ejemplo 7: UNIBUS: Compartiendo un registro

Para entender cómo acceder a los controladores, utilizaremos como ejemplo un registro de 5 bits. Hay dos circuitos productores que escriben en el registro los valores 0x03 y 0x1F al apretar los pulsadores SW1 y SW2 respectivamente.

La salida del registro está conectada a 5 LEDs para poder ver el valor almacenado.

Utilizamos un bus de datos de 5 bits para llevar los valores, y un bus de control de 1 bit para la señal de load del registro

(07-UNIBUS-compartiendo-registro.ice)

Bus con campos

Por un bus podemos llevar información estructurada, o divida en sub-partes. Por ejemplo, para acceder a un controlador, o al registro del ejemplo anterior, podemos llevar por un mismo bus tanto los datos como el control. Esto simplifica los diseños, al no tener que usar dos buses separados sino uno con dos campos

Para agrupar los campos en un bus usamos bloques Join, y para separarlos bloques Split

Ejemplo 8: UNIBUS: Compartiendo un registro. Implementación 2

Este ejemplo es similar al 7, pero usando un único BUS de 6 bits con dos campos, uno de datos de 5 bits y un bit adicional para la señal load

Los dos productores agrupan el dato y la señal de load, usando un bloque join 5-1 para introducirlo en el bus. Al final del bus, en la derecha, se usa un bloque Split 5-1 para separarlos y conectarlos al registro

(08-UNIBUS-compartiendo-registro-II.ice)

Ejemplo 9: UNIBUS: Compartiendo un registro. Implementación 3

Para simplificar nuestros diseños, una vez que los productores están perfectamente definidos y funcionando, los podemos agrupar en sus respectivos bloques. Este ejemplo es exactamente el mismo que los dos anteriores, pero con los productores encapsulados

(09-UNIBUS-compartiendo-registro-III.ice)

Ahora se aprecia mucho mejor la estructura del circuito y el flujo de información

Esto es lo que se ha metido en el bloque productor 1:

El bloque productor 2 es similar, pero cambiando el valor que se produce al apretar el pulsador

Ejemplo 10: UNIBUS: Compartiendo un registro. Implementación 4

Para terminar esta sección, refinaremos nuestro ejemplo anterior un poco más: Crearemos bloques que incluyan el acceso al bus. De esta forma todo queda aún más compacto, y de un único vistazo sabemos lo que está ocurriendo: dos productores conectados en un bus que acceden a un registro

(10-UNIBUS-compartiendo-registro-III.ice)

Esto se hace típicamente en la última fase, cuando ya tenemos un diseño muy estable y que no requiera grandes cambios. En las etapas iniciales, cuando estamos diseñando, conviene no encapsular demasiado, porque todo está sometido a muchos cambios (tamaño del bus, salidas del productor, etc...)

Los nuevos bloques creados contienen el circuito del productor (que en este caso está encapuslado en el bloque productor1) y el bloque de acceso al bus. En esta figura vemos el productor 1:

Bus unidireccional con Feedback

Los controladores tienen señales de Feedback, que típicamente son:

  • Busy: Indica el estado del controlador: Libre (ocioso) u Ocupando (en funcionamiento)
  • Done: Tic que indica que ha finalizado la última operación

Estas señales las necesitamos si queremos acceder al controlador en bucle cerrado. Por ejemplo, antes de enviar un dato, podemos comprobar la señal de busy para enviar el dato si ya está libre o esperar en caso de que esté ocupado. También podemos usar la señal de done para transferir un grupo de datos a la máxima velocidad que permite el controlador

Las señales de Feedback se transmite por un bus en sentido contrario, que llamaremos Bus de Feedback

En realidad es un bus muy simple porque es de sólo lectura. Los productores NO escriben información en este bus, por lo que NO hay que tener elementos de acceso al bus

Como en Icestudio la información va de izquierda a derecha (siempre), este bus lo describiremos utilizando un par de etiquetas: una para crear el bus y otra para generarlo en la parte izquierda:

Este bus de Feedback lo recolocamos al lado del otro. La figura es igual, pero ahora ambos buses están juntos:

Ejemplo 11: Controlador falso (Fake controller)

Para hacer ejemplos en los siguientes apartados, primero vamos a construirnos un controlador falso, que simula a un periférico de escritura en los LEDs. La interfaz de este controlador es una entrada de datos de 4 bits (data) y una señal de escritura (write). Como salida tiene busy, done y el dato a mostrar en los LEDs

El productor que lo quiere usar debe introducir por su entrada el dato a escribir y enviar un tic por write. El controlador espera un tiempo fijo (simulando los cálculos internos y operaciones que debe realizar) y finalmente muestra el valor en los LEDs

En este ejemplo se ha construido el controlador y se prueba con un circuito que escribe el valor 0xF al apretar el pulsador SW1. La señal de busy se muestra por el LED7, y el controlador muestra el valor recibido en los LEDs 0 - 3

(11-fake-controller-test-1.ice)

El tiempo del controlador se ha establecido en 10 ciclos, muy rápido, para medirlo con el analizador lógico y entender mejor su temporización

Este es el escenario de pruebas, con la tarjeta Alhammbra-II conectada al analizador lógico. Al apretar el pulsador SW1 los LEDs 0 - 3 se encienden, y se hace la captura en el analizador

Ejemplo 12: Controlador falso. Implementacion II

Este ejemplo es similar al anterior, pero ahora hemos encapsulado el controlador false en el bloque fake controller, y hemos cambiado el tiempo de espera a 1 segundo. Ya no necesitamos el analizador lógico

(12-fake-controller-test-2.ice)

Al apretar SW1 veremos cómo el LED7 se enciende durante 1 segundo, indicando que el controlador está ocupado en sus cálculos internos. Transcurrido ese tiempo escribe el valor 0xF en los LEDs, se apaga el LED7 y termina

Si apretamos nuevamente SW1 veremos cómo el LED7 se enciende nuevamente y se escribe otra vez el valor en los LEDs (pero como es el mismo que antes no notaremos ningún cambio)

En este vídeo de youtube se muestra su funcionamiento

Click to see the youtube video

Ejemplo 13: Secuencia en los LEDs

Este es un ejemplo de utilización de la señal done del controlador falso para generar una secuencia de dos estados. Al apretar el pulsador SW1 se escriben los valores 0x3 y 0xC en el controlador (mostrándose en los LEDs)

En este circuito sólo hay 1 productor, por lo que no es necesario ningún bus

(13-BUSF-secuencia-LEDs-test-1.ice)

En este vídeo de Youtube se muestra el funcionamiento del circuito

Click to see the youtube video

Ejemplo 14: Dos Secuencias en los LEDs

Si ahora queremos generar dos secuencias diferentes en los LEDs, activadas por los botones SW1 y SW2, usamos un bus de 5 bits (4 bits de datos + 1 bit de write). La realimentación de la señal done la hacemos a través de la etiqueta correspondiente

(14-BUSF-secuencia-LEDs-test-2.ice)

Las secuencias están controladas por una máquina de contador en cada productor. Su señal busy es la utilizada para el acceso al bus. Mientras la máquina 1 está activada, sus datos se inyectan en el bus

En este vídeo de Youtube se muestra el funcionamiento

Click to see the youtube video

Ejemplo 15: Dos secuencias en los LEDs. Implementación 2

Este ejemplo es exactamente el mismo que el ejemplo 14 (y ocupa los mismos recursos), pero se ha reestructurado. Los productores 1 y 2 se han metido en sus bloques correspondientes y las señales de feedbad (busy y done) se han agrupado en un bus de 2 bits, que sale del controlador

En otra parte del circuito, cuando se necesitan usar estas señales, se sacan directamente del bus de feedback

(15-BUSF-secuencia-LEDs-test-3.ice)

Este ejemplo es un paso intermedio hacia el bus con feecback final

Unificación en un BUS

El bus con los datos y el control se puede unificar con el bus de feedback para simplificar los bloques de los productores y la arquitectura en general

NOTA: Se puede unificar, pero no es obligatorio. En algunos circuitos puede interesar dejarlos por separado. Esto es decisión del diseñador

En caso de realizarse la unificación, situaremos las lineas de feedback en los bits de menor peso del Bus. A este bus unificado lo denominamos BUSF (Bus con Feedback)

El componente de acceso al bus ahora es ligeramente diferente porque los productores sólo acceden en escritura a los bits de datos y control, pero NO a los de Feedback (que sólo los escribe el controlador).

Para leer las señales de Feedback del bus, utilizamos un bloque Split, que obtiene el bus de datos + control por un lado, y las líneas de feedback por el otro

Para fijar las ideas, vamos a trabajar con el ejemplo 15, en el que tenemos 4 bits de datos, 1-bit de control y 2 bits de feedback. En total necesitamos un bus de 7-bits

Generación del BUSF

En los buses unidireccionales normales, el bus se crea en la izquierda, con un valor por defecto. En el caso del BUSF el bus lo crea el controlador. Se pone el valor por defecto en el bus de datos y de control, y se agrupan las señales de feedback. Todo ello se agrupa para formar el bus completo. Las agrupaciones se hacen usando bloques Join

En esta figura se muestra un ejemplo de construcción del BUSF de 7-bits

Esta construcción se hace en el controlador ampliado, que incluye el controlador normal junto con los elementos necesarios para la creación del BUSF

Lectura de los campos del BUSF

Para leer los campos del BUSF se utilizan bloques Split en cascada. En la primera etapa se extraen los sub-buses de feedback y de campos. En una segunda etapa se extraen los campos individuales

Acceso al BUSF

Los productores escriben en el BUSF pero SÓLO en el bus de campos, y deben dejar intactas las señales de Feedback. Por ello, el circito de acceso primero debe obtener el bus de campos (mediante un bloque Split), inyectar el valor en ese bus (dato + control) y volver a reconstruir el bus con las señales de feedback originales

Para el ejemplo que estamos construyendo, así es cómo se realiza:

Como esto hay que hacerlo para todos los productores que accedan al bus, conviene agruparlo en un nuevo bloque de acceso, que llamaremos BUSF-access. El bloque de este ejemplo es BUSF-access-7-5: Acceso a un BUSF de tamaño 7 bits, de los cuales 5bits se corresponden con el bus de campos

Controlador Ampliado

Por último, el controlador hay que envolverlo con el cableado necesario para extraer las señales de datos y control, y agrupar sus salidas para crear el BUSF (como hemos visto en apartados anteriores)

Para el ejemplo que estamos trabajando, la implementación del controlador ampliado es la mostrada en esta figura:

Y así es como queda el nuevo bloque:

Ahora ya resulta muy sencillo utilizarlo con el BUSF, y conectar diferentes productores, como veremos en le siguiente ejemplo

Ejemplo 16: Dos secuencias en los LEDs. Implementación 3

Así es como queda el ejemplo de las dos secuencias cuando usamos un BUSF unificado, con un controlador ampliado

(16-BUSF-secuencia-LEDs-test-4.ice)

La ventaja de este bus unificado es que ahora los productores los podemos ampliar para que se conecten directamente, simplificando todavía más los diseños, como vemos en el siguiente ejemplo

Ejemplo 17: Dos secuencias en los LEDs. Implementación 4

Este es el ejemplo final, en el que se usa un BUS único de 7-bits para conectar los dos productores al Controlador, y que ambos productores puedan leer las señales de Feedback del controlador a través del mismo bus

(17-BUSF-secuencia-LEDs-test-5.ice)

Bus Bidireccional

El caso más general de bus es cuando hay varias unidades que pueden intercambiar datos entre ellas. Todas ellas hacen de productores y de consumidores, pudiendo escribir en el bus y leer de él

En esta figura mostramos el esquema general, usando tres unidades de ejemplo, pero podría haber muchas más

Así, por ejemplo, la unidad 1 podría enviar información a la unidad 3 (U1->U3), o a la inversa (U3->U1), o bien la Unidad 2 enviar datos a la Unidad 1 (U2->U1), o la unidad 3 a la unidad 2 (U3->U2), etc...

Bus UNIDIRECCIONAL equivalente

El bus bidireccional es equivalente a uno UNIDIRECCIONAL, como el primero que vimos, pero con información adicional de lectura (por medio de una etiqueta). La clave está en dividir el bus en dos segmentos: uno donde las unidades hacen la escritura y otro donde hacen la lectura

Vamos a ir refinando el modelo general, incorporando detalles progresivamente, hasta llegar a obtener un bus equivalente Unidimensional

Las unidades son circuitos normales, que tienen patas diferentes para las entradas y las salidas. Así, por ejemplo, un registro de 2 bits tiene 2 bits de salida (salida q), y dos bits de entrada de datos (entrada d). En nuestro modelo esto lo representamos mediante flechas separadas. Todos los cables tienen una anchura de D bits, siendo D el tamaño del bus

En este tipo de buses, las señales eléctricas se propagan en ambas direcciones. Así, si la unidad 2 escribe en el bus, la señal se propaga hacia la derecha y hacia la izquierda, inundando el bus

Sin embargo, en las FPGAs y en el interior de los chips, los cables llevan la información sólo en una dirección. El dibujo anterior lo podemos reorganizar para que la información sólo fluja en una dirección. Basta con alargar el bus y curvarlo para pasar por la zona inferior de las unidades. Y desde ahí tirar los cables de lectura

Este esquema es totalmente equivalente al anterior, pero con cables que llevan la información en una dirección. Cada unidad puede transferir datos a cualquiera de las otras, con independencia de su situación en el bus, como se muestra en este ejemplo

Observamos que en el bus hay dos segmentos diferenciados. El segmento superior es donde se realizan las escrituras. Los cables de salida de las unidades se conectan en la parte superior. El segmento inferior es donde se conecta los cables de lectura del bus

Seguimos refinando el modelo. Ahora añadimos el valor por defecto del Bus, que típicamente es de 0, y además separamos los dos segmentos mediante una etiqueta, de manera que ahora ambos apuntan hacia la derecha (pero sigue siendo el mismo bus)

Este circuito sigue siendo totalmente equivalente a los anteriores: Todas las unidades se pueden comunicar con todas

El segmento del bus de lectura lo podemos sustituir por la etiqueta, en vez de dibujarlo como un bus. En los cables de escritura utilizamos un bloque de acceso al medio para la escritura de la información. Obtenemos el siguiente esquema equivalente, que incluye más detalles

Lo que tenemos ahora es en realidad un Bus unidireccional como los que hemos utilizado hasta ahora. El recurso compartido es la etiqueta BUS, que hace que la información llege a todos los consumidores (que son los propios productores). Pero a todos los efecto este bus general es similar al unidireccional. Los bloques de acceso al bus que usamos son los mismos que para los buses bidireccionales

Caso de estudio: Dos registros conectados en bus

Para entender bien los detalles, vamos a partir de un circuito en el que hay dos registros de 2 bits conectados mediante un bus general (unidireccional). El ejemplo se podría hacer con más registros, pero utilizaremos sólo 2 para simplicar la explicación. Llamaremos a cada unidad con el registro R1 y R2 respectivamente

El esquema general sería el siguiente:

Ahora lo convertimos en el bus unidireccional equivalente, y añadimos los detalles de todas las señales

Tenemos 4 señales de control o microórdenes:

  • l1 : Cargar el registro R1 con el valor disponible en el Bus (lectura)
  • l2 : Cargar el registro R2 con el valor disponible en el Bus (lectura)
  • oe1 : Volcar el registro R1 al Bus (escritura)
  • oe2 : volcar el registro R2 al Bus (escritura)

Activando correctamente estas microórdenes se realizan las transferencia de información del registro R1 al R2 (R1->R2) o bien del R2 al R1 (R2->R1)

  • Transferencia R1->R2: Hay que activar oe1 y l2. El resto de señales deben estar a cero (oe2=0, l1=0)
  • Transferencia R2->R1: Hay que activar oe2 y l1. El resto de señales deben estar a cero (oe1=0, l2=0)

La generación de las microórdenes la realiza un controlador especializado (lo que en las CPUs se conoce como Unidad de Control). Nosotros las generaremos manualmente, utilizando pulsadores

Ejemplo 18: Transferencias entre 2 registros

En este ejemplo materializamos las ideas presentadas en el apartado anterior. Conectamos ambos registros a través de un BUS BIDIRECCIONAL. Los registros R1 y R2 están inicializados con los valores 1 y 2 respectivamente. Su salidas, además, están conectadas a los LEDs para poder comprobar sus valores

Al apretar el pulsador SW1 se realiza la transferencia R2->R1 y al apretar SW2 la transferencia R1->R2

(18-BIDIR-Dos-regs-test-1.ice)

En este vídeo de Youtube se muestra su funcionamiento

Click to see the youtube video

Bus bidireccional UNIFICADO

El bus bidireccional en realidad está formado por dos partes: el segmento de escritura, que funciona igual que un bus unidireccional, y el segmento de lectura, para el que utilizamos la etiqueta del BUS.

Esto es suficiente para utilizar este bus en nuestro diseños. PERO en ocasiones, cuando la complejidad de los diseños es alta y queremos hacerlo más modular y legible, es posible crear un BUS UNIFICADO que incluya en paralelo tanto el segmento de escritura como el de lectura. Esto tiene la ventaja de que podemos crear módulos que se conectan directamente al BUS (sin tener que introducirles la etiqueta del bus como entrada)

Si nuestro bus es de D bits, cada segmento tiene D bits. Construimos un nuevo bus agrupando los dos segmentos, por lo que tendrá un tamaño de 2*D bits. Además, el segmento de escritura se une al de lectura tras llegar a la parte derecha (donde la etiqueta), ya que en ese punto se garantiza que todos las unidades han tenido la oportunidad de volcar su datos

Para realizar este conexionado, además del valor por defecto, necesitamos incluir un bloque especial para Crear el bus unificado. Los bloques de acceso también son especiales, ya que sólo escriben en el segmento de escritura (D bits). Este es el esquema:

En esta figura se muestran los detalles del bloque de creación del bus. El segmento de escritura va por los bits de mayor peso, y el de lectura por los bits de menor peso. El bloque primero separa los dos segmentos recibidos por la etiqueta. El que llega de escritura se conecta con el de lectura y se envía por el Bus. El de escritura se crea con el valor por defecto de 0

Este es el esquema del nuevo bloque de acceso al bus bidireccional. Recibe un bus de 2*D Bits, e inyecta el dato de D bits sólo en el segmento de escritura

Ejemplo 19: Transferencia entre dos registros. Implementación 2

Este es el mismo ejemplo que el 18: pero utilizando un bus unificado. Con este bus los registros ya se pueden encapsular en sus bloques correspondientes: R1 y R2

(19-BIDIR-Dos-regs-test-2.ice)

Esta es la implementación del bloque New Bus:

Y esta es la implementación del bloque R1:

Y por último, esta es la implementación del bloque de acceso al bus bidireccional:

Conclusiones

Los buses nos permiten organizar y simplificar los diseños, para que sean más fáciles de entender. También nos permiten implementar diseños retro, que se basaban principalmente en tener un bus al que se conectan otros componentes (aunque las arquitecturas modernas no son "orientadas a buses")

Con estos buses ahora podemos implementar controladores de mayor nivel, haciendo circuitos que accedan a ellos a través del Bus. Esto nos será muy útil en los siguientes cuadernos técnicos para implementar controladores del LCD, del puerto serie, de acceso a memorias, etc...

Autor

Licencia

Créditos y agradecimientos

Enlaces