Ter o Quartus Prime Lite 20.1 instalado e funcional. Ele está disponível no site da Intel:
A lógica combinacional permite criar uma variedade de circuitos. Porém, em termos de blocos funcionais, os principais são:
Decodificador;
Multiplex;
Comparador;
Somador e subtrator;
A Unidade Lógica e Aritmética (ULA ou ALU).
A conexão adequada desses circuitos, e a adição de registradores, permite a criação de um caminho de dados (ou fluxo de dados) que é a peça base de um processador.
Nosso foco será, principalmente, o decodificador e veremos, de passagem, o MUX e o DEMUX.
Um decodificador é um circuito digital que transforma uma entrada codificada, por exemplo em binário com n bits, em uma saída decodificada, por exemplo o código 1 de 2^n.
Esse tipo de decodificador é a base para o projeto de um MUX. Ele também é muito usado na criação do endereçamento de um processador.
Vamos considerar o decodificador com valor de n igual a dois. Ou seja, duas entradas binárias e quatro saídas mutuamente exclusivas. Porém, para sofisticar o projeto, vamos adicionar uma entrada que habilite o funcionamento do decodificador. O diagrama e a tabela da verdade estão mostrados abaixo.
Decodificador de 2 para 1 de 4
Para implementar tal decodificador precisamos analisar cada bit da saída separadamente e obter a sua equação booleana.
Para a saída S0, teremos a seguinte tabela da verdade e a equação correspondente:
Habilita | A1 | A0 | S0 |
---|---|---|---|
0 | X | X | 0 |
1 | 0 | 0 | 1 |
1 | 0 | 1 | 0 |
1 | 1 | 0 | 0 |
1 | 1 | 1 | 0 |
Pela soma de produtos, a equação é: S0 = Habilita AND not(A1) AND not(A0).
Quais as equações para as outras saídas?
Para a saída S1, temos:
Habilita | A1 | A0 | S1 |
---|---|---|---|
0 | X | X | 0 |
1 | 0 | 0 | 0 |
1 | 0 | 1 | 1 |
1 | 1 | 0 | 0 |
1 | 1 | 1 | 0 |
Para a saída S2, temos:
Habilita | A1 | A0 | S2 |
---|---|---|---|
0 | X | X | 0 |
1 | 0 | 0 | 0 |
1 | 0 | 1 | 0 |
1 | 1 | 0 | 1 |
1 | 1 | 1 | 0 |
Para a saída S3, temos:
Habilita | A1 | A0 | S3 |
---|---|---|---|
0 | X | X | 0 |
1 | 0 | 0 | 0 |
1 | 0 | 1 | 0 |
1 | 1 | 0 | 0 |
1 | 1 | 1 | 1 |
Como fica a implementação desse circuito?
Implementação do Decodificador de 2 para 1 de 4
Para criar um decodificador com 3 entradas e 8 saídas, podemos usar dois decodificadores de 2 entradas e 4 saídas e utilizar a entrada Habilita para concatenar esses decodificadores.
Implementação do Decodificador de 2 para 1 de 4
Para fazer um decodificador de 1 para 16, podemos utilizar 5 decodificadores de 1 para 4.
Para criar tanto um MUX quanto um DEMUX, utilizamos um decodificador de acordo com o número de entradas do MUX (ou saídas do DEMUX).
Abaixo, temos o exemplo de um MUX do tipo 4 x 1:
Implementação de MUX com Decodificador de 2 para 1 de 4
Abaixo, temos o exemplo de um DEMUX do tipo 1 x 4:
Implementação de DEMUX com Decodificador de 2 para 1 de 4
Outra forma comum de se utilizar decodificadores é na conversão de código. Vamos usar o exemplo de um decodificador de binário para display de sete segmentos.
Decodificador Binário para Sete Segmentos
Cada segmento, nomeado pelas letras minúsculas, acende quando ativado, formando os 16 caracteres da representação hexadecimal, como mostrado abaixo.
Display de Sete Segmentos Mostrando Hexadecimal
Os segmentos dos displays da placa DE0-CV, acendem quando o nível BAIXO é escrito na sua porta correspondente. Com essa informação, foi montada a tabela da verdade mostrada abaixo.
b3 | b2 | b1 | b0 | Hexadecimal | g | f | e | d | c | b | a |
---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 1 |
0 | 0 | 1 | 0 | 2 | 0 | 1 | 0 | 0 | 1 | 0 | 0 |
0 | 0 | 1 | 1 | 3 | 0 | 1 | 1 | 0 | 0 | 0 | 0 |
0 | 1 | 0 | 0 | 4 | 0 | 0 | 1 | 1 | 0 | 0 | 1 |
0 | 1 | 0 | 1 | 5 | 0 | 0 | 1 | 0 | 0 | 1 | 0 |
0 | 1 | 1 | 0 | 6 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
0 | 1 | 1 | 1 | 7 | 1 | 1 | 1 | 1 | 0 | 0 | 0 |
1 | 0 | 0 | 0 | 8 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | 0 | 1 | 9 | 0 | 0 | 1 | 0 | 0 | 0 | 0 |
1 | 0 | 1 | 0 | A | 0 | 0 | 0 | 1 | 0 | 0 | 0 |
1 | 0 | 1 | 1 | B | 0 | 0 | 0 | 0 | 0 | 1 | 1 |
1 | 1 | 0 | 0 | C | 1 | 0 | 0 | 0 | 1 | 1 | 0 |
1 | 1 | 0 | 1 | D | 0 | 1 | 0 | 0 | 0 | 0 | 1 |
1 | 1 | 1 | 0 | E | 0 | 0 | 0 | 0 | 1 | 1 | 0 |
1 | 1 | 1 | 1 | F | 0 | 0 | 0 | 1 | 1 | 1 | 0 |
Seria possível montar o decoficador utilizando uma memória ROM?
Verificando a tabela da verdade do decodificador, notamos que o código binário consta de quatro bits e possui todas as combinações possíveis. Portanto, poderíamos utilizar uma memória ROM com 16 posições (uma para cada código binário de entrada) e o conteúdo de cada posição seria o código de ativação dos segmentos do display.
Dessa forma, se utilizarmos uma memória ROM de 16 posições e sete bits por posição, podemos implementar esse decodificador. Na verdade, uma memória ROM, de tamanho adequado, pode implementar qualquer tabela da verdade.
Abaixo, temos o código VHDL para o decodificador. Ele é formado por dois arquivos VHDL e um arquivo de configuração da pinagem da FPGA. Os arquivos VHDL são o arquivo principal (chamado de AulaDelta1.vhd) e o arquivo com a memória ROM (memoriaROM.vhd). O arquivo com a pinagem é criado, automaticamente, durante a criação do projeto no Quartus, sempre com o nome do tipo: nome_do_projeto.qsf. Porém, é necessário acrescentar, no fim desse arquivo, a configuração dos pinos que está no terceiro arquivo, abaixo, e tem o nome: AulaDelta1.qsf.
Nome do arquivo: AulaDelta1.vhd
library ieee;
use ieee.std_logic_1164.all;
entity AulaDelta1 is
generic (
dataWidth: natural := 8;
addrWidth: natural := 4
);
port (
SW: in std_logic_vector(9 downto 0);
HEX0 : out std_logic_vector (6 DOWNTO 0);
LEDR : out std_logic_vector(9 downto 0)
);
end entity;
architecture funcionamento of AulaDelta1 is
begin
ROM1 : entity work.memoriaROM generic map (dataWidth => 7, addrWidth => 4)
port map (Endereco => SW(3 downto 0), Dado => HEX0);
LEDR <= SW;
end architecture;
Nome do arquivo: memoriaROM.vhd
library IEEE;
use IEEE.std_logic_1164.all;
use ieee.numeric_std.all;
entity memoriaROM is
generic (
dataWidth: natural := 8;
addrWidth: natural := 4
);
port (
Endereco : in std_logic_vector (addrWidth-1 DOWNTO 0);
Dado : out std_logic_vector (dataWidth-1 DOWNTO 0)
);
end entity;
architecture assincrona of memoriaROM is
type blocoMemoria is array(0 TO 2**addrWidth - 1) of std_logic_vector(dataWidth-1 DOWNTO 0);
function initMemory
return blocoMemoria is variable tmp : blocoMemoria := (others => (others => '0'));
begin
-- Inicializa os endereços: Falta preencher.
tmp(0) := "1000000";
tmp(1) := "0000000";
tmp(2) := "0000000";
tmp(3) := "0000000";
tmp(4) := "0000000";
tmp(5) := "0000000";
tmp(6) := "0000000";
tmp(7) := "0000000";
tmp(8) := "0000000";
tmp(9) := "0000000";
tmp(10) := "0000000";
tmp(11) := "0000000";
tmp(12) := "0000000";
tmp(13) := "0000000";
tmp(14) := "0000000";
tmp(15) := "0000000";
return tmp;
end initMemory;
signal memROM : blocoMemoria := initMemory;
begin
Dado <= memROM (to_integer(unsigned(Endereco)));
end architecture;
Nome do arquivo: AulaDelta1.qsf
#============================================================
# FAMILY "Cyclone V"
# DEVICE 5CEBA4F23C7N
# Board DE0-CV
#============================================================
# Inicio da configuração dos pinos.
#============================================================
# HEX0
#============================================================
set_location_assignment PIN_U21 -to HEX0[0]
set_location_assignment PIN_V21 -to HEX0[1]
set_location_assignment PIN_W22 -to HEX0[2]
set_location_assignment PIN_W21 -to HEX0[3]
set_location_assignment PIN_Y22 -to HEX0[4]
set_location_assignment PIN_Y21 -to HEX0[5]
set_location_assignment PIN_AA22 -to HEX0[6]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to HEX0[0]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to HEX0[1]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to HEX0[2]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to HEX0[3]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to HEX0[4]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to HEX0[5]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to HEX0[6]
set_instance_assignment -name CURRENT_STRENGTH_NEW DEFAULT -to HEX0
set_instance_assignment -name SLEW_RATE 1 -to HEX0
#============================================================
# LEDR
#============================================================
set_location_assignment PIN_AA2 -to LEDR[0]
set_location_assignment PIN_AA1 -to LEDR[1]
set_location_assignment PIN_W2 -to LEDR[2]
set_location_assignment PIN_Y3 -to LEDR[3]
set_location_assignment PIN_N2 -to LEDR[4]
set_location_assignment PIN_N1 -to LEDR[5]
set_location_assignment PIN_U2 -to LEDR[6]
set_location_assignment PIN_U1 -to LEDR[7]
set_location_assignment PIN_L2 -to LEDR[8]
set_location_assignment PIN_L1 -to LEDR[9]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LEDR[0]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LEDR[1]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LEDR[2]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LEDR[3]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LEDR[4]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LEDR[5]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LEDR[6]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LEDR[7]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LEDR[8]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LEDR[9]
set_instance_assignment -name CURRENT_STRENGTH_NEW DEFAULT -to LEDR
set_instance_assignment -name SLEW_RATE 1 -to LEDR
#============================================================
# SW
#============================================================
set_location_assignment PIN_U13 -to SW[0]
set_location_assignment PIN_V13 -to SW[1]
set_location_assignment PIN_T13 -to SW[2]
set_location_assignment PIN_T12 -to SW[3]
set_location_assignment PIN_AA15 -to SW[4]
set_location_assignment PIN_AB15 -to SW[5]
set_location_assignment PIN_AA14 -to SW[6]
set_location_assignment PIN_AA13 -to SW[7]
set_location_assignment PIN_AB13 -to SW[8]
set_location_assignment PIN_AB12 -to SW[9]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SW[0]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SW[1]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SW[2]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SW[3]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SW[4]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SW[5]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SW[6]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SW[7]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SW[8]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SW[9]
#====================================================================
# Fim da configuração dos pinos utilizados em Design de Computadores.
#====================================================================