-
Notifications
You must be signed in to change notification settings - Fork 196
Capítulo 29: Puertas triestado
Ejemplos de este capítulo en github
Las puertas triestado (También conocidas como Buffers triestado) nos permiten desconectar las salidas de nuestros circuitos, impidiendo que vuelquen su tensión (0 ó 1) en el cable al que se conectan.
Las describiremos en Verilog, las simularemos y documentaremos las LIMITACIONES QUE PRESENTAN al ser sintetizadas con las herramientas libres del proyecto icestorm. El soporte de Yosys, Arachne y Icestorm para puertas triestado es muy limitado todavía al día de hoy (Nov - 2015)
Describiremos cómo funcionan y cómo se modelan en verilog
Las puertas triestado se comportan como interruptores que conectan la entrada con la salida cuando su señal de habilitación está activada. Su símbolo es el siguiente:
Tiene 3 puertos de 1 bit:
- entrada: Señal de entrada
- salida: Señal de salida
- enable: Señal de habilitación
Cuando la señal de habilitacion está a 1, la entrada está conectada directamente a la salida. Sin embargo, cuando está a 0, la salida queda desconectada. Se considera que está en un tercer estado, denominado alta impedancia, y se representa con la letra Z. Así, la salida de una puerta triestado puede encontrarse en los estados 0, 1 ó Z
Una puerta triestado se modela de la siguiente forma:
assign salida = (enable) ? entrada : 1'bz;
El sintetizador reconoce que es una puerta triestado porque se le asigna el valor z cuando enable es 0
El primer ejemplo es un hola mundo: conexión de un led a través de una puerta triestado
Se coloca un biestable con un 1 a su entrada, para que se cargue en el primer flanco de subida. Su salida se conecta al led a través de una puerta triestado. La señal de enable se conecta a un divisor de frecuencia que genera un pulso cuadrado de 1 segundo, de manera que el led deberá estar medio segundo encendido y medio segundo apagado
El código verilog es el siguiente:
`default_nettype none
`include "divider.vh"
module tristate1 (
input wire clk, //-- Entrada de reloj
output wire led0); //-- Led a controlar
//-- Parametro: periodo de parpadeo
parameter DELAY = `T_1s;
//-- Cable con la señal de tiempo
wire clk_delay;
//-- Biestable que está siempre a 1
reg reg1;
always @(posedge clk)
reg1 <= 1'b1;
//-- Conectar el biestable al led a traves de la puerta tri-estado
assign led0 = (clk_delay) ? reg1 : 1'bz;
//-- Divisor para temporizacion
divider #(DELAY)
CH0 (
.clk_in(clk),
.clk_out(clk_delay)
);
endmodule
El banco de pruebas sólo instancia el componente tristate1 y genera el reloj. La pausa se pone en 4 ciclos para poderla apreciar mejor en la simulación. El código del banco de pruebas es:
module tristate1_tb();
//-- Pausa pequeña: divisor
localparam DELAY = 4;
//-- Registro para generar la señal de reloj
reg clk = 0;
//-- Led a controlar
wire led0;
//-- Instanciar el componente
tristate1 #(.DELAY(DELAY))
dut(
.clk(clk),
.led0(led0)
);
//-- Generador de reloj. Periodo 2 unidades
always #1 clk = ~clk;
//-- Proceso al inicio
initial begin
//-- Fichero donde almacenar los resultados
$dumpfile("tristate1_tb.vcd");
$dumpvars(0, tristate1_tb);
# 100 $display("FIN de la simulacion");
$finish;
end
endmodule
La simulación se realiza con el siguiente comando:
$ make sim
Y la simulación en gtkwave es:
Se puede ver cómo la señal del led permanece a 1 durante 2 ciclos de reloj, y luego a alta impedancia (color amarillo) durante los otros 2 ciclos
La síntesis se realiza con el comando:
$ make sint
Los recursos empleados son:
Recurso | ocupación |
---|---|
PIOs | 3 / 96 |
PLBs | 10 / 160 |
BRAMs | 0 / 16 |
El diseño se carga con:
$ sudo iceprog tristate1.bin
Al ejecutarse se verá cómo parpadea el led a la frecuencia de 1 Hz
En este ejemplo conectaremos la salida de tres registros de 1 bit a un bus de 1 bit, mediante puertas triestado
El bus de un bit está conectado a un led de salida para poder visualizar lo que ocurre. Los tres biestables están conectados al bus a través de puertas triestado. Se inicializan con los valores iniciales 1, 0 y 1 respectivamente.
Las puertas triestado están habilitadas por los bits 0, 1 y 2 de un registro de desplazamiento, que inicialmente tiene el valor binario 0001, y va tomando los valores 0010, 0100 y 1000 por cada pulso de la señal clk_delay (de 1 segundo). De esta forma, primero se vuelca al bus el registro 0, luego el 1, luego el 2 y después ninguno. Al cabo de 4 ciclos de clk_delay se vuelve a comenzar
`default_nettype none
`include "divider.vh"
module tristate2 (
input wire clk, //-- Entrada de reloj
output wire led0); //-- Led a controlar
//-- Parametro: periodo de parpadeo
parameter DELAY = `T_1s;
//-- Cable con la señal de tiempo
wire clk_delay;
//-- Bus de 1 bit
wire bus;
//-- Señal de reset
reg rstn = 0;
//-- Registro de desplazamiento
reg [3:0] sreg;
//-- Definir los 3 bistables a conectar al bus, cada uno con un
//-- valor inicial cualquiera
reg reg0;
always @(posedge clk)
reg0 <= 1'b1;
reg reg1;
always @(posedge clk)
reg1 <= 1'b0;
reg reg2;
always @(posedge clk)
reg2 <= 1'b1;
//-- Conectar los biestables al bus, a traves de puertas triestado
assign bus = (sreg[0]) ? reg0 : 1'bz;
assign bus = (sreg[1]) ? reg1 : 1'bz;
assign bus = (sreg[2]) ? reg2 : 1'bz;
//-- Conectar el bus al led
assign led0 = bus;
//-- Registros de desplazamiento
always @(posedge clk)
if (!rstn)
sreg <= 4'b0001;
else if (clk_delay)
sreg <= {sreg[2:0],sreg[3]};
//-- Inicializador
always @(posedge clk)
rstn <= 1'b1;
//-- Divisor para temporizacion
dividerp1 #(DELAY)
CH0 (
.clk(clk),
.clk_out(clk_delay)
);
endmodule
Lo importante del ejemplo es la conexión al mismo bus de los tres registros mediante las asignaciones:
assign bus = (sreg[0]) ? reg0 : 1'bz;
assign bus = (sreg[1]) ? reg1 : 1'bz;
assign bus = (sreg[2]) ? reg2 : 1'bz;
El banco de pruebas es similar al del ejemplo anterior.
Para simular ejecutamos el comando:
$ make sim2
En gtkwave obtenemos lo siguiente:
Observamos cómo primero se vuelca el registro 0, que saca un 1 por el led. Luego el registro 1, que vuelca un 0, después el 2, que vuelve a volcar un 1 y finalmente todos desconectados, visualizándose la línea amarilla que indica alta impedancia. El ciclo se repite indefinidamente
La síntesis se realiza con el comando:
$ make sint2
Los recursos empleados son:
Recurso | ocupación |
---|---|
PIOs | 3 / 96 |
PLBs | 13 / 160 |
BRAMs | 0 / 16 |
El diseño se carga con:
$ sudo iceprog tristate2.bin
Al ejecutarse se verá cómo parpadea el led a la frecuencia de 1 Hz
La versión actual del sintetizador usado en el proyecto icestorm (Yosys) tiene un soporte para puertas triestado MUY LIMITADO. Por ello, de momento conviene NO USARLAS EN NUESTROS DISEÑOS
Mostraremos una serie de ejemplos que sí funcionan en simulación, pero que al sintetizarse con las herramientas libres obtenemos errores. Se incluyen aquí como documentación, para poder comprobar en las versiones futuras y si ya está solucionado
$ yosys -V
Yosys 0.5+385 (git sha1 ddf3e2d, clang 3.6.0-2ubuntu1 -fPIC -Os)
$ arachne-pnr -v
arachne-pnr 0.1+134+0 (git sha1 788cf79, g++ 4.9.2-10ubuntu13 -O2)
En este ejemplo conectaremos un registro de 2 bits a dos leds mediante una puerta triestado de 2 bits. El diagrama es el siguiente:
La descripción en verilog:
`default_nettype none
module error1 (
input wire clk, //-- Entrada de reloj
output wire [1:0] leds); //-- Leds a controlar
wire ena = 1'b1;
//-- Registro de 2 bits
reg [1:0] reg1;
//-- Cargar el registro con valor inicial
always @(posedge clk)
reg1 <= 2'b11;
//-- Conectar el registro a 2 leds
assign leds = (ena) ? reg1 : 2'bzz;
endmodule
El código verilog es correcto, por lo que se simula sin problema, mostrándose el número binario 11 por los leds:
$ make sim3
Sin embargo, al sintetizar obtenemos el siguiente mensaje de error:
$ make sint3
...
2.12.2. Executing Verilog-2005 frontend.
Parsing Verilog input from `/usr/local/bin/../share/yosys/ice40/arith_map.v' to AST representation.
Generating RTLIL representation for module `\_80_ice40_alu'.
Successfully finished Verilog frontend.
Mapping error1.$ternary$error1.v:42$2 ($tribuf) with simplemap.
terminate called after throwing an instance of 'std::out_of_range'
what(): vector::_M_range_check: __n (which is 1) >= this->size() (which is 1)
Aborted (core dumped)
Makefile:143: recipe for target 'error1.bin' failed
make: *** [error1.bin] Error 134
En este ejemplo se conectan dos registros de un bit a un bus de 2 bits mediante dos puertas triestado que usan la misma señal de habilitación:
La descripción en verilog es:
`default_nettype none
module error2 (
input wire clk, //-- Entrada de reloj
output wire [1:0] leds); //-- Leds a controlar
//-- Senal de habilitacion para las puertas
wire ena = 1'b1;
//-- Registro de 1 bit
reg reg0;
always @(posedge clk)
reg0 <= 1'b1;
//-- Registro de 1 bit
reg reg1;
always @(posedge clk)
reg1 <= 1'b1;
//-- Conectar los registros al cable de 2 bits
//-- Se controlan con la misma señal de habilitacion
assign leds[0] = (ena) ? reg0 : 1'bz;
assign leds[1] = (ena) ? reg1 : 1'bz;
endmodule
Se simula con el comando:
$ make sim4
y se obtiene la misma simulación que en el ejemplo error1
Sintetizamos con:
$ make sint4
y se obtiene el siguiente mensaje de error
arachne-pnr -d 1k -p error2.pcf error2.blif -o error2.txt
seed: 1
device: 1k
read_chipdb +/share/arachne-pnr/chipdb-1k.bin...
supported packages: tq144, vq100
read_blif error2.blif...
prune...
read_pcf error2.pcf...
instantiate_io...
fatal error: $_TBUF_ gate must drive top-level output or inout port
Makefile:176: recipe for target 'error2.bin' failed
make: *** [error2.bin] Error 1
En este caso es el arachne el que provoca el fallo
Las puertas triestado se usan normalmente para interconectar elementos a través de un bus****. La alternativa es sustituirlas por multiplexores
Imaginemos un bus en el que hay 3 registros que pueden escribir en él, y dos que pueden leer. El acceso en escritura de los registro se controla mediante las 3 señales de habilitación de las puertas triestado
La alternativa es sustituir las puertas triestado por un multiplexor de 4 a 1, con una señal de selección de 2 bits:
Todo
TODO
0 You are leaving the privative sector (EN)
1 ¡Hola mundo! (EN) (RU)
2 De un bit a datos (EN)
3 Puerta NOT (EN)
4 Contador de 26 bits (EN)
5 Prescaler de N bits (EN)
6 Múltiples prescalers (EN)
7 Contador de 4 bits con prescaler (EN)
8 Registro de 4 bits (EN)
9 Inicializador (EN)
10 Registro de desplazamiento (EN)
11 Multiplexor de 2 a 1 (EN)
12 Multiplexor de M a 1 (EN)
13 Inicializando registros (EN)
14 Registro de N bits con reset síncrono
15 Divisor de frecuencias
16 Contador de segundos
17 Generando tonos audibles
18 Tocando notas
19 Secuenciando notas
20 Comunicaciones serie asíncronas
21 Baudios y transmisión
22 Reglas de diseño síncrono
23 Controladores y autómatas finitos
24 Unidad de transmisión serie asíncrona
25 Unidad de recepción serie asíncrona
26 Memoria ROM
27 Memoria ROM genérica
28 Memoria RAM
29 Puertas triestado
30 Hacia el microprocesador y más allá