- Encontro 6-8 (15,17,22 ago) - Funções e portas lógicas
- Encontro 9 (24 ago) - Álgebra booleana
- Encontro 10 (29 ago) - Projeto de circuitos combinacionais
- Encontro 11 (31 ago) - Exercícios de álgebra de Boole
- Encontro 12 (5 set) - Expressão booleana - Tabela verdade - Circuito com portas lógicas
- Encontro 13 a 15 (12, 14 e 19 set) - Simplificação de expressões lógicas - Mapas de Karnaugh-Veitch
As atividades de hoje buscarão mostrar as características básicas de comunicações com protocolos de transporte.
Aplicações e protocolos de transporte
Faça uma rápida pesquisa e descubra que protocolos de transporte (e que ports) são usados por estas aplicações:
- SSH
- FTP
- BitTorrent
- emule
- WINS
- Compartilhamento de arquivos do Windows
- Windows Terminal Service
- NFS
- Openvpn
- RADIUS
- DHCP
- SNMP
- NTP
- LDAP
- Mysql
- Postgresql
- Oracle RDBMS
- Syslog
- CUPS
Que protocolo de transporte predomina nesse conjunto ?
Tipos de protocolos de transporte: TCP x UDP
Nestes experimentos, serão evidenciadas diferenças entre os protocolos TCP e UDP.
Experimento 1
Ambos protocolos de transporte podem ser usados por aplicações que precisem se comunicar. Porém cada um deles têm certas propriedades, então a escolha precisa ser feita dependendo do tipo de comunicação a ser feita pela aplicação. Por exemplo, o que aconteceria se um arquivo fosse transferido de um computador a outro com ambos protocolos ?
- Abra um terminal e execute o seguinte comando para fazer o download de um arquivo a ser usado no experimento:
wget http://tele.sj.ifsc.edu.br/~tisemp/RES/ubuntu.iso
- Observe o tamanho do arquivo transferido ... ele deve ter exatamente 832569344 bytes (cerca de 832 MB). Você pode fazer isso com o comando ls -l ubuntu.iso, ou executando o gerenciador de arquivos e visualizando as propriedades desse arquivo.
- Escolha um colega para fazer o experimento, em que o arquivo será transferido de um computador para o outro.
- A primeira transferência será feita usando o protocolo TCP da seguinte forma:
- No computador receptor execute:
- No computador transmissor execute (X é o número do seu computador, visível em sua etiqueta):
time nc 192.168.1.X 5555 < ubuntu.iso
- Quando completar a transferência, verifique o tamanho do arquivo recebido. Ele é igual ao arquivo original? E quanto tempo levou para transmiti-lo ?
- A segunda transferência será feita usando o protocolo UDP:
- No computador receptor faça o download deste programa. Em seguida acrescente a ele permissão de execução (chmod +x receptor).
- No computador receptor execute:
./receptor 5555 > arquivo
- No computador transmissor faça o download deste programa. Em seguida acrescente a ele permissão de execução (chmod +x transmissor).
- No computador transmissor execute (X é o número do seu computador, visível em sua etiqueta):
./transmissor 192.168.1.X 5555 < ubuntu.iso
- Quando completar a transferência, verifique o tamanho do arquivo recebido. Ele é igual ao arquivo original ? E quanto tempo levou para transmiti-lo ?
- Compare as transferências feitas com TCP e UDP. O que eles têm em comum ? Que diferenças lhe pareceram mais pronunciadas ? Como isso deve afetar as aplicações que usam esses protocolos ?
Experimento 2
Transferências usando cada um desses protocolos podem apresentar características bem distintas. Neste segundo experimento, serão feitas transferências simultâneas de arquivos a partir de um mesmo servidor, comparando-se o resultado obtido com TCP e UDP. Essas transferência ocorrerão entre os computadores do laboratório e um servidor externo ao laboratório, como mostrado na figura abaixo:
- Abra um terminal em seu computador, e nele execute este comando:
wget http://tele.sj.ifsc.edu.br/~tisemp/RES/ubuntu.iso
- Observe a taxa de transferência (velocidade do download) obtida. Que valores ela apresenta ? Quanto tempo levou para o arquivo ser transferido ?
- Após todos terem copiado o arquivo, o professor irá se logar em um dos computadores do laboratório e repetir a transferência. Porém desta vez ele irá fazê-la sozinho. Que taxas ele obteve, e quanto tempo levou ?
- O professor irá repetir a transferência novamente, mas desta vez ele irá pedir que um aluno também a inicie logo em seguida. Qual foi a taxa obtida por ambos ?
- Finalmente, o professor irá repetir a transferência porém com mais dois alunos fazendo-a ao mesmo tempo. Que se pode concluir quanto a taxa de transferência obtida ?
- Para poder fazer uma comparação, as transferências serão feitas novamente porém usando UDP como protocolo de transporte. Para isso siga estes passos:
- Abra dois terminais. Em um deles execute este comando: ... e no outro execute:
./receptor 5555 > arquivo
- Como se comparam as transferências usando TCP e UDP?
Unidade 3 - Introdução a linguagem VHDL e Quartus/ModelSim
Unidade 3 - Introdução a linguagem VHDL e Quartus/ModelSim
|
- Encontro 16 (21 set) - Linguagem VHDL
- Encontro 17 (26 set) - Avaliação A1b
- Encontro 18 (28 set) - Linguagem VHDL (cont)
- Declaração das bibliotecas e pacotes LIBRARY / PACKAGE
library library_name;
use library_name.package_name.all;
entity entity_name is
[generic (
cons_name1: const_type const_value;
cons_name2: const_type const_value;
...
cons_nameN: const_type const_value);]
[port (
signal_name1: mode signal_type;
signal_name2: mode signal_type;
...
signal_nameN: mode signal_type);]
[declarative_part]
[begin
statement_part]
end [entity] [entity_name];
architecture arch_name of entity_name is
[declarative_part]
begin
statement_part
end [architecture] [arch_name];
- Exemplo - Declaração de uma porta NAND em VHDL
library std;
use std.standard.all;
entity nand_gate is
port (a, b: in bit; x: out bit);
end entity;
architecture nome_arch of nand_gate is
begin
x <= a nand b;
end architecture;
- Uso do ambiente EDA - QUARTUS Prime para programação em VHDL.
- PASSO 0
Acesse a nuvem do IFSC usando um terminal via ssh:
USER=LOGIN_SIGAA
ssh $USER@quartus.sj.ifsc.edu.br -XC
Insira a senha do SIGAA
LOGIN_SIGAA@quartus.sj.ifsc.edu.br's password:
- PASSO 1
Abra o Quartus Prime digitando no terminal
quartus20.1.sh
Em seguida abra um arquivo para inserir o código VHDL. No menu superior selecione [File > New > Design Files: VHDL File] e [OK]
- PASSO 2
- Copie o código VHDL acima para o espaço de edição e salve o arquivo com o nome da entity: nand_gate.vhd, em um pasta exclusiva para este projeto.
- Ao ser perguntado se deseja criar um novo projeto, responda [Yes]. Os próximos passos podem ser realizados da seguinte forma:
- Na tela Introduction [Next >]
- Na tela Directory, Name, Top-Level Entity
- Note onde o projeto será salvo.
/home/USER/PASTA_DO_PROJETO/
- Note o nome do projeto. Se quiser pode mudá-lo
nand_gate
- Note o nome da top-level design entity
nand_gate
- Na tela Project Type [Next >]
- Na tela Add Files [Next >], pois seu arquivo já está na lista dos arquivos.
- Na tela Family, Device & Board Settings, escolha a Family = [Cyclone IV E] e o Device = [EP4CE6E22A7] e [Next >]
- Na tela EDA Tool Setting [Next >]
- Note na tela Summary os dados do projeto e clique [Finish]
- PASSO 3
Realize a Analysis & Synthesis [Processing > Start > Start Analysis & Synthesis], ou use um dos botões que o professor mostrou em aula.
- Note o Compilation Report
- PASSO 4
- Use o RTL Viewer para ver a descrição RTL do circuito. Selecione [Tools > Netlist Vieweres > RTL Viewer].
- Use o Technology Map Viewer para ver a como o circuito foi mapeado para os elementos lógicos disponíveis no dispositivo FPGA selecionado. Selecione [Tools > Netlist Vieweres > Technology Map Viewer].
- PASSO 5
- Modifique a descrição do circuito para implementar o circuito da função Y = (A.B)' + C.D'B', salve o projeto Ckt2.vhd e de o mesmo nome para a entity.
- Encontro 19 (3 out.) - Simulador ModelSim
- Abra o circuito que foi salvo na aula anterior. Após abrir o Quartus, clique em [File > Open Project] e selecione a pasta onde salvou o projeto. Depois clique sobre o arquivo nand_gate.qpf. Note que abrir um projeto é diferente de abrir um arquivo, pois todos os arquivos de configuração estão associados a esse .qpf.
- Encontro 20 (5 out.)
- Avaliação A1c - Simplificação de expressões lógicas:
- Encontro 21 (10 out.)
- Escreva o código VHDL e faça a simulação para o circuito correspondente a expressão lógica:
Y = AB + AC'
Z = A'BC + C'
|
Unidade 3 - Circuitos lógicos combinacionais
Unidade 3 - Circuitos lógicos combinacionais
|
- Encontro 22, 23 (17 e 20 out.)
- Encontro 24 (24 out.)
- Conhecer o Código Gray
- Implementação de conversor Binário para Gray (bin2gray)
-------------------------
-- File: bin2gray_v1.vhd --
-------------------------
entity bin2gray_v1 is
port
(
b0, b1, b2, b3 : in bit;
g0, g1, g2, g3 : in bit
);
end entity;
--Exemplo implementando o circuito diretamente com as portas lógicas
architecture ifsc_v1 of ____ is
begin
end architecture;
Como o circuito de um conversor bin2gray, possui uma certa quantidade de bits de entrada e a mesma quantidade de saída, não é adequado descrever esse circuito utilizando o tipo bit. O VHDL dispõe do tipo bit_vector; de vetores para descrever esse tipo de entrada e saída.
-------------------------
-- File: bin2gray_v2.vhd --
-------------------------
entity bin2gray_v2 is
port
(
b : in bit_vector(3 downto 0);
g : out bit_vector(3 downto 0)
);
end entity;
--Exemplo implementando o circuito diretamente com as portas lógicas
architecture ifsc_v2 of ____ is
begin
end architecture;
Caso se deseje aumentar o número de bits da entrada, na abordagem acima é necessário aumentar o número de operações ou exclusivo, e para cada quantidade de bits é necessário ter uma nova descrição. Usando corretamente a instrução generic, e a instrução for generate, é possível escrever um código único (genérico) para qualquer numero de bits.
- O GENERIC permite parametrizar um circuito, definindo os valores que se deseja alterar em um circuito em diferentes soluções. Um exemplo comum é alterar o número de bits das entradas e saídas do circuito. Essa instrução é declarada na ENTITY, antes da declaração das PORT.
[generic (
cons_name1: const_type const_value;
cons_name2: const_type const_value;
...
cons_nameN: const_type const_value);]
- Uso da instrução FOR-GENERATE
label: FOR identificador IN faixa GENERATE
[Parte_Declarativa
BEGIN]
Instruções_concorrentes
...
END GENERATE [label];
-------------------------
-- File: bin2gray_v3.vhd --
-------------------------
entity bin2gray_v3 is
generic (N : natural := 4 );
port
(
b : in bit_vector(N-1 downto 0);
g : out bit_vector(N-1 downto 0)
);
end entity;
architecture ifsc_v3 of ____ is
begin
end architecture;
- Após cada implementação analise o diagrama RTL e verifique se as 3 soluções apresentadas resultam no mesmo circuito.
- Efetua a simulação com o Modelsim para verificar se as entradas em código binário sequêncial de "0000" até "1111" resultam corretamente nas saídas em Código Gray.
- Verifique se a versão bin2gray_v3 pode ser alterada para 10 bits e continua gerando o circuito correto.
- Descubra quantas portas ou exclusivo seriam necessárias para o caso de N bits.
- DESAFIO: Implementação de conversor Gray para Binário (gray2bin)
Considerando o que aprendeu com as duas versões do conversor bin2gray, descreva o circuito do conversor gray2bin.
-------------------------
-- File: gray2bin.vhd --
-------------------------
entity gray2bin is
generic (N : natural := 4 )
port
(
g : in std_logic_vector(____)
b : out std_logic_vector(____)
)
end entity
architecture ifsc_v1 of ____ is
begin
end architecture
architecture ifsc_v2 of ____ is
begin
end architecture
- Encontro 25 e 26 (26 e 31 out.)
- Conhecer o multiplexador digital.
Um multiplexador digital de N entradas e 1 saída, frequentemente abreviado como MUX N:1, é um circuito digital muito utilizado para rotear sinais digitais Ele desempenha a função de selecionar uma das entradas para ser encaminhada para a saída com base em um sinal de seleção (ou controle).
A tabela verdade que descreve um MUX2:1 é mostrada abaixo:
X1
|
X0
|
Sel
|
Y
|
0
|
0
|
0
|
0
|
0
|
0
|
1
|
0
|
0
|
1
|
0
|
1
|
0
|
1
|
1
|
0
|
1
|
0
|
0
|
0
|
1
|
0
|
1
|
1
|
1
|
1
|
0
|
1
|
1
|
1
|
1
|
1
|
O MUX2:1 também pode ser representado de forma resumida por:
X1
|
X0
|
Sel
|
Y
|
-
|
X0
|
0
|
X0
|
X1
|
-
|
1
|
X1
|
Onde o X0 e X1 na entrada podem assumir os valores 0 ou 1, e o simbolo "-" corresponde ao don't care (em VDHL)
A função booleana que descreve a operação de um MUX 2:1 pode ser representada da seguinte forma:
Onde Y é a saída; Sel é o sinal de seleção; X0 e X1 são as entradas.
O MUX4:1 pode ser representado de forma resumida pela tabela verdade:
Entradas
|
Seleção
|
Saída
|
X3
|
X2
|
X1
|
X0
|
Sel1
|
Sel0
|
Y
|
-
|
-
|
-
|
X0
|
0
|
0
|
X0
|
-
|
-
|
X1
|
-
|
0
|
1
|
X1
|
-
|
X2
|
-
|
-
|
1
|
0
|
X2
|
X3
|
-
|
-
|
-
|
1
|
1
|
X3
|
A função booleana que descreve a operação de um MUX 4:1 pode ser representada da seguinte forma:
Dada a função booleana do MUX4:1 é simples para descreve-lo em VHDL utilizando apenas operadores lógicos.
entity mux4x1 is
port
(
-- Input ports
X: in bit_vector (3 downto 0);
Sel : in bit_vector (1 downto 0);
-- Output ports
Y : out bit
);
end entity;
-- Implementação com lógica pura
architecture v_logica_pura of mux4x1 is
begin
Y <= (X(0) and (not Sel(1)) and (not Sel(0))) or
...
end architecture;
No entanto, o MUX4:1 também pode ser descrito utilizando a instrução WHEN-ELSE
<optional_label>: <target> <=
<value> when <condition> else
<value> when <condition> else
<value> when <condition> else
...
<value>;
- Importante: O último ELSE deve cobrir todos os demais valores para evitar a criação de LATCHES.
Warning (13012): Latch ... has unsafe behavior
- No QuartusII existe um template pronto para ser utilizado em: [Edit > Insert Template > Language templates = VHDL (+) > Constructs (+) > Concurrent Statemens (+) > Conditional Signal Assignment]
No caso do MUX4:1 ele poderia ser descrito como:
-- Implementação com WHEN ELSE
architecture v_WHEN_ELSE of mux4x1 is
begin
Y <= X(0) when Sel = "00" else
X(1) when Sel = "01" else
X(2) when Sel = "10" else
X(3);
end architecture;
Outra forma de descrever o MUX4:1 seria utilizando a instrução WITH-SELECT
<optional_label>: with <expression> select
<target> <=
<value> when <choices>,
<value> when <choices>,
<value> when <choices>,
...
<value> when others;
- Importante: Para cobrir todas as demais possibilidades deve ser utilizado o WHEN OTHERS evitando novamente a criação de LATCHES, ou erros de análise.
Error (10313): VHDL Case Statement error ...: Case Statement choices must cover all possible values of expression
- No QuartusII existe um template pronto para ser utilizado em: [Edit > Insert Template > Language templates = VHDL (+) > Constructs (+) > Concurrent Statemens (+) > Selected Signal Assignment]. Mas ATENÇÃO, faltam as virgulas após cada escolha.
-- Implementação com WITH SELECT
architecture v_WITH_SELECT of mux4x1 is
begin
with Sel select
Y <= X(0) when "00", -- note o uso da ,
X(1) when "01",
X(2) when "10",
X(3) when others; -- note o uso de others, para todos os demais valores.
-- Não pode ser substituido por "11" mesmo que o signal seja bit_vector.
end architecture;
- Note que para associar uma entre várias arquiteturas com a sua ENTITY pode-se utilizar a instrução CONFIGURATION. No exemplo abaixo a ARCHITECTURE que está descomentada é a que será associada a ENTITY mux4x1.
- Caso não se use a instrução CONFIGURATION, a última ARCHITECTURE será associada a ENTITY.
- Apesar de apenas uma das ARCHITECTUREs ser associada, todas elas devem estar sintaticamente corretas, pois passarão pelo processo de ANÁLISE E SINTESE.
-- Design Unit que associa a architecture com a entity
configuration cfg_ifsc of mux4x1 is
for v_logica_pura end for;
-- for v_WHEN_ELSE end for;
-- for v_WITH_SELECT end for;
end configuration;
- Faça a análise e sintese do mux4x1, associando a architecture v_logica_pura, depois v_WITH_SELECT, depois v_WHEN e por último v_IF_ELSE.
- Note a diferença entre os RTL Viewer obtidos para cada architecture.
Figura 2.1 - Código RTL do mux4x1 v_logica_pura
Fonte: Elaborado pelo autor.
Figura 2.2 - Código RTL do mux4x1 v_WHEN_ELSE
Fonte: Elaborado pelo autor.
Figura 2.3 - Código RTL do mux4x1 v_WITH_SELECT
Fonte: Elaborado pelo autor.
- OBS: Register Transfer-Level (RTL) é uma abstração na qual o circuito é descrito em termos de fluxo de sinais entre os registradores presentes no hardware e as operações combinacionais realizadas com esses dados.
- Note a que ao verificar o Technology Map Viewer, nos 3 primeiros casos serão usados os mesmos elementos lógicos.
Figura 2.4 - Technology Map do mux4x1 para a família Cyclone
Fonte: Elaborado pelo autor.
- Note que o elemento lógico acima possui uma LUT (LookUp Table) que basicamente implementa o circuito combinacional através de uma tabela de consulta (Tabela Verdade), a qual pode ser visualizada clicando com o botão Direito do Mouse e selecionando Properties, juntamente com Mapa de Karnaugh e seu Circuito Lógico representado por portas. Todas as representações são equivalentes.
Figura 2.5 - Elemento Lógico usado no mux4x1 para a família Cyclone (node properties)
Fonte: Elaborado pelo autor.
- Dependendo da família de FPGA que se estiver usando, o compilador implementar o circuito descrito com um número diferente de elementos lógicos (LEs). No caso da família Cyclone, na qual a LUT tem 4 entradas, são necessários 2 LEs para mapear uma lógica combinacional com 6 entradas e 1 saída (Mux4x1).
No entanto se utilizarmos um dispositivo FPGA da família Aria 10, que tem LUT tem 6 entradas, será necessário apenas 1 LE, conforme ilustrado a seguir.
Figura 2.5 - Technology Map do mux4x1 para a família Aria 10
Fonte: Elaborado pelo autor.
- Realize a simulação das 3 arquiteturas do MUX4:1 no Modelsim
- Crie um arquivo tb_mux4x1_v1.do que repita a simulação da arquitetura v1
- Crie um arquivo tb_mux4x1_v2.do que repita a simulação da arquitetura v2
- Crie um arquivo tb_mux4x1_v3.do que repita a simulação da arquitetura v1
- Inclua todos os arquivos .do no projeto do Quartus e salve o arquivo QAR
- Encontro 27 e 28 (ANP e 7 nov.)
- Encontro 29 (9 nov.)
- Encontro 30 (14 nov.)
- Decodificador de 4 endereços [3]
- Implementar em VHDL usando with-select e portas lógicas
- Implementar a implementar em VHDL de um decodificador de 32 endereços
- Encontro 31 e 32 (16 e 21 nov.)
- Demultiplexador de 1 para 4 [4]
- Implementar a implementar em VHDL
- Demultiplexador com enable. [5]
- Implementar a implementar em VHDL
- NOTA
- No dia 16 nov. ocorreram fortes chuvas na grande Florianópolis, e em virtude disso muitos alunos não puderam comparecer. As 8h50 faltou energia no campus e as aulas foram suspensas.
- Encontro 33 (23 nov.)
- Comentários no código (duplo traço --)
-- Isso eh uma linha de comentario
y <= a * b ; --o sinal y recebe o resultado da multiplicacao a x b
- Representação de caracteres, strings e números em VHDL. No circuito, os caracteres são representados através de bits de acordo com a tabela ASCII básica (00 a 7F). A definição dessa tabela é feita o pacote standard.vhd da biblioteca std.
- Caracteres (entre aspas simples)
caracter: 'A' 'x' '#' (com aspas simples)
- Palavras (entre aspas duplas), é definida no VHDL como um vetor de caracteres.
type string is array (positive range <>) of character;
string: "IFSC" "teste" "teste123"
elemento ("bit") único: '0' '1' 'Z' (entre aspas simples)
vetor de elementos ("bits"): "0110" "101001Z" (entre aspas duplas)
vetor de 1 elemento ("bit"): "0" "1" (entre aspas duplas)
inteiros: 5 1101 1102 (sem aspas)
0 -> '0'
7 (em base 2) -> "0111" ou b"0111" ou B"0111"
1023 (em base 2) -> "001111111111" ou b"1111111111" ou B"1111111111"
44 (em base 8) -> 5*8^1 + 4*8^0 -> O"54" ou o"54"
1023 (em base 8)-> 1*8^3 + 7*8^2 + 7*8^1 + 7*8^0 -> o"1777" 8#1777#
1023 (em base 16) -> 3*16^2 + 15*16^1 + 15*16^0 = X"3FF" ou x"3FF" 16#3FF#
1023 -> 1023 ou 1_023
1000 -> 1000 ou 1_000 ou 1E3 ou 10#1000#
- Cuidado ao usar o "_" pois algumas ferramentas não o reconhecem.
- Números em outras bases (de 2 a 16)
85 (em base 5) -> (3*5^2 + 2*5^1 + 0*5^0) -> 5#320#
1539 (em base 3) -> (2*3^2+0*3^1+1*3^0)*3^4 -> 3#201#E4
- Objetos de VHDL: CONSTANT, SIGNAL, VARIABLE, FILE.
O objeto CONSTANT pode ser declarado na parte declarativa da ENTITY, ARCHITECTURE, PACKAGE, PACKAGE_BODY, BLOCK, GENERATE, PROCESS, FUNCTION e PROCEDURE.
constant <constant_name> : <type> := <constant_value>;
-- Declarações comuns de constantes
constant GND : std_logic := '0';
constant VCC : std_logic := '1';
constant SSD_0 : std_logic_vector(0 to 6) := "1111110";
constant MAX : natural := 44;
O objeto SIGNAL pode ser declarado na parte declarativa da ENTITY, ARCHITECTURE, PACKAGE, BLOCK, GENERATE. Os sinais não podem ser declarados no código sequencial (PROCESS, FUNCTION e PROCEDURE), mas podem ser usados.
-- Signal sem valor default
-- Para atribuir um valor a um signal use "<=" como operador.
signal <name> : <type>;
-- Signal com valor default
signal <name> : <type> := <default_value>;
-- Declarações comuns de signals
signal <name> : std_logic;
signal <name> : std_logic_vector(<msb_index> downto <lsb_index>);
signal <name> : integer;
signal <name> : integer range <low> to <high>;
O objeto VARIABLE (variável) só pode ser declarada e usada dentro do escopo no código sequencial (PROCESS, FUNCTION e PROCEDURE).
-- Variables devem ser declarada em process ou subprogramas.
-- Para atribuir um valor a um variable use ":=" como operador.
-- Variable sem valor default.
variable <name> : <type>;
-- Variable com valor default.
variable <name> : <type> := <default_value>;
-- Declarações comuns de variables
variable <name> : std_logic;
variable <name> : std_logic_vector(<msb_index> downto <lsb_index>);
variable <name> : integer;
variable <name> : integer range <low> to <high>;
- Palavra chave OTHERS para formação de agregados
Exemplos de declaração de CONSTANT, SIGNAL, VARIABLE, inicializando o valor usando o agregados
CONSTANT a: BIT_VECTOR(5 DOWNTO 0) := (OTHERS => '0'); -- "000000"
CONSTANT b: BIT_VECTOR(7 DOWNTO 0) := (7 => '0', OTHERS => '1'); -- "01111111"
CONSTANT c: BIT_VECTOR(7 DOWNTO 0) := (7 => '0', 6 DOWNTO 0 => '1'); -- "01111111"
CONSTANT d: BIT_VECTOR(7 DOWNTO 0) := "01111111";
SIGNAL e: STD_LOGIC_VECTOR(7 DOWNTO 0); -- Not initialized
SIGNAL f: STD_LOGIC_VECTOR(1 TO 8) := (2|3|8 => '1', 4 => 'Z', OTHERS => '0' ); -- "011Z0001"
VARIABLE g: BIT_VECTOR(1 TO 16); -- Not initialized
VARIABLE h: BIT_VECTOR(1 TO 16) := (1 TO 8 => '1', OTHERS => '0'); -- "1111111100000000"
- Ver pag. 31 a 35 de [1]
-
- ATENÇÃO!!! Não use as bibliotecas que não são padrão (std_logic_arith, std_logic_unsigned, std_logic_signed)
- Classificação dos tipos de dados.
A biblioteca standard.vhd define os tipos BIT, BIT_VECTOR, BOOLEAN, INTEGER, NATURAL, POSITIVE, CHARACTER, STRING.
package standard is
type boolean is (false,true);
type bit is ('0', '1');
type severity_level is (note, warning, error, failure);
type integer is range -2147483647 to 2147483647;
type real is range -1.0E308 to 1.0E308;
type time is range -2147483648 to 2147483647
units
fs;
ps = 1000 fs;
ns = 1000 ps;
us = 1000 ns;
ms = 1000 us;
sec = 1000 ms;
min = 60 sec;
hr = 60 min;
end units;
subtype natural is integer range 0 to integer'high;
subtype positive is integer range 1 to integer'high;
type string is array (positive range <>) of character;
type bit_vector is array (natural range <>) of bit;
A biblioteca Std logic 1164.vhd define os tipos STD_(U)LOGIG, STD_(U)LOGIG_VECTOR.
PACKAGE std_logic_1164 IS
TYPE std_ulogic IS ( 'U', -- Uninitialized
'X', -- Forcing Unknown
'0', -- Forcing 0
'1', -- Forcing 1
'Z', -- High Impedance
'W', -- Weak Unknown
'L', -- Weak 0
'H', -- Weak 1
'-' -- Don't care
);
TYPE std_ulogic_vector IS ARRAY ( NATURAL RANGE <> ) OF std_ulogic;
SUBTYPE std_logic IS resolved std_ulogic;
TYPE std_logic_vector IS ARRAY ( NATURAL RANGE <>) OF std_logic;
A biblioteca Std logic 1164.vhd ainda define algumas funções importantes como a rising_edge que determina se um sinal está na borda de subida (usado em sinais de clock).
-------------------------------------------------------------------
-- conversion functions
-------------------------------------------------------------------
FUNCTION To_bit ( s : std_ulogic; xmap : BIT := '0') RETURN BIT;
FUNCTION To_bitvector ( s : std_logic_vector ; xmap : BIT := '0') RETURN BIT_VECTOR;
FUNCTION To_StdULogic ( b : BIT ) RETURN std_ulogic;
FUNCTION To_StdLogicVector ( b : BIT_VECTOR ) RETURN std_logic_vector;
-------------------------------------------------------------------
-- edge detection
-------------------------------------------------------------------
FUNCTION rising_edge (SIGNAL s : std_ulogic) RETURN BOOLEAN;
FUNCTION falling_edge (SIGNAL s : std_ulogic) RETURN BOOLEAN;
-------------------------------------------------------------------
-- edge detection
-------------------------------------------------------------------
FUNCTION rising_edge (SIGNAL s : std_ulogic) RETURN BOOLEAN IS
-- altera built_in builtin_rising_edge
BEGIN
RETURN (s'EVENT AND (To_X01(s) = '1') AND
(To_X01(s'LAST_VALUE) = '0'));
END;
A biblioteca Numeric std.vhd define os tipos UNSIGNED e SIGNED.
package NUMERIC_STD is
type UNSIGNED is array (NATURAL range <>) of STD_LOGIC;
type SIGNED is array (NATURAL range <>) of STD_LOGIC;
A biblioteca Numeric std.vhd ainda define os operadores (abs, "+", "-", "*", "/", rem, mod, sll, slr, ror, rol), comparações ("=", '/=', ">", ">=", "<", "<=") e operadores lógicos (not, and, nand, or, nor, xor, xnor) para os tipos SIGNED e UNSIGNED. Além disso também define algumas funções muito utilizadas como:
--============================================================================
-- RESIZE Functions
--============================================================================
function RESIZE (ARG: SIGNED; NEW_SIZE: NATURAL) return SIGNED;
function RESIZE (ARG: UNSIGNED; NEW_SIZE: NATURAL) return UNSIGNED;
--============================================================================
-- Conversion Functions
--============================================================================
function TO_INTEGER (ARG: UNSIGNED) return NATURAL;
function TO_INTEGER (ARG: SIGNED) return INTEGER;
function TO_UNSIGNED (ARG, SIZE: NATURAL) return UNSIGNED;
function TO_SIGNED (ARG: INTEGER; SIZE: NATURAL) return SIGNED;
- Ver pag. 73 a 78 de [1]
- Resumo dos Tipos predefinidos.
Tipo de Dado
|
Package
|
Library
|
Valores
|
Observações
|
BOOLEAN |
standard |
std |
TRUE e FALSE |
sintetizável
|
BIT |
standard |
std |
valores '0', '1' |
sintetizável
|
INTEGER |
standard |
std |
números inteiros de 32 bits [de -2^31-1 até + (2^31 - 1)] |
sintetizável
|
NATURAL |
standard |
std |
números inteiros não negativos [de 0 até + (2^31 - 1)] |
sintetizável
|
POSITIVE |
standard |
std |
números inteiros positivos [de 1 até + (2^31 - 1)] |
sintetizável
|
BOOLEAN_VECTOR |
standard (2008) |
std |
vetor de BOOLEAN |
sintetizável
|
BIT_VECTOR |
standard |
std |
vetor de BIT |
sintetizável
|
INTEGER_VECTOR |
standard (2008) |
std |
vetor de INTEGER |
sintetizável
|
REAL |
standard |
std |
números reais [de -1.0E-38 até + 1.0E38] |
simulação
|
CHARACTER |
standard |
std |
caracteres ASCII |
|
STRING |
standard |
std |
vetor de CHARACTER |
|
Tipo de Dado
|
Package
|
Library
|
Valores
|
Observações
|
STD_LOGIC |
std_logic_1164 |
ieee |
valores 'U', 'X', '0', '1', 'Z', 'W', 'L', 'H', '-' |
sintetizável
|
STD_LOGIC_VECTOR |
std_logic_1164 |
ieee |
vetor de STD_LOGIC |
sintetizável
|
SIGNED |
numeric_std |
ieee |
STD_LOGIC_VECTOR que aceitam operações aritméticas com sinal |
sintetizável
|
UNSIGNED |
numeric_std |
ieee |
STD_LOGIC_VECTOR que aceitam operações aritméticas sem sinal |
sintetizável
|
SIGNED |
numeric_bit |
ieee |
BIT_VECTOR que aceitam operações aritméticas com sinal |
sintetizável
|
UNSIGNED |
numeric_bit |
ieee |
BIT_VECTOR que aceitam operações aritméticas sem sinal |
sintetizável
|
SIGNED |
std_logic_arith |
ieee |
STD_LOGIC_VECTOR que aceitam operações aritméticas com sinal |
sintetizável (não é padrão, não utilizar)
|
UNSIGNED |
std_logic_arith |
ieee |
STD_LOGIC_VECTOR que aceitam operações aritméticas sem sinal |
sintetizável (não é padrão, não utilizar)
|
UFIXED |
fixed_pkg + (2008) |
ieee |
números de ponto fixo sem sinal |
sintetizável
|
SFIXED |
fixed_pkg + (2008) |
ieee |
números de ponto fixo com sinal |
sintetizável
|
FLOAT |
float_pkg + (2008) |
ieee |
Números de ponto flutuante |
sintetizável
|
- Exemplo: Buffer Tri-state
library ieee;
use ieee.std_logic_1164.all;
entity tri_state is
generic (N: NATURAL := 1);
port
(
input : in std_logic_vector(N-1 downto 0);
ena : in std_logic;
output : out std_logic_vector(N-1 downto 0);
);
end entity;
architecture tri_state of tri_state is
begin
output <= input when ena = '1' else "Z";
end architecture;
- Importante: O terceiro estado 'Z' só pode ser usado em saídas, e a sua realização nos FPGAs só ocorre nos nós de I/O.
- Curiosidade
- Existem circuitos comerciais que implementam essa função three-state 16 buffers, 8 buffers, 1 buffer. Porque não utilizar um CPLD ou FPGA em seu lugar?
- Exemplo de aplicação
- Demultiplexador com saída em 3-state. [7]
- Baseado no Demultiplexador com enable, implemente ele com 3-state. Se o circuito não estiver habilitado, as saídas devem ficar em 3-state.
- Para implementar em VHDL será necessário utilizar o tipo de dado std_logic ou std_logic_vector
|
Unidade 4 - Circuitos aritméticos
Unidade 4 - Circuitos aritméticos
|
- Encontro 34 (28 nov.)
- Circuitos aritméticos: somadores, incrementador, decrementador, complemento de dois, multiplicador, comparadores
- Encontro 35 (30 nov.)
- Ver slides [10]
- Ver pag. XXX a XXX de [2]
ANTERIOR
- Encontro 36 (05 dez.)
Para implementar circuitos aritméticos, ao invés de se descrever o circuito com portas lógicas conforme mostrado para somadores, subtratores, comparadores e multiplicadores, deve-se utilizar os operadores aritméticos, e o compilador realizará a escolha do melhor circuito para cada caso. Inicialmente apresentamos alguns exemplos utilizando dados do tipo integer.
Para o uso do tipo integer, se não houver limitação da faixa de valores, o compilador entenderá que os sinais devem ter 32 bits, o que gera circuitos muito maiores que normalmente necessário. Assim, ao usar as entradas e saidas como integer sem range, o diagrama RTL mostrará que o circuito foi construido com 32 bits [31..0]. Nos dispositivos da familia Cyclone IV E serão utilizados 32 elementos lógicos para tal circuito.
entity somador is
port (
a, b : in integer;
s : out integer;
end entity;
architecture ifsc of somador is
begin
s <= a + b;
end architecture;
Figura 4.1 - Código RTL do somador com tipo integer sem range
Fonte: Elaborado pelo autor.
Figura 4.2 - Technology Map do somador com tipo integer sem range
Fonte: Elaborado pelo autor.
Por isso, o uso correto do tipo integer, exige que se limite a faixa de valores (range 0 to 15), o que fará com que o compilador atribua para os sinais a quantidade correta de bits, gerando circuitos de tamanho adequado.
Assim, ao usar as entradas e saidas como integer com range 0 to 15, o diagrama RTL mostrará que o circuito foi construido com 4 bits [3..0]. Nos dispositivos da familia Cyclone IV E serão utilizados 4 elementos lógicos para tal circuito.
entity somador is
port (
a, b : in integer range 0 to 15;
s : out integer range 0 to 15);
end entity;
architecture ifsc of somador is
begin
s <= a + b;
end architecture;
Figura 4.3 - Código RTL do somador com tipo integer com range
Fonte: Elaborado pelo autor.
Figura 4.4 - Technology Map do somador com tipo integer com range
Fonte: Elaborado pelo autor.
Para fazer uma subtração, basta trocar o operador "+" pelo "-", e o compilador irá implementar um subtrator realizando o complemento 2 da entrada b.
entity subtrator is
port (
a, b : in integer range 0 to 15;
s : out integer range 0 to 15);
end entity;
architecture ifsc of subtrator is
begin
s <= a - b;
end architecture;
Figura 4.5 - Código RTL do subtrator com tipo integer com range
Fonte: Elaborado pelo autor.
Note nesta figura que as entradas b[3..0] são conectadas ao B[4..1] do somador, e que o B[0] é conectado ao Vcc ("1"). O mesmo ocorre com a entrada A. Ao mesmo tempo a entrada b é invertida, gerando assim o complemento de dois dessa entrada. Assim para realizar uma subtração pode ser utilizado o mesmo circuito do somador.
Para fazer uma multiplicação, basta usar o operador "*"e o compilador irá implementar um multiplicador. Neste caso para evitar o overflow é importante definir o range da saída com um tamanho suficiente para comportar o maior produto
entity multiplicador is
port (
a, b : in integer range 0 to 15;
s : out integer range 0 to 15*15);
end entity;
architecture ifsc of multiplicador is
begin
s <= a * b;
end architecture;
Figura 4.6 - Código RTL do multiplicador com tipo integer com range
Fonte: Elaborado pelo autor.
Note que esse circuito no Cyclone IV E necessita de 31 elementos lógicos, e no caso em que multiplicador tem entradas com 4 bits [3..0], a saída terá 8 bits [7..0]
Caso a saída não tenha a quantidade suficiente de bits, haverá overflow e a resultado poderá estar incorreto.
Caso se esqueça de limitar o range dos sinais de entrada, o compilador novamente assumirá que devem ser usada a faixa inteira dos inteiros (32 bis).
Figura 4.7 - Código RTL do multiplicador com tipo integer sem range
Fonte: Elaborado pelo autor.
Note que esse circuito no Cyclone IV E aparentemente utiliza apenas 28 elementos lógicos, mas é importante observar que ele utiliza 6 dispositivo DSP (multiplicador de bits), os quais estão disponíveis dentro do FPGA. Se desativar o uso dos multiplicadores internos, forçando o uso dos elementos lógicos o total de elementos lógicos passará para 592, mostrando o desperdício de hardware que pode ocorrer.
Para forçar o uso de elementos lógicos no lugar dos DSP realize a seguinte sequencia: Assignments > Settings > Compiler Settings > [Advanced Settings (Synthesis)] > Filter = DSP > DSP Block Balancing = Logic Elements > [OK]
Detalhando a sequencia
|
- No menu, vá para "Assignments" e depois escolha "Settings".
- Na janela "Settings", clique em "Compiler Settings". Em seguida, clique em "Advanced Settings (Synthesis)".
- Digite em Filter = DSP e na opção "DSP Block Balancing" configure com "Logic Elements" para forçar o uso dos elementos lógicos no lugar dos DSPs.
- Depois clique em "OK" para aplicar as alterações.
|
Para fazer uma divisão, basta usar o operador "/" e o compilador irá implementar um divisor inteiro. O tamanho do quociente deve ser igual ao dividendo.
entity divisor is
port (
dividendo : in integer range 0 to 15;
divisor : in integer range 0 to 3;
quociente : out integer range 0 to 15;
resto : out integer range 0 to 3
);
end entity;
architecture ifsc of divisor is
begin
quociente <= dividendo / divisor;
resto <= dividendo rem divisor;
end architecture;
Figura 4.8 - Código RTL do divisor com tipo integer com range
Fonte: Elaborado pelo autor.
Multiplicações e divisões por potências de 2 (2, 4, 8, 16, ... $2^N$) não necessitam de nenhum elemento lógico pois podem ser implementados pelo simples deslocamento dos signais.
Figura 4.8 - Código RTL do multiplicador por 4
Fonte: Elaborado pelo autor.
Figura 4.9 - Código RTL do divisor por 2
Fonte: Elaborado pelo autor.
Multiplicações por constantes não precisam utilizar os multiplicadores, e são implementadas através de simples deslocamentos de sinais e somas. Assim multiplicar por 10 corresponde a multiplicar por 2 somar com a multiplicação por 8.
Figura 4.10 - Código RTL do multiplicador por 10
Fonte: Elaborado pelo autor.
ATUAL
- Encontro 37 (07 dez.)
package NUMERIC_STD is
type UNSIGNED is array (NATURAL range <>) of STD_LOGIC;
type SIGNED is array (NATURAL range <>) of STD_LOGIC;
A biblioteca Numeric std.vhd ainda define os operadores (abs, "+", "-", "*", "/", rem, mod, sll, slr, ror, rol), comparações ("=", '/=', ">", ">=", "<", "<=") e operadores lógicos (not, and, nand, or, nor, xor, xnor) para os tipos SIGNED e UNSIGNED. Além disso também define algumas funções muito utilizadas como:
--============================================================================
-- RESIZE Functions
--============================================================================
function RESIZE (ARG: SIGNED; NEW_SIZE: NATURAL) return SIGNED;
function RESIZE (ARG: UNSIGNED; NEW_SIZE: NATURAL) return UNSIGNED;
--============================================================================
-- Conversion Functions
--============================================================================
function TO_INTEGER (ARG: UNSIGNED) return NATURAL;
function TO_INTEGER (ARG: SIGNED) return INTEGER;
function TO_UNSIGNED (ARG, SIZE: NATURAL) return UNSIGNED;
function TO_SIGNED (ARG: INTEGER; SIZE: NATURAL) return SIGNED;
- Ver pag. 73 a 78 de [1]
FONTE: http://www.doulos.com/knowhow/vhdl_designers_guide/numeric_std/
- Exemplo 1
Fazer um circuito que detecte se existe alguma vaga vazia em um lote de 4 vagas. A entrada x(n) está baixo '0' se a vaga está vazia, e alto '1' se tem carro. A saída y estará alta '1' sempre que houver uma ou mais vagas vazias, e em baixo '0' se não houver nenhuma vaga.
Para fazer este circuito, podemos testar cada posição da entrada x e verificar se alguma delas está com '0', e neste caso mudar a saída para '1', caso contrário a saída será '0'.
Conforme veremos a seguir, é possível realizar diversas descrições em VHDL para esse circuito.
- Solução 1
Testar cada uma das entradas x e verificar se há alguma delas com '0', então indicar que a saída é '1', senão a saída será '0'.
library ieee;
use ieee.std_logic_1164.all;
entity vagas is
generic (N : natural := 4 );
port (
x : in std_logic_vector (N-1 downto 0);
y : out std_logic
);
end entity;
architecture ifsc_v1 of vagas is
begin
-- usando when-else
y <= '1' when x(0) = '0' else
'1' when x(1) = '0' else
'1' when x(2) = '0' else
'1' when x(3) = '0' else
'0';
end architecture;
Figura 4.12 - RTL do indicador de vagas com when-else
Fonte: Elaborado pelo autor.
Figura 4.13 - Technology Map do indicador de vagas
Fonte: Elaborado pelo autor.
Note neste Technology Map que para implementar esse circuito, o compilador deduziu que basta inverter as entradas X e realizar a operação OR sobre elas para determinar se tem ou não vagas.
Fazendo a simulação do circuito podemos perceber que ele está funcionando, pois a saída y está em '1' sempre quando existe alguma vaga x(i) = '0'. A única situação em que a saída y está em '0' é quando todas as entradas estão em '1' (todas vagas ocupadas).
Figura 4.14 - Simulação do indicador de vagas
Fonte: Elaborado pelo autor.
- Solução 2
Realizar uma operação ou sobre todas as entradas x invertidas.
architecture ifsc_v2 of vagas is
begin
-- usando or e not
y <= (not x(0)) or (not x(1)) or (not x(2)) or (not x(3));
end architecture;
Figura 4.15 - RTL do indicador de vagas com portas NOT e OR
Fonte: Elaborado pelo autor.
Note que o Technology Map e a simulação produzem o mesmo resultado, apesar da descrição do hardware ser complemente diferente.
Tanto na solução 1 como na 2, se tivermos mais vagas para verificar, será necessário alterar a descrição. Então para realizar uma descrição que seja genérica é necessário transformar essas soluções ou encontrar outras.
- Solução 3
Realizar uma operação ou sobre todas as entradas x invertidas. Para tornar genérico o código use o for generate para fazer a operação de NOT e OR sobre as entradas. A seguir é apresentado o esboço da ideia, e fica por conta do estudante implementar essa solução.
architecture ifsc_v3 of vagas is
signal tmp : std_logic_vector(N downto 0);
begin
tmp(0) <= '0'; -- inicializar tmp(0) com 0, pois nao afeta o resultado do OR.
-- use o for-generate para implementar de forma generica as seguintes linhas:
-- tmp(1) <= tmp(0) or (not x(0)); -- retorna 0 OR (not x0) => (not x0)
-- tmp(2) <= tmp(1) or (not x(1)); -- retorna (not x0) OR (not x1)
-- tmp(3) <= tmp(2) or (not x(2)); -- retorna (not x0) OR (not x1) OR (not x2)
--
-- tmp(i+1) <= tmp(i) or (not x(i));
-- ...
-- tmp(N) <= tmp(N-1) or (not x(N-1)); -- retorna (not x0) OR (not x1) ... OR (not xN)
y <= tmp(N); -- tmp(N) tem o resultado, precisa ser enviado para a saida y.
end architecture;
|
- Ver pag. 39 a 54 de [1]
- Encontro 38 (12 dez.)
- Avaliação A2 (Unidade 3 e 4, e VHDL).
|